blob: af95a159f9f7349b9e2e7d8ddc653139b7c147cd [file] [log] [blame]
[email protected]a1595312012-01-22 03:25:041// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]5af3c572010-07-20 14:16:272// Use of this source code is governed by a BSD-style license that can be
[email protected]aea80602009-09-18 00:55:083// found in the LICENSE file.
4
xunjieli179a6e72016-04-26 19:47:455#include <cmath>
dchengc7eeda422015-12-26 03:56:486#include <utility>
[email protected]a33cad2b62010-07-30 22:24:397#include <vector>
8
[email protected]49639fa2011-12-20 23:22:419#include "base/bind.h"
danakjdb9ae7942020-11-11 16:01:3510#include "base/callback_helpers.h"
Bence Békydb3cf652017-10-10 15:22:1011#include "base/compiler_specific.h"
thestigd8df0332014-09-04 06:33:2912#include "base/files/file_util.h"
[email protected]ea1a3f62012-11-16 20:34:2313#include "base/files/scoped_temp_dir.h"
[email protected]fc9d88472013-08-14 02:31:1714#include "base/run_loop.h"
Avi Drissman4365a4782018-12-28 19:26:2415#include "base/stl_util.h"
Bence Békyd74f4382018-02-20 18:26:1916#include "base/strings/string_piece.h"
Devlin Cronine4bcb40e2018-06-05 18:02:4717#include "base/test/metrics/histogram_tester.h"
Matt Menkef2ee07c2019-08-29 02:10:3618#include "base/test/scoped_feature_list.h"
[email protected]999dd8c2013-11-12 06:45:5419#include "base/test/test_file_util.h"
gabf767595f2016-05-11 18:50:3520#include "base/threading/thread_task_runner_handle.h"
Matt Menke5062be22019-05-01 17:50:2421#include "build/build_config.h"
[email protected]018aabc2010-10-29 16:16:5922#include "net/base/auth.h"
mmenkecbc2b712014-10-09 20:29:0723#include "net/base/chunked_upload_data_stream.h"
Bence Béky8ddc2492018-06-13 01:02:0424#include "net/base/completion_once_callback.h"
mmenkecbc2b712014-10-09 20:29:0725#include "net/base/elements_upload_data_stream.h"
Matt Menkef2ee07c2019-08-29 02:10:3626#include "net/base/features.h"
Tsuyoshi Horo01faed62019-02-20 22:11:3727#include "net/base/ip_endpoint.h"
Matt Menkef2ee07c2019-08-29 02:10:3628#include "net/base/network_isolation_key.h"
tbansal28e68f82016-02-04 02:56:1529#include "net/base/proxy_delegate.h"
Lily Houghton582d4622018-01-22 22:43:4030#include "net/base/proxy_server.h"
[email protected]262eec82013-03-19 21:01:3631#include "net/base/request_priority.h"
tbansal28e68f82016-02-04 02:56:1532#include "net/base/test_proxy_delegate.h"
[email protected]b2d26cfd2012-12-11 10:36:0633#include "net/base/upload_bytes_element_reader.h"
[email protected]b2d26cfd2012-12-11 10:36:0634#include "net/base/upload_file_element_reader.h"
Bence Béky1a5d8562018-01-05 17:29:2835#include "net/dns/mock_host_resolver.h"
aberentbba302d2015-12-03 10:20:1936#include "net/http/http_auth_scheme.h"
bnc3171a2432016-12-28 18:40:2637#include "net/http/http_network_session.h"
[email protected]87bfa3f2010-09-30 14:54:5638#include "net/http/http_network_session_peer.h"
[email protected]513963e2013-06-15 01:53:0439#include "net/http/http_network_transaction.h"
Matt Menke6e879bd2019-03-18 17:26:0440#include "net/http/http_proxy_connect_job.h"
Bence Béky3a0c48532018-03-02 13:38:5141#include "net/http/http_response_info.h"
[email protected]513963e2013-06-15 01:53:0442#include "net/http/http_server_properties.h"
[email protected]c41737d2014-05-14 07:47:1943#include "net/http/http_transaction_test_util.h"
Yoichi Osato4c75c0c2020-06-24 08:03:5744#include "net/http/test_upload_data_stream_not_allow_http1.h"
Matt Menkec74a9262020-06-09 15:49:2145#include "net/http/transport_security_state.h"
mikecirone8b85c432016-09-08 19:11:0046#include "net/log/net_log_event_type.h"
mikecironef22f9812016-10-04 03:40:1947#include "net/log/net_log_with_source.h"
mmenke16a7cbdd2015-04-24 23:00:5648#include "net/log/test_net_log.h"
mmenke43758e62015-05-04 21:09:4649#include "net/log/test_net_log_util.h"
Nicolas Arciniega8ec5bfa2020-03-20 05:07:2650#include "net/proxy_resolution/configured_proxy_resolution_service.h"
[email protected]bb88e1d32013-05-03 23:11:0751#include "net/socket/next_proto.h"
Paul Jensena457017a2018-01-19 23:52:0452#include "net/socket/socket_tag.h"
Bence Béky94658bf2018-05-11 19:22:5853#include "net/spdy/buffered_spdy_framer.h"
54#include "net/spdy/spdy_http_stream.h"
55#include "net/spdy/spdy_http_utils.h"
56#include "net/spdy/spdy_session.h"
57#include "net/spdy/spdy_session_pool.h"
58#include "net/spdy/spdy_test_util_common.h"
[email protected]514aeaf2014-05-23 10:31:5159#include "net/ssl/ssl_connection_status_flags.h"
bncce36dca22015-04-21 22:11:2360#include "net/test/cert_test_util.h"
robpercival214763f2016-07-01 23:27:0161#include "net/test/gtest_util.h"
rsleevia69c79a2016-06-22 03:28:4362#include "net/test/test_data_directory.h"
Gabriel Charettec7108742019-08-23 03:31:4063#include "net/test/test_with_task_environment.h"
Victor Vasiliev27cc7712019-01-24 11:50:1464#include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
65#include "net/third_party/quiche/src/spdy/core/spdy_test_utils.h"
rhalavati9ebaba7e2017-04-27 06:16:2966#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
[email protected]d2db0292011-01-26 20:23:4467#include "net/url_request/url_request_test_util.h"
Bence Béky0ca719f2018-01-31 13:41:1968#include "net/websockets/websocket_test_util.h"
[email protected]251029e2014-03-19 06:04:4069#include "testing/gmock/include/gmock/gmock.h"
[email protected]aea80602009-09-18 00:55:0870#include "testing/platform_test.h"
71
robpercival214763f2016-07-01 23:27:0172using net::test::IsError;
73using net::test::IsOk;
74
[email protected]aea80602009-09-18 00:55:0875//-----------------------------------------------------------------------------
76
[email protected]d1eda932009-11-04 01:03:1077namespace net {
[email protected]dae22c52010-07-30 02:16:3578
[email protected]cbdd73162013-03-18 23:27:3379namespace {
[email protected]251029e2014-03-19 06:04:4080
81using testing::Each;
82using testing::Eq;
83
xunjieli179a6e72016-04-26 19:47:4584const int32_t kBufferSize = SpdyHttpStream::kRequestBodyBufferSize;
85
[email protected]513963e2013-06-15 01:53:0486} // namespace
87
Bence Békyd2df6c1c82018-04-20 22:52:0188const char kPushedUrl[] = "https://www.example.org/foo.dat";
89
Gabriel Charette694c3c332019-08-19 14:53:0590class SpdyNetworkTransactionTest : public TestWithTaskEnvironment {
[email protected]34437af82009-11-06 02:28:4991 protected:
rdsmithebb50aa2015-11-12 03:44:3892 SpdyNetworkTransactionTest()
David Benjaminbae08ba2019-10-18 21:06:1593 : TestWithTaskEnvironment(
94 base::test::TaskEnvironment::TimeSource::MOCK_TIME),
95 default_url_(kDefaultUrl),
bncd16676a2016-07-20 16:23:0196 host_port_pair_(HostPortPair::FromURL(default_url_)) {}
[email protected]2d6728692011-03-12 01:39:5597
bncd16676a2016-07-20 16:23:0198 ~SpdyNetworkTransactionTest() override {
Bence Békydb3cf652017-10-10 15:22:1099 // UploadDataStream may post a deletion task back to the message loop on
[email protected]fc9d88472013-08-14 02:31:17100 // destruction.
101 upload_data_stream_.reset();
102 base::RunLoop().RunUntilIdle();
103 }
104
dcheng67be2b1f2014-10-27 21:47:29105 void SetUp() override {
Bence Békydb3cf652017-10-10 15:22:10106 request_.method = "GET";
107 request_.url = GURL(kDefaultUrl);
Ramin Halavatib5e433e62018-02-07 07:41:10108 request_.traffic_annotation =
109 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
[email protected]69e6b4a2012-10-18 08:03:01110 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
[email protected]aea80602009-09-18 00:55:08111 }
112
[email protected]72552f02009-10-28 15:25:01113 struct TransactionHelperResult {
[email protected]aea80602009-09-18 00:55:08114 int rv;
Bence Béky4e83f492018-05-13 23:14:25115 std::string status_line;
116 std::string response_data;
[email protected]8b070372009-11-16 22:01:25117 HttpResponseInfo response_info;
[email protected]aea80602009-09-18 00:55:08118 };
119
[email protected]3caf5542010-07-16 15:19:47120 // A helper class that handles all the initial npn/ssl setup.
121 class NormalSpdyTransactionHelper {
122 public:
rdsmith82957ad2015-09-16 19:42:03123 NormalSpdyTransactionHelper(
124 const HttpRequestInfo& request,
125 RequestPriority priority,
tfarina428341112016-09-22 13:38:20126 const NetLogWithSource& log,
danakjaee3e1ec2016-04-16 00:23:18127 std::unique_ptr<SpdySessionDependencies> session_deps)
[email protected]30c942b2010-07-21 16:59:59128 : request_(request),
[email protected]262eec82013-03-19 21:01:36129 priority_(priority),
tombergan5d22c182017-01-11 02:05:35130 session_deps_(session_deps.get() == nullptr
Jeremy Roman0579ed62017-08-29 15:56:19131 ? std::make_unique<SpdySessionDependencies>()
bncd16676a2016-07-20 16:23:01132 : std::move(session_deps)),
xunjieli925519532017-01-30 15:33:17133 log_(log) {
134 session_deps_->net_log = log.net_log();
135 session_ =
136 SpdySessionDependencies::SpdyCreateSession(session_deps_.get());
137 }
[email protected]61b4efc2012-04-27 18:12:50138
[email protected]19ec8a72010-08-23 03:38:23139 ~NormalSpdyTransactionHelper() {
140 // Any test which doesn't close the socket by sending it an EOF will
141 // have a valid session left open, which leaks the entire session pool.
142 // This is just fine - in fact, some of our tests intentionally do this
143 // so that we can check consistency of the SpdySessionPool as the test
144 // finishes. If we had put an EOF on the socket, the SpdySession would
145 // have closed and we wouldn't be able to check the consistency.
146
147 // Forcefully close existing sessions here.
148 session()->spdy_session_pool()->CloseAllSessions();
149 }
150
[email protected]3caf5542010-07-16 15:19:47151 void RunPreTestSetup() {
[email protected]3caf5542010-07-16 15:19:47152 // We're now ready to use SSL-npn SPDY.
bnc3f6a8552017-05-17 13:40:34153 trans_ =
Jeremy Roman0579ed62017-08-29 15:56:19154 std::make_unique<HttpNetworkTransaction>(priority_, session_.get());
[email protected]cb54b3b22010-06-03 16:28:55155 }
[email protected]aea80602009-09-18 00:55:08156
[email protected]3caf5542010-07-16 15:19:47157 // Start the transaction, read some data, finish.
158 void RunDefaultTest() {
[email protected]34b345f92013-02-22 03:27:26159 if (!StartDefaultTest())
160 return;
161 FinishDefaultTest();
162 }
163
164 bool StartDefaultTest() {
[email protected]514aeaf2014-05-23 10:31:51165 output_.rv = trans_->Start(&request_, callback_.callback(), log_);
[email protected]aea80602009-09-18 00:55:08166
[email protected]3caf5542010-07-16 15:19:47167 // We expect an IO Pending or some sort of error.
168 EXPECT_LT(output_.rv, 0);
[email protected]34b345f92013-02-22 03:27:26169 return output_.rv == ERR_IO_PENDING;
170 }
[email protected]aea80602009-09-18 00:55:08171
[email protected]34b345f92013-02-22 03:27:26172 void FinishDefaultTest() {
[email protected]514aeaf2014-05-23 10:31:51173 output_.rv = callback_.WaitForResult();
bnceb9aa7112017-01-05 01:03:46174 // Finish async network reads/writes.
175 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:47176 if (output_.rv != OK) {
bnc301745a2015-03-10 03:22:16177 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
[email protected]3caf5542010-07-16 15:19:47178 return;
179 }
[email protected]ff57bb82009-11-12 06:52:14180
[email protected]3caf5542010-07-16 15:19:47181 // Verify responses.
182 const HttpResponseInfo* response = trans_->GetResponseInfo();
wezca1070932016-05-26 20:30:52183 ASSERT_TRUE(response);
184 ASSERT_TRUE(response->headers);
bnc80bb1d42016-10-26 18:11:34185 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
bnc927c4962016-07-21 14:45:59186 response->connection_info);
187 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
188 EXPECT_TRUE(response->was_fetched_via_spdy);
bnc94c92842016-09-21 15:22:52189 EXPECT_TRUE(response->was_alpn_negotiated);
Tsuyoshi Horo01faed62019-02-20 22:11:37190 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
191 EXPECT_EQ(443, response->remote_endpoint.port());
[email protected]3caf5542010-07-16 15:19:47192 output_.status_line = response->headers->GetStatusLine();
193 output_.response_info = *response; // Make a copy so we can verify.
194 output_.rv = ReadTransaction(trans_.get(), &output_.response_data);
[email protected]3caf5542010-07-16 15:19:47195 }
196
bncfacdd852015-01-09 19:22:54197 void FinishDefaultTestWithoutVerification() {
198 output_.rv = callback_.WaitForResult();
bnceb9aa7112017-01-05 01:03:46199 // Finish async network reads/writes.
200 base::RunLoop().RunUntilIdle();
bncfacdd852015-01-09 19:22:54201 if (output_.rv != OK)
bnc301745a2015-03-10 03:22:16202 session_->spdy_session_pool()->CloseCurrentSessions(ERR_ABORTED);
bncfacdd852015-01-09 19:22:54203 }
204
maksim.sisov8d2df66d2016-06-20 07:07:11205 void WaitForCallbackToComplete() { output_.rv = callback_.WaitForResult(); }
mmenke666a6fea2015-12-19 04:16:33206
[email protected]3caf5542010-07-16 15:19:47207 // Most tests will want to call this function. In particular, the MockReads
208 // should end with an empty read, and that read needs to be processed to
209 // ensure proper deletion of the spdy_session_pool.
210 void VerifyDataConsumed() {
rch08e3aa3e2015-05-16 14:27:52211 for (const SocketDataProvider* provider : data_vector_) {
212 EXPECT_TRUE(provider->AllReadDataConsumed());
213 EXPECT_TRUE(provider->AllWriteDataConsumed());
[email protected]3caf5542010-07-16 15:19:47214 }
215 }
216
217 // Occasionally a test will expect to error out before certain reads are
218 // processed. In that case we want to explicitly ensure that the reads were
219 // not processed.
220 void VerifyDataNotConsumed() {
rch08e3aa3e2015-05-16 14:27:52221 for (const SocketDataProvider* provider : data_vector_) {
222 EXPECT_FALSE(provider->AllReadDataConsumed());
223 EXPECT_FALSE(provider->AllWriteDataConsumed());
[email protected]3caf5542010-07-16 15:19:47224 }
225 }
226
rch08e3aa3e2015-05-16 14:27:52227 void RunToCompletion(SocketDataProvider* data) {
[email protected]3caf5542010-07-16 15:19:47228 RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:58229 AddData(data);
[email protected]3caf5542010-07-16 15:19:47230 RunDefaultTest();
231 VerifyDataConsumed();
232 }
[email protected]e6b06862010-07-20 16:32:58233
[email protected]514aeaf2014-05-23 10:31:51234 void RunToCompletionWithSSLData(
rch08e3aa3e2015-05-16 14:27:52235 SocketDataProvider* data,
danakjaee3e1ec2016-04-16 00:23:18236 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
[email protected]514aeaf2014-05-23 10:31:51237 RunPreTestSetup();
dchengc7eeda422015-12-26 03:56:48238 AddDataWithSSLSocketDataProvider(data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:51239 RunDefaultTest();
240 VerifyDataConsumed();
241 }
242
rch08e3aa3e2015-05-16 14:27:52243 void AddData(SocketDataProvider* data) {
Jeremy Roman0579ed62017-08-29 15:56:19244 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:49245 ssl_provider->ssl_info.cert =
bncce36dca22015-04-21 22:11:23246 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
dchengc7eeda422015-12-26 03:56:48247 AddDataWithSSLSocketDataProvider(data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:51248 }
249
250 void AddDataWithSSLSocketDataProvider(
rch08e3aa3e2015-05-16 14:27:52251 SocketDataProvider* data,
danakjaee3e1ec2016-04-16 00:23:18252 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
[email protected]3caf5542010-07-16 15:19:47253 data_vector_.push_back(data);
bnc3cf2a592016-08-11 14:48:36254 if (ssl_provider->next_proto == kProtoUnknown)
255 ssl_provider->next_proto = kProtoHTTP2;
rchebf12982015-04-10 01:15:00256
257 session_deps_->socket_factory->AddSSLSocketDataProvider(
258 ssl_provider.get());
olli.raulaae011c422015-12-10 07:38:51259 ssl_vector_.push_back(std::move(ssl_provider));
[email protected]d4f00222012-07-10 06:24:51260
[email protected]3b7828432010-08-18 18:33:27261 session_deps_->socket_factory->AddSocketDataProvider(data);
262 }
263
[email protected]3caf5542010-07-16 15:19:47264 HttpNetworkTransaction* trans() { return trans_.get(); }
265 void ResetTrans() { trans_.reset(); }
bnc4d782f492016-08-18 13:50:00266 const TransactionHelperResult& output() { return output_; }
mmenkee65e7af2015-10-13 17:16:42267 HttpNetworkSession* session() const { return session_.get(); }
bncd16676a2016-07-20 16:23:01268 SpdySessionDependencies* session_deps() { return session_deps_.get(); }
[email protected]3caf5542010-07-16 15:19:47269
270 private:
rch08e3aa3e2015-05-16 14:27:52271 typedef std::vector<SocketDataProvider*> DataVector;
danakjaee3e1ec2016-04-16 00:23:18272 typedef std::vector<std::unique_ptr<SSLSocketDataProvider>> SSLVector;
273 typedef std::vector<std::unique_ptr<SocketDataProvider>> AlternateVector;
Bence Békydb3cf652017-10-10 15:22:10274 const HttpRequestInfo request_;
275 const RequestPriority priority_;
danakjaee3e1ec2016-04-16 00:23:18276 std::unique_ptr<SpdySessionDependencies> session_deps_;
277 std::unique_ptr<HttpNetworkSession> session_;
[email protected]3caf5542010-07-16 15:19:47278 TransactionHelperResult output_;
[email protected]3caf5542010-07-16 15:19:47279 SSLVector ssl_vector_;
[email protected]514aeaf2014-05-23 10:31:51280 TestCompletionCallback callback_;
danakjaee3e1ec2016-04-16 00:23:18281 std::unique_ptr<HttpNetworkTransaction> trans_;
[email protected]3caf5542010-07-16 15:19:47282 DataVector data_vector_;
tfarina428341112016-09-22 13:38:20283 const NetLogWithSource log_;
[email protected]3caf5542010-07-16 15:19:47284 };
[email protected]aea80602009-09-18 00:55:08285
286 void ConnectStatusHelperWithExpectedStatus(const MockRead& status,
287 int expected_status);
288
289 void ConnectStatusHelper(const MockRead& status);
[email protected]d3cee19d2010-06-22 18:42:18290
Bence Békydb3cf652017-10-10 15:22:10291 HttpRequestInfo CreateGetPushRequest() const WARN_UNUSED_RESULT {
292 HttpRequestInfo request;
293 request.method = "GET";
Bence Békyd2df6c1c82018-04-20 22:52:01294 request.url = GURL(kPushedUrl);
Ramin Halavatib5e433e62018-02-07 07:41:10295 request.traffic_annotation =
296 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békydb3cf652017-10-10 15:22:10297 return request;
[email protected]e3ebba0f2010-08-05 17:59:58298 }
299
Bence Békydb3cf652017-10-10 15:22:10300 void UsePostRequest() {
301 ASSERT_FALSE(upload_data_stream_);
302 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
303 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
304 kUploadData, kUploadDataSize));
305 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
306 std::move(element_readers), 0);
307
308 request_.method = "POST";
309 request_.upload_data_stream = upload_data_stream_.get();
[email protected]d3cee19d2010-06-22 18:42:18310 }
311
Bence Békydb3cf652017-10-10 15:22:10312 void UseFilePostRequest() {
313 ASSERT_FALSE(upload_data_stream_);
314 base::FilePath file_path;
315 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
316 CHECK_EQ(static_cast<int>(kUploadDataSize),
317 base::WriteFile(file_path, kUploadData, kUploadDataSize));
318
319 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
320 element_readers.push_back(std::make_unique<UploadFileElementReader>(
321 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
322 kUploadDataSize, base::Time()));
323 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
324 std::move(element_readers), 0);
325
326 request_.method = "POST";
327 request_.upload_data_stream = upload_data_stream_.get();
Ramin Halavatib5e433e62018-02-07 07:41:10328 request_.traffic_annotation =
329 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
[email protected]3deb9a52010-11-11 00:24:40330 }
331
Bence Békydb3cf652017-10-10 15:22:10332 void UseUnreadableFilePostRequest() {
333 ASSERT_FALSE(upload_data_stream_);
[email protected]999dd8c2013-11-12 06:45:54334 base::FilePath file_path;
vabrb8582322016-09-09 08:05:37335 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
[email protected]999dd8c2013-11-12 06:45:54336 CHECK_EQ(static_cast<int>(kUploadDataSize),
[email protected]e5c2a22e2014-03-06 20:42:30337 base::WriteFile(file_path, kUploadData, kUploadDataSize));
[email protected]92be8eb2014-08-07 22:57:11338 CHECK(base::MakeFileUnreadable(file_path));
[email protected]999dd8c2013-11-12 06:45:54339
danakjaee3e1ec2016-04-16 00:23:18340 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Jeremy Roman0579ed62017-08-29 15:56:19341 element_readers.push_back(std::make_unique<UploadFileElementReader>(
skyostil4891b25b2015-06-11 11:43:45342 base::ThreadTaskRunnerHandle::Get().get(), file_path, 0,
ricea2deef682016-09-09 08:04:07343 kUploadDataSize, base::Time()));
Jeremy Roman0579ed62017-08-29 15:56:19344 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
bnc3f6a8552017-05-17 13:40:34345 std::move(element_readers), 0);
[email protected]999dd8c2013-11-12 06:45:54346
Bence Békydb3cf652017-10-10 15:22:10347 request_.method = "POST";
348 request_.upload_data_stream = upload_data_stream_.get();
[email protected]999dd8c2013-11-12 06:45:54349 }
350
Bence Békydb3cf652017-10-10 15:22:10351 void UseComplexPostRequest() {
352 ASSERT_FALSE(upload_data_stream_);
353 const int kFileRangeOffset = 1;
354 const int kFileRangeLength = 3;
355 CHECK_LT(kFileRangeOffset + kFileRangeLength, kUploadDataSize);
[email protected]69e6b4a2012-10-18 08:03:01356
Bence Békydb3cf652017-10-10 15:22:10357 base::FilePath file_path;
358 CHECK(base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &file_path));
359 CHECK_EQ(static_cast<int>(kUploadDataSize),
360 base::WriteFile(file_path, kUploadData, kUploadDataSize));
[email protected]69e6b4a2012-10-18 08:03:01361
Bence Békydb3cf652017-10-10 15:22:10362 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
363 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
364 kUploadData, kFileRangeOffset));
365 element_readers.push_back(std::make_unique<UploadFileElementReader>(
366 base::ThreadTaskRunnerHandle::Get().get(), file_path, kFileRangeOffset,
367 kFileRangeLength, base::Time()));
368 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
369 kUploadData + kFileRangeOffset + kFileRangeLength,
370 kUploadDataSize - (kFileRangeOffset + kFileRangeLength)));
371 upload_data_stream_ = std::make_unique<ElementsUploadDataStream>(
372 std::move(element_readers), 0);
[email protected]329b68b2012-11-14 17:54:27373
Bence Békydb3cf652017-10-10 15:22:10374 request_.method = "POST";
375 request_.upload_data_stream = upload_data_stream_.get();
[email protected]69e6b4a2012-10-18 08:03:01376 }
377
Bence Békydb3cf652017-10-10 15:22:10378 void UseChunkedPostRequest() {
379 ASSERT_FALSE(upload_chunked_data_stream_);
380 upload_chunked_data_stream_ = std::make_unique<ChunkedUploadDataStream>(0);
381 request_.method = "POST";
382 request_.upload_data_stream = upload_chunked_data_stream_.get();
[email protected]0c9bf872011-03-04 17:53:22383 }
384
[email protected]19ec8a72010-08-23 03:38:23385 // Read the result of a particular transaction, knowing that we've got
386 // multiple transactions in the read pipeline; so as we read, we may have
387 // to skip over data destined for other transactions while we consume
388 // the data for |trans|.
Bence Béky4e83f492018-05-13 23:14:25389 int ReadResult(HttpNetworkTransaction* trans, std::string* result) {
[email protected]19ec8a72010-08-23 03:38:23390 const int kSize = 3000;
[email protected]e3ebba0f2010-08-05 17:59:58391
[email protected]19ec8a72010-08-23 03:38:23392 int bytes_read = 0;
Victor Costan9c7302b2018-08-27 16:39:44393 scoped_refptr<IOBufferWithSize> buf =
394 base::MakeRefCounted<IOBufferWithSize>(kSize);
[email protected]49639fa2011-12-20 23:22:41395 TestCompletionCallback callback;
[email protected]19ec8a72010-08-23 03:38:23396 while (true) {
[email protected]90499482013-06-01 00:39:50397 int rv = trans->Read(buf.get(), kSize, callback.callback());
[email protected]19ec8a72010-08-23 03:38:23398 if (rv == ERR_IO_PENDING) {
[email protected]19ec8a72010-08-23 03:38:23399 rv = callback.WaitForResult();
400 } else if (rv <= 0) {
401 break;
402 }
403 result->append(buf->data(), rv);
404 bytes_read += rv;
[email protected]e3ebba0f2010-08-05 17:59:58405 }
[email protected]19ec8a72010-08-23 03:38:23406 return bytes_read;
407 }
[email protected]e3ebba0f2010-08-05 17:59:58408
[email protected]19ec8a72010-08-23 03:38:23409 void VerifyStreamsClosed(const NormalSpdyTransactionHelper& helper) {
410 // This lengthy block is reaching into the pool to dig out the active
411 // session. Once we have the session, we verify that the streams are
412 // all closed and not leaked at this point.
Bence Békydb3cf652017-10-10 15:22:10413 SpdySessionKey key(HostPortPair::FromURL(request_.url),
Paul Jensena457017a2018-01-19 23:52:04414 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:34415 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
Matt Menkec74a9262020-06-09 15:49:21416 request_.network_isolation_key,
417 false /* disable_secure_dns */);
mmenkee65e7af2015-10-13 17:16:42418 HttpNetworkSession* session = helper.session();
[email protected]795cbf82013-07-22 09:37:27419 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:15420 session->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:31421 key, /* enable_ip_based_pooling = */ true,
422 /* is_websocket = */ false, log_);
wezca1070932016-05-26 20:30:52423 ASSERT_TRUE(spdy_session);
Bence Béky285e7d42017-12-04 20:22:11424 EXPECT_EQ(0u, num_active_streams(spdy_session));
425 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
[email protected]19ec8a72010-08-23 03:38:23426 }
[email protected]e3ebba0f2010-08-05 17:59:58427
rch08e3aa3e2015-05-16 14:27:52428 void RunServerPushTest(SequencedSocketData* data,
[email protected]e3ebba0f2010-08-05 17:59:58429 HttpResponseInfo* response,
[email protected]a7a265ef2010-12-08 18:05:57430 HttpResponseInfo* push_response,
Bence Béky4e83f492018-05-13 23:14:25431 const std::string& expected) {
Bence Békydb3cf652017-10-10 15:22:10432 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
433 nullptr);
[email protected]e3ebba0f2010-08-05 17:59:58434 helper.RunPreTestSetup();
[email protected]d08358502010-12-03 22:04:03435 helper.AddData(data);
[email protected]e3ebba0f2010-08-05 17:59:58436
437 HttpNetworkTransaction* trans = helper.trans();
438
439 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:41440 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:10441 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:01442 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e3ebba0f2010-08-05 17:59:58443 rv = callback.WaitForResult();
444
bnceb9aa7112017-01-05 01:03:46445 // Finish async network reads/writes.
446 base::RunLoop().RunUntilIdle();
447
[email protected]e3ebba0f2010-08-05 17:59:58448 // Request the pushed path.
bnc691fda62016-08-12 00:43:16449 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Békydb3cf652017-10-10 15:22:10450 HttpRequestInfo request = CreateGetPushRequest();
451 rv = trans2.Start(&request, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:01452 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:17453 base::RunLoop().RunUntilIdle();
[email protected]e3ebba0f2010-08-05 17:59:58454
[email protected]513963e2013-06-15 01:53:04455 // The data for the pushed path may be coming in more than 1 frame. Compile
[email protected]e3ebba0f2010-08-05 17:59:58456 // the results into a single string.
[email protected]19ec8a72010-08-23 03:38:23457
458 // Read the server push body.
Bence Béky4e83f492018-05-13 23:14:25459 std::string result2;
bnc691fda62016-08-12 00:43:16460 ReadResult(&trans2, &result2);
[email protected]19ec8a72010-08-23 03:38:23461 // Read the response body.
Bence Béky4e83f492018-05-13 23:14:25462 std::string result;
rch0aecfd82015-05-19 17:22:32463 ReadResult(trans, &result);
[email protected]e3ebba0f2010-08-05 17:59:58464
465 // Verify that we consumed all test data.
rch37de576c2015-05-17 20:28:17466 EXPECT_TRUE(data->AllReadDataConsumed());
467 EXPECT_TRUE(data->AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:58468
caseqe8340bc92016-04-20 00:02:57469 LoadTimingInfo load_timing_info;
470 EXPECT_TRUE(trans->GetLoadTimingInfo(&load_timing_info));
471 EXPECT_TRUE(load_timing_info.push_start.is_null());
472 EXPECT_TRUE(load_timing_info.push_end.is_null());
473
474 LoadTimingInfo load_timing_info2;
bnc691fda62016-08-12 00:43:16475 EXPECT_TRUE(trans2.GetLoadTimingInfo(&load_timing_info2));
caseqe8340bc92016-04-20 00:02:57476 EXPECT_FALSE(load_timing_info2.push_start.is_null());
477 EXPECT_FALSE(load_timing_info2.push_end.is_null());
478
[email protected]e3ebba0f2010-08-05 17:59:58479 // Verify that the received push data is same as the expected push data.
[email protected]19ec8a72010-08-23 03:38:23480 EXPECT_EQ(result2.compare(expected), 0) << "Received data: "
481 << result2
482 << "||||| Expected data: "
483 << expected;
[email protected]e3ebba0f2010-08-05 17:59:58484
bnc42331402016-07-25 13:36:15485 // Verify the response HEADERS.
[email protected]e3ebba0f2010-08-05 17:59:58486 // Copy the response info, because trans goes away.
487 *response = *trans->GetResponseInfo();
bnc691fda62016-08-12 00:43:16488 *push_response = *trans2.GetResponseInfo();
[email protected]19ec8a72010-08-23 03:38:23489
490 VerifyStreamsClosed(helper);
[email protected]e3ebba0f2010-08-05 17:59:58491 }
492
morlovichab1d1c1e2017-02-07 19:59:28493 void RunBrokenPushTest(SequencedSocketData* data, int expected_rv) {
Bence Békydb3cf652017-10-10 15:22:10494 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
495 nullptr);
morlovichab1d1c1e2017-02-07 19:59:28496 helper.RunPreTestSetup();
497 helper.AddData(data);
498
499 HttpNetworkTransaction* trans = helper.trans();
500
501 // Start the transaction with basic parameters.
502 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:10503 int rv = trans->Start(&request_, callback.callback(), log_);
morlovichab1d1c1e2017-02-07 19:59:28504 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
505 rv = callback.WaitForResult();
506 EXPECT_EQ(expected_rv, rv);
507
508 // Finish async network reads/writes.
509 base::RunLoop().RunUntilIdle();
510
511 // Verify that we consumed all test data.
512 EXPECT_TRUE(data->AllReadDataConsumed());
513 EXPECT_TRUE(data->AllWriteDataConsumed());
514
515 if (expected_rv == OK) {
516 // Expected main request to succeed, even if push failed.
517 HttpResponseInfo response = *trans->GetResponseInfo();
518 EXPECT_TRUE(response.headers);
519 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
520 }
521 }
522
[email protected]49639fa2011-12-20 23:22:41523 static void DeleteSessionCallback(NormalSpdyTransactionHelper* helper,
524 int result) {
525 helper->ResetTrans();
526 }
527
mmenkee65e7af2015-10-13 17:16:42528 static void StartTransactionCallback(HttpNetworkSession* session,
529 GURL url,
Bence Békyd3dde832017-09-19 19:02:31530 NetLogWithSource log,
mmenkee65e7af2015-10-13 17:16:42531 int result) {
krasin0bfeb6b2017-01-13 21:48:04532 HttpRequestInfo request;
bnc691fda62016-08-12 00:43:16533 HttpNetworkTransaction trans(DEFAULT_PRIORITY, session);
[email protected]49639fa2011-12-20 23:22:41534 TestCompletionCallback callback;
[email protected]49639fa2011-12-20 23:22:41535 request.method = "GET";
rchebf12982015-04-10 01:15:00536 request.url = url;
Ramin Halavatib5e433e62018-02-07 07:41:10537 request.traffic_annotation =
538 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békyd3dde832017-09-19 19:02:31539 int rv = trans.Start(&request, callback.callback(), log);
robpercival214763f2016-07-01 23:27:01540 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]49639fa2011-12-20 23:22:41541 callback.WaitForResult();
542 }
543
Bence Békydb3cf652017-10-10 15:22:10544 ChunkedUploadDataStream* upload_chunked_data_stream() {
mmenkecbc2b712014-10-09 20:29:07545 return upload_chunked_data_stream_.get();
546 }
547
Bence Béky285e7d42017-12-04 20:22:11548 size_t num_active_streams(base::WeakPtr<SpdySession> session) {
549 return session->active_streams_.size();
550 }
551
Bence Békyfd2c1fd2017-12-15 02:32:03552 static size_t num_unclaimed_pushed_streams(
553 base::WeakPtr<SpdySession> session) {
554 return session->pool_->push_promise_index()->CountStreamsForSession(
555 session.get());
Bence Béky285e7d42017-12-04 20:22:11556 }
557
Bence Békyfd2c1fd2017-12-15 02:32:03558 static bool has_unclaimed_pushed_stream_for_url(
559 base::WeakPtr<SpdySession> session,
560 const GURL& url) {
561 return session->pool_->push_promise_index()->FindStream(
562 url, session.get()) != kNoPushedStreamFound;
Bence Béky285e7d42017-12-04 20:22:11563 }
564
Ryan Hamilton0239aac2018-05-19 00:03:13565 static spdy::SpdyStreamId spdy_stream_hi_water_mark(
Yoav Weiss9693572f2018-01-04 09:37:34566 base::WeakPtr<SpdySession> session) {
567 return session->stream_hi_water_mark_;
568 }
569
David Benjaminbae08ba2019-10-18 21:06:15570 base::RepeatingClosure FastForwardByCallback(base::TimeDelta delta) {
571 return base::BindRepeating(&SpdyNetworkTransactionTest::FastForwardBy,
572 base::Unretained(this), delta);
573 }
574
bncb26024382016-06-29 02:39:45575 const GURL default_url_;
576 const HostPortPair host_port_pair_;
Bence Békydb3cf652017-10-10 15:22:10577 HttpRequestInfo request_;
[email protected]9ec54f82013-05-10 02:53:05578 SpdyTestUtil spdy_util_;
Bence Békyd3dde832017-09-19 19:02:31579 const NetLogWithSource log_;
[email protected]9ec54f82013-05-10 02:53:05580
[email protected]d3cee19d2010-06-22 18:42:18581 private:
danakjaee3e1ec2016-04-16 00:23:18582 std::unique_ptr<ChunkedUploadDataStream> upload_chunked_data_stream_;
583 std::unique_ptr<UploadDataStream> upload_data_stream_;
[email protected]ea1a3f62012-11-16 20:34:23584 base::ScopedTempDir temp_dir_;
[email protected]aea80602009-09-18 00:55:08585};
586
[email protected]3caf5542010-07-16 15:19:47587// Verify HttpNetworkTransaction constructor.
bncd16676a2016-07-20 16:23:01588TEST_F(SpdyNetworkTransactionTest, Constructor) {
Jeremy Roman0579ed62017-08-29 15:56:19589 auto session_deps = std::make_unique<SpdySessionDependencies>();
danakjaee3e1ec2016-04-16 00:23:18590 std::unique_ptr<HttpNetworkSession> session(
[email protected]bb88e1d32013-05-03 23:11:07591 SpdySessionDependencies::SpdyCreateSession(session_deps.get()));
bncd16676a2016-07-20 16:23:01592 auto trans =
Jeremy Roman0579ed62017-08-29 15:56:19593 std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY, session.get());
[email protected]aea80602009-09-18 00:55:08594}
595
bncd16676a2016-07-20 16:23:01596TEST_F(SpdyNetworkTransactionTest, Get) {
[email protected]75f30cc22010-06-28 21:41:38597 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:13598 spdy::SpdySerializedFrame req(
599 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:41600 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]72552f02009-10-28 15:25:01601
Ryan Hamilton0239aac2018-05-19 00:03:13602 spdy::SpdySerializedFrame resp(
603 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
604 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]72552f02009-10-28 15:25:01605 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41606 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:52607 MockRead(ASYNC, 0, 3) // EOF
[email protected]72552f02009-10-28 15:25:01608 };
609
Ryan Sleevib8d7ea02018-05-07 20:01:01610 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:10611 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:57612 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:47613 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:01614 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:02615 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]72552f02009-10-28 15:25:01616 EXPECT_EQ("hello!", out.response_data);
617}
618
Bence Béky2fcf4fa2018-04-06 20:06:01619TEST_F(SpdyNetworkTransactionTest, SetPriority) {
620 for (bool set_priority_before_starting_transaction : {true, false}) {
621 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:13622 spdy::SpdySerializedFrame req(
Bence Béky2fcf4fa2018-04-06 20:06:01623 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
624 MockWrite writes[] = {CreateMockWrite(req, 0)};
625
Ryan Hamilton0239aac2018-05-19 00:03:13626 spdy::SpdySerializedFrame resp(
Bence Béky2fcf4fa2018-04-06 20:06:01627 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:13628 spdy::SpdySerializedFrame body(
629 spdy_test_util.ConstructSpdyDataFrame(1, true));
Bence Béky2fcf4fa2018-04-06 20:06:01630 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
631 MockRead(ASYNC, 0, 3)};
632
Ryan Sleevib8d7ea02018-05-07 20:01:01633 SequencedSocketData data(reads, writes);
Bence Béky2fcf4fa2018-04-06 20:06:01634 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
635 helper.RunPreTestSetup();
636 helper.AddData(&data);
637
638 if (set_priority_before_starting_transaction) {
639 helper.trans()->SetPriority(LOWEST);
640 EXPECT_TRUE(helper.StartDefaultTest());
641 } else {
642 EXPECT_TRUE(helper.StartDefaultTest());
643 helper.trans()->SetPriority(LOWEST);
644 }
645
646 helper.FinishDefaultTest();
647 helper.VerifyDataConsumed();
648
649 TransactionHelperResult out = helper.output();
650 EXPECT_THAT(out.rv, IsOk());
651 EXPECT_EQ("HTTP/1.1 200", out.status_line);
652 EXPECT_EQ("hello!", out.response_data);
653 }
654}
655
Bence Béky7a4836c2018-05-08 03:52:48656// Test that changing the request priority of an existing stream triggers
Bence Béky73b85292018-06-14 04:56:43657// sending PRIORITY frames in case there are multiple open streams and their
Bence Béky7a4836c2018-05-08 03:52:48658// relative priorities change.
Bence Béky73b85292018-06-14 04:56:43659TEST_F(SpdyNetworkTransactionTest, SetPriorityOnExistingStream) {
Bence Béky7a4836c2018-05-08 03:52:48660 const char* kUrl2 = "https://www.example.org/bar";
661
Ryan Hamilton0239aac2018-05-19 00:03:13662 spdy::SpdySerializedFrame req1(
663 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
664 spdy::SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet(kUrl2, 3, MEDIUM));
665 spdy::SpdySerializedFrame priority1(
Bence Béky7a4836c2018-05-08 03:52:48666 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
Ryan Hamilton0239aac2018-05-19 00:03:13667 spdy::SpdySerializedFrame priority2(
Bence Béky7a4836c2018-05-08 03:52:48668 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
669 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 2),
670 CreateMockWrite(priority1, 4),
671 CreateMockWrite(priority2, 5)};
672
Ryan Hamilton0239aac2018-05-19 00:03:13673 spdy::SpdySerializedFrame resp1(
674 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
675 spdy::SpdySerializedFrame resp2(
676 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
677 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
678 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky7a4836c2018-05-08 03:52:48679 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(resp2, 3),
680 CreateMockRead(body1, 6), CreateMockRead(body2, 7),
681 MockRead(ASYNC, 0, 8)};
682
683 SequencedSocketData data(reads, writes);
684 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
685 helper.RunPreTestSetup();
686 helper.AddData(&data);
687 EXPECT_TRUE(helper.StartDefaultTest());
688
689 // Open HTTP/2 connection and create first stream.
690 base::RunLoop().RunUntilIdle();
691
692 HttpNetworkTransaction trans2(MEDIUM, helper.session());
693 HttpRequestInfo request2;
694 request2.url = GURL(kUrl2);
695 request2.method = "GET";
696 request2.traffic_annotation =
697 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
698 TestCompletionCallback callback2;
699 int rv = trans2.Start(&request2, callback2.callback(), log_);
700 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
701
702 // Create second stream.
703 base::RunLoop().RunUntilIdle();
704
705 // First request has HIGHEST priority, second request has MEDIUM priority.
706 // Changing the priority of the first request to LOWEST changes their order,
707 // and therefore triggers sending PRIORITY frames.
708 helper.trans()->SetPriority(LOWEST);
709
710 helper.FinishDefaultTest();
711 helper.VerifyDataConsumed();
712
713 TransactionHelperResult out = helper.output();
714 EXPECT_THAT(out.rv, IsOk());
715 EXPECT_EQ("HTTP/1.1 200", out.status_line);
716 EXPECT_EQ("hello!", out.response_data);
717
718 rv = callback2.WaitForResult();
719 ASSERT_THAT(rv, IsOk());
720 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
721 ASSERT_TRUE(response2);
722 ASSERT_TRUE(response2->headers);
723 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
724 response2->connection_info);
725 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
726}
727
Bence Béky73b85292018-06-14 04:56:43728// Create two requests: a lower priority one first, then a higher priority one.
729// Test that the second request gets sent out first.
730TEST_F(SpdyNetworkTransactionTest, RequestsOrderedByPriority) {
731 const char* kUrl2 = "https://www.example.org/foo";
732
733 // First send second request on stream 1, then first request on stream 3.
734 spdy::SpdySerializedFrame req2(
735 spdy_util_.ConstructSpdyGet(kUrl2, 1, HIGHEST));
736 spdy::SpdySerializedFrame req1(
737 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOW));
738 MockWrite writes[] = {CreateMockWrite(req2, 0), CreateMockWrite(req1, 1)};
739
740 spdy::SpdySerializedFrame resp2(
741 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
742 spdy::SpdySerializedFrame resp1(
743 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
744 spdy::SpdySerializedFrame body2(
745 spdy_util_.ConstructSpdyDataFrame(1, "stream 1", true));
746 spdy::SpdySerializedFrame body1(
747 spdy_util_.ConstructSpdyDataFrame(3, "stream 3", true));
748 MockRead reads[] = {CreateMockRead(resp2, 2), CreateMockRead(body2, 3),
749 CreateMockRead(resp1, 4), CreateMockRead(body1, 5),
750 MockRead(ASYNC, 0, 6)};
751
752 SequencedSocketData data(reads, writes);
753 NormalSpdyTransactionHelper helper(request_, LOW, log_, nullptr);
754 helper.RunPreTestSetup();
755 helper.AddData(&data);
756
757 // Create HTTP/2 connection. This is necessary because starting the first
758 // transaction does not create the connection yet, so the second request
759 // could not use the same connection, whereas running the message loop after
760 // starting the first transaction would call Socket::Write() with the first
761 // HEADERS frame, so the second transaction could not get ahead of it.
762 SpdySessionKey key(HostPortPair("www.example.org", 443),
Matt Menke2436b2f2018-12-11 18:07:11763 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:34764 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
765 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky73b85292018-06-14 04:56:43766 auto spdy_session = CreateSpdySession(helper.session(), key, log_);
767 EXPECT_TRUE(spdy_session);
768
769 // Start first transaction.
770 EXPECT_TRUE(helper.StartDefaultTest());
771
772 // Start second transaction.
773 HttpNetworkTransaction trans2(HIGHEST, helper.session());
774 HttpRequestInfo request2;
775 request2.url = GURL(kUrl2);
776 request2.method = "GET";
777 request2.traffic_annotation =
778 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
779 TestCompletionCallback callback2;
780 int rv = trans2.Start(&request2, callback2.callback(), log_);
781 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
782
783 // Complete first transaction and verify results.
784 helper.FinishDefaultTest();
785 helper.VerifyDataConsumed();
786
787 TransactionHelperResult out = helper.output();
788 EXPECT_THAT(out.rv, IsOk());
789 EXPECT_EQ("HTTP/1.1 200", out.status_line);
790 EXPECT_EQ("stream 3", out.response_data);
791
792 // Complete second transaction and verify results.
793 rv = callback2.WaitForResult();
794 ASSERT_THAT(rv, IsOk());
795 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
796 ASSERT_TRUE(response2);
797 ASSERT_TRUE(response2->headers);
798 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
799 response2->connection_info);
800 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
801 std::string response_data;
802 ReadTransaction(&trans2, &response_data);
803 EXPECT_EQ("stream 1", response_data);
804}
805
806// Test that already enqueued HEADERS frames are reordered if their relative
807// priority changes.
808TEST_F(SpdyNetworkTransactionTest, QueuedFramesReorderedOnPriorityChange) {
809 const char* kUrl2 = "https://www.example.org/foo";
810 const char* kUrl3 = "https://www.example.org/bar";
811
812 spdy::SpdySerializedFrame req1(
813 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
814 spdy::SpdySerializedFrame req3(spdy_util_.ConstructSpdyGet(kUrl3, 3, MEDIUM));
815 spdy::SpdySerializedFrame req2(spdy_util_.ConstructSpdyGet(kUrl2, 5, LOWEST));
816 MockWrite writes[] = {MockWrite(ASYNC, ERR_IO_PENDING, 0),
817 CreateMockWrite(req1, 1), CreateMockWrite(req3, 2),
818 CreateMockWrite(req2, 3)};
819
820 spdy::SpdySerializedFrame resp1(
821 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
822 spdy::SpdySerializedFrame resp3(
823 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
824 spdy::SpdySerializedFrame resp2(
825 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
826 spdy::SpdySerializedFrame body1(
827 spdy_util_.ConstructSpdyDataFrame(1, "stream 1", true));
828 spdy::SpdySerializedFrame body3(
829 spdy_util_.ConstructSpdyDataFrame(3, "stream 3", true));
830 spdy::SpdySerializedFrame body2(
831 spdy_util_.ConstructSpdyDataFrame(5, "stream 5", true));
832 MockRead reads[] = {CreateMockRead(resp1, 4), CreateMockRead(body1, 5),
833 CreateMockRead(resp3, 6), CreateMockRead(body3, 7),
834 CreateMockRead(resp2, 8), CreateMockRead(body2, 9),
835 MockRead(ASYNC, 0, 10)};
836
837 SequencedSocketData data(reads, writes);
838 // Priority of first request does not matter, because Socket::Write() will be
839 // called with its HEADERS frame before the other requests start.
840 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
841 helper.RunPreTestSetup();
842 helper.AddData(&data);
843 EXPECT_TRUE(helper.StartDefaultTest());
844
845 // Open HTTP/2 connection, create HEADERS frame for first request, and call
846 // Socket::Write() with that frame. After this, no other request can get
847 // ahead of the first one.
848 base::RunLoop().RunUntilIdle();
849
850 HttpNetworkTransaction trans2(HIGHEST, helper.session());
851 HttpRequestInfo request2;
852 request2.url = GURL(kUrl2);
853 request2.method = "GET";
854 request2.traffic_annotation =
855 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
856 TestCompletionCallback callback2;
857 int rv = trans2.Start(&request2, callback2.callback(), log_);
858 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
859
860 HttpNetworkTransaction trans3(MEDIUM, helper.session());
861 HttpRequestInfo request3;
862 request3.url = GURL(kUrl3);
863 request3.method = "GET";
864 request3.traffic_annotation =
865 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
866 TestCompletionCallback callback3;
867 rv = trans3.Start(&request3, callback3.callback(), log_);
868 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
869
870 // Create HEADERS frames for second and third request and enqueue them in
871 // SpdyWriteQueue with their original priorities. Writing of the first
872 // HEADERS frame to the socked still has not completed.
873 base::RunLoop().RunUntilIdle();
874
875 // Second request is of HIGHEST, third of MEDIUM priority. Changing second
876 // request to LOWEST changes their relative order. This should result in
877 // already enqueued frames being reordered within SpdyWriteQueue.
878 trans2.SetPriority(LOWEST);
879
880 // Complete async write of the first HEADERS frame.
881 data.Resume();
882
883 helper.FinishDefaultTest();
884 TransactionHelperResult out = helper.output();
885 EXPECT_THAT(out.rv, IsOk());
886 EXPECT_EQ("HTTP/1.1 200", out.status_line);
887 EXPECT_EQ("stream 1", out.response_data);
888
889 rv = callback2.WaitForResult();
890 ASSERT_THAT(rv, IsOk());
891 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
892 ASSERT_TRUE(response2);
893 ASSERT_TRUE(response2->headers);
894 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
895 response2->connection_info);
896 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
897 std::string response_data;
898 ReadTransaction(&trans2, &response_data);
899 EXPECT_EQ("stream 5", response_data);
900
901 rv = callback3.WaitForResult();
902 ASSERT_THAT(rv, IsOk());
903 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
904 ASSERT_TRUE(response3);
905 ASSERT_TRUE(response3->headers);
906 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
907 response3->connection_info);
908 EXPECT_EQ("HTTP/1.1 200", response3->headers->GetStatusLine());
909 ReadTransaction(&trans3, &response_data);
910 EXPECT_EQ("stream 3", response_data);
911
912 helper.VerifyDataConsumed();
913}
914
bncd16676a2016-07-20 16:23:01915TEST_F(SpdyNetworkTransactionTest, GetAtEachPriority) {
[email protected]3d08dd382013-10-19 00:13:11916 for (RequestPriority p = MINIMUM_PRIORITY; p <= MAXIMUM_PRIORITY;
[email protected]31ae7ab2012-04-24 21:09:05917 p = RequestPriority(p + 1)) {
bncd16676a2016-07-20 16:23:01918 SpdyTestUtil spdy_test_util;
bnc38dcd392016-02-09 23:19:49919
[email protected]c9c6f5c2010-07-31 01:30:03920 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:13921 spdy::SpdySerializedFrame req(
922 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, p));
bncdf80d44fd2016-07-15 20:27:41923 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]c9c6f5c2010-07-31 01:30:03924
Ryan Hamilton0239aac2018-05-19 00:03:13925 spdy::SpdyPriority spdy_prio = 0;
bncdf80d44fd2016-07-15 20:27:41926 EXPECT_TRUE(GetSpdyPriority(req, &spdy_prio));
Ryan Hamilton0239aac2018-05-19 00:03:13927 // this repeats the RequestPriority-->spdy::SpdyPriority mapping from
928 // spdy::SpdyFramer::ConvertRequestPriorityToSpdyPriority to make
[email protected]c9c6f5c2010-07-31 01:30:03929 // sure it's being done right.
bnc05808ff42016-01-08 23:48:25930 switch (p) {
931 case HIGHEST:
932 EXPECT_EQ(0, spdy_prio);
933 break;
934 case MEDIUM:
935 EXPECT_EQ(1, spdy_prio);
936 break;
937 case LOW:
938 EXPECT_EQ(2, spdy_prio);
939 break;
940 case LOWEST:
941 EXPECT_EQ(3, spdy_prio);
942 break;
943 case IDLE:
944 EXPECT_EQ(4, spdy_prio);
945 break;
rdsmith5eb6fbc2016-10-21 17:36:08946 case THROTTLED:
947 EXPECT_EQ(5, spdy_prio);
948 break;
bnc05808ff42016-01-08 23:48:25949 default:
950 FAIL();
[email protected]c9c6f5c2010-07-31 01:30:03951 }
952
Ryan Hamilton0239aac2018-05-19 00:03:13953 spdy::SpdySerializedFrame resp(
bnc42331402016-07-25 13:36:15954 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:13955 spdy::SpdySerializedFrame body(
956 spdy_test_util.ConstructSpdyDataFrame(1, true));
[email protected]c9c6f5c2010-07-31 01:30:03957 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:41958 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:52959 MockRead(ASYNC, 0, 3) // EOF
[email protected]c9c6f5c2010-07-31 01:30:03960 };
961
Ryan Sleevib8d7ea02018-05-07 20:01:01962 SequencedSocketData data(reads, writes);
[email protected]c9c6f5c2010-07-31 01:30:03963
Bence Békydb3cf652017-10-10 15:22:10964 NormalSpdyTransactionHelper helper(request_, p, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:57965 helper.RunToCompletion(&data);
[email protected]c9c6f5c2010-07-31 01:30:03966 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:01967 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:02968 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]c9c6f5c2010-07-31 01:30:03969 EXPECT_EQ("hello!", out.response_data);
970 }
971}
972
[email protected]2bd93022010-07-17 00:58:44973// Start three gets simultaniously; making sure that multiplexed
974// streams work properly.
975
976// This can't use the TransactionHelper method, since it only
977// handles a single transaction, and finishes them as soon
978// as it launches them.
979
980// TODO(gavinp): create a working generalized TransactionHelper that
981// can allow multiple streams in flight.
982
bncd16676a2016-07-20 16:23:01983TEST_F(SpdyNetworkTransactionTest, ThreeGets) {
Ryan Hamilton0239aac2018-05-19 00:03:13984 spdy::SpdySerializedFrame req(
985 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
986 spdy::SpdySerializedFrame resp(
987 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
988 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
989 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]2bd93022010-07-17 00:58:44990
Ryan Hamilton0239aac2018-05-19 00:03:13991 spdy::SpdySerializedFrame req2(
992 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
993 spdy::SpdySerializedFrame resp2(
994 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
995 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
996 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]2bd93022010-07-17 00:58:44997
Ryan Hamilton0239aac2018-05-19 00:03:13998 spdy::SpdySerializedFrame req3(
999 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST));
1000 spdy::SpdySerializedFrame resp3(
1001 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1002 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
1003 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]2bd93022010-07-17 00:58:441004
[email protected]1b323172011-03-01 17:50:171005 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411006 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
1007 CreateMockWrite(req3, 6),
[email protected]2bd93022010-07-17 00:58:441008 };
1009 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411010 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1011 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1012 CreateMockRead(resp3, 7), CreateMockRead(body3, 8),
[email protected]2bd93022010-07-17 00:58:441013
bncdf80d44fd2016-07-15 20:27:411014 CreateMockRead(fbody, 9), CreateMockRead(fbody2, 10),
1015 CreateMockRead(fbody3, 11),
[email protected]2bd93022010-07-17 00:58:441016
rch08e3aa3e2015-05-16 14:27:521017 MockRead(ASYNC, 0, 12), // EOF
[email protected]2bd93022010-07-17 00:58:441018 };
Ryan Sleevib8d7ea02018-05-07 20:01:011019 SequencedSocketData data(reads, writes);
1020 SequencedSocketData data_placeholder1;
1021 SequencedSocketData data_placeholder2;
[email protected]2bd93022010-07-17 00:58:441022
[email protected]2bd93022010-07-17 00:58:441023 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101024 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081025 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571026 helper.AddData(&data);
rchaeb3f052015-04-14 16:02:491027 // We require placeholder data because three get requests are sent out at
1028 // the same time which results in three sockets being connected. The first
1029 // on will negotiate SPDY and will be used for all requests.
mmenkecc2298e2015-12-07 18:20:181030 helper.AddData(&data_placeholder1);
1031 helper.AddData(&data_placeholder2);
[email protected]49639fa2011-12-20 23:22:411032 TestCompletionCallback callback1;
1033 TestCompletionCallback callback2;
1034 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441035
krasin0bfeb6b2017-01-13 21:48:041036 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1037 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1038 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
1039
Bence Békydb3cf652017-10-10 15:22:101040 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011041 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101042 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011043 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101044 out.rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:011045 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]2bd93022010-07-17 00:58:441046
[email protected]bdebd1b2010-08-09 20:18:081047 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011048 ASSERT_THAT(out.rv, IsOk());
[email protected]bdebd1b2010-08-09 20:18:081049 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011050 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441051
bnc691fda62016-08-12 00:43:161052 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521053 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081054 EXPECT_TRUE(response1->was_fetched_via_spdy);
1055 out.status_line = response1->headers->GetStatusLine();
1056 out.response_info = *response1;
[email protected]2bd93022010-07-17 00:58:441057
bnc691fda62016-08-12 00:43:161058 trans2.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441059
bnc691fda62016-08-12 00:43:161060 out.rv = ReadTransaction(&trans1, &out.response_data);
[email protected]bdebd1b2010-08-09 20:18:081061 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011062 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441063
robpercival214763f2016-07-01 23:27:011064 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021065 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441066 EXPECT_EQ("hello!hello!", out.response_data);
1067}
1068
bncd16676a2016-07-20 16:23:011069TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBinding) {
Ryan Hamilton0239aac2018-05-19 00:03:131070 spdy::SpdySerializedFrame req(
1071 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1072 spdy::SpdySerializedFrame resp(
1073 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1074 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1075 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]1b323172011-03-01 17:50:171076
Ryan Hamilton0239aac2018-05-19 00:03:131077 spdy::SpdySerializedFrame req2(
1078 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1079 spdy::SpdySerializedFrame resp2(
1080 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1081 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1082 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]1b323172011-03-01 17:50:171083
1084 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411085 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
[email protected]1b323172011-03-01 17:50:171086 };
1087 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411088 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1089 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1090 CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
rch08e3aa3e2015-05-16 14:27:521091 MockRead(ASYNC, 0, 8), // EOF
[email protected]1b323172011-03-01 17:50:171092 };
Ryan Sleevib8d7ea02018-05-07 20:01:011093 SequencedSocketData data(reads, writes);
[email protected]1b323172011-03-01 17:50:171094
[email protected]d973e99a2012-02-17 21:02:361095 MockConnect never_finishing_connect(SYNCHRONOUS, ERR_IO_PENDING);
Ryan Sleevib8d7ea02018-05-07 20:01:011096 SequencedSocketData data_placeholder;
[email protected]dd54bd82012-07-19 23:44:571097 data_placeholder.set_connect_data(never_finishing_connect);
[email protected]1b323172011-03-01 17:50:171098
[email protected]1b323172011-03-01 17:50:171099 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101100 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]1b323172011-03-01 17:50:171101 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571102 helper.AddData(&data);
rchaeb3f052015-04-14 16:02:491103 // We require placeholder data because two requests are sent out at
1104 // the same time which results in two sockets being connected. The first
1105 // on will negotiate SPDY and will be used for all requests.
[email protected]dd54bd82012-07-19 23:44:571106 helper.AddData(&data_placeholder);
bnc691fda62016-08-12 00:43:161107 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1108 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
[email protected]1b323172011-03-01 17:50:171109
[email protected]49639fa2011-12-20 23:22:411110 TestCompletionCallback callback1;
1111 TestCompletionCallback callback2;
[email protected]1b323172011-03-01 17:50:171112
Bence Békydb3cf652017-10-10 15:22:101113 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011114 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101115 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011116 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]1b323172011-03-01 17:50:171117
1118 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011119 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171120 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011121 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171122
bnc691fda62016-08-12 00:43:161123 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521124 EXPECT_TRUE(response1->headers);
[email protected]1b323172011-03-01 17:50:171125 EXPECT_TRUE(response1->was_fetched_via_spdy);
1126 out.status_line = response1->headers->GetStatusLine();
1127 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161128 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011129 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021130 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171131 EXPECT_EQ("hello!hello!", out.response_data);
1132
bnc691fda62016-08-12 00:43:161133 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521134 EXPECT_TRUE(response2->headers);
[email protected]1b323172011-03-01 17:50:171135 EXPECT_TRUE(response2->was_fetched_via_spdy);
1136 out.status_line = response2->headers->GetStatusLine();
1137 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161138 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011139 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021140 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171141 EXPECT_EQ("hello!hello!", out.response_data);
1142
1143 helper.VerifyDataConsumed();
1144}
1145
bncd16676a2016-07-20 16:23:011146TEST_F(SpdyNetworkTransactionTest, TwoGetsLateBindingFromPreconnect) {
Ryan Hamilton0239aac2018-05-19 00:03:131147 spdy::SpdySerializedFrame req(
1148 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1149 spdy::SpdySerializedFrame resp(
1150 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1151 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1152 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]1b323172011-03-01 17:50:171153
Ryan Hamilton0239aac2018-05-19 00:03:131154 spdy::SpdySerializedFrame req2(
1155 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1156 spdy::SpdySerializedFrame resp2(
1157 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1158 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1159 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]1b323172011-03-01 17:50:171160
1161 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411162 CreateMockWrite(req, 0), CreateMockWrite(req2, 3),
[email protected]1b323172011-03-01 17:50:171163 };
1164 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411165 CreateMockRead(resp, 1), CreateMockRead(body, 2),
1166 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
1167 CreateMockRead(fbody, 6), CreateMockRead(fbody2, 7),
rch08e3aa3e2015-05-16 14:27:521168 MockRead(ASYNC, 0, 8), // EOF
[email protected]1b323172011-03-01 17:50:171169 };
Ryan Sleevib8d7ea02018-05-07 20:01:011170 SequencedSocketData preconnect_data(reads, writes);
[email protected]1b323172011-03-01 17:50:171171
[email protected]d973e99a2012-02-17 21:02:361172 MockConnect never_finishing_connect(ASYNC, ERR_IO_PENDING);
[email protected]1b323172011-03-01 17:50:171173
Ryan Sleevib8d7ea02018-05-07 20:01:011174 SequencedSocketData data_placeholder;
[email protected]dd54bd82012-07-19 23:44:571175 data_placeholder.set_connect_data(never_finishing_connect);
[email protected]1b323172011-03-01 17:50:171176
[email protected]1b323172011-03-01 17:50:171177 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101178 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]1b323172011-03-01 17:50:171179 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571180 helper.AddData(&preconnect_data);
[email protected]1b323172011-03-01 17:50:171181 // We require placeholder data because 3 connections are attempted (first is
1182 // the preconnect, 2nd and 3rd are the never finished connections.
[email protected]dd54bd82012-07-19 23:44:571183 helper.AddData(&data_placeholder);
1184 helper.AddData(&data_placeholder);
[email protected]1b323172011-03-01 17:50:171185
bnc691fda62016-08-12 00:43:161186 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1187 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
[email protected]1b323172011-03-01 17:50:171188
[email protected]49639fa2011-12-20 23:22:411189 TestCompletionCallback callback1;
1190 TestCompletionCallback callback2;
[email protected]1b323172011-03-01 17:50:171191
[email protected]1b323172011-03-01 17:50:171192 // Preconnect the first.
[email protected]1b323172011-03-01 17:50:171193 HttpStreamFactory* http_stream_factory =
1194 helper.session()->http_stream_factory();
[email protected]1b323172011-03-01 17:50:171195
Bence Békydb3cf652017-10-10 15:22:101196 http_stream_factory->PreconnectStreams(1, request_);
[email protected]1b323172011-03-01 17:50:171197
Bence Békydb3cf652017-10-10 15:22:101198 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011199 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101200 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011201 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]1b323172011-03-01 17:50:171202
1203 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011204 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171205 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011206 ASSERT_THAT(out.rv, IsOk());
[email protected]1b323172011-03-01 17:50:171207
bnc691fda62016-08-12 00:43:161208 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521209 EXPECT_TRUE(response1->headers);
[email protected]1b323172011-03-01 17:50:171210 EXPECT_TRUE(response1->was_fetched_via_spdy);
1211 out.status_line = response1->headers->GetStatusLine();
1212 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161213 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011214 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021215 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171216 EXPECT_EQ("hello!hello!", out.response_data);
1217
bnc691fda62016-08-12 00:43:161218 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521219 EXPECT_TRUE(response2->headers);
[email protected]1b323172011-03-01 17:50:171220 EXPECT_TRUE(response2->was_fetched_via_spdy);
1221 out.status_line = response2->headers->GetStatusLine();
1222 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161223 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011224 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021225 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]1b323172011-03-01 17:50:171226 EXPECT_EQ("hello!hello!", out.response_data);
1227
1228 helper.VerifyDataConsumed();
1229}
1230
[email protected]2bd93022010-07-17 00:58:441231// Similar to ThreeGets above, however this test adds a SETTINGS
1232// frame. The SETTINGS frame is read during the IO loop waiting on
1233// the first transaction completion, and sets a maximum concurrent
1234// stream limit of 1. This means that our IO loop exists after the
1235// second transaction completes, so we can assert on read_index().
bncd16676a2016-07-20 16:23:011236TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrent) {
[email protected]2bd93022010-07-17 00:58:441237 // Construct the request.
rdsmithebb50aa2015-11-12 03:44:381238 // Each request fully completes before the next starts.
Ryan Hamilton0239aac2018-05-19 00:03:131239 spdy::SpdySerializedFrame req(
1240 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1241 spdy::SpdySerializedFrame resp(
1242 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1243 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1244 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381245 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441246
Ryan Hamilton0239aac2018-05-19 00:03:131247 spdy::SpdySerializedFrame req2(
1248 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1249 spdy::SpdySerializedFrame resp2(
1250 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1251 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1252 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
rdsmithebb50aa2015-11-12 03:44:381253 spdy_util_.UpdateWithStreamDestruction(3);
[email protected]2bd93022010-07-17 00:58:441254
Ryan Hamilton0239aac2018-05-19 00:03:131255 spdy::SpdySerializedFrame req3(
1256 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, LOWEST));
1257 spdy::SpdySerializedFrame resp3(
1258 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1259 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, false));
1260 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]2bd93022010-07-17 00:58:441261
Ryan Hamilton0239aac2018-05-19 00:03:131262 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461263 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131264 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1265 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201266 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131267 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]2bd93022010-07-17 00:58:441268
[email protected]2d6728692011-03-12 01:39:551269 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411270 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
1271 CreateMockWrite(req2, 6), CreateMockWrite(req3, 10),
[email protected]2bd93022010-07-17 00:58:441272 };
[email protected]2d6728692011-03-12 01:39:551273
[email protected]2bd93022010-07-17 00:58:441274 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411275 CreateMockRead(settings_frame, 1),
1276 CreateMockRead(resp, 2),
1277 CreateMockRead(body, 3),
1278 CreateMockRead(fbody, 4),
1279 CreateMockRead(resp2, 7),
1280 CreateMockRead(body2, 8),
1281 CreateMockRead(fbody2, 9),
1282 CreateMockRead(resp3, 11),
1283 CreateMockRead(body3, 12),
1284 CreateMockRead(fbody3, 13),
[email protected]2bd93022010-07-17 00:58:441285
rch08e3aa3e2015-05-16 14:27:521286 MockRead(ASYNC, 0, 14), // EOF
[email protected]2bd93022010-07-17 00:58:441287 };
1288
Ryan Sleevib8d7ea02018-05-07 20:01:011289 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441290
[email protected]2bd93022010-07-17 00:58:441291 TransactionHelperResult out;
1292 {
Bence Békydb3cf652017-10-10 15:22:101293 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
1294 nullptr);
[email protected]2d6728692011-03-12 01:39:551295 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571296 helper.AddData(&data);
bnc691fda62016-08-12 00:43:161297 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1298 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1299 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
[email protected]2bd93022010-07-17 00:58:441300
[email protected]49639fa2011-12-20 23:22:411301 TestCompletionCallback callback1;
1302 TestCompletionCallback callback2;
1303 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441304
Bence Békydb3cf652017-10-10 15:22:101305 out.rv = trans1.Start(&request_, callback1.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441306 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]513963e2013-06-15 01:53:041307 // Run transaction 1 through quickly to force a read of our SETTINGS
1308 // frame.
[email protected]2bd93022010-07-17 00:58:441309 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011310 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441311
Bence Békydb3cf652017-10-10 15:22:101312 out.rv = trans2.Start(&request_, callback2.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441313 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101314 out.rv = trans3.Start(&request_, callback3.callback(), log_);
[email protected]2bd93022010-07-17 00:58:441315 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1316 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011317 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441318
1319 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011320 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441321
bnc691fda62016-08-12 00:43:161322 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521323 ASSERT_TRUE(response1);
1324 EXPECT_TRUE(response1->headers);
[email protected]2bd93022010-07-17 00:58:441325 EXPECT_TRUE(response1->was_fetched_via_spdy);
1326 out.status_line = response1->headers->GetStatusLine();
1327 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161328 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011329 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021330 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441331 EXPECT_EQ("hello!hello!", out.response_data);
1332
bnc691fda62016-08-12 00:43:161333 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441334 out.status_line = response2->headers->GetStatusLine();
1335 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161336 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011337 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021338 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441339 EXPECT_EQ("hello!hello!", out.response_data);
1340
bnc691fda62016-08-12 00:43:161341 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
[email protected]2bd93022010-07-17 00:58:441342 out.status_line = response3->headers->GetStatusLine();
1343 out.response_info = *response3;
bnc691fda62016-08-12 00:43:161344 out.rv = ReadTransaction(&trans3, &out.response_data);
robpercival214763f2016-07-01 23:27:011345 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021346 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]2bd93022010-07-17 00:58:441347 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]044dcc52010-09-17 15:44:261348
1349 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:441350 }
robpercival214763f2016-07-01 23:27:011351 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441352}
1353
1354// Similar to ThreeGetsWithMaxConcurrent above, however this test adds
1355// a fourth transaction. The third and fourth transactions have
1356// different data ("hello!" vs "hello!hello!") and because of the
1357// user specified priority, we expect to see them inverted in
1358// the response from the server.
bncd16676a2016-07-20 16:23:011359TEST_F(SpdyNetworkTransactionTest, FourGetsWithMaxConcurrentPriority) {
[email protected]2bd93022010-07-17 00:58:441360 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:131361 spdy::SpdySerializedFrame req(
1362 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1363 spdy::SpdySerializedFrame resp(
1364 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1365 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1366 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381367 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441368
Ryan Hamilton0239aac2018-05-19 00:03:131369 spdy::SpdySerializedFrame req2(
1370 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1371 spdy::SpdySerializedFrame resp2(
1372 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1373 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1374 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
rdsmithebb50aa2015-11-12 03:44:381375 spdy_util_.UpdateWithStreamDestruction(3);
[email protected]2bd93022010-07-17 00:58:441376
Ryan Hamilton0239aac2018-05-19 00:03:131377 spdy::SpdySerializedFrame req4(
1378 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, HIGHEST));
1379 spdy::SpdySerializedFrame resp4(
1380 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
1381 spdy::SpdySerializedFrame fbody4(spdy_util_.ConstructSpdyDataFrame(5, true));
rdsmithebb50aa2015-11-12 03:44:381382 spdy_util_.UpdateWithStreamDestruction(5);
[email protected]2bd93022010-07-17 00:58:441383
Ryan Hamilton0239aac2018-05-19 00:03:131384 spdy::SpdySerializedFrame req3(
1385 spdy_util_.ConstructSpdyGet(nullptr, 0, 7, LOWEST));
1386 spdy::SpdySerializedFrame resp3(
1387 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 7));
1388 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(7, false));
1389 spdy::SpdySerializedFrame fbody3(spdy_util_.ConstructSpdyDataFrame(7, true));
[email protected]2bd93022010-07-17 00:58:441390
Ryan Hamilton0239aac2018-05-19 00:03:131391 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461392 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131393 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1394 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201395 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131396 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
rch08e3aa3e2015-05-16 14:27:521397 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411398 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
rch08e3aa3e2015-05-16 14:27:521399 // By making these synchronous, it guarantees that they are not *started*
1400 // before their sequence number, which in turn verifies that only a single
1401 // request is in-flight at a time.
bncdf80d44fd2016-07-15 20:27:411402 CreateMockWrite(req2, 6, SYNCHRONOUS),
1403 CreateMockWrite(req4, 10, SYNCHRONOUS),
1404 CreateMockWrite(req3, 13, SYNCHRONOUS),
[email protected]2bd93022010-07-17 00:58:441405 };
1406 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411407 CreateMockRead(settings_frame, 1),
1408 CreateMockRead(resp, 2),
1409 CreateMockRead(body, 3),
1410 CreateMockRead(fbody, 4),
1411 CreateMockRead(resp2, 7),
1412 CreateMockRead(body2, 8),
1413 CreateMockRead(fbody2, 9),
1414 CreateMockRead(resp4, 11),
1415 CreateMockRead(fbody4, 12),
1416 CreateMockRead(resp3, 14),
1417 CreateMockRead(body3, 15),
1418 CreateMockRead(fbody3, 16),
[email protected]2bd93022010-07-17 00:58:441419
rch08e3aa3e2015-05-16 14:27:521420 MockRead(ASYNC, 0, 17), // EOF
[email protected]2bd93022010-07-17 00:58:441421 };
Ryan Sleevib8d7ea02018-05-07 20:01:011422 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441423 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101424 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081425 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571426 helper.AddData(&data);
rch08e3aa3e2015-05-16 14:27:521427
bnc691fda62016-08-12 00:43:161428 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
1429 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
1430 HttpNetworkTransaction trans3(DEFAULT_PRIORITY, helper.session());
1431 HttpNetworkTransaction trans4(HIGHEST, helper.session());
[email protected]2bd93022010-07-17 00:58:441432
[email protected]49639fa2011-12-20 23:22:411433 TestCompletionCallback callback1;
1434 TestCompletionCallback callback2;
1435 TestCompletionCallback callback3;
1436 TestCompletionCallback callback4;
[email protected]2bd93022010-07-17 00:58:441437
Bence Békydb3cf652017-10-10 15:22:101438 out.rv = trans1.Start(&request_, callback1.callback(), log_);
robpercival214763f2016-07-01 23:27:011439 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]e0935cc2012-03-24 14:12:481440 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]bdebd1b2010-08-09 20:18:081441 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011442 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441443
bnceb9aa7112017-01-05 01:03:461444 // Finish async network reads and writes associated with |trans1|.
1445 base::RunLoop().RunUntilIdle();
1446
Bence Békydb3cf652017-10-10 15:22:101447 out.rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:011448 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101449 out.rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:011450 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:101451 out.rv = trans4.Start(&request_, callback4.callback(), log_);
robpercival214763f2016-07-01 23:27:011452 ASSERT_THAT(out.rv, IsError(ERR_IO_PENDING));
[email protected]2bd93022010-07-17 00:58:441453
[email protected]bdebd1b2010-08-09 20:18:081454 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011455 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441456
[email protected]bdebd1b2010-08-09 20:18:081457 out.rv = callback3.WaitForResult();
robpercival214763f2016-07-01 23:27:011458 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441459
bnc691fda62016-08-12 00:43:161460 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521461 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081462 EXPECT_TRUE(response1->was_fetched_via_spdy);
1463 out.status_line = response1->headers->GetStatusLine();
1464 out.response_info = *response1;
bnc691fda62016-08-12 00:43:161465 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011466 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021467 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081468 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441469
bnc691fda62016-08-12 00:43:161470 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081471 out.status_line = response2->headers->GetStatusLine();
1472 out.response_info = *response2;
bnc691fda62016-08-12 00:43:161473 out.rv = ReadTransaction(&trans2, &out.response_data);
robpercival214763f2016-07-01 23:27:011474 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021475 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081476 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441477
[email protected]bdebd1b2010-08-09 20:18:081478 // notice: response3 gets two hellos, response4 gets one
1479 // hello, so we know dequeuing priority was respected.
bnc691fda62016-08-12 00:43:161480 const HttpResponseInfo* response3 = trans3.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081481 out.status_line = response3->headers->GetStatusLine();
1482 out.response_info = *response3;
bnc691fda62016-08-12 00:43:161483 out.rv = ReadTransaction(&trans3, &out.response_data);
robpercival214763f2016-07-01 23:27:011484 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021485 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081486 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441487
[email protected]bdebd1b2010-08-09 20:18:081488 out.rv = callback4.WaitForResult();
robpercival214763f2016-07-01 23:27:011489 EXPECT_THAT(out.rv, IsOk());
bnc691fda62016-08-12 00:43:161490 const HttpResponseInfo* response4 = trans4.GetResponseInfo();
[email protected]bdebd1b2010-08-09 20:18:081491 out.status_line = response4->headers->GetStatusLine();
1492 out.response_info = *response4;
bnc691fda62016-08-12 00:43:161493 out.rv = ReadTransaction(&trans4, &out.response_data);
robpercival214763f2016-07-01 23:27:011494 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021495 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081496 EXPECT_EQ("hello!", out.response_data);
1497 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011498 EXPECT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441499}
1500
1501// Similar to ThreeGetsMaxConcurrrent above, however, this test
rch08e3aa3e2015-05-16 14:27:521502// deletes a session in the middle of the transaction to ensure
[email protected]2bd93022010-07-17 00:58:441503// that we properly remove pendingcreatestream objects from
1504// the spdy_session
bncd16676a2016-07-20 16:23:011505TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentDelete) {
[email protected]2bd93022010-07-17 00:58:441506 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:131507 spdy::SpdySerializedFrame req(
1508 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
1509 spdy::SpdySerializedFrame resp(
1510 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1511 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1512 spdy::SpdySerializedFrame fbody(spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381513 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]2bd93022010-07-17 00:58:441514
Ryan Hamilton0239aac2018-05-19 00:03:131515 spdy::SpdySerializedFrame req2(
1516 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
1517 spdy::SpdySerializedFrame resp2(
1518 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
1519 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, false));
1520 spdy::SpdySerializedFrame fbody2(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]2bd93022010-07-17 00:58:441521
Ryan Hamilton0239aac2018-05-19 00:03:131522 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461523 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131524 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1525 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201526 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131527 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]2bd93022010-07-17 00:58:441528
[email protected]d4a77c12014-05-15 20:45:211529 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411530 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 5),
1531 CreateMockWrite(req2, 6),
[email protected]2bd93022010-07-17 00:58:441532 };
1533 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411534 CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
1535 CreateMockRead(body, 3), CreateMockRead(fbody, 4),
1536 CreateMockRead(resp2, 7), CreateMockRead(body2, 8),
1537 CreateMockRead(fbody2, 9), MockRead(ASYNC, 0, 10), // EOF
[email protected]2bd93022010-07-17 00:58:441538 };
1539
Ryan Sleevib8d7ea02018-05-07 20:01:011540 SequencedSocketData data(reads, writes);
[email protected]2bd93022010-07-17 00:58:441541
[email protected]2bd93022010-07-17 00:58:441542 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:101543 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdebd1b2010-08-09 20:18:081544 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571545 helper.AddData(&data);
Jeremy Roman0579ed62017-08-29 15:56:191546 auto trans1 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341547 helper.session());
Jeremy Roman0579ed62017-08-29 15:56:191548 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341549 helper.session());
Jeremy Roman0579ed62017-08-29 15:56:191550 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
bnc3f6a8552017-05-17 13:40:341551 helper.session());
[email protected]2bd93022010-07-17 00:58:441552
[email protected]49639fa2011-12-20 23:22:411553 TestCompletionCallback callback1;
1554 TestCompletionCallback callback2;
1555 TestCompletionCallback callback3;
[email protected]2bd93022010-07-17 00:58:441556
Bence Békydb3cf652017-10-10 15:22:101557 out.rv = trans1->Start(&request_, callback1.callback(), log_);
[email protected]bdebd1b2010-08-09 20:18:081558 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]e0935cc2012-03-24 14:12:481559 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]bdebd1b2010-08-09 20:18:081560 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011561 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441562
Bence Békydb3cf652017-10-10 15:22:101563 out.rv = trans2->Start(&request_, callback2.callback(), log_);
[email protected]bdebd1b2010-08-09 20:18:081564 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101565 out.rv = trans3->Start(&request_, callback3.callback(), log_);
olli.raula7ca9cd1d2016-01-04 06:50:371566 trans3.reset();
[email protected]bdebd1b2010-08-09 20:18:081567 ASSERT_EQ(out.rv, ERR_IO_PENDING);
1568 out.rv = callback2.WaitForResult();
robpercival214763f2016-07-01 23:27:011569 ASSERT_THAT(out.rv, IsOk());
[email protected]2bd93022010-07-17 00:58:441570
[email protected]bdebd1b2010-08-09 20:18:081571 const HttpResponseInfo* response1 = trans1->GetResponseInfo();
wezca1070932016-05-26 20:30:521572 ASSERT_TRUE(response1);
1573 EXPECT_TRUE(response1->headers);
[email protected]bdebd1b2010-08-09 20:18:081574 EXPECT_TRUE(response1->was_fetched_via_spdy);
1575 out.status_line = response1->headers->GetStatusLine();
1576 out.response_info = *response1;
1577 out.rv = ReadTransaction(trans1.get(), &out.response_data);
robpercival214763f2016-07-01 23:27:011578 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021579 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081580 EXPECT_EQ("hello!hello!", out.response_data);
[email protected]2bd93022010-07-17 00:58:441581
[email protected]bdebd1b2010-08-09 20:18:081582 const HttpResponseInfo* response2 = trans2->GetResponseInfo();
wezca1070932016-05-26 20:30:521583 ASSERT_TRUE(response2);
[email protected]bdebd1b2010-08-09 20:18:081584 out.status_line = response2->headers->GetStatusLine();
1585 out.response_info = *response2;
1586 out.rv = ReadTransaction(trans2.get(), &out.response_data);
robpercival214763f2016-07-01 23:27:011587 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021588 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bdebd1b2010-08-09 20:18:081589 EXPECT_EQ("hello!hello!", out.response_data);
1590 helper.VerifyDataConsumed();
robpercival214763f2016-07-01 23:27:011591 EXPECT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261592}
[email protected]2bd93022010-07-17 00:58:441593
[email protected]448d4ca52012-03-04 04:12:231594namespace {
1595
Bence Béky8ddc2492018-06-13 01:02:041596// A helper class that will delete |transaction| on error when the callback is
1597// invoked.
[email protected]49639fa2011-12-20 23:22:411598class KillerCallback : public TestCompletionCallbackBase {
[email protected]044dcc52010-09-17 15:44:261599 public:
1600 explicit KillerCallback(HttpNetworkTransaction* transaction)
Bence Béky8ddc2492018-06-13 01:02:041601 : transaction_(transaction) {}
[email protected]044dcc52010-09-17 15:44:261602
Chris Watkins61914cb2017-12-01 19:59:001603 ~KillerCallback() override = default;
[email protected]49639fa2011-12-20 23:22:411604
Bence Béky8ddc2492018-06-13 01:02:041605 CompletionOnceCallback callback() {
1606 return base::BindOnce(&KillerCallback::OnComplete, base::Unretained(this));
1607 }
[email protected]49639fa2011-12-20 23:22:411608
[email protected]044dcc52010-09-17 15:44:261609 private:
[email protected]49639fa2011-12-20 23:22:411610 void OnComplete(int result) {
1611 if (result < 0)
1612 delete transaction_;
1613
1614 SetResult(result);
1615 }
1616
[email protected]044dcc52010-09-17 15:44:261617 HttpNetworkTransaction* transaction_;
1618};
1619
[email protected]448d4ca52012-03-04 04:12:231620} // namespace
1621
[email protected]044dcc52010-09-17 15:44:261622// Similar to ThreeGetsMaxConcurrrentDelete above, however, this test
1623// closes the socket while we have a pending transaction waiting for
1624// a pending stream creation. http://crbug.com/52901
bncd16676a2016-07-20 16:23:011625TEST_F(SpdyNetworkTransactionTest, ThreeGetsWithMaxConcurrentSocketClose) {
Matt Menke66e502a72019-04-15 13:34:381626 // Construct the request. Each stream uses a different priority to provide
1627 // more useful failure information if the requests are made in an unexpected
1628 // order.
Ryan Hamilton0239aac2018-05-19 00:03:131629 spdy::SpdySerializedFrame req(
Matt Menke66e502a72019-04-15 13:34:381630 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
Ryan Hamilton0239aac2018-05-19 00:03:131631 spdy::SpdySerializedFrame resp(
1632 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1633 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, false));
1634 spdy::SpdySerializedFrame fin_body(
1635 spdy_util_.ConstructSpdyDataFrame(1, true));
rdsmithebb50aa2015-11-12 03:44:381636 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]044dcc52010-09-17 15:44:261637
Ryan Hamilton0239aac2018-05-19 00:03:131638 spdy::SpdySerializedFrame req2(
Matt Menke66e502a72019-04-15 13:34:381639 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM));
Ryan Hamilton0239aac2018-05-19 00:03:131640 spdy::SpdySerializedFrame resp2(
1641 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
[email protected]044dcc52010-09-17 15:44:261642
Ryan Hamilton0239aac2018-05-19 00:03:131643 spdy::SettingsMap settings;
Avi Drissman13fc8932015-12-20 04:40:461644 const uint32_t max_concurrent_streams = 1;
Ryan Hamilton0239aac2018-05-19 00:03:131645 settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] = max_concurrent_streams;
1646 spdy::SpdySerializedFrame settings_frame(
[email protected]c10b20852013-05-15 21:29:201647 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:131648 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
[email protected]044dcc52010-09-17 15:44:261649
Matt Menke66e502a72019-04-15 13:34:381650 MockWrite writes[] = {CreateMockWrite(req, 0),
1651 CreateMockWrite(settings_ack, 6),
1652 CreateMockWrite(req2, 7)};
[email protected]044dcc52010-09-17 15:44:261653 MockRead reads[] = {
Matt Menke66e502a72019-04-15 13:34:381654 CreateMockRead(settings_frame, 1), CreateMockRead(resp, 2),
bncdf80d44fd2016-07-15 20:27:411655 CreateMockRead(body, 3),
Matt Menke66e502a72019-04-15 13:34:381656 // Delay the request here. For this test to pass, the three HTTP streams
1657 // have to be created in order, but SpdySession doesn't actually guarantee
1658 // that (See note in SpdySession::ProcessPendingStreamRequests). As a
1659 // workaround, delay finishing up the first stream until the second and
1660 // third streams are waiting in the SPDY stream request queue.
1661 MockRead(ASYNC, ERR_IO_PENDING, 4), CreateMockRead(fin_body, 5),
1662 CreateMockRead(resp2, 8),
David Benjamin73dc5242019-05-15 21:59:281663 // The exact error does not matter, but some errors, such as
1664 // ERR_CONNECTION_RESET, may trigger a retry, which this test does not
1665 // account for.
1666 MockRead(ASYNC, ERR_SSL_BAD_RECORD_MAC_ALERT, 9), // Abort!
[email protected]044dcc52010-09-17 15:44:261667 };
1668
Ryan Sleevib8d7ea02018-05-07 20:01:011669 SequencedSocketData data(reads, writes);
1670 SequencedSocketData data_placeholder;
[email protected]044dcc52010-09-17 15:44:261671
[email protected]044dcc52010-09-17 15:44:261672 TransactionHelperResult out;
Matt Menke66e502a72019-04-15 13:34:381673 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_, nullptr);
[email protected]044dcc52010-09-17 15:44:261674 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:571675 helper.AddData(&data);
[email protected]044dcc52010-09-17 15:44:261676 // We require placeholder data because three get requests are sent out, so
1677 // there needs to be three sets of SSL connection data.
[email protected]dd54bd82012-07-19 23:44:571678 helper.AddData(&data_placeholder);
1679 helper.AddData(&data_placeholder);
Matt Menke66e502a72019-04-15 13:34:381680 HttpNetworkTransaction trans1(HIGHEST, helper.session());
1681 HttpNetworkTransaction trans2(MEDIUM, helper.session());
[email protected]262eec82013-03-19 21:01:361682 HttpNetworkTransaction* trans3(
mmenkee65e7af2015-10-13 17:16:421683 new HttpNetworkTransaction(DEFAULT_PRIORITY, helper.session()));
[email protected]044dcc52010-09-17 15:44:261684
[email protected]49639fa2011-12-20 23:22:411685 TestCompletionCallback callback1;
1686 TestCompletionCallback callback2;
[email protected]044dcc52010-09-17 15:44:261687 KillerCallback callback3(trans3);
1688
Bence Békydb3cf652017-10-10 15:22:101689 out.rv = trans1.Start(&request_, callback1.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261690 ASSERT_EQ(out.rv, ERR_IO_PENDING);
[email protected]e0935cc2012-03-24 14:12:481691 // Run transaction 1 through quickly to force a read of our SETTINGS frame.
[email protected]044dcc52010-09-17 15:44:261692 out.rv = callback1.WaitForResult();
robpercival214763f2016-07-01 23:27:011693 ASSERT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261694
Bence Békydb3cf652017-10-10 15:22:101695 out.rv = trans2.Start(&request_, callback2.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261696 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Bence Békydb3cf652017-10-10 15:22:101697 out.rv = trans3->Start(&request_, callback3.callback(), log_);
[email protected]044dcc52010-09-17 15:44:261698 ASSERT_EQ(out.rv, ERR_IO_PENDING);
Matt Menke66e502a72019-04-15 13:34:381699
1700 // Run until both transactions are in the SpdySession's queue, waiting for the
1701 // final request to complete.
1702 base::RunLoop().RunUntilIdle();
1703 data.Resume();
1704
[email protected]044dcc52010-09-17 15:44:261705 out.rv = callback3.WaitForResult();
David Benjamin73dc5242019-05-15 21:59:281706 EXPECT_THAT(out.rv, IsError(ERR_SSL_BAD_RECORD_MAC_ALERT));
[email protected]044dcc52010-09-17 15:44:261707
[email protected]044dcc52010-09-17 15:44:261708 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:521709 ASSERT_TRUE(response1);
1710 EXPECT_TRUE(response1->headers);
[email protected]044dcc52010-09-17 15:44:261711 EXPECT_TRUE(response1->was_fetched_via_spdy);
1712 out.status_line = response1->headers->GetStatusLine();
1713 out.response_info = *response1;
1714 out.rv = ReadTransaction(&trans1, &out.response_data);
robpercival214763f2016-07-01 23:27:011715 EXPECT_THAT(out.rv, IsOk());
[email protected]044dcc52010-09-17 15:44:261716
1717 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:521718 ASSERT_TRUE(response2);
[email protected]044dcc52010-09-17 15:44:261719 out.status_line = response2->headers->GetStatusLine();
1720 out.response_info = *response2;
1721 out.rv = ReadTransaction(&trans2, &out.response_data);
David Benjamin73dc5242019-05-15 21:59:281722 EXPECT_THAT(out.rv, IsError(ERR_SSL_BAD_RECORD_MAC_ALERT));
[email protected]044dcc52010-09-17 15:44:261723
1724 helper.VerifyDataConsumed();
[email protected]2bd93022010-07-17 00:58:441725}
1726
[email protected]d8ef27b2010-08-06 17:34:391727// Test that a simple PUT request works.
bncd16676a2016-07-20 16:23:011728TEST_F(SpdyNetworkTransactionTest, Put) {
Bence Békydb3cf652017-10-10 15:22:101729 // Setup the request.
1730 request_.method = "PUT";
[email protected]d8ef27b2010-08-06 17:34:391731
Bence Béky4c325e52020-10-22 20:48:011732 spdy::Http2HeaderBlock put_headers(
bncb26024382016-06-29 02:39:451733 spdy_util_.ConstructPutHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131734 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:151735 spdy_util_.ConstructSpdyHeaders(1, std::move(put_headers), LOWEST, true));
[email protected]d8ef27b2010-08-06 17:34:391736 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411737 CreateMockWrite(req, 0),
[email protected]d8ef27b2010-08-06 17:34:391738 };
1739
Ryan Hamilton0239aac2018-05-19 00:03:131740 spdy::SpdySerializedFrame resp(
1741 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1742 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d8ef27b2010-08-06 17:34:391743 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411744 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521745 MockRead(ASYNC, 0, 3) // EOF
[email protected]d8ef27b2010-08-06 17:34:391746 };
1747
Ryan Sleevib8d7ea02018-05-07 20:01:011748 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101749 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571750 helper.RunToCompletion(&data);
[email protected]d8ef27b2010-08-06 17:34:391751 TransactionHelperResult out = helper.output();
1752
robpercival214763f2016-07-01 23:27:011753 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021754 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]d8ef27b2010-08-06 17:34:391755}
1756
1757// Test that a simple HEAD request works.
bncd16676a2016-07-20 16:23:011758TEST_F(SpdyNetworkTransactionTest, Head) {
Bence Békydb3cf652017-10-10 15:22:101759 // Setup the request.
1760 request_.method = "HEAD";
[email protected]d8ef27b2010-08-06 17:34:391761
Bence Béky4c325e52020-10-22 20:48:011762 spdy::Http2HeaderBlock head_headers(
bncb26024382016-06-29 02:39:451763 spdy_util_.ConstructHeadHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131764 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyHeaders(
bnc42331402016-07-25 13:36:151765 1, std::move(head_headers), LOWEST, true));
[email protected]d8ef27b2010-08-06 17:34:391766 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411767 CreateMockWrite(req, 0),
[email protected]d8ef27b2010-08-06 17:34:391768 };
1769
Ryan Hamilton0239aac2018-05-19 00:03:131770 spdy::SpdySerializedFrame resp(
1771 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
1772 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d8ef27b2010-08-06 17:34:391773 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411774 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521775 MockRead(ASYNC, 0, 3) // EOF
[email protected]d8ef27b2010-08-06 17:34:391776 };
1777
Ryan Sleevib8d7ea02018-05-07 20:01:011778 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101779 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571780 helper.RunToCompletion(&data);
[email protected]d8ef27b2010-08-06 17:34:391781 TransactionHelperResult out = helper.output();
1782
robpercival214763f2016-07-01 23:27:011783 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021784 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]d8ef27b2010-08-06 17:34:391785}
1786
[email protected]72552f02009-10-28 15:25:011787// Test that a simple POST works.
bncd16676a2016-07-20 16:23:011788TEST_F(SpdyNetworkTransactionTest, Post) {
Ryan Hamilton0239aac2018-05-19 00:03:131789 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351790 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131791 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:141792 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411793 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]ff57bb82009-11-12 06:52:141794 };
[email protected]72552f02009-10-28 15:25:011795
Ryan Hamilton0239aac2018-05-19 00:03:131796 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]ff57bb82009-11-12 06:52:141797 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411798 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521799 MockRead(ASYNC, 0, 4) // EOF
[email protected]aea80602009-09-18 00:55:081800 };
1801
Ryan Sleevib8d7ea02018-05-07 20:01:011802 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101803 UsePostRequest();
1804 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571805 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:471806 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011807 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021808 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]aea80602009-09-18 00:55:081809 EXPECT_EQ("hello!", out.response_data);
1810}
1811
[email protected]69e6b4a2012-10-18 08:03:011812// Test that a POST with a file works.
bncd16676a2016-07-20 16:23:011813TEST_F(SpdyNetworkTransactionTest, FilePost) {
Ryan Hamilton0239aac2018-05-19 00:03:131814 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351815 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131816 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]69e6b4a2012-10-18 08:03:011817 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411818 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]69e6b4a2012-10-18 08:03:011819 };
1820
Ryan Hamilton0239aac2018-05-19 00:03:131821 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]69e6b4a2012-10-18 08:03:011822 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411823 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521824 MockRead(ASYNC, 0, 4) // EOF
[email protected]69e6b4a2012-10-18 08:03:011825 };
1826
Ryan Sleevib8d7ea02018-05-07 20:01:011827 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101828 UseFilePostRequest();
1829 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]69e6b4a2012-10-18 08:03:011830 helper.RunToCompletion(&data);
1831 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011832 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021833 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]69e6b4a2012-10-18 08:03:011834 EXPECT_EQ("hello!", out.response_data);
1835}
1836
[email protected]999dd8c2013-11-12 06:45:541837// Test that a POST with a unreadable file fails.
bncd16676a2016-07-20 16:23:011838TEST_F(SpdyNetworkTransactionTest, UnreadableFilePost) {
[email protected]999dd8c2013-11-12 06:45:541839 MockWrite writes[] = {
rch08e3aa3e2015-05-16 14:27:521840 MockWrite(ASYNC, 0, 0) // EOF
[email protected]999dd8c2013-11-12 06:45:541841 };
1842 MockRead reads[] = {
rch08e3aa3e2015-05-16 14:27:521843 MockRead(ASYNC, 0, 1) // EOF
[email protected]999dd8c2013-11-12 06:45:541844 };
1845
Ryan Sleevib8d7ea02018-05-07 20:01:011846 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101847 UseUnreadableFilePostRequest();
1848 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]999dd8c2013-11-12 06:45:541849 helper.RunPreTestSetup();
1850 helper.AddData(&data);
1851 helper.RunDefaultTest();
1852
1853 base::RunLoop().RunUntilIdle();
1854 helper.VerifyDataNotConsumed();
robpercival214763f2016-07-01 23:27:011855 EXPECT_THAT(helper.output().rv, IsError(ERR_ACCESS_DENIED));
[email protected]999dd8c2013-11-12 06:45:541856}
1857
[email protected]69e6b4a2012-10-18 08:03:011858// Test that a complex POST works.
bncd16676a2016-07-20 16:23:011859TEST_F(SpdyNetworkTransactionTest, ComplexPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131860 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:351861 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131862 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]69e6b4a2012-10-18 08:03:011863 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411864 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
[email protected]69e6b4a2012-10-18 08:03:011865 };
1866
Ryan Hamilton0239aac2018-05-19 00:03:131867 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]69e6b4a2012-10-18 08:03:011868 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411869 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521870 MockRead(ASYNC, 0, 4) // EOF
[email protected]69e6b4a2012-10-18 08:03:011871 };
1872
Ryan Sleevib8d7ea02018-05-07 20:01:011873 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101874 UseComplexPostRequest();
1875 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]69e6b4a2012-10-18 08:03:011876 helper.RunToCompletion(&data);
1877 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011878 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021879 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]69e6b4a2012-10-18 08:03:011880 EXPECT_EQ("hello!", out.response_data);
1881}
1882
[email protected]0c9bf872011-03-04 17:53:221883// Test that a chunked POST works.
bncd16676a2016-07-20 16:23:011884TEST_F(SpdyNetworkTransactionTest, ChunkedPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131885 spdy::SpdySerializedFrame req(
1886 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1887 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]0c9bf872011-03-04 17:53:221888 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411889 CreateMockWrite(req, 0), CreateMockWrite(body, 1),
[email protected]0c9bf872011-03-04 17:53:221890 };
1891
Ryan Hamilton0239aac2018-05-19 00:03:131892 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]0c9bf872011-03-04 17:53:221893 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411894 CreateMockRead(resp, 2), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:521895 MockRead(ASYNC, 0, 4) // EOF
[email protected]0c9bf872011-03-04 17:53:221896 };
1897
Ryan Sleevib8d7ea02018-05-07 20:01:011898 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101899 UseChunkedPostRequest();
1900 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]34b345f92013-02-22 03:27:261901
1902 // These chunks get merged into a single frame when being sent.
1903 const int kFirstChunkSize = kUploadDataSize/2;
mmenkecbc2b712014-10-09 20:29:071904 upload_chunked_data_stream()->AppendData(kUploadData, kFirstChunkSize, false);
1905 upload_chunked_data_stream()->AppendData(
[email protected]34b345f92013-02-22 03:27:261906 kUploadData + kFirstChunkSize, kUploadDataSize - kFirstChunkSize, true);
1907
[email protected]dd54bd82012-07-19 23:44:571908 helper.RunToCompletion(&data);
[email protected]0c9bf872011-03-04 17:53:221909 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011910 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021911 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]34b345f92013-02-22 03:27:261912 EXPECT_EQ(kUploadData, out.response_data);
1913}
1914
1915// Test that a chunked POST works with chunks appended after transaction starts.
bncd16676a2016-07-20 16:23:011916TEST_F(SpdyNetworkTransactionTest, DelayedChunkedPost) {
Ryan Hamilton0239aac2018-05-19 00:03:131917 spdy::SpdySerializedFrame req(
1918 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
1919 spdy::SpdySerializedFrame chunk1(spdy_util_.ConstructSpdyDataFrame(1, false));
1920 spdy::SpdySerializedFrame chunk2(spdy_util_.ConstructSpdyDataFrame(1, false));
1921 spdy::SpdySerializedFrame chunk3(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]34b345f92013-02-22 03:27:261922 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411923 CreateMockWrite(req, 0), CreateMockWrite(chunk1, 1),
1924 CreateMockWrite(chunk2, 2), CreateMockWrite(chunk3, 3),
[email protected]34b345f92013-02-22 03:27:261925 };
1926
Ryan Hamilton0239aac2018-05-19 00:03:131927 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]34b345f92013-02-22 03:27:261928 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411929 CreateMockRead(resp, 4), CreateMockRead(chunk1, 5),
1930 CreateMockRead(chunk2, 6), CreateMockRead(chunk3, 7),
rch08e3aa3e2015-05-16 14:27:521931 MockRead(ASYNC, 0, 8) // EOF
[email protected]34b345f92013-02-22 03:27:261932 };
1933
Ryan Sleevib8d7ea02018-05-07 20:01:011934 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:101935 UseChunkedPostRequest();
1936 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]34b345f92013-02-22 03:27:261937
mmenkecbc2b712014-10-09 20:29:071938 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
[email protected]34b345f92013-02-22 03:27:261939
1940 helper.RunPreTestSetup();
1941 helper.AddData(&data);
1942 ASSERT_TRUE(helper.StartDefaultTest());
1943
[email protected]fc9d88472013-08-14 02:31:171944 base::RunLoop().RunUntilIdle();
mmenkecbc2b712014-10-09 20:29:071945 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, false);
[email protected]fc9d88472013-08-14 02:31:171946 base::RunLoop().RunUntilIdle();
mmenkecbc2b712014-10-09 20:29:071947 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
[email protected]34b345f92013-02-22 03:27:261948
1949 helper.FinishDefaultTest();
1950 helper.VerifyDataConsumed();
1951
Bence Béky4e83f492018-05-13 23:14:251952 std::string expected_response;
[email protected]34b345f92013-02-22 03:27:261953 expected_response += kUploadData;
1954 expected_response += kUploadData;
1955 expected_response += kUploadData;
1956
1957 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011958 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021959 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]34b345f92013-02-22 03:27:261960 EXPECT_EQ(expected_response, out.response_data);
[email protected]0c9bf872011-03-04 17:53:221961}
1962
[email protected]a33cad2b62010-07-30 22:24:391963// Test that a POST without any post data works.
bncd16676a2016-07-20 16:23:011964TEST_F(SpdyNetworkTransactionTest, NullPost) {
Bence Békydb3cf652017-10-10 15:22:101965 // Setup the request.
1966 request_.method = "POST";
[email protected]a33cad2b62010-07-30 22:24:391967 // Create an empty UploadData.
Bence Békydb3cf652017-10-10 15:22:101968 request_.upload_data_stream = nullptr;
[email protected]a33cad2b62010-07-30 22:24:391969
[email protected]329b68b2012-11-14 17:54:271970 // When request.upload_data_stream is NULL for post, content-length is
[email protected]a33cad2b62010-07-30 22:24:391971 // expected to be 0.
Bence Béky4c325e52020-10-22 20:48:011972 spdy::Http2HeaderBlock req_block(
bncb26024382016-06-29 02:39:451973 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
Ryan Hamilton0239aac2018-05-19 00:03:131974 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:151975 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
[email protected]d2c1a97b2014-03-03 19:25:091976
[email protected]a33cad2b62010-07-30 22:24:391977 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:411978 CreateMockWrite(req, 0),
[email protected]a33cad2b62010-07-30 22:24:391979 };
1980
Ryan Hamilton0239aac2018-05-19 00:03:131981 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
1982 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]a33cad2b62010-07-30 22:24:391983 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:411984 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:521985 MockRead(ASYNC, 0, 3) // EOF
[email protected]a33cad2b62010-07-30 22:24:391986 };
1987
Ryan Sleevib8d7ea02018-05-07 20:01:011988 SequencedSocketData data(reads, writes);
[email protected]a33cad2b62010-07-30 22:24:391989
Bence Békydb3cf652017-10-10 15:22:101990 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:571991 helper.RunToCompletion(&data);
[email protected]a33cad2b62010-07-30 22:24:391992 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:011993 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:021994 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]a33cad2b62010-07-30 22:24:391995 EXPECT_EQ("hello!", out.response_data);
1996}
1997
[email protected]edd3b0a52009-11-24 18:56:361998// Test that a simple POST works.
bncd16676a2016-07-20 16:23:011999TEST_F(SpdyNetworkTransactionTest, EmptyPost) {
[email protected]329b68b2012-11-14 17:54:272000 // Create an empty UploadDataStream.
danakjaee3e1ec2016-04-16 00:23:182001 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
olli.raula6df48b2a2015-11-26 07:40:222002 ElementsUploadDataStream stream(std::move(element_readers), 0);
[email protected]329b68b2012-11-14 17:54:272003
Bence Békydb3cf652017-10-10 15:22:102004 // Setup the request.
2005 request_.method = "POST";
2006 request_.upload_data_stream = &stream;
[email protected]edd3b0a52009-11-24 18:56:362007
Avi Drissman13fc8932015-12-20 04:40:462008 const uint64_t kContentLength = 0;
[email protected]d2c1a97b2014-03-03 19:25:092009
Bence Béky4c325e52020-10-22 20:48:012010 spdy::Http2HeaderBlock req_block(
bncb26024382016-06-29 02:39:452011 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, kContentLength));
Ryan Hamilton0239aac2018-05-19 00:03:132012 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:152013 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block), LOWEST, true));
[email protected]d2c1a97b2014-03-03 19:25:092014
[email protected]edd3b0a52009-11-24 18:56:362015 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412016 CreateMockWrite(req, 0),
[email protected]edd3b0a52009-11-24 18:56:362017 };
2018
Ryan Hamilton0239aac2018-05-19 00:03:132019 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
2020 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]edd3b0a52009-11-24 18:56:362021 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412022 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:522023 MockRead(ASYNC, 0, 3) // EOF
[email protected]edd3b0a52009-11-24 18:56:362024 };
2025
Ryan Sleevib8d7ea02018-05-07 20:01:012026 SequencedSocketData data(reads, writes);
[email protected]bf2491a92009-11-29 16:39:482027
Bence Békydb3cf652017-10-10 15:22:102028 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572029 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:472030 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012031 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022032 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]edd3b0a52009-11-24 18:56:362033 EXPECT_EQ("hello!", out.response_data);
2034}
2035
[email protected]35c3fc732014-02-15 00:16:072036// While we're doing a post, the server sends the reply before upload completes.
bncd16676a2016-07-20 16:23:012037TEST_F(SpdyNetworkTransactionTest, ResponseBeforePostCompletes) {
Ryan Hamilton0239aac2018-05-19 00:03:132038 spdy::SpdySerializedFrame req(
2039 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
2040 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]35c3fc732014-02-15 00:16:072041 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412042 CreateMockWrite(req, 0), CreateMockWrite(body, 3),
[email protected]35c3fc732014-02-15 00:16:072043 };
Ryan Hamilton0239aac2018-05-19 00:03:132044 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]a5566f9702010-05-05 22:25:432045 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412046 CreateMockRead(resp, 1), CreateMockRead(body, 2),
2047 MockRead(ASYNC, 0, 4) // EOF
[email protected]a5566f9702010-05-05 22:25:432048 };
2049
[email protected]35c3fc732014-02-15 00:16:072050 // Write the request headers, and read the complete response
2051 // while still waiting for chunked request data.
Ryan Sleevib8d7ea02018-05-07 20:01:012052 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102053 UseChunkedPostRequest();
2054 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]c92f4b4542012-07-26 23:53:212055 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332056 helper.AddData(&data);
[email protected]c92f4b4542012-07-26 23:53:212057
[email protected]35c3fc732014-02-15 00:16:072058 ASSERT_TRUE(helper.StartDefaultTest());
[email protected]c92f4b4542012-07-26 23:53:212059
maksim.sisov8d2df66d2016-06-20 07:07:112060 base::RunLoop().RunUntilIdle();
mmenke666a6fea2015-12-19 04:16:332061
bnc42331402016-07-25 13:36:152062 // Process the request headers, response headers, and response body.
[email protected]35c3fc732014-02-15 00:16:072063 // The request body is still in flight.
[email protected]35c3fc732014-02-15 00:16:072064 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
bnc84e7fb52015-12-02 11:50:022065 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]35c3fc732014-02-15 00:16:072066
2067 // Finish sending the request body.
mmenkecbc2b712014-10-09 20:29:072068 upload_chunked_data_stream()->AppendData(kUploadData, kUploadDataSize, true);
maksim.sisov8d2df66d2016-06-20 07:07:112069 helper.WaitForCallbackToComplete();
robpercival214763f2016-07-01 23:27:012070 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]35c3fc732014-02-15 00:16:072071
Bence Béky4e83f492018-05-13 23:14:252072 std::string response_body;
robpercival214763f2016-07-01 23:27:012073 EXPECT_THAT(ReadTransaction(helper.trans(), &response_body), IsOk());
[email protected]35c3fc732014-02-15 00:16:072074 EXPECT_EQ(kUploadData, response_body);
bnceb9aa7112017-01-05 01:03:462075
2076 // Finish async network reads/writes.
2077 base::RunLoop().RunUntilIdle();
[email protected]35c3fc732014-02-15 00:16:072078 helper.VerifyDataConsumed();
[email protected]a5566f9702010-05-05 22:25:432079}
2080
[email protected]f9a26d72010-08-03 18:07:132081// The client upon cancellation tries to send a RST_STREAM frame. The mock
2082// socket causes the TCP write to return zero. This test checks that the client
2083// tries to queue up the RST_STREAM frame again.
bncd16676a2016-07-20 16:23:012084TEST_F(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
Ryan Hamilton0239aac2018-05-19 00:03:132085 spdy::SpdySerializedFrame req(
2086 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2087 spdy::SpdySerializedFrame rst(
2088 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
[email protected]f9a26d72010-08-03 18:07:132089 MockWrite writes[] = {
Raul Tambre94493c652019-03-11 17:18:352090 CreateMockWrite(req, 0, SYNCHRONOUS),
2091 MockWrite(SYNCHRONOUS, nullptr, 0, 2),
bncdf80d44fd2016-07-15 20:27:412092 CreateMockWrite(rst, 3, SYNCHRONOUS),
[email protected]f9a26d72010-08-03 18:07:132093 };
2094
Ryan Hamilton0239aac2018-05-19 00:03:132095 spdy::SpdySerializedFrame resp(
2096 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]f9a26d72010-08-03 18:07:132097 MockRead reads[] = {
Raul Tambre94493c652019-03-11 17:18:352098 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, nullptr, 0, 4) // EOF
[email protected]f9a26d72010-08-03 18:07:132099 };
2100
Ryan Sleevib8d7ea02018-05-07 20:01:012101 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102102 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]f9a26d72010-08-03 18:07:132103 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332104 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:002105 helper.StartDefaultTest();
2106 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
[email protected]f9a26d72010-08-03 18:07:132107
bnc4d782f492016-08-18 13:50:002108 helper.WaitForCallbackToComplete();
2109 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]3b7828432010-08-18 18:33:272110
[email protected]f9a26d72010-08-03 18:07:132111 helper.ResetTrans();
mmenke666a6fea2015-12-19 04:16:332112 base::RunLoop().RunUntilIdle();
[email protected]3b7828432010-08-18 18:33:272113
[email protected]f9a26d72010-08-03 18:07:132114 helper.VerifyDataConsumed();
2115}
2116
[email protected]93300672009-10-24 13:22:512117// Test that the transaction doesn't crash when we don't have a reply.
bnc42331402016-07-25 13:36:152118TEST_F(SpdyNetworkTransactionTest, ResponseWithoutHeaders) {
Ryan Hamilton0239aac2018-05-19 00:03:132119 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]ff57bb82009-11-12 06:52:142120 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412121 CreateMockRead(body, 1), MockRead(ASYNC, 0, 3) // EOF
[email protected]93300672009-10-24 13:22:512122 };
2123
Ryan Hamilton0239aac2018-05-19 00:03:132124 spdy::SpdySerializedFrame req(
2125 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2126 spdy::SpdySerializedFrame rst(
2127 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
rch08e3aa3e2015-05-16 14:27:522128 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412129 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
rch08e3aa3e2015-05-16 14:27:522130 };
Ryan Sleevib8d7ea02018-05-07 20:01:012131 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102132 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572133 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:472134 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:182135 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]93300672009-10-24 13:22:512136}
2137
[email protected]d30022352010-06-24 19:17:582138// Test that the transaction doesn't crash when we get two replies on the same
2139// stream ID. See http://crbug.com/45639.
bncd16676a2016-07-20 16:23:012140TEST_F(SpdyNetworkTransactionTest, ResponseWithTwoSynReplies) {
Ryan Hamilton0239aac2018-05-19 00:03:132141 spdy::SpdySerializedFrame req(
2142 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2143 spdy::SpdySerializedFrame rst(
2144 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]2aeef782013-06-21 18:30:562145 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412146 CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
[email protected]2aeef782013-06-21 18:30:562147 };
[email protected]d30022352010-06-24 19:17:582148
Ryan Hamilton0239aac2018-05-19 00:03:132149 spdy::SpdySerializedFrame resp0(
2150 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2151 spdy::SpdySerializedFrame resp1(
2152 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2153 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d30022352010-06-24 19:17:582154 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412155 CreateMockRead(resp0, 1), CreateMockRead(resp1, 2),
2156 CreateMockRead(body, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]d30022352010-06-24 19:17:582157 };
2158
Ryan Sleevib8d7ea02018-05-07 20:01:012159 SequencedSocketData data(reads, writes);
[email protected]d30022352010-06-24 19:17:582160
Bence Békydb3cf652017-10-10 15:22:102161 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472162 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572163 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472164
2165 HttpNetworkTransaction* trans = helper.trans();
[email protected]d30022352010-06-24 19:17:582166
[email protected]49639fa2011-12-20 23:22:412167 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102168 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012169 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d30022352010-06-24 19:17:582170 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:012171 EXPECT_THAT(rv, IsOk());
[email protected]d30022352010-06-24 19:17:582172
2173 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:522174 ASSERT_TRUE(response);
2175 EXPECT_TRUE(response->headers);
[email protected]d30022352010-06-24 19:17:582176 EXPECT_TRUE(response->was_fetched_via_spdy);
Bence Béky4e83f492018-05-13 23:14:252177 std::string response_data;
[email protected]3caf5542010-07-16 15:19:472178 rv = ReadTransaction(trans, &response_data);
Bence Békyd0d69502019-06-25 19:47:182179 EXPECT_THAT(rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]3caf5542010-07-16 15:19:472180
2181 helper.VerifyDataConsumed();
[email protected]d30022352010-06-24 19:17:582182}
2183
bncd16676a2016-07-20 16:23:012184TEST_F(SpdyNetworkTransactionTest, ResetReplyWithTransferEncoding) {
[email protected]b3503002012-03-27 04:57:252185 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132186 spdy::SpdySerializedFrame req(
2187 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2188 spdy::SpdySerializedFrame rst(
2189 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252190 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412191 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
[email protected]b3503002012-03-27 04:57:252192 };
2193
2194 const char* const headers[] = {
[email protected]513963e2013-06-15 01:53:042195 "transfer-encoding", "chunked"
[email protected]b3503002012-03-27 04:57:252196 };
Ryan Hamilton0239aac2018-05-19 00:03:132197 spdy::SpdySerializedFrame resp(
2198 spdy_util_.ConstructSpdyGetReply(headers, 1, 1));
2199 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b3503002012-03-27 04:57:252200 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412201 CreateMockRead(resp, 1), CreateMockRead(body, 3),
rch08e3aa3e2015-05-16 14:27:522202 MockRead(ASYNC, 0, 4) // EOF
[email protected]b3503002012-03-27 04:57:252203 };
2204
Ryan Sleevib8d7ea02018-05-07 20:01:012205 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102206 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572207 helper.RunToCompletion(&data);
[email protected]b3503002012-03-27 04:57:252208 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:182209 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252210
2211 helper.session()->spdy_session_pool()->CloseAllSessions();
2212 helper.VerifyDataConsumed();
2213}
2214
bncd16676a2016-07-20 16:23:012215TEST_F(SpdyNetworkTransactionTest, ResetPushWithTransferEncoding) {
[email protected]b3503002012-03-27 04:57:252216 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132217 spdy::SpdySerializedFrame req(
2218 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2219 spdy::SpdySerializedFrame priority(
tombergan5d22c182017-01-11 02:05:352220 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132221 spdy::SpdySerializedFrame rst(
2222 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b3503002012-03-27 04:57:252223 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352224 CreateMockWrite(req, 0), CreateMockWrite(priority, 3),
2225 CreateMockWrite(rst, 5),
[email protected]b3503002012-03-27 04:57:252226 };
2227
Ryan Hamilton0239aac2018-05-19 00:03:132228 spdy::SpdySerializedFrame resp(
2229 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]513963e2013-06-15 01:53:042230 const char* const headers[] = {
2231 "transfer-encoding", "chunked"
2232 };
Ryan Hamilton0239aac2018-05-19 00:03:132233 spdy::SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(
Avi Drissman4365a4782018-12-28 19:26:242234 headers, base::size(headers) / 2, 2, 1, "https://www.example.org/1"));
Ryan Hamilton0239aac2018-05-19 00:03:132235 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b3503002012-03-27 04:57:252236 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:352237 CreateMockRead(resp, 1), CreateMockRead(push, 2), CreateMockRead(body, 4),
2238 MockRead(ASYNC, 0, 6) // EOF
[email protected]b3503002012-03-27 04:57:252239 };
2240
Ryan Sleevib8d7ea02018-05-07 20:01:012241 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:102242 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:572243 helper.RunToCompletion(&data);
[email protected]b3503002012-03-27 04:57:252244 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:012245 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:022246 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]b3503002012-03-27 04:57:252247 EXPECT_EQ("hello!", out.response_data);
2248
2249 helper.session()->spdy_session_pool()->CloseAllSessions();
2250 helper.VerifyDataConsumed();
2251}
2252
bncd16676a2016-07-20 16:23:012253TEST_F(SpdyNetworkTransactionTest, CancelledTransaction) {
[email protected]75f30cc22010-06-28 21:41:382254 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:132255 spdy::SpdySerializedFrame req(
2256 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]34437af82009-11-06 02:28:492257 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412258 CreateMockWrite(req),
[email protected]34437af82009-11-06 02:28:492259 };
2260
Ryan Hamilton0239aac2018-05-19 00:03:132261 spdy::SpdySerializedFrame resp(
2262 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]34437af82009-11-06 02:28:492263 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412264 CreateMockRead(resp),
2265 // This following read isn't used by the test, except during the
2266 // RunUntilIdle() call at the end since the SpdySession survives the
2267 // HttpNetworkTransaction and still tries to continue Read()'ing. Any
2268 // MockRead will do here.
2269 MockRead(ASYNC, 0, 0) // EOF
[email protected]34437af82009-11-06 02:28:492270 };
2271
Ryan Sleevib8d7ea02018-05-07 20:01:012272 StaticSocketDataProvider data(reads, writes);
[email protected]3caf5542010-07-16 15:19:472273
Bence Békydb3cf652017-10-10 15:22:102274 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472275 helper.RunPreTestSetup();
[email protected]e3ebba0f2010-08-05 17:59:582276 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472277 HttpNetworkTransaction* trans = helper.trans();
[email protected]34437af82009-11-06 02:28:492278
[email protected]49639fa2011-12-20 23:22:412279 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102280 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012281 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]3caf5542010-07-16 15:19:472282 helper.ResetTrans(); // Cancel the transaction.
[email protected]34437af82009-11-06 02:28:492283
[email protected]30c942b2010-07-21 16:59:592284 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]34437af82009-11-06 02:28:492285 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:172286 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472287 helper.VerifyDataNotConsumed();
[email protected]34437af82009-11-06 02:28:492288}
[email protected]72552f02009-10-28 15:25:012289
[email protected]6c6ea172010-07-27 20:04:032290// Verify that the client sends a Rst Frame upon cancelling the stream.
bncd16676a2016-07-20 16:23:012291TEST_F(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
Ryan Hamilton0239aac2018-05-19 00:03:132292 spdy::SpdySerializedFrame req(
2293 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2294 spdy::SpdySerializedFrame rst(
2295 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
[email protected]6c6ea172010-07-27 20:04:032296 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:412297 CreateMockWrite(req, 0, SYNCHRONOUS),
2298 CreateMockWrite(rst, 2, SYNCHRONOUS),
[email protected]6c6ea172010-07-27 20:04:032299 };
2300
Ryan Hamilton0239aac2018-05-19 00:03:132301 spdy::SpdySerializedFrame resp(
2302 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]6c6ea172010-07-27 20:04:032303 MockRead reads[] = {
Raul Tambre94493c652019-03-11 17:18:352304 CreateMockRead(resp, 1, ASYNC), MockRead(ASYNC, nullptr, 0, 3) // EOF
[email protected]6c6ea172010-07-27 20:04:032305 };
2306
Ryan Sleevib8d7ea02018-05-07 20:01:012307 SequencedSocketData data(reads, writes);
[email protected]6c6ea172010-07-27 20:04:032308
Bence Békydb3cf652017-10-10 15:22:102309 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]6c6ea172010-07-27 20:04:032310 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:332311 helper.AddData(&data);
[email protected]6c6ea172010-07-27 20:04:032312 HttpNetworkTransaction* trans = helper.trans();
2313
[email protected]49639fa2011-12-20 23:22:412314 TestCompletionCallback callback;
[email protected]6c6ea172010-07-27 20:04:032315
Bence Békydb3cf652017-10-10 15:22:102316 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012317 EXPECT_THAT(callback.GetResult(rv), IsOk());
[email protected]6c6ea172010-07-27 20:04:032318
[email protected]3b7828432010-08-18 18:33:272319 helper.ResetTrans();
mmenke666a6fea2015-12-19 04:16:332320 base::RunLoop().RunUntilIdle();
[email protected]3b7828432010-08-18 18:33:272321
[email protected]6c6ea172010-07-27 20:04:032322 helper.VerifyDataConsumed();
2323}
2324
[email protected]b278eb72010-07-09 20:17:002325// Verify that the client can correctly deal with the user callback attempting
2326// to start another transaction on a session that is closing down. See
2327// http://crbug.com/47455
bncd16676a2016-07-20 16:23:012328TEST_F(SpdyNetworkTransactionTest, StartTransactionOnReadCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:132329 spdy::SpdySerializedFrame req(
2330 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:412331 MockWrite writes[] = {CreateMockWrite(req)};
bnceb9aa7112017-01-05 01:03:462332 MockWrite writes2[] = {CreateMockWrite(req, 0),
2333 MockWrite(SYNCHRONOUS, ERR_IO_PENDING, 3)};
[email protected]b278eb72010-07-09 20:17:002334
[email protected]cbdd73162013-03-18 23:27:332335 // The indicated length of this frame is longer than its actual length. When
2336 // the session receives an empty frame after this one, it shuts down the
[email protected]b278eb72010-07-09 20:17:002337 // session, and calls the read callback with the incomplete data.
Avi Drissman13fc8932015-12-20 04:40:462338 const uint8_t kGetBodyFrame2[] = {
2339 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
2340 0x07, 'h', 'e', 'l', 'l', 'o', '!',
[email protected]b278eb72010-07-09 20:17:002341 };
2342
Ryan Hamilton0239aac2018-05-19 00:03:132343 spdy::SpdySerializedFrame resp(
2344 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]b278eb72010-07-09 20:17:002345 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412346 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:092347 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2348 MockRead(ASYNC, reinterpret_cast<const char*>(kGetBodyFrame2),
Avi Drissman4365a4782018-12-28 19:26:242349 base::size(kGetBodyFrame2), 3),
rch32320842015-05-16 15:57:092350 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
Raul Tambre94493c652019-03-11 17:18:352351 MockRead(ASYNC, nullptr, 0, 5), // EOF
[email protected]b278eb72010-07-09 20:17:002352 };
2353 MockRead reads2[] = {
Raul Tambre94493c652019-03-11 17:18:352354 CreateMockRead(resp, 1), MockRead(ASYNC, nullptr, 0, 2), // EOF
[email protected]b278eb72010-07-09 20:17:002355 };
2356
Ryan Sleevib8d7ea02018-05-07 20:01:012357 SequencedSocketData data(reads, writes);
2358 SequencedSocketData data2(reads2, writes2);
[email protected]3caf5542010-07-16 15:19:472359
Bence Békydb3cf652017-10-10 15:22:102360 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3ebba0f2010-08-05 17:59:582361 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572362 helper.AddData(&data);
2363 helper.AddData(&data2);
[email protected]3caf5542010-07-16 15:19:472364 HttpNetworkTransaction* trans = helper.trans();
[email protected]b278eb72010-07-09 20:17:002365
2366 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:412367 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102368 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012369 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b278eb72010-07-09 20:17:002370 rv = callback.WaitForResult();
2371
[email protected]b278eb72010-07-09 20:17:002372 const int kSize = 3000;
Victor Costan9c7302b2018-08-27 16:39:442373 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kSize);
[email protected]49639fa2011-12-20 23:22:412374 rv = trans->Read(
rchebf12982015-04-10 01:15:002375 buf.get(), kSize,
Yannic Bonenberger00e09842019-08-31 20:46:192376 base::BindOnce(&SpdyNetworkTransactionTest::StartTransactionCallback,
2377 helper.session(), default_url_, log_));
robpercival214763f2016-07-01 23:27:012378 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]3caf5542010-07-16 15:19:472379 // This forces an err_IO_pending, which sets the callback.
mmenkee24011922015-12-17 22:12:592380 data.Resume();
2381 data.RunUntilPaused();
2382
[email protected]3caf5542010-07-16 15:19:472383 // This finishes the read.
mmenkee24011922015-12-17 22:12:592384 data.Resume();
2385 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472386 helper.VerifyDataConsumed();
[email protected]b278eb72010-07-09 20:17:002387}
2388
Mostyn Bramley-Moore699c5312018-05-01 10:48:092389// Verify that the client can correctly deal with the user callback deleting
2390// the transaction. Failures will usually be flagged by thread and/or memory
2391// checking tools. See http://crbug.com/46925
bncd16676a2016-07-20 16:23:012392TEST_F(SpdyNetworkTransactionTest, DeleteSessionOnReadCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:132393 spdy::SpdySerializedFrame req(
2394 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:412395 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]9be804c82010-06-24 17:59:462396
Ryan Hamilton0239aac2018-05-19 00:03:132397 spdy::SpdySerializedFrame resp(
2398 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2399 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]9be804c82010-06-24 17:59:462400 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412401 CreateMockRead(resp, 1),
Raul Tambre94493c652019-03-11 17:18:352402 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
2403 CreateMockRead(body, 3), MockRead(ASYNC, nullptr, 0, 4), // EOF
[email protected]9be804c82010-06-24 17:59:462404 };
2405
Ryan Sleevib8d7ea02018-05-07 20:01:012406 SequencedSocketData data(reads, writes);
[email protected]3caf5542010-07-16 15:19:472407
Bence Békydb3cf652017-10-10 15:22:102408 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:472409 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:572410 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:472411 HttpNetworkTransaction* trans = helper.trans();
[email protected]9be804c82010-06-24 17:59:462412
2413 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:412414 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:102415 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:012416 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]9be804c82010-06-24 17:59:462417 rv = callback.WaitForResult();
2418
2419 // Setup a user callback which will delete the session, and clear out the
2420 // memory holding the stream object. Note that the callback deletes trans.
[email protected]9be804c82010-06-24 17:59:462421 const int kSize = 3000;
Victor Costan9c7302b2018-08-27 16:39:442422 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kSize);
[email protected]49639fa2011-12-20 23:22:412423 rv = trans->Read(
Yannic Bonenberger00e09842019-08-31 20:46:192424 buf.get(), kSize,
2425 base::BindOnce(&SpdyNetworkTransactionTest::DeleteSessionCallback,
2426 base::Unretained(&helper)));
robpercival214763f2016-07-01 23:27:012427 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
mmenkee24011922015-12-17 22:12:592428 data.Resume();
[email protected]9be804c82010-06-24 17:59:462429
2430 // Finish running rest of tasks.
[email protected]fc9d88472013-08-14 02:31:172431 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:472432 helper.VerifyDataConsumed();
[email protected]9be804c82010-06-24 17:59:462433}
2434
allada71b2efb2016-09-09 04:57:482435TEST_F(SpdyNetworkTransactionTest, TestRawHeaderSizeSuccessfullRequest) {
Bence Béky4c325e52020-10-22 20:48:012436 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:132437 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
allada71b2efb2016-09-09 04:57:482438 headers["user-agent"] = "";
2439 headers["accept-encoding"] = "gzip, deflate";
2440
Ryan Hamilton0239aac2018-05-19 00:03:132441 spdy::SpdySerializedFrame req(
allada71b2efb2016-09-09 04:57:482442 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
2443 MockWrite writes[] = {
2444 CreateMockWrite(req, 0),
2445 };
2446
Ryan Hamilton0239aac2018-05-19 00:03:132447 spdy::SpdySerializedFrame resp(
2448 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
allada71b2efb2016-09-09 04:57:482449
Ryan Hamilton0239aac2018-05-19 00:03:132450 spdy::SpdySerializedFrame response_body_frame(
Bence Békyd74f4382018-02-20 18:26:192451 spdy_util_.ConstructSpdyDataFrame(1, "should not include", true));
allada71b2efb2016-09-09 04:57:482452
2453 MockRead response_headers(CreateMockRead(resp, 1));
2454 MockRead reads[] = {
2455 response_headers, CreateMockRead(response_body_frame, 2),
Raul Tambre94493c652019-03-11 17:18:352456 MockRead(ASYNC, nullptr, 0, 3) // EOF
allada71b2efb2016-09-09 04:57:482457 };
Ryan Sleevib8d7ea02018-05-07 20:01:012458 SequencedSocketData data(reads, writes);
allada71b2efb2016-09-09 04:57:482459
2460 TestDelegate delegate;
2461 SpdyURLRequestContext spdy_url_request_context;
2462 TestNetworkDelegate network_delegate;
2463 spdy_url_request_context.set_network_delegate(&network_delegate);
2464 SSLSocketDataProvider ssl_data(ASYNC, OK);
2465 ssl_data.next_proto = kProtoHTTP2;
2466
2467 std::unique_ptr<URLRequest> request(spdy_url_request_context.CreateRequest(
rhalavati9ebaba7e2017-04-27 06:16:292468 GURL(kDefaultUrl), DEFAULT_PRIORITY, &delegate,
2469 TRAFFIC_ANNOTATION_FOR_TESTS));
allada71b2efb2016-09-09 04:57:482470 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(&ssl_data);
2471 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data);
2472
2473 request->Start();
2474 base::RunLoop().Run();
2475
2476 EXPECT_LT(0, request->GetTotalSentBytes());
2477 EXPECT_LT(0, request->GetTotalReceivedBytes());
allada71b2efb2016-09-09 04:57:482478 EXPECT_EQ(response_headers.data_len, request->raw_header_size());
2479 EXPECT_TRUE(data.AllReadDataConsumed());
2480 EXPECT_TRUE(data.AllWriteDataConsumed());
2481}
2482
2483TEST_F(SpdyNetworkTransactionTest,
2484 TestRawHeaderSizeSuccessfullPushHeadersFirst) {
Bence Béky4c325e52020-10-22 20:48:012485 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:132486 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
allada71b2efb2016-09-09 04:57:482487 headers["user-agent"] = "";
2488 headers["accept-encoding"] = "gzip, deflate";
2489
Ryan Hamilton0239aac2018-05-19 00:03:132490 spdy::SpdySerializedFrame req(
allada71b2efb2016-09-09 04:57:482491 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132492 spdy::SpdySerializedFrame priority(
tombergan5d22c182017-01-11 02:05:352493 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
allada71b2efb2016-09-09 04:57:482494 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352495 CreateMockWrite(req, 0), CreateMockWrite(priority, 2),
allada71b2efb2016-09-09 04:57:482496 };
2497
Ryan Hamilton0239aac2018-05-19 00:03:132498 spdy::SpdySerializedFrame resp(
2499 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2500 spdy::SpdySerializedFrame response_body_frame(
Bence Békyd74f4382018-02-20 18:26:192501 spdy_util_.ConstructSpdyDataFrame(1, "should not include", true));
allada71b2efb2016-09-09 04:57:482502
Bence Béky4c325e52020-10-22 20:48:012503 spdy::Http2HeaderBlock push_headers;
bncc055fa32017-06-19 13:44:422504 push_headers[":method"] = "GET";
Bence Béky4e83f492018-05-13 23:14:252505 spdy_util_.AddUrlToHeaderBlock(std::string(kDefaultUrl) + "b.dat",
allada71b2efb2016-09-09 04:57:482506 &push_headers);
2507
Ryan Hamilton0239aac2018-05-19 00:03:132508 spdy::SpdySerializedFrame push_init_frame(
Bence Békyf1d78522018-01-11 01:16:502509 spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(push_headers)));
allada71b2efb2016-09-09 04:57:482510
Ryan Hamilton0239aac2018-05-19 00:03:132511 spdy::SpdySerializedFrame push_headers_frame(
allada71b2efb2016-09-09 04:57:482512 spdy_util_.ConstructSpdyPushHeaders(2, nullptr, 0));
2513
Ryan Hamilton0239aac2018-05-19 00:03:132514 spdy::SpdySerializedFrame push_body_frame(
Bence Békyd74f4382018-02-20 18:26:192515 spdy_util_.ConstructSpdyDataFrame(2, "should not include either", false));
allada71b2efb2016-09-09 04:57:482516
2517 MockRead push_init_read(CreateMockRead(push_init_frame, 1));
tombergan5d22c182017-01-11 02:05:352518 MockRead response_headers(CreateMockRead(resp, 5));
allada71b2efb2016-09-09 04:57:482519 // raw_header_size() will contain the size of the push promise frame
2520 // initialization.
2521 int expected_response_headers_size =
2522 response_headers.data_len + push_init_read.data_len;
2523
2524 MockRead reads[] = {
2525 push_init_read,
tombergan5d22c182017-01-11 02:05:352526 CreateMockRead(push_headers_frame, 3),
2527 CreateMockRead(push_body_frame, 4),
allada71b2efb2016-09-09 04:57:482528 response_headers,
tombergan5d22c182017-01-11 02:05:352529 CreateMockRead(response_body_frame, 6),
2530 MockRead(ASYNC, 0, 7) // EOF
allada71b2efb2016-09-09 04:57:482531 };
2532
Ryan Sleevib8d7ea02018-05-07 20:01:012533 SequencedSocketData data(reads, writes);
allada71b2efb2016-09-09 04:57:482534
2535 TestDelegate delegate;
2536 SpdyURLRequestContext spdy_url_request_context;
2537 TestNetworkDelegate network_delegate;
2538 spdy_url_request_context.set_network_delegate(&network_delegate);
2539 SSLSocketDataProvider ssl_data(ASYNC, OK);
2540 ssl_data.next_proto = kProtoHTTP2;
2541
2542 std::unique_ptr<URLRequest> request(spdy_url_request_context.CreateRequest(
rhalavati9ebaba7e2017-04-27 06:16:292543 GURL(kDefaultUrl), DEFAULT_PRIORITY, &delegate,
2544 TRAFFIC_ANNOTATION_FOR_TESTS));
allada71b2efb2016-09-09 04:57:482545 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(&ssl_data);
2546 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data);
2547
2548 request->Start();
2549 base::RunLoop().Run();
2550
2551 EXPECT_LT(0, request->GetTotalSentBytes());
2552 EXPECT_LT(0, request->GetTotalReceivedBytes());
allada71b2efb2016-09-09 04:57:482553 EXPECT_EQ(expected_response_headers_size, request->raw_header_size());
2554 EXPECT_TRUE(data.AllReadDataConsumed());
2555 EXPECT_TRUE(data.AllWriteDataConsumed());
2556}
2557
bncf2ba58832017-06-07 00:22:282558TEST_F(SpdyNetworkTransactionTest, RedirectGetRequest) {
2559 SpdyURLRequestContext spdy_url_request_context;
Matt Menke5062be22019-05-01 17:50:242560 // Use a different port to avoid trying to reuse the initial H2 session.
2561 const char kRedirectUrl[] = "https://www.foo.com:8080/index.php";
[email protected]e3ebba0f2010-08-05 17:59:582562
bncf2ba58832017-06-07 00:22:282563 SSLSocketDataProvider ssl_provider0(ASYNC, OK);
2564 ssl_provider0.next_proto = kProtoHTTP2;
2565 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2566 &ssl_provider0);
[email protected]e3ebba0f2010-08-05 17:59:582567
Bence Béky4c325e52020-10-22 20:48:012568 spdy::Http2HeaderBlock headers0(
Ryan Hamilton0239aac2018-05-19 00:03:132569 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bncf2ba58832017-06-07 00:22:282570 headers0["user-agent"] = "";
2571 headers0["accept-encoding"] = "gzip, deflate";
bnc086b39e12016-06-24 13:05:262572
Ryan Hamilton0239aac2018-05-19 00:03:132573 spdy::SpdySerializedFrame req0(
bncf2ba58832017-06-07 00:22:282574 spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132575 spdy::SpdySerializedFrame rst(
2576 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
Shivani Sharmac18f9762017-10-23 16:43:232577 MockWrite writes0[] = {CreateMockWrite(req0, 0), CreateMockWrite(rst, 2)};
bnc086b39e12016-06-24 13:05:262578
Matt Menke5062be22019-05-01 17:50:242579 const char* const kExtraHeaders[] = {"location", kRedirectUrl};
Ryan Hamilton0239aac2018-05-19 00:03:132580 spdy::SpdySerializedFrame resp0(spdy_util_.ConstructSpdyReplyError(
Avi Drissman4365a4782018-12-28 19:26:242581 "301", kExtraHeaders, base::size(kExtraHeaders) / 2, 1));
Shivani Sharmac18f9762017-10-23 16:43:232582 MockRead reads0[] = {CreateMockRead(resp0, 1), MockRead(ASYNC, 0, 3)};
[email protected]e3ebba0f2010-08-05 17:59:582583
Ryan Sleevib8d7ea02018-05-07 20:01:012584 SequencedSocketData data0(reads0, writes0);
bncf2ba58832017-06-07 00:22:282585 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
[email protected]e3ebba0f2010-08-05 17:59:582586
bncf2ba58832017-06-07 00:22:282587 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
2588 ssl_provider1.next_proto = kProtoHTTP2;
2589 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2590 &ssl_provider1);
[email protected]513963e2013-06-15 01:53:042591
bncf2ba58832017-06-07 00:22:282592 SpdyTestUtil spdy_util1;
Bence Béky4c325e52020-10-22 20:48:012593 spdy::Http2HeaderBlock headers1(
Matt Menke5062be22019-05-01 17:50:242594 spdy_util1.ConstructGetHeaderBlock(kRedirectUrl));
bncf2ba58832017-06-07 00:22:282595 headers1["user-agent"] = "";
2596 headers1["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132597 spdy::SpdySerializedFrame req1(
bncf2ba58832017-06-07 00:22:282598 spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
2599 MockWrite writes1[] = {CreateMockWrite(req1, 0)};
[email protected]e3ebba0f2010-08-05 17:59:582600
Ryan Hamilton0239aac2018-05-19 00:03:132601 spdy::SpdySerializedFrame resp1(
2602 spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
2603 spdy::SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282604 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
2605 MockRead(ASYNC, 0, 3)};
2606
Ryan Sleevib8d7ea02018-05-07 20:01:012607 SequencedSocketData data1(reads1, writes1);
bncf2ba58832017-06-07 00:22:282608 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
2609
2610 TestDelegate delegate;
bncf2ba58832017-06-07 00:22:282611
2612 std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
2613 default_url_, DEFAULT_PRIORITY, &delegate, TRAFFIC_ANNOTATION_FOR_TESTS);
2614 request->Start();
Wez0e717112018-06-18 23:09:222615 delegate.RunUntilRedirect();
bncf2ba58832017-06-07 00:22:282616
2617 EXPECT_EQ(1, delegate.received_redirect_count());
2618
Arthur Sonzognib8465ff72019-01-04 18:44:352619 request->FollowDeferredRedirect(base::nullopt /* removed_headers */,
2620 base::nullopt /* modified_headers */);
Wez0e717112018-06-18 23:09:222621 delegate.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282622
2623 EXPECT_EQ(1, delegate.response_started_count());
2624 EXPECT_FALSE(delegate.received_data_before_response());
2625 EXPECT_THAT(delegate.request_status(), IsOk());
2626 EXPECT_EQ("hello!", delegate.data_received());
2627
Wez0e717112018-06-18 23:09:222628 // Pump the message loop to allow read data to be consumed.
2629 base::RunLoop().RunUntilIdle();
2630
bncf2ba58832017-06-07 00:22:282631 EXPECT_TRUE(data0.AllReadDataConsumed());
2632 EXPECT_TRUE(data0.AllWriteDataConsumed());
2633 EXPECT_TRUE(data1.AllReadDataConsumed());
2634 EXPECT_TRUE(data1.AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:582635}
2636
bncf2ba58832017-06-07 00:22:282637TEST_F(SpdyNetworkTransactionTest, RedirectServerPush) {
bncf2ba58832017-06-07 00:22:282638 const char redirected_url[] = "https://www.foo.com/index.php";
2639 SpdyURLRequestContext spdy_url_request_context;
[email protected]3a8d6852011-03-11 23:43:442640
bncf2ba58832017-06-07 00:22:282641 SSLSocketDataProvider ssl_provider0(ASYNC, OK);
2642 ssl_provider0.next_proto = kProtoHTTP2;
Ryan Sleevi4f832092017-11-21 23:25:492643 ssl_provider0.ssl_info.cert =
bncf2ba58832017-06-07 00:22:282644 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Ryan Sleevi4f832092017-11-21 23:25:492645 ASSERT_TRUE(ssl_provider0.ssl_info.cert);
bncf2ba58832017-06-07 00:22:282646 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2647 &ssl_provider0);
2648
Bence Béky4c325e52020-10-22 20:48:012649 spdy::Http2HeaderBlock headers0(
Ryan Hamilton0239aac2018-05-19 00:03:132650 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bncf2ba58832017-06-07 00:22:282651 headers0["user-agent"] = "";
2652 headers0["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132653 spdy::SpdySerializedFrame req0(
bncf2ba58832017-06-07 00:22:282654 spdy_util_.ConstructSpdyHeaders(1, std::move(headers0), LOWEST, true));
Ryan Hamilton0239aac2018-05-19 00:03:132655 spdy::SpdySerializedFrame priority(
bncf2ba58832017-06-07 00:22:282656 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:132657 spdy::SpdySerializedFrame rst(
2658 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
bncf2ba58832017-06-07 00:22:282659 MockWrite writes[] = {CreateMockWrite(req0, 0), CreateMockWrite(priority, 3),
2660 CreateMockWrite(rst, 5)};
[email protected]3a8d6852011-03-11 23:43:442661
Ryan Hamilton0239aac2018-05-19 00:03:132662 spdy::SpdySerializedFrame resp0(
2663 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2664 spdy::SpdySerializedFrame push(spdy_util_.ConstructSpdyPush(
Bence Békyd2df6c1c82018-04-20 22:52:012665 nullptr, 0, 2, 1, kPushedUrl, "301", redirected_url));
Ryan Hamilton0239aac2018-05-19 00:03:132666 spdy::SpdySerializedFrame body0(spdy_util_.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282667 MockRead reads[] = {CreateMockRead(resp0, 1), CreateMockRead(push, 2),
2668 CreateMockRead(body0, 4), MockRead(ASYNC, 0, 6)};
[email protected]e3ebba0f2010-08-05 17:59:582669
Ryan Sleevib8d7ea02018-05-07 20:01:012670 SequencedSocketData data0(reads, writes);
bncf2ba58832017-06-07 00:22:282671 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data0);
[email protected]e3ebba0f2010-08-05 17:59:582672
bncf2ba58832017-06-07 00:22:282673 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
2674 ssl_provider1.next_proto = kProtoHTTP2;
2675 spdy_url_request_context.socket_factory().AddSSLSocketDataProvider(
2676 &ssl_provider1);
[email protected]e3ebba0f2010-08-05 17:59:582677
bncf2ba58832017-06-07 00:22:282678 SpdyTestUtil spdy_util1;
Bence Béky4c325e52020-10-22 20:48:012679 spdy::Http2HeaderBlock headers1(
Ryan Hamilton0239aac2018-05-19 00:03:132680 spdy_util1.ConstructGetHeaderBlock(redirected_url));
bncf2ba58832017-06-07 00:22:282681 headers1["user-agent"] = "";
2682 headers1["accept-encoding"] = "gzip, deflate";
Ryan Hamilton0239aac2018-05-19 00:03:132683 spdy::SpdySerializedFrame req1(
bncf2ba58832017-06-07 00:22:282684 spdy_util1.ConstructSpdyHeaders(1, std::move(headers1), LOWEST, true));
2685 MockWrite writes1[] = {CreateMockWrite(req1, 0)};
[email protected]e3ebba0f2010-08-05 17:59:582686
Ryan Hamilton0239aac2018-05-19 00:03:132687 spdy::SpdySerializedFrame resp1(
2688 spdy_util1.ConstructSpdyGetReply(nullptr, 0, 1));
2689 spdy::SpdySerializedFrame body1(spdy_util1.ConstructSpdyDataFrame(1, true));
bncf2ba58832017-06-07 00:22:282690 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
2691 MockRead(ASYNC, 0, 3)};
[email protected]e3ebba0f2010-08-05 17:59:582692
Ryan Sleevib8d7ea02018-05-07 20:01:012693 SequencedSocketData data1(reads1, writes1);
bncf2ba58832017-06-07 00:22:282694 spdy_url_request_context.socket_factory().AddSocketDataProvider(&data1);
[email protected]e3ebba0f2010-08-05 17:59:582695
bncf2ba58832017-06-07 00:22:282696 TestDelegate delegate0;
2697 std::unique_ptr<URLRequest> request = spdy_url_request_context.CreateRequest(
2698 default_url_, DEFAULT_PRIORITY, &delegate0, TRAFFIC_ANNOTATION_FOR_TESTS);
2699
2700 request->Start();
Wez0e717112018-06-18 23:09:222701 delegate0.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282702
2703 EXPECT_EQ(0, delegate0.received_redirect_count());
2704 EXPECT_EQ("hello!", delegate0.data_received());
2705
2706 TestDelegate delegate1;
2707 std::unique_ptr<URLRequest> request1 = spdy_url_request_context.CreateRequest(
Bence Békyd2df6c1c82018-04-20 22:52:012708 GURL(kPushedUrl), DEFAULT_PRIORITY, &delegate1,
2709 TRAFFIC_ANNOTATION_FOR_TESTS);
bncf2ba58832017-06-07 00:22:282710
bncf2ba58832017-06-07 00:22:282711 request1->Start();
Wez0e717112018-06-18 23:09:222712 delegate1.RunUntilRedirect();
bncf2ba58832017-06-07 00:22:282713 EXPECT_EQ(1, delegate1.received_redirect_count());
2714
Arthur Sonzognib8465ff72019-01-04 18:44:352715 request1->FollowDeferredRedirect(base::nullopt /* removed_headers */,
2716 base::nullopt /* modified_headers */);
Wez0e717112018-06-18 23:09:222717 delegate1.RunUntilComplete();
bncf2ba58832017-06-07 00:22:282718 EXPECT_EQ(1, delegate1.response_started_count());
2719 EXPECT_FALSE(delegate1.received_data_before_response());
2720 EXPECT_EQ(OK, delegate1.request_status());
2721 EXPECT_EQ("hello!", delegate1.data_received());
2722
Wez0e717112018-06-18 23:09:222723 // Pump the message loop to allow read data to be consumed.
2724 base::RunLoop().RunUntilIdle();
2725
bncf2ba58832017-06-07 00:22:282726 EXPECT_TRUE(data0.AllReadDataConsumed());
2727 EXPECT_TRUE(data0.AllWriteDataConsumed());
2728 EXPECT_TRUE(data1.AllReadDataConsumed());
2729 EXPECT_TRUE(data1.AllWriteDataConsumed());
[email protected]e3ebba0f2010-08-05 17:59:582730}
2731
bncd16676a2016-07-20 16:23:012732TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:132733 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:482734 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:132735 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352736 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]e3ebba0f2010-08-05 17:59:582737 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352738 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]e3ebba0f2010-08-05 17:59:582739 };
2740
Ryan Hamilton0239aac2018-05-19 00:03:132741 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352742 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132743 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:012744 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:132745 spdy::SpdySerializedFrame stream1_body(
2746 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]8a0fc822013-06-27 20:52:432747 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:132748 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:192749 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]e3ebba0f2010-08-05 17:59:582750 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:352751 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
2752 CreateMockRead(stream1_body, 4), CreateMockRead(stream2_body, 5),
2753 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:582754 };
2755
2756 HttpResponseInfo response;
2757 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:252758 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:012759 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:572760 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:032761 &response,
2762 &response2,
2763 expected_push_result);
[email protected]e3ebba0f2010-08-05 17:59:582764
bnc42331402016-07-25 13:36:152765 // Verify the response headers.
wezca1070932016-05-26 20:30:522766 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:022767 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]e3ebba0f2010-08-05 17:59:582768
2769 // Verify the pushed stream.
wezca1070932016-05-26 20:30:522770 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:042771 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]e3ebba0f2010-08-05 17:59:582772}
2773
Bence Béky02b906a2018-07-18 21:03:392774// When server push is disabled by
2775// HttpNetworkSession::initial_settings[SETTINGS_ENABLE_PUSH] = 0, verify that
2776// such a setting is sent out in the initial SETTINGS frame, and if the server
2777// creates a pushed stream despite of this, it is immediately reset.
2778TEST_F(SpdyNetworkTransactionTest, ServerPushDisabled) {
Bence Békyda83e052018-07-20 01:03:322779 base::HistogramTester histogram_tester;
2780
Bence Béky02b906a2018-07-18 21:03:392781 spdy::SpdySerializedFrame preface(
2782 const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
2783 spdy::kHttp2ConnectionHeaderPrefixSize,
2784 /* owns_buffer = */ false);
2785
2786 spdy::SettingsMap initial_settings;
2787 initial_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
2788 initial_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
2789 initial_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
2790 kSpdyMaxConcurrentPushedStreams;
Bence Béky6cee52f2019-10-24 16:52:332791 initial_settings[spdy::SETTINGS_MAX_HEADER_LIST_SIZE] =
2792 kSpdyMaxHeaderListSize;
Bence Béky02b906a2018-07-18 21:03:392793 spdy::SpdySerializedFrame initial_settings_frame(
2794 spdy_util_.ConstructSpdySettings(initial_settings));
2795
2796 spdy::SpdySerializedFrame req(
2797 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2798 spdy::SpdySerializedFrame rst(
2799 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
2800
2801 MockWrite writes[] = {CreateMockWrite(preface, 0),
2802 CreateMockWrite(initial_settings_frame, 1),
2803 CreateMockWrite(req, 2), CreateMockWrite(rst, 5)};
2804
2805 spdy::SpdySerializedFrame reply(
2806 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2807 spdy::SpdySerializedFrame push(
2808 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
2809 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
2810 MockRead reads[] = {CreateMockRead(reply, 3), CreateMockRead(push, 4),
2811 CreateMockRead(body, 6), MockRead(ASYNC, OK, 7)};
2812
2813 SequencedSocketData data(reads, writes);
2814
2815 auto session_deps = std::make_unique<SpdySessionDependencies>();
2816 session_deps->http2_settings[spdy::SETTINGS_ENABLE_PUSH] = 0;
2817 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
2818 std::move(session_deps));
2819
2820 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
2821 SpdySessionPoolPeer pool_peer(spdy_session_pool);
2822 pool_peer.SetEnableSendingInitialData(true);
2823
2824 helper.RunToCompletion(&data);
Bence Békyda83e052018-07-20 01:03:322825
2826 histogram_tester.ExpectBucketCount(
2827 "Net.SpdyPushedStreamFate",
2828 static_cast<int>(SpdyPushedStreamFate::kPushDisabled), 1);
2829 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
Bence Béky02b906a2018-07-18 21:03:392830}
2831
Bence Béky5b1e4ce72018-01-11 14:55:152832TEST_F(SpdyNetworkTransactionTest, ServerPushHeadMethod) {
Ryan Hamilton0239aac2018-05-19 00:03:132833 spdy::SpdySerializedFrame req(
2834 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2835 spdy::SpdySerializedFrame priority(
Bence Béky5b1e4ce72018-01-11 14:55:152836 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
2837 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 2)};
2838
Bence Béky4c325e52020-10-22 20:48:012839 spdy::Http2HeaderBlock push_promise_header_block;
Ryan Hamilton0239aac2018-05-19 00:03:132840 push_promise_header_block[spdy::kHttp2MethodHeader] = "HEAD";
Bence Békyd2df6c1c82018-04-20 22:52:012841 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:132842 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Béky5b1e4ce72018-01-11 14:55:152843 1, 2, std::move(push_promise_header_block)));
2844
Bence Béky4c325e52020-10-22 20:48:012845 spdy::Http2HeaderBlock push_response_headers;
Ryan Hamilton0239aac2018-05-19 00:03:132846 push_response_headers[spdy::kHttp2StatusHeader] = "200";
Bence Béky5b1e4ce72018-01-11 14:55:152847 push_response_headers["foo"] = "bar";
Ryan Hamilton0239aac2018-05-19 00:03:132848 spdy::SpdyHeadersIR headers_ir(2, std::move(push_response_headers));
2849 spdy::SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir));
Bence Béky5b1e4ce72018-01-11 14:55:152850
Ryan Hamilton0239aac2018-05-19 00:03:132851 spdy::SpdySerializedFrame resp(
2852 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2853 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Béky5b1e4ce72018-01-11 14:55:152854 MockRead reads[] = {
2855 CreateMockRead(push_promise, 1), CreateMockRead(push_headers, 3),
2856 CreateMockRead(resp, 4), CreateMockRead(body, 5),
2857 // Do not close the connection after first request is done.
2858 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
2859
Ryan Sleevib8d7ea02018-05-07 20:01:012860 SequencedSocketData data(reads, writes);
Bence Béky5b1e4ce72018-01-11 14:55:152861
2862 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
2863 helper.RunPreTestSetup();
2864 helper.AddData(&data);
2865
2866 // Run first request. This reads PUSH_PROMISE.
2867 helper.RunDefaultTest();
2868
2869 // Request the pushed resource.
2870 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
2871 HttpRequestInfo request = CreateGetPushRequest();
2872 request.method = "HEAD";
Ramin Halavatib5e433e62018-02-07 07:41:102873 request.traffic_annotation =
2874 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky5b1e4ce72018-01-11 14:55:152875 TestCompletionCallback callback;
2876 int rv = trans.Start(&request, callback.callback(), log_);
2877 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2878 rv = callback.WaitForResult();
2879 EXPECT_THAT(rv, IsOk());
2880
2881 const HttpResponseInfo* response = trans.GetResponseInfo();
2882 ASSERT_TRUE(response);
2883 EXPECT_TRUE(response->was_fetched_via_spdy);
2884 EXPECT_TRUE(response->was_alpn_negotiated);
2885 ASSERT_TRUE(response->headers);
2886 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
2887 std::string value;
2888 EXPECT_TRUE(response->headers->GetNormalizedHeader("foo", &value));
2889 EXPECT_EQ("bar", value);
2890
2891 helper.VerifyDataConsumed();
2892}
2893
2894TEST_F(SpdyNetworkTransactionTest, ServerPushHeadDoesNotMatchGetRequest) {
Ryan Hamilton0239aac2018-05-19 00:03:132895 spdy::SpdySerializedFrame req1(
2896 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
2897 spdy::SpdySerializedFrame priority(
Bence Béky5b1e4ce72018-01-11 14:55:152898 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
2899 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:132900 spdy::SpdySerializedFrame req2(
2901 spdy_util_.ConstructSpdyGet(kPushedUrl, 3, LOWEST));
Bence Béky5b1e4ce72018-01-11 14:55:152902 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 2),
2903 CreateMockWrite(req2, 6)};
2904
Bence Béky4c325e52020-10-22 20:48:012905 spdy::Http2HeaderBlock push_promise_header_block;
Ryan Hamilton0239aac2018-05-19 00:03:132906 push_promise_header_block[spdy::kHttp2MethodHeader] = "HEAD";
Bence Békyd2df6c1c82018-04-20 22:52:012907 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:132908 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Béky5b1e4ce72018-01-11 14:55:152909 1, 2, std::move(push_promise_header_block)));
2910
Bence Béky4c325e52020-10-22 20:48:012911 spdy::Http2HeaderBlock push_response_headers;
Ryan Hamilton0239aac2018-05-19 00:03:132912 push_response_headers[spdy::kHttp2StatusHeader] = "200";
Bence Béky5b1e4ce72018-01-11 14:55:152913 push_response_headers["foo"] = "bar";
Ryan Hamilton0239aac2018-05-19 00:03:132914 spdy::SpdyHeadersIR headers_ir(2, std::move(push_response_headers));
2915 spdy::SpdySerializedFrame push_headers(spdy_util_.SerializeFrame(headers_ir));
Bence Béky5b1e4ce72018-01-11 14:55:152916
Ryan Hamilton0239aac2018-05-19 00:03:132917 spdy::SpdySerializedFrame resp1(
2918 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
2919 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
2920 spdy::SpdySerializedFrame resp2(
2921 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
2922 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky5b1e4ce72018-01-11 14:55:152923 MockRead reads[] = {CreateMockRead(push_promise, 1),
2924 CreateMockRead(push_headers, 3),
2925 CreateMockRead(resp1, 4),
2926 CreateMockRead(body1, 5),
2927 CreateMockRead(resp2, 7),
2928 CreateMockRead(body2, 8),
2929 MockRead(ASYNC, 0, 9)};
2930
Ryan Sleevib8d7ea02018-05-07 20:01:012931 SequencedSocketData data(reads, writes);
Bence Béky5b1e4ce72018-01-11 14:55:152932
2933 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
2934 helper.RunPreTestSetup();
2935 helper.AddData(&data);
2936
2937 // Run first request. This reads PUSH_PROMISE.
2938 helper.RunDefaultTest();
2939
2940 // Request the pushed resource.
2941 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
2942 HttpRequestInfo request = CreateGetPushRequest();
2943 TestCompletionCallback callback;
2944 int rv = trans.Start(&request, callback.callback(), log_);
2945 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
2946 rv = callback.WaitForResult();
2947 EXPECT_THAT(rv, IsOk());
2948
2949 const HttpResponseInfo* response = trans.GetResponseInfo();
2950 ASSERT_TRUE(response);
2951 EXPECT_TRUE(response->was_fetched_via_spdy);
2952 EXPECT_TRUE(response->was_alpn_negotiated);
2953 ASSERT_TRUE(response->headers);
2954 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
2955 std::string value;
2956 EXPECT_FALSE(response->headers->GetNormalizedHeader("foo", &value));
2957 std::string result;
2958 ReadResult(&trans, &result);
2959 EXPECT_EQ("hello!", result);
2960
2961 // Read EOF.
2962 base::RunLoop().RunUntilIdle();
2963
2964 helper.VerifyDataConsumed();
2965}
2966
bncd16676a2016-07-20 16:23:012967TEST_F(SpdyNetworkTransactionTest, ServerPushSingleDataFrame2) {
Ryan Hamilton0239aac2018-05-19 00:03:132968 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:482969 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:132970 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:352971 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
rch08e3aa3e2015-05-16 14:27:522972 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:352973 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
rch08e3aa3e2015-05-16 14:27:522974 };
[email protected]82918cc2010-08-25 17:24:502975
Ryan Hamilton0239aac2018-05-19 00:03:132976 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:352977 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:132978 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:012979 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
[email protected]8a0fc822013-06-27 20:52:432980 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:132981 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:192982 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:132983 spdy::SpdySerializedFrame stream1_body(
2984 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]82918cc2010-08-25 17:24:502985 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:412986 CreateMockRead(stream1_reply, 1),
2987 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:352988 CreateMockRead(stream2_body, 4),
2989 CreateMockRead(stream1_body, 5, SYNCHRONOUS),
2990 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]82918cc2010-08-25 17:24:502991 };
2992
2993 HttpResponseInfo response;
2994 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:252995 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:012996 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:572997 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:032998 &response,
2999 &response2,
3000 expected_push_result);
[email protected]82918cc2010-08-25 17:24:503001
bnc42331402016-07-25 13:36:153002 // Verify the response headers.
wezca1070932016-05-26 20:30:523003 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023004 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]82918cc2010-08-25 17:24:503005
3006 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523007 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043008 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]82918cc2010-08-25 17:24:503009}
3010
tombergan5d22c182017-01-11 02:05:353011TEST_F(SpdyNetworkTransactionTest, ServerPushUpdatesPriority) {
Ryan Hamilton0239aac2018-05-19 00:03:133012 spdy::SpdySerializedFrame stream1_headers(
Bence Béky27ad0a12018-02-08 00:35:483013 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
Ryan Hamilton0239aac2018-05-19 00:03:133014 spdy::SpdySerializedFrame stream3_headers(
Bence Béky27ad0a12018-02-08 00:35:483015 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, MEDIUM));
Ryan Hamilton0239aac2018-05-19 00:03:133016 spdy::SpdySerializedFrame stream5_headers(
Bence Béky27ad0a12018-02-08 00:35:483017 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, MEDIUM));
tombergan5d22c182017-01-11 02:05:353018
3019 // Stream 1 pushes two streams that are initially prioritized below stream 5.
3020 // Stream 2 is later prioritized below stream 1 after it matches a request.
Ryan Hamilton0239aac2018-05-19 00:03:133021 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353022 spdy_util_.ConstructSpdyPriority(2, 5, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133023 spdy::SpdySerializedFrame stream4_priority(
tombergan5d22c182017-01-11 02:05:353024 spdy_util_.ConstructSpdyPriority(4, 2, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133025 spdy::SpdySerializedFrame stream4_priority_update(
tombergan5d22c182017-01-11 02:05:353026 spdy_util_.ConstructSpdyPriority(4, 5, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133027 spdy::SpdySerializedFrame stream2_priority_update(
tombergan5d22c182017-01-11 02:05:353028 spdy_util_.ConstructSpdyPriority(2, 1, HIGHEST, true));
3029
[email protected]e3ebba0f2010-08-05 17:59:583030 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353031 CreateMockWrite(stream1_headers, 0),
3032 CreateMockWrite(stream3_headers, 1),
3033 CreateMockWrite(stream5_headers, 2),
3034 CreateMockWrite(stream2_priority, 7),
3035 CreateMockWrite(stream4_priority, 9),
3036 CreateMockWrite(stream4_priority_update, 11),
3037 CreateMockWrite(stream2_priority_update, 12),
[email protected]e3ebba0f2010-08-05 17:59:583038 };
3039
Ryan Hamilton0239aac2018-05-19 00:03:133040 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353041 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133042 spdy::SpdySerializedFrame stream3_reply(
tombergan5d22c182017-01-11 02:05:353043 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Ryan Hamilton0239aac2018-05-19 00:03:133044 spdy::SpdySerializedFrame stream5_reply(
tombergan5d22c182017-01-11 02:05:353045 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
3046
Ryan Hamilton0239aac2018-05-19 00:03:133047 spdy::SpdySerializedFrame stream2_push(
Bence Békyd2df6c1c82018-04-20 22:52:013048 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133049 spdy::SpdySerializedFrame stream4_push(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513050 nullptr, 0, 4, 1, "https://www.example.org/bar.dat"));
tombergan5d22c182017-01-11 02:05:353051
Ryan Hamilton0239aac2018-05-19 00:03:133052 spdy::SpdySerializedFrame stream1_body(
3053 spdy_util_.ConstructSpdyDataFrame(1, true));
3054 spdy::SpdySerializedFrame stream2_body(
3055 spdy_util_.ConstructSpdyDataFrame(2, true));
3056 spdy::SpdySerializedFrame stream3_body(
3057 spdy_util_.ConstructSpdyDataFrame(3, true));
3058 spdy::SpdySerializedFrame stream5_body(
3059 spdy_util_.ConstructSpdyDataFrame(5, true));
tombergan5d22c182017-01-11 02:05:353060
3061 MockRead reads[] = {
3062 CreateMockRead(stream1_reply, 3),
3063 CreateMockRead(stream3_reply, 4),
3064 CreateMockRead(stream5_reply, 5),
3065 CreateMockRead(stream2_push, 6),
3066 CreateMockRead(stream4_push, 8),
3067 MockRead(ASYNC, ERR_IO_PENDING, 10),
3068 CreateMockRead(stream1_body, 13),
3069 CreateMockRead(stream2_body, 14),
3070 CreateMockRead(stream3_body, 15),
3071 CreateMockRead(stream5_body, 16),
3072 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 17), // Force a pause
3073 };
3074
Ryan Sleevib8d7ea02018-05-07 20:01:013075 SequencedSocketData data(reads, writes);
3076 SequencedSocketData data_placeholder1;
3077 SequencedSocketData data_placeholder2;
3078 SequencedSocketData data_placeholder3;
tombergan5d22c182017-01-11 02:05:353079
Bence Békydb3cf652017-10-10 15:22:103080 NormalSpdyTransactionHelper helper(request_, LOWEST, log_, nullptr);
tombergan5d22c182017-01-11 02:05:353081 helper.RunPreTestSetup();
3082 helper.AddData(&data);
3083 helper.AddData(&data_placeholder1); // other requests reuse the same socket
3084 helper.AddData(&data_placeholder2);
3085 helper.AddData(&data_placeholder3);
3086 HttpNetworkTransaction trans1(HIGHEST, helper.session());
3087 HttpNetworkTransaction trans3(MEDIUM, helper.session());
3088 HttpNetworkTransaction trans5(MEDIUM, helper.session());
3089
3090 TestCompletionCallback callback1;
3091 TestCompletionCallback callback3;
3092 TestCompletionCallback callback5;
3093
3094 // Start the ordinary requests.
Bence Békydb3cf652017-10-10 15:22:103095 ASSERT_THAT(trans1.Start(&request_, callback1.callback(), log_),
tombergan5d22c182017-01-11 02:05:353096 IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:103097 ASSERT_THAT(trans3.Start(&request_, callback3.callback(), log_),
tombergan5d22c182017-01-11 02:05:353098 IsError(ERR_IO_PENDING));
Bence Békydb3cf652017-10-10 15:22:103099 ASSERT_THAT(trans5.Start(&request_, callback5.callback(), log_),
tombergan5d22c182017-01-11 02:05:353100 IsError(ERR_IO_PENDING));
3101 data.RunUntilPaused();
3102
tombergan5d22c182017-01-11 02:05:353103 // Start a request that matches the push.
Bence Békydb3cf652017-10-10 15:22:103104 HttpRequestInfo push_req = CreateGetPushRequest();
krasin0bfeb6b2017-01-13 21:48:043105
3106 HttpNetworkTransaction trans2(HIGHEST, helper.session());
3107 TestCompletionCallback callback2;
Bence Békyd3dde832017-09-19 19:02:313108 ASSERT_THAT(trans2.Start(&push_req, callback2.callback(), log_),
tombergan5d22c182017-01-11 02:05:353109 IsError(ERR_IO_PENDING));
3110 data.Resume();
3111
3112 base::RunLoop().RunUntilIdle();
3113 ASSERT_THAT(callback1.WaitForResult(), IsOk());
3114 ASSERT_THAT(callback2.WaitForResult(), IsOk());
3115 ASSERT_THAT(callback3.WaitForResult(), IsOk());
3116 ASSERT_THAT(callback5.WaitForResult(), IsOk());
3117 helper.VerifyDataConsumed();
3118}
3119
3120TEST_F(SpdyNetworkTransactionTest, ServerPushServerAborted) {
Ryan Hamilton0239aac2018-05-19 00:03:133121 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483122 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133123 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353124 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
3125 MockWrite writes[] = {
3126 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3127 };
3128
Ryan Hamilton0239aac2018-05-19 00:03:133129 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353130 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133131 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013132 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133133 spdy::SpdySerializedFrame stream2_rst(
3134 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_PROTOCOL_ERROR));
3135 spdy::SpdySerializedFrame stream1_body(
3136 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]e3ebba0f2010-08-05 17:59:583137 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413138 CreateMockRead(stream1_reply, 1),
bnceb9aa7112017-01-05 01:03:463139 CreateMockRead(stream2_syn, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:353140 CreateMockRead(stream2_rst, 4),
3141 CreateMockRead(stream1_body, 5, SYNCHRONOUS),
3142 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583143 };
3144
Ryan Sleevib8d7ea02018-05-07 20:01:013145 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103146 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3ebba0f2010-08-05 17:59:583147
3148 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:573149 helper.AddData(&data);
[email protected]e3ebba0f2010-08-05 17:59:583150
3151 HttpNetworkTransaction* trans = helper.trans();
3152
3153 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:413154 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:103155 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:013156 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e3ebba0f2010-08-05 17:59:583157 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:013158 EXPECT_THAT(rv, IsOk());
[email protected]19ec8a72010-08-23 03:38:233159
3160 // Verify that we consumed all test data.
tombergan5d22c182017-01-11 02:05:353161 base::RunLoop().RunUntilIdle();
rch08e3aa3e2015-05-16 14:27:523162 EXPECT_TRUE(data.AllReadDataConsumed());
3163 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]19ec8a72010-08-23 03:38:233164
bnc42331402016-07-25 13:36:153165 // Verify the response headers.
[email protected]19ec8a72010-08-23 03:38:233166 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:523167 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023168 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233169}
3170
[email protected]8a0fc822013-06-27 20:52:433171// Verify that we don't leak streams and that we properly send a reset
3172// if the server pushes the same stream twice.
bncd16676a2016-07-20 16:23:013173TEST_F(SpdyNetworkTransactionTest, ServerPushDuplicate) {
Bence Békyeacd48f2018-05-14 11:34:333174 base::HistogramTester histogram_tester;
3175
Ryan Hamilton0239aac2018-05-19 00:03:133176 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483177 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133178 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353179 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133180 spdy::SpdySerializedFrame stream3_rst(
3181 spdy_util_.ConstructSpdyRstStream(4, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]fdc165a2010-09-03 03:51:293182 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353183 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3184 CreateMockWrite(stream3_rst, 5),
[email protected]fdc165a2010-09-03 03:51:293185 };
3186
Ryan Hamilton0239aac2018-05-19 00:03:133187 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353188 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133189 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013190 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133191 spdy::SpdySerializedFrame stream3_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013192 spdy_util_.ConstructSpdyPush(nullptr, 0, 4, 1, kPushedUrl));
tombergan5d22c182017-01-11 02:05:353193
[email protected]8a0fc822013-06-27 20:52:433194 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:133195 spdy::SpdySerializedFrame stream1_body(
3196 spdy_util_.ConstructSpdyDataFrame(1, true));
3197 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:193198 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
tombergan5d22c182017-01-11 02:05:353199
[email protected]fdc165a2010-09-03 03:51:293200 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413201 CreateMockRead(stream1_reply, 1),
3202 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353203 CreateMockRead(stream3_syn, 4),
3204 CreateMockRead(stream1_body, 6),
3205 CreateMockRead(stream2_body, 7),
3206 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 8), // Force a pause
[email protected]fdc165a2010-09-03 03:51:293207 };
3208
3209 HttpResponseInfo response;
3210 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:253211 std::string expected_push_result("pushed");
Ryan Sleevib8d7ea02018-05-07 20:01:013212 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:573213 RunServerPushTest(&data,
[email protected]d08358502010-12-03 22:04:033214 &response,
3215 &response2,
3216 expected_push_result);
[email protected]fdc165a2010-09-03 03:51:293217
bnc42331402016-07-25 13:36:153218 // Verify the response headers.
wezca1070932016-05-26 20:30:523219 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023220 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]fdc165a2010-09-03 03:51:293221
3222 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523223 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043224 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
Bence Békyeacd48f2018-05-14 11:34:333225
3226 histogram_tester.ExpectBucketCount(
3227 "Net.SpdyPushedStreamFate",
3228 static_cast<int>(SpdyPushedStreamFate::kAcceptedNoVary), 1);
3229 histogram_tester.ExpectBucketCount(
3230 "Net.SpdyPushedStreamFate",
3231 static_cast<int>(SpdyPushedStreamFate::kDuplicateUrl), 1);
3232 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 2);
[email protected]fdc165a2010-09-03 03:51:293233}
3234
bncd16676a2016-07-20 16:23:013235TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:133236 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483237 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133238 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353239 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]19ec8a72010-08-23 03:38:233240 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353241 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]19ec8a72010-08-23 03:38:233242 };
3243
Ryan Hamilton0239aac2018-05-19 00:03:133244 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353245 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133246 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013247 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Bence Békyd74f4382018-02-20 18:26:193248 static const char kPushedData[] = "pushed payload for chunked test";
Ryan Hamilton0239aac2018-05-19 00:03:133249 spdy::SpdySerializedFrame stream2_body_base(
Bence Békyd74f4382018-02-20 18:26:193250 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]8a0fc822013-06-27 20:52:433251 const size_t kChunkSize = strlen(kPushedData) / 4;
Ryan Hamilton0239aac2018-05-19 00:03:133252 spdy::SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
3253 false);
3254 spdy::SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
3255 kChunkSize, false);
3256 spdy::SpdySerializedFrame stream2_body3(
3257 stream2_body_base.data() + 2 * kChunkSize, kChunkSize, false);
3258 spdy::SpdySerializedFrame stream2_body4(
3259 stream2_body_base.data() + 3 * kChunkSize,
3260 stream2_body_base.size() - 3 * kChunkSize, false);
3261 spdy::SpdySerializedFrame stream1_body(
3262 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]19ec8a72010-08-23 03:38:233263 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413264 CreateMockRead(stream1_reply, 1),
3265 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353266 CreateMockRead(stream2_body1, 4),
3267 CreateMockRead(stream2_body2, 5),
3268 CreateMockRead(stream2_body3, 6),
3269 CreateMockRead(stream2_body4, 7),
3270 CreateMockRead(stream1_body, 8, SYNCHRONOUS),
3271 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9), // Force a pause
[email protected]19ec8a72010-08-23 03:38:233272 };
3273
3274 HttpResponseInfo response;
3275 HttpResponseInfo response2;
Bence Béky4e83f492018-05-13 23:14:253276 std::string expected_push_result(kPushedData);
Ryan Sleevib8d7ea02018-05-07 20:01:013277 SequencedSocketData data(reads, writes);
[email protected]8a0fc822013-06-27 20:52:433278 RunServerPushTest(&data, &response, &response2, kPushedData);
[email protected]19ec8a72010-08-23 03:38:233279
bnc42331402016-07-25 13:36:153280 // Verify the response headers.
wezca1070932016-05-26 20:30:523281 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023282 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233283
3284 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523285 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043286 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233287}
3288
bncd16676a2016-07-20 16:23:013289TEST_F(SpdyNetworkTransactionTest, ServerPushMultipleDataFrameInterrupted) {
Ryan Hamilton0239aac2018-05-19 00:03:133290 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483291 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133292 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353293 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
[email protected]19ec8a72010-08-23 03:38:233294 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353295 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
[email protected]19ec8a72010-08-23 03:38:233296 };
3297
Ryan Hamilton0239aac2018-05-19 00:03:133298 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353299 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133300 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013301 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Bence Békyd74f4382018-02-20 18:26:193302 static const char kPushedData[] = "pushed payload for chunked test";
Ryan Hamilton0239aac2018-05-19 00:03:133303 spdy::SpdySerializedFrame stream2_body_base(
Bence Békyd74f4382018-02-20 18:26:193304 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
[email protected]8a0fc822013-06-27 20:52:433305 const size_t kChunkSize = strlen(kPushedData) / 4;
Ryan Hamilton0239aac2018-05-19 00:03:133306 spdy::SpdySerializedFrame stream2_body1(stream2_body_base.data(), kChunkSize,
3307 false);
3308 spdy::SpdySerializedFrame stream2_body2(stream2_body_base.data() + kChunkSize,
3309 kChunkSize, false);
3310 spdy::SpdySerializedFrame stream2_body3(
3311 stream2_body_base.data() + 2 * kChunkSize, kChunkSize, false);
3312 spdy::SpdySerializedFrame stream2_body4(
3313 stream2_body_base.data() + 3 * kChunkSize,
3314 stream2_body_base.size() - 3 * kChunkSize, false);
3315 spdy::SpdySerializedFrame stream1_body(
3316 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]19ec8a72010-08-23 03:38:233317 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413318 CreateMockRead(stream1_reply, 1),
3319 CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353320 CreateMockRead(stream2_body1, 4),
3321 CreateMockRead(stream2_body2, 5),
3322 CreateMockRead(stream2_body3, 6),
3323 CreateMockRead(stream2_body4, 7),
3324 CreateMockRead(stream1_body, 8, SYNCHRONOUS),
3325 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9) // Force a pause.
[email protected]19ec8a72010-08-23 03:38:233326 };
3327
3328 HttpResponseInfo response;
3329 HttpResponseInfo response2;
Ryan Sleevib8d7ea02018-05-07 20:01:013330 SequencedSocketData data(reads, writes);
[email protected]8a0fc822013-06-27 20:52:433331 RunServerPushTest(&data, &response, &response2, kPushedData);
[email protected]19ec8a72010-08-23 03:38:233332
bnc42331402016-07-25 13:36:153333 // Verify the response headers.
wezca1070932016-05-26 20:30:523334 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:023335 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233336
3337 // Verify the pushed stream.
wezca1070932016-05-26 20:30:523338 EXPECT_TRUE(response2.headers);
bnccdc749f2016-01-27 16:39:043339 EXPECT_EQ("HTTP/1.1 200", response2.headers->GetStatusLine());
[email protected]19ec8a72010-08-23 03:38:233340}
3341
morlovichab1d1c1e2017-02-07 19:59:283342TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidUrl) {
Bence Békyeacd48f2018-05-14 11:34:333343 base::HistogramTester histogram_tester;
3344
morlovichab1d1c1e2017-02-07 19:59:283345 // Coverage on how a non-empty invalid GURL in a PUSH_PROMISE is handled.
Bence Béky4c325e52020-10-22 20:48:013346 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:133347 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
3348 spdy::SpdySerializedFrame req(
morlovichab1d1c1e2017-02-07 19:59:283349 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
3350
3351 // Can't use ConstructSpdyPush here since it wants to parse a URL and
3352 // split it into the appropriate :header pieces. So we have to hand-fill
3353 // those pieces in.
Bence Béky4c325e52020-10-22 20:48:013354 spdy::Http2HeaderBlock push_promise_header_block;
Ryan Hamilton0239aac2018-05-19 00:03:133355 push_promise_header_block[spdy::kHttp2AuthorityHeader] = "";
3356 push_promise_header_block[spdy::kHttp2SchemeHeader] = "";
3357 push_promise_header_block[spdy::kHttp2PathHeader] = "/index.html";
morlovichab1d1c1e2017-02-07 19:59:283358
Ryan Hamilton0239aac2018-05-19 00:03:133359 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:503360 1, 2, std::move(push_promise_header_block)));
morlovichab1d1c1e2017-02-07 19:59:283361
Ryan Hamilton0239aac2018-05-19 00:03:133362 spdy::SpdySerializedFrame stream2_rst(
3363 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
morlovichab1d1c1e2017-02-07 19:59:283364
3365 MockWrite writes[] = {CreateMockWrite(req, 0),
3366 CreateMockWrite(stream2_rst, 2)};
3367 MockRead reads[] = {
Bence Békyf1d78522018-01-11 01:16:503368 CreateMockRead(push_promise, 1), MockRead(ASYNC, 0, 3) /* EOF */
morlovichab1d1c1e2017-02-07 19:59:283369 };
Ryan Sleevib8d7ea02018-05-07 20:01:013370 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283371 RunBrokenPushTest(&data, ERR_CONNECTION_CLOSED);
Bence Békyeacd48f2018-05-14 11:34:333372
3373 histogram_tester.ExpectBucketCount(
3374 "Net.SpdyPushedStreamFate",
3375 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
3376 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
morlovichab1d1c1e2017-02-07 19:59:283377}
3378
bncd16676a2016-07-20 16:23:013379TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID0) {
Ryan Hamilton0239aac2018-05-19 00:03:133380 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483381 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133382 spdy::SpdySerializedFrame goaway(
3383 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_PROTOCOL_ERROR,
3384 "Framer error: 1 (INVALID_STREAM_ID)."));
[email protected]19ec8a72010-08-23 03:38:233385 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413386 CreateMockWrite(stream1_syn, 0), CreateMockWrite(goaway, 3),
[email protected]19ec8a72010-08-23 03:38:233387 };
3388
Ryan Hamilton0239aac2018-05-19 00:03:133389 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353390 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133391 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013392 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 0, kPushedUrl));
[email protected]19ec8a72010-08-23 03:38:233393 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413394 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
[email protected]19ec8a72010-08-23 03:38:233395 };
Ryan Sleevib8d7ea02018-05-07 20:01:013396 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283397 RunBrokenPushTest(&data, OK);
[email protected]e3ebba0f2010-08-05 17:59:583398}
3399
bncd16676a2016-07-20 16:23:013400TEST_F(SpdyNetworkTransactionTest, ServerPushInvalidAssociatedStreamID9) {
Bence Békyeacd48f2018-05-14 11:34:333401 base::HistogramTester histogram_tester;
3402
Ryan Hamilton0239aac2018-05-19 00:03:133403 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483404 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133405 spdy::SpdySerializedFrame stream1_body(
3406 spdy_util_.ConstructSpdyDataFrame(1, true));
3407 spdy::SpdySerializedFrame stream2_rst(
3408 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_STREAM_CLOSED));
[email protected]e3ebba0f2010-08-05 17:59:583409 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413410 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
[email protected]e3ebba0f2010-08-05 17:59:583411 };
3412
Ryan Hamilton0239aac2018-05-19 00:03:133413 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353414 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133415 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013416 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 9, kPushedUrl));
[email protected]e3ebba0f2010-08-05 17:59:583417 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413418 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
3419 CreateMockRead(stream1_body, 4),
rch08e3aa3e2015-05-16 14:27:523420 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5), // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583421 };
3422
Ryan Sleevib8d7ea02018-05-07 20:01:013423 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283424 RunBrokenPushTest(&data, OK);
Bence Békyeacd48f2018-05-14 11:34:333425
3426 histogram_tester.ExpectBucketCount(
3427 "Net.SpdyPushedStreamFate",
3428 static_cast<int>(SpdyPushedStreamFate::kInactiveAssociatedStream), 1);
3429 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]e3ebba0f2010-08-05 17:59:583430}
3431
bncd16676a2016-07-20 16:23:013432TEST_F(SpdyNetworkTransactionTest, ServerPushNoURL) {
Bence Békyeacd48f2018-05-14 11:34:333433 base::HistogramTester histogram_tester;
3434
Ryan Hamilton0239aac2018-05-19 00:03:133435 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483436 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133437 spdy::SpdySerializedFrame stream1_body(
3438 spdy_util_.ConstructSpdyDataFrame(1, true));
3439 spdy::SpdySerializedFrame stream2_rst(
3440 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]e3ebba0f2010-08-05 17:59:583441 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413442 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_rst, 3),
[email protected]e3ebba0f2010-08-05 17:59:583443 };
3444
Ryan Hamilton0239aac2018-05-19 00:03:133445 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353446 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Béky4c325e52020-10-22 20:48:013447 spdy::Http2HeaderBlock incomplete_headers;
Ryan Hamilton0239aac2018-05-19 00:03:133448 incomplete_headers[spdy::kHttp2StatusHeader] = "200 OK";
bnc086b39e12016-06-24 13:05:263449 incomplete_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:133450 spdy::SpdySerializedFrame stream2_syn(
Bence Békyf1d78522018-01-11 01:16:503451 spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(incomplete_headers)));
[email protected]e3ebba0f2010-08-05 17:59:583452 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413453 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
3454 CreateMockRead(stream1_body, 4),
rch08e3aa3e2015-05-16 14:27:523455 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5) // Force a pause
[email protected]e3ebba0f2010-08-05 17:59:583456 };
3457
Ryan Sleevib8d7ea02018-05-07 20:01:013458 SequencedSocketData data(reads, writes);
morlovichab1d1c1e2017-02-07 19:59:283459 RunBrokenPushTest(&data, OK);
Bence Békyeacd48f2018-05-14 11:34:333460
3461 histogram_tester.ExpectBucketCount(
3462 "Net.SpdyPushedStreamFate",
3463 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
3464 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]e3ebba0f2010-08-05 17:59:583465}
3466
bnc0cb98b22016-03-04 17:10:523467// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY.
bncd16676a2016-07-20 16:23:013468TEST_F(SpdyNetworkTransactionTest, ServerPushOnPushedStream) {
Bence Békyeacd48f2018-05-14 11:34:333469 base::HistogramTester histogram_tester;
3470
Ryan Hamilton0239aac2018-05-19 00:03:133471 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483472 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133473 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353474 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133475 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
3476 2, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:563477 "Received pushed stream id 4 on invalid stream id 2 (must be odd)."));
bnc0cb98b22016-03-04 17:10:523478 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:353479 CreateMockWrite(stream1_syn, 0), CreateMockWrite(stream2_priority, 3),
3480 CreateMockWrite(goaway, 5),
bnc0cb98b22016-03-04 17:10:523481 };
3482
Ryan Hamilton0239aac2018-05-19 00:03:133483 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:353484 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133485 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013486 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133487 spdy::SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513488 nullptr, 0, 4, 2, "https://www.example.org/bar.dat"));
bnc0cb98b22016-03-04 17:10:523489 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413490 CreateMockRead(stream1_reply, 1), CreateMockRead(stream2_syn, 2),
tombergan5d22c182017-01-11 02:05:353491 CreateMockRead(stream3_syn, 4),
bnc0cb98b22016-03-04 17:10:523492 };
3493
Ryan Sleevib8d7ea02018-05-07 20:01:013494 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103495 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523496 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:333497
3498 histogram_tester.ExpectBucketCount(
3499 "Net.SpdyPushedStreamFate",
3500 static_cast<int>(SpdyPushedStreamFate::kAssociatedStreamIdParityError),
3501 1);
3502 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bnc0cb98b22016-03-04 17:10:523503}
3504
3505// PUSH_PROMISE on a closed client-initiated stream should trigger RST_STREAM.
bncd16676a2016-07-20 16:23:013506TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedStream) {
Bence Békyeacd48f2018-05-14 11:34:333507 base::HistogramTester histogram_tester;
3508
Ryan Hamilton0239aac2018-05-19 00:03:133509 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483510 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133511 spdy::SpdySerializedFrame rst(
3512 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_STREAM_CLOSED));
bnc0cb98b22016-03-04 17:10:523513 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:413514 CreateMockWrite(stream1_syn, 0), CreateMockWrite(rst, 5),
bnc0cb98b22016-03-04 17:10:523515 };
3516
Ryan Hamilton0239aac2018-05-19 00:03:133517 spdy::SpdySerializedFrame stream1_reply(
bnc42331402016-07-25 13:36:153518 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133519 spdy::SpdySerializedFrame stream1_body(
3520 spdy_util_.ConstructSpdyDataFrame(1, true));
3521 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013522 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
bnc0cb98b22016-03-04 17:10:523523 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:413524 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
3525 CreateMockRead(stream2_syn, 3), MockRead(SYNCHRONOUS, ERR_IO_PENDING, 4),
bnc0cb98b22016-03-04 17:10:523526 };
3527
Ryan Sleevib8d7ea02018-05-07 20:01:013528 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103529 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523530 helper.RunPreTestSetup();
3531 helper.AddData(&data);
3532
3533 HttpNetworkTransaction* trans = helper.trans();
3534
3535 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:103536 int rv = trans->Start(&request_, callback.callback(), log_);
bnc0cb98b22016-03-04 17:10:523537 rv = callback.GetResult(rv);
robpercival214763f2016-07-01 23:27:013538 EXPECT_THAT(rv, IsOk());
bnceb9aa7112017-01-05 01:03:463539
3540 // Finish async network reads/writes.
3541 base::RunLoop().RunUntilIdle();
3542
bnc0cb98b22016-03-04 17:10:523543 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:523544 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523545 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
3546
3547 EXPECT_TRUE(data.AllReadDataConsumed());
3548 EXPECT_TRUE(data.AllWriteDataConsumed());
3549 VerifyStreamsClosed(helper);
Bence Békyeacd48f2018-05-14 11:34:333550
3551 histogram_tester.ExpectBucketCount(
3552 "Net.SpdyPushedStreamFate",
3553 static_cast<int>(SpdyPushedStreamFate::kInactiveAssociatedStream), 1);
3554 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bnc0cb98b22016-03-04 17:10:523555}
3556
3557// PUSH_PROMISE on a server-initiated stream should trigger GOAWAY even if
3558// stream is closed.
bncd16676a2016-07-20 16:23:013559TEST_F(SpdyNetworkTransactionTest, ServerPushOnClosedPushedStream) {
Bence Békyeacd48f2018-05-14 11:34:333560 base::HistogramTester histogram_tester;
3561
Ryan Hamilton0239aac2018-05-19 00:03:133562 spdy::SpdySerializedFrame stream1_syn(
Bence Béky27ad0a12018-02-08 00:35:483563 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:133564 spdy::SpdySerializedFrame stream2_priority(
tombergan5d22c182017-01-11 02:05:353565 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:133566 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
3567 2, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:563568 "Received pushed stream id 4 on invalid stream id 2 (must be odd)."));
Bence Béky7bf94362018-01-10 13:19:363569 MockWrite writes[] = {CreateMockWrite(stream1_syn, 0),
3570 CreateMockWrite(stream2_priority, 3),
3571 CreateMockWrite(goaway, 8)};
bnc0cb98b22016-03-04 17:10:523572
Ryan Hamilton0239aac2018-05-19 00:03:133573 spdy::SpdySerializedFrame stream2_syn(
Bence Békyd2df6c1c82018-04-20 22:52:013574 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133575 spdy::SpdySerializedFrame stream1_reply(
Bence Béky7bf94362018-01-10 13:19:363576 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:133577 spdy::SpdySerializedFrame stream1_body(
3578 spdy_util_.ConstructSpdyDataFrame(1, true));
bnc0cb98b22016-03-04 17:10:523579 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:133580 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:193581 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:133582 spdy::SpdySerializedFrame stream3_syn(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:513583 nullptr, 0, 4, 2, "https://www.example.org/bar.dat"));
bnc0cb98b22016-03-04 17:10:523584
3585 MockRead reads[] = {
Bence Béky7bf94362018-01-10 13:19:363586 CreateMockRead(stream2_syn, 1), CreateMockRead(stream1_reply, 2),
tombergan5d22c182017-01-11 02:05:353587 CreateMockRead(stream1_body, 4), CreateMockRead(stream2_body, 5),
Bence Béky7bf94362018-01-10 13:19:363588 MockRead(ASYNC, ERR_IO_PENDING, 6), CreateMockRead(stream3_syn, 7)};
bnc0cb98b22016-03-04 17:10:523589
Ryan Sleevib8d7ea02018-05-07 20:01:013590 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:103591 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc0cb98b22016-03-04 17:10:523592 helper.RunPreTestSetup();
3593 helper.AddData(&data);
3594
3595 HttpNetworkTransaction* trans1 = helper.trans();
3596 TestCompletionCallback callback1;
Bence Békydb3cf652017-10-10 15:22:103597 int rv = trans1->Start(&request_, callback1.callback(), log_);
bnc0cb98b22016-03-04 17:10:523598 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:013599 EXPECT_THAT(rv, IsOk());
bnc0cb98b22016-03-04 17:10:523600 HttpResponseInfo response = *trans1->GetResponseInfo();
wezca1070932016-05-26 20:30:523601 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523602 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
3603
bnc691fda62016-08-12 00:43:163604 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
bnc0cb98b22016-03-04 17:10:523605 TestCompletionCallback callback2;
Bence Békydb3cf652017-10-10 15:22:103606 HttpRequestInfo request = CreateGetPushRequest();
3607 rv = trans2.Start(&request, callback2.callback(), log_);
bnc0cb98b22016-03-04 17:10:523608 rv = callback2.GetResult(rv);
robpercival214763f2016-07-01 23:27:013609 EXPECT_THAT(rv, IsOk());
bnc691fda62016-08-12 00:43:163610 response = *trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:523611 EXPECT_TRUE(response.headers);
bnc0cb98b22016-03-04 17:10:523612 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
Bence Béky4e83f492018-05-13 23:14:253613 std::string result;
bnc691fda62016-08-12 00:43:163614 ReadResult(&trans2, &result);
bnc0cb98b22016-03-04 17:10:523615 EXPECT_EQ(kPushedData, result);
3616
3617 data.Resume();
3618 base::RunLoop().RunUntilIdle();
3619
3620 EXPECT_TRUE(data.AllReadDataConsumed());
3621 EXPECT_TRUE(data.AllWriteDataConsumed());
Bence Békyeacd48f2018-05-14 11:34:333622
3623 histogram_tester.ExpectBucketCount(
3624 "Net.SpdyPushedStreamFate",
3625 static_cast<int>(SpdyPushedStreamFate::kAssociatedStreamIdParityError),
3626 1);
3627 histogram_tester.ExpectBucketCount(
3628 "Net.SpdyPushedStreamFate",
3629 static_cast<int>(SpdyPushedStreamFate::kAcceptedNoVary), 1);
3630 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 2);
bnc0cb98b22016-03-04 17:10:523631}
3632
Bence Békye8955cf22018-01-02 17:31:293633TEST_F(SpdyNetworkTransactionTest, ServerCancelsPush) {
Ryan Hamilton0239aac2018-05-19 00:03:133634 spdy::SpdySerializedFrame req1(
3635 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
3636 spdy::SpdySerializedFrame priority(
Bence Békye8955cf22018-01-02 17:31:293637 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Bence Béky1a5d8562018-01-05 17:29:283638 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:133639 spdy::SpdySerializedFrame req2(
3640 spdy_util_.ConstructSpdyGet(kPushedUrl, 3, LOWEST));
Bence Béky1a5d8562018-01-05 17:29:283641 MockWrite writes1[] = {CreateMockWrite(req1, 0), CreateMockWrite(priority, 3),
3642 CreateMockWrite(req2, 6)};
Bence Békye8955cf22018-01-02 17:31:293643
Ryan Hamilton0239aac2018-05-19 00:03:133644 spdy::SpdySerializedFrame reply1(
3645 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3646 spdy::SpdySerializedFrame push(
Bence Békyd2df6c1c82018-04-20 22:52:013647 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
Ryan Hamilton0239aac2018-05-19 00:03:133648 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3649 spdy::SpdySerializedFrame rst(
3650 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_INTERNAL_ERROR));
3651 spdy::SpdySerializedFrame reply2(
3652 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
3653 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Bence Béky1a5d8562018-01-05 17:29:283654 MockRead reads1[] = {CreateMockRead(reply1, 1), CreateMockRead(push, 2),
3655 CreateMockRead(body1, 4), CreateMockRead(rst, 5),
3656 CreateMockRead(reply2, 7), CreateMockRead(body2, 8),
3657 MockRead(ASYNC, 0, 9)};
Bence Békye8955cf22018-01-02 17:31:293658
Ryan Sleevib8d7ea02018-05-07 20:01:013659 SequencedSocketData data(reads1, writes1);
Bence Békye8955cf22018-01-02 17:31:293660
3661 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
3662 helper.RunPreTestSetup();
3663 helper.AddData(&data);
3664
Bence Béky1a5d8562018-01-05 17:29:283665 // First request opens up connection.
Bence Békye8955cf22018-01-02 17:31:293666 HttpNetworkTransaction* trans1 = helper.trans();
3667 TestCompletionCallback callback1;
3668 int rv = trans1->Start(&request_, callback1.callback(), log_);
3669 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3670
3671 // Read until response body arrives. PUSH_PROMISE comes earlier.
3672 rv = callback1.WaitForResult();
3673 EXPECT_THAT(rv, IsOk());
Bence Béky1a5d8562018-01-05 17:29:283674 const HttpResponseInfo* response = trans1->GetResponseInfo();
3675 EXPECT_TRUE(response->headers);
3676 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3677 std::string result1;
3678 ReadResult(trans1, &result1);
3679 EXPECT_EQ("hello!", result1);
3680
3681 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
3682 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113683 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343684 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
3685 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky1a5d8562018-01-05 17:29:283686 base::WeakPtr<SpdySession> spdy_session =
3687 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313688 key, /* enable_ip_based_pooling = */ true,
3689 /* is_websocket = */ false, log_);
Bence Béky1a5d8562018-01-05 17:29:283690 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
Bence Békye8955cf22018-01-02 17:31:293691
3692 // Create request matching pushed stream.
Bence Békye8955cf22018-01-02 17:31:293693 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Béky1a5d8562018-01-05 17:29:283694 HttpRequestInfo request2 = CreateGetPushRequest();
Bence Békye8955cf22018-01-02 17:31:293695 TestCompletionCallback callback2;
Bence Béky1a5d8562018-01-05 17:29:283696 rv = trans2.Start(&request2, callback2.callback(), log_);
Bence Békye8955cf22018-01-02 17:31:293697 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3698
Bence Béky1a5d8562018-01-05 17:29:283699 // Pushed stream is now claimed by second request.
3700 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
3701
3702 // Second request receives RST_STREAM and is retried on the same connection.
Bence Békye8955cf22018-01-02 17:31:293703 rv = callback2.WaitForResult();
Bence Béky1a5d8562018-01-05 17:29:283704 EXPECT_THAT(rv, IsOk());
3705 response = trans2.GetResponseInfo();
3706 EXPECT_TRUE(response->headers);
3707 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3708 std::string result2;
3709 ReadResult(&trans2, &result2);
3710 EXPECT_EQ("hello!", result2);
Bence Békye8955cf22018-01-02 17:31:293711
3712 // Read EOF.
3713 base::RunLoop().RunUntilIdle();
3714
Bence Béky1a5d8562018-01-05 17:29:283715 helper.VerifyDataConsumed();
3716}
3717
3718// Regression test for https://crbug.com/776415.
3719// A client-initiated request can only pool to an existing HTTP/2 connection if
3720// the IP address matches. However, a resource can be pushed by the server on a
3721// connection even if the IP address does not match. This test verifies that if
3722// the request binds to such a pushed stream, and after that the server resets
3723// the stream before SpdySession::GetPushedStream() is called, then the retry
3724// (using a client-initiated stream) does not pool to this connection.
3725TEST_F(SpdyNetworkTransactionTest, ServerCancelsCrossOriginPush) {
3726 const char* kUrl1 = "https://www.example.org";
3727 const char* kUrl2 = "https://mail.example.org";
3728
3729 auto resolver = std::make_unique<MockHostResolver>();
3730 resolver->rules()->ClearRules();
3731 resolver->rules()->AddRule("www.example.org", "127.0.0.1");
3732 resolver->rules()->AddRule("mail.example.org", "127.0.0.2");
3733
3734 auto session_deps = std::make_unique<SpdySessionDependencies>();
3735 session_deps->host_resolver = std::move(resolver);
3736 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
3737 std::move(session_deps));
3738
Ryan Hamilton0239aac2018-05-19 00:03:133739 spdy::SpdySerializedFrame req1(spdy_util_.ConstructSpdyGet(kUrl1, 1, LOWEST));
3740 spdy::SpdySerializedFrame priority(
Bence Béky1a5d8562018-01-05 17:29:283741 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
3742 MockWrite writes1[] = {CreateMockWrite(req1, 0),
3743 CreateMockWrite(priority, 3)};
3744
Ryan Hamilton0239aac2018-05-19 00:03:133745 spdy::SpdySerializedFrame reply1(
3746 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3747 spdy::SpdySerializedFrame push(
Bence Béky1a5d8562018-01-05 17:29:283748 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kUrl2));
Ryan Hamilton0239aac2018-05-19 00:03:133749 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3750 spdy::SpdySerializedFrame rst(
3751 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_INTERNAL_ERROR));
Bence Béky1a5d8562018-01-05 17:29:283752 MockRead reads1[] = {
3753 CreateMockRead(reply1, 1), CreateMockRead(push, 2),
3754 CreateMockRead(body1, 4), CreateMockRead(rst, 5),
3755 MockRead(ASYNC, ERR_IO_PENDING, 6), MockRead(ASYNC, 0, 7)};
3756
Ryan Sleevib8d7ea02018-05-07 20:01:013757 SequencedSocketData data1(reads1, writes1);
Bence Béky1a5d8562018-01-05 17:29:283758
3759 SpdyTestUtil spdy_util2;
Ryan Hamilton0239aac2018-05-19 00:03:133760 spdy::SpdySerializedFrame req2(spdy_util2.ConstructSpdyGet(kUrl2, 1, LOWEST));
Bence Béky1a5d8562018-01-05 17:29:283761 MockWrite writes2[] = {CreateMockWrite(req2, 0)};
3762
Ryan Hamilton0239aac2018-05-19 00:03:133763 spdy::SpdySerializedFrame reply2(
3764 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3765 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:193766 1, "Response on the second connection.", true));
Bence Béky1a5d8562018-01-05 17:29:283767 MockRead reads2[] = {CreateMockRead(reply2, 1), CreateMockRead(body2, 2),
3768 MockRead(ASYNC, 0, 3)};
3769
Ryan Sleevib8d7ea02018-05-07 20:01:013770 SequencedSocketData data2(reads2, writes2);
Bence Béky1a5d8562018-01-05 17:29:283771
3772 helper.RunPreTestSetup();
3773 helper.AddData(&data1);
3774 helper.AddData(&data2);
3775
3776 // First request opens up connection to www.example.org.
3777 HttpNetworkTransaction* trans1 = helper.trans();
3778 HttpRequestInfo request1;
3779 request1.method = "GET";
3780 request1.url = GURL(kUrl1);
Ramin Halavatib5e433e62018-02-07 07:41:103781 request1.traffic_annotation =
3782 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky1a5d8562018-01-05 17:29:283783 TestCompletionCallback callback1;
3784 int rv = trans1->Start(&request1, callback1.callback(), log_);
3785 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3786
3787 // Read until response body arrives. PUSH_PROMISE comes earlier.
3788 rv = callback1.WaitForResult();
3789 EXPECT_THAT(rv, IsOk());
3790 const HttpResponseInfo* response = trans1->GetResponseInfo();
3791 EXPECT_TRUE(response->headers);
3792 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3793 std::string result1;
3794 ReadResult(trans1, &result1);
3795 EXPECT_EQ("hello!", result1);
3796
3797 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
3798 SpdySessionKey key1(HostPortPair::FromURL(GURL(kUrl1)), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113799 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343800 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
3801 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky1a5d8562018-01-05 17:29:283802 base::WeakPtr<SpdySession> spdy_session1 =
3803 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313804 key1, /* enable_ip_based_pooling = */ true,
3805 /* is_websocket = */ false, log_);
Bence Béky1a5d8562018-01-05 17:29:283806 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session1));
3807
3808 // While cross-origin push for kUrl2 is allowed on spdy_session1,
3809 // a client-initiated request would not pool to this connection,
3810 // because the IP address does not match.
3811 SpdySessionKey key2(HostPortPair::FromURL(GURL(kUrl2)), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:113812 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343813 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
3814 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky1a5d8562018-01-05 17:29:283815 EXPECT_FALSE(spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:313816 key2, /* enable_ip_based_pooling = */ true,
3817 /* is_websocket = */ false, log_));
Bence Béky1a5d8562018-01-05 17:29:283818
3819 // Create request matching pushed stream.
3820 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
3821 HttpRequestInfo request2;
3822 request2.method = "GET";
3823 request2.url = GURL(kUrl2);
Ramin Halavatib5e433e62018-02-07 07:41:103824 request2.traffic_annotation =
3825 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky1a5d8562018-01-05 17:29:283826 TestCompletionCallback callback2;
3827 rv = trans2.Start(&request2, callback2.callback(), log_);
3828 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
3829
3830 // Pushed stream is now claimed by second request.
3831 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session1));
3832
3833 // Second request receives RST_STREAM and is retried on a new connection.
3834 rv = callback2.WaitForResult();
3835 EXPECT_THAT(rv, IsOk());
3836 response = trans2.GetResponseInfo();
3837 EXPECT_TRUE(response->headers);
3838 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3839 std::string result2;
3840 ReadResult(&trans2, &result2);
3841 EXPECT_EQ("Response on the second connection.", result2);
3842
3843 // Make sure that the first connection is still open. This is important in
3844 // order to test that the retry created its own connection (because the IP
3845 // address does not match), instead of using the connection of the cancelled
3846 // pushed stream.
3847 EXPECT_TRUE(spdy_session1);
3848
3849 // Read EOF.
3850 data1.Resume();
3851 base::RunLoop().RunUntilIdle();
3852
3853 helper.VerifyDataConsumed();
Bence Békye8955cf22018-01-02 17:31:293854}
3855
Matt Menke5062be22019-05-01 17:50:243856TEST_F(SpdyNetworkTransactionTest, NoConnectionPoolingOverTunnel) {
3857 // Use port 443 for two reasons: This makes the endpoint is port 443 check in
3858 // NormalSpdyTransactionHelper pass, and this means that the tunnel uses the
3859 // same port as the servers, to further confuse things.
3860 const char kPacString[] = "PROXY myproxy:443";
3861
3862 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:563863 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Matt Menke5062be22019-05-01 17:50:243864 kPacString, TRAFFIC_ANNOTATION_FOR_TESTS));
3865 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
3866 std::move(session_deps));
3867
3868 // Only one request uses the first connection.
3869 spdy::SpdySerializedFrame req1(
3870 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
3871 MockWrite writes1[] = {
3872 MockWrite(ASYNC, 0,
3873 "CONNECT www.example.org:443 HTTP/1.1\r\n"
3874 "Host: www.example.org:443\r\n"
3875 "Proxy-Connection: keep-alive\r\n\r\n"),
3876 CreateMockWrite(req1, 2),
3877 };
3878
3879 spdy::SpdySerializedFrame resp1(
3880 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3881 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3882 MockRead reads1[] = {MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
3883 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
3884 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
3885
3886 MockConnect connect1(ASYNC, OK);
3887 SequencedSocketData data1(connect1, reads1, writes1);
3888
3889 // Run a transaction to completion to set up a SPDY session.
3890 helper.RunToCompletion(&data1);
3891 TransactionHelperResult out = helper.output();
3892 EXPECT_THAT(out.rv, IsOk());
3893 EXPECT_EQ("HTTP/1.1 200", out.status_line);
3894 EXPECT_EQ("hello!", out.response_data);
3895
3896 // A new SPDY session should have been created.
3897 SpdySessionKey key1(HostPortPair("www.example.org", 443),
3898 ProxyServer::FromPacString(kPacString),
3899 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:343900 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
3901 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:243902 base::WeakPtr<SpdySession> session1 =
3903 helper.session()->spdy_session_pool()->FindAvailableSession(
3904 key1, true /* enable_up_base_pooling */, false /* is_websocket */,
3905 NetLogWithSource());
3906 ASSERT_TRUE(session1);
3907
3908 // The second request uses a second connection.
3909 SpdyTestUtil spdy_util2;
3910 spdy::SpdySerializedFrame req2(
3911 spdy_util2.ConstructSpdyGet("https://example.test", 1, LOWEST));
3912 MockWrite writes2[] = {
3913 MockWrite(ASYNC, 0,
3914 "CONNECT example.test:443 HTTP/1.1\r\n"
3915 "Host: example.test:443\r\n"
3916 "Proxy-Connection: keep-alive\r\n\r\n"),
3917 CreateMockWrite(req2, 2),
3918 };
3919
3920 spdy::SpdySerializedFrame resp2(
3921 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
3922 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
3923 MockRead reads2[] = {MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
3924 CreateMockRead(resp2, 3), CreateMockRead(body2, 4),
3925 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
3926
3927 MockConnect connect2(ASYNC, OK);
3928 SequencedSocketData data2(connect2, reads2, writes2);
3929 helper.AddData(&data2);
3930
3931 HttpRequestInfo request2;
3932 request2.method = "GET";
3933 request2.url = GURL("https://example.test/");
3934 request2.load_flags = 0;
3935 request2.traffic_annotation =
3936 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
3937 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
3938 helper.session());
3939
3940 TestCompletionCallback callback;
3941 EXPECT_THAT(trans2->Start(&request2, callback.callback(), NetLogWithSource()),
3942 IsError(ERR_IO_PENDING));
3943
3944 // Wait for the second request to get headers. It should create a new H2
3945 // session to do so.
3946 EXPECT_THAT(callback.WaitForResult(), IsOk());
3947
3948 const HttpResponseInfo* response = trans2->GetResponseInfo();
3949 ASSERT_TRUE(response);
3950 ASSERT_TRUE(response->headers);
3951 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
3952 EXPECT_TRUE(response->was_fetched_via_spdy);
3953 EXPECT_TRUE(response->was_alpn_negotiated);
3954 std::string response_data;
3955 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
3956 EXPECT_EQ("hello!", response_data);
3957
3958 // Inspect the new session.
dalyk51ab46b2019-10-15 15:14:343959 SpdySessionKey key2(
3960 HostPortPair("example.test", 443), ProxyServer::FromPacString(kPacString),
3961 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
3962 SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:243963 base::WeakPtr<SpdySession> session2 =
3964 helper.session()->spdy_session_pool()->FindAvailableSession(
3965 key2, true /* enable_up_base_pooling */, false /* is_websocket */,
3966 NetLogWithSource());
3967 ASSERT_TRUE(session2);
3968 ASSERT_TRUE(session1);
3969 EXPECT_NE(session1.get(), session2.get());
3970}
3971
3972// Check that if a session is found after host resolution, but is closed before
3973// the task to try to use it executes, the request will continue to create a new
3974// socket and use it.
3975TEST_F(SpdyNetworkTransactionTest, ConnectionPoolingSessionClosedBeforeUse) {
3976 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
3977
3978 // Only one request uses the first connection.
3979 spdy::SpdySerializedFrame req1(
3980 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
3981 MockWrite writes1[] = {
3982 CreateMockWrite(req1, 0),
3983 };
3984
3985 spdy::SpdySerializedFrame resp1(
3986 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
3987 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
3988 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
3989 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
3990
3991 MockConnect connect1(ASYNC, OK);
3992 SequencedSocketData data1(connect1, reads1, writes1);
3993
3994 // Run a transaction to completion to set up a SPDY session.
3995 helper.RunToCompletion(&data1);
3996 TransactionHelperResult out = helper.output();
3997 EXPECT_THAT(out.rv, IsOk());
3998 EXPECT_EQ("HTTP/1.1 200", out.status_line);
3999 EXPECT_EQ("hello!", out.response_data);
4000
4001 // A new SPDY session should have been created.
4002 SpdySessionKey key1(HostPortPair("www.example.org", 443),
4003 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344004 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
4005 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244006 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4007 key1, true /* enable_up_base_pooling */, false /* is_websocket */,
4008 NetLogWithSource()));
4009
4010 // The second request uses a second connection.
4011 SpdyTestUtil spdy_util2;
4012 spdy::SpdySerializedFrame req2(
4013 spdy_util2.ConstructSpdyGet("https://example.test", 1, LOWEST));
4014 MockWrite writes2[] = {
4015 CreateMockWrite(req2, 0),
4016 };
4017
4018 spdy::SpdySerializedFrame resp2(
4019 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
4020 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
4021 MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
4022 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
4023
4024 MockConnect connect2(ASYNC, OK);
4025 SequencedSocketData data2(connect2, reads2, writes2);
4026 helper.AddData(&data2);
4027
4028 HttpRequestInfo request2;
4029 request2.method = "GET";
4030 request2.url = GURL("https://example.test/");
4031 request2.load_flags = 0;
4032 request2.traffic_annotation =
4033 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4034 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4035 helper.session());
4036
4037 // Set on-demand mode and run the second request to the DNS lookup.
4038 helper.session_deps()->host_resolver->set_ondemand_mode(true);
4039 TestCompletionCallback callback;
4040 EXPECT_THAT(trans2->Start(&request2, callback.callback(), NetLogWithSource()),
4041 IsError(ERR_IO_PENDING));
4042 base::RunLoop().RunUntilIdle();
4043 ASSERT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
4044
4045 // Resolve the request now, which should create an alias for the SpdySession
4046 // immediately, but the task to use the session for the second request should
4047 // run asynchronously, so it hasn't run yet.
4048 helper.session_deps()->host_resolver->ResolveOnlyRequestNow();
4049 SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
4050 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344051 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
4052 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244053 base::WeakPtr<SpdySession> session1 =
4054 helper.session()->spdy_session_pool()->FindAvailableSession(
4055 key2, true /* enable_up_base_pooling */, false /* is_websocket */,
4056 NetLogWithSource());
4057 ASSERT_TRUE(session1);
4058 EXPECT_EQ(key1, session1->spdy_session_key());
4059 // Remove the session before the second request can try to use it.
4060 helper.session()->spdy_session_pool()->CloseAllSessions();
4061
4062 // Wait for the second request to get headers. It should create a new H2
4063 // session to do so.
4064 EXPECT_THAT(callback.WaitForResult(), IsOk());
4065
4066 const HttpResponseInfo* response = trans2->GetResponseInfo();
4067 ASSERT_TRUE(response);
4068 ASSERT_TRUE(response->headers);
4069 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4070 EXPECT_TRUE(response->was_fetched_via_spdy);
4071 EXPECT_TRUE(response->was_alpn_negotiated);
4072 std::string response_data;
4073 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4074 EXPECT_EQ("hello!", response_data);
4075
4076 // Inspect the new session.
4077 base::WeakPtr<SpdySession> session2 =
4078 helper.session()->spdy_session_pool()->FindAvailableSession(
4079 key2, true /* enable_up_base_pooling */, false /* is_websocket */,
4080 NetLogWithSource());
4081 ASSERT_TRUE(session2);
4082 EXPECT_EQ(key2, session2->spdy_session_key());
4083 helper.VerifyDataConsumed();
4084}
4085
4086#if defined(OS_ANDROID)
4087
4088// Test this if two HttpNetworkTransactions try to repurpose the same
4089// SpdySession with two different SocketTags, only one request gets the session,
4090// while the other makes a new SPDY session.
4091TEST_F(SpdyNetworkTransactionTest, ConnectionPoolingMultipleSocketTags) {
4092 const SocketTag kSocketTag1(SocketTag::UNSET_UID, 1);
4093 const SocketTag kSocketTag2(SocketTag::UNSET_UID, 2);
4094 const SocketTag kSocketTag3(SocketTag::UNSET_UID, 3);
4095
4096 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
4097
4098 // The first and third requests use the first connection.
4099 spdy::SpdySerializedFrame req1(
4100 spdy_util_.ConstructSpdyGet("https://www.example.org", 1, LOWEST));
4101 spdy_util_.UpdateWithStreamDestruction(1);
4102 spdy::SpdySerializedFrame req3(
4103 spdy_util_.ConstructSpdyGet("https://example.test/request3", 3, LOWEST));
4104 MockWrite writes1[] = {
4105 CreateMockWrite(req1, 0),
4106 CreateMockWrite(req3, 3),
4107 };
4108
4109 spdy::SpdySerializedFrame resp1(
4110 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4111 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
4112 spdy::SpdySerializedFrame resp3(
4113 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
4114 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(3, true));
4115 MockRead reads1[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
4116 CreateMockRead(resp3, 4), CreateMockRead(body3, 5),
4117 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
4118
4119 SequencedSocketData data1(MockConnect(ASYNC, OK), reads1, writes1);
4120 helper.AddData(&data1);
4121
4122 // Due to the vagaries of how the socket pools work, in this particular case,
4123 // the second ConnectJob will be cancelled, but only after it tries to start
4124 // connecting. This does not happen in the general case of a bunch of requests
4125 // using the same socket tag.
4126 SequencedSocketData data2(MockConnect(SYNCHRONOUS, ERR_IO_PENDING),
4127 base::span<const MockRead>(),
4128 base::span<const MockWrite>());
4129 helper.AddData(&data2);
4130
4131 // The second request uses a second connection.
4132 SpdyTestUtil spdy_util2;
4133 spdy::SpdySerializedFrame req2(
4134 spdy_util2.ConstructSpdyGet("https://example.test/request2", 1, LOWEST));
4135 MockWrite writes2[] = {
4136 CreateMockWrite(req2, 0),
4137 };
4138
4139 spdy::SpdySerializedFrame resp2(
4140 spdy_util2.ConstructSpdyGetReply(nullptr, 0, 1));
4141 spdy::SpdySerializedFrame body2(spdy_util2.ConstructSpdyDataFrame(1, true));
4142 MockRead reads2[] = {CreateMockRead(resp2, 1), CreateMockRead(body2, 2),
4143 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
4144
4145 SequencedSocketData data3(MockConnect(ASYNC, OK), reads2, writes2);
4146 helper.AddData(&data3);
4147
4148 // Run a transaction to completion to set up a SPDY session. This can't use
4149 // RunToCompletion(), since it can't call VerifyDataConsumed() yet.
4150 helper.RunPreTestSetup();
4151 helper.RunDefaultTest();
4152 TransactionHelperResult out = helper.output();
4153 EXPECT_THAT(out.rv, IsOk());
4154 EXPECT_EQ("HTTP/1.1 200", out.status_line);
4155 EXPECT_EQ("hello!", out.response_data);
4156
4157 // A new SPDY session should have been created.
4158 SpdySessionKey key1(HostPortPair("www.example.org", 443),
4159 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344160 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
4161 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244162 EXPECT_TRUE(helper.session()->spdy_session_pool()->FindAvailableSession(
4163 key1, true /* enable_up_base_pooling */, false /* is_websocket */,
4164 NetLogWithSource()));
4165
4166 // Set on-demand mode for the next two requests.
4167 helper.session_deps()->host_resolver->set_ondemand_mode(true);
4168
4169 HttpRequestInfo request2;
4170 request2.socket_tag = kSocketTag2;
4171 request2.method = "GET";
4172 request2.url = GURL("https://example.test/request2");
4173 request2.load_flags = 0;
4174 request2.traffic_annotation =
4175 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4176 auto trans2 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4177 helper.session());
4178 TestCompletionCallback callback2;
4179 EXPECT_THAT(
4180 trans2->Start(&request2, callback2.callback(), NetLogWithSource()),
4181 IsError(ERR_IO_PENDING));
4182
4183 HttpRequestInfo request3;
4184 request3.socket_tag = kSocketTag3;
4185 request3.method = "GET";
4186 request3.url = GURL("https://example.test/request3");
4187 request3.load_flags = 0;
4188 request3.traffic_annotation =
4189 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
4190 auto trans3 = std::make_unique<HttpNetworkTransaction>(DEFAULT_PRIORITY,
4191 helper.session());
4192 TestCompletionCallback callback3;
4193 EXPECT_THAT(
4194 trans3->Start(&request3, callback3.callback(), NetLogWithSource()),
4195 IsError(ERR_IO_PENDING));
4196
4197 // Run the message loop until both requests are waiting on the host resolver.
4198 base::RunLoop().RunUntilIdle();
4199 ASSERT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
4200
4201 // Complete the second requests's DNS lookup now, which should create an alias
4202 // for the SpdySession immediately, but the task to use the session for the
4203 // second request should run asynchronously, so it hasn't run yet.
4204 helper.session_deps()->host_resolver->ResolveNow(2);
4205 SpdySessionKey key2(HostPortPair("example.test", 443), ProxyServer::Direct(),
4206 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344207 SpdySessionKey::IsProxySession::kFalse, kSocketTag2,
4208 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244209
4210 // Complete the third requests's DNS lookup now, which should hijack the
4211 // SpdySession from the second request.
4212 helper.session_deps()->host_resolver->ResolveNow(3);
4213 SpdySessionKey key3(HostPortPair("example.test", 443), ProxyServer::Direct(),
4214 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:344215 SpdySessionKey::IsProxySession::kFalse, kSocketTag3,
4216 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:244217
4218 // Wait for the second request to get headers. It should create a new H2
4219 // session to do so.
4220 EXPECT_THAT(callback2.WaitForResult(), IsOk());
4221
4222 const HttpResponseInfo* response = trans2->GetResponseInfo();
4223 ASSERT_TRUE(response);
4224 ASSERT_TRUE(response->headers);
4225 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4226 EXPECT_TRUE(response->was_fetched_via_spdy);
4227 EXPECT_TRUE(response->was_alpn_negotiated);
4228 std::string response_data;
4229 ASSERT_THAT(ReadTransaction(trans2.get(), &response_data), IsOk());
4230 EXPECT_EQ("hello!", response_data);
4231
4232 // Wait for the third request to get headers. It should have reused the first
4233 // session.
4234 EXPECT_THAT(callback3.WaitForResult(), IsOk());
4235
4236 response = trans3->GetResponseInfo();
4237 ASSERT_TRUE(response);
4238 ASSERT_TRUE(response->headers);
4239 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
4240 EXPECT_TRUE(response->was_fetched_via_spdy);
4241 EXPECT_TRUE(response->was_alpn_negotiated);
4242 ASSERT_THAT(ReadTransaction(trans3.get(), &response_data), IsOk());
4243 EXPECT_EQ("hello!", response_data);
4244
4245 helper.VerifyDataConsumed();
4246}
4247
4248#endif // defined(OS_ANDROID)
4249
bncc055fa32017-06-19 13:44:424250// Regression test for https://crbug.com/727653.
4251TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithNoMethod) {
Bence Békyeacd48f2018-05-14 11:34:334252 base::HistogramTester histogram_tester;
4253
Ryan Hamilton0239aac2018-05-19 00:03:134254 spdy::SpdySerializedFrame req(
4255 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4256 spdy::SpdySerializedFrame rst(
4257 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
bncc055fa32017-06-19 13:44:424258 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 3)};
4259
Ryan Hamilton0239aac2018-05-19 00:03:134260 spdy::SpdySerializedFrame reply(
4261 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncc055fa32017-06-19 13:44:424262
Bence Béky4c325e52020-10-22 20:48:014263 spdy::Http2HeaderBlock push_promise_header_block;
Bence Békyd2df6c1c82018-04-20 22:52:014264 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:134265 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:504266 1, 2, std::move(push_promise_header_block)));
bncc055fa32017-06-19 13:44:424267
Ryan Hamilton0239aac2018-05-19 00:03:134268 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyf1d78522018-01-11 01:16:504269 MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2),
4270 CreateMockRead(body, 4),
4271 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
bncc055fa32017-06-19 13:44:424272
Ryan Sleevib8d7ea02018-05-07 20:01:014273 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104274 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc055fa32017-06-19 13:44:424275 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:334276
4277 histogram_tester.ExpectBucketCount(
4278 "Net.SpdyPushedStreamFate",
4279 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
4280 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bncc055fa32017-06-19 13:44:424281}
4282
4283// Regression test for https://crbug.com/727653.
4284TEST_F(SpdyNetworkTransactionTest, RejectServerPushWithInvalidMethod) {
Bence Békyeacd48f2018-05-14 11:34:334285 base::HistogramTester histogram_tester;
4286
Ryan Hamilton0239aac2018-05-19 00:03:134287 spdy::SpdySerializedFrame req(
4288 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4289 spdy::SpdySerializedFrame rst(
4290 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_REFUSED_STREAM));
bncc055fa32017-06-19 13:44:424291 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 3)};
4292
Ryan Hamilton0239aac2018-05-19 00:03:134293 spdy::SpdySerializedFrame reply(
4294 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncc055fa32017-06-19 13:44:424295
Bence Béky4c325e52020-10-22 20:48:014296 spdy::Http2HeaderBlock push_promise_header_block;
bncc055fa32017-06-19 13:44:424297 push_promise_header_block[":method"] = "POST";
Bence Békyd2df6c1c82018-04-20 22:52:014298 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &push_promise_header_block);
Ryan Hamilton0239aac2018-05-19 00:03:134299 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:504300 1, 2, std::move(push_promise_header_block)));
bncc055fa32017-06-19 13:44:424301
Ryan Hamilton0239aac2018-05-19 00:03:134302 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyf1d78522018-01-11 01:16:504303 MockRead reads[] = {CreateMockRead(reply, 1), CreateMockRead(push_promise, 2),
4304 CreateMockRead(body, 4),
4305 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
bncc055fa32017-06-19 13:44:424306
Ryan Sleevib8d7ea02018-05-07 20:01:014307 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104308 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc055fa32017-06-19 13:44:424309 helper.RunToCompletion(&data);
Bence Békyeacd48f2018-05-14 11:34:334310
4311 histogram_tester.ExpectBucketCount(
4312 "Net.SpdyPushedStreamFate",
4313 static_cast<int>(SpdyPushedStreamFate::kInvalidUrl), 1);
4314 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
bncc055fa32017-06-19 13:44:424315}
4316
bnc42331402016-07-25 13:36:154317// Verify that various response headers parse correctly through the HTTP layer.
4318TEST_F(SpdyNetworkTransactionTest, ResponseHeaders) {
4319 struct ResponseHeadersTests {
Bence Békye5438512017-11-22 23:07:424320 int extra_header_count;
4321 const char* extra_headers[4];
4322 size_t expected_header_count;
Bence Béky4e83f492018-05-13 23:14:254323 base::StringPiece expected_headers[8];
Bence Békye5438512017-11-22 23:07:424324 } test_cases[] = {
4325 // No extra headers.
Yoichi Osato85350eb72020-09-11 02:14:304326 {0, {}, 1, {"hello", "bye"}},
Bence Békye5438512017-11-22 23:07:424327 // Comma-separated header value.
4328 {1,
4329 {"cookie", "val1, val2"},
Yoichi Osato85350eb72020-09-11 02:14:304330 2,
4331 {"hello", "bye", "cookie", "val1, val2"}},
Bence Békye5438512017-11-22 23:07:424332 // Multiple headers are preserved: they are joined with \0 separator in
Bence Béky4c325e52020-10-22 20:48:014333 // spdy::Http2HeaderBlock.AppendValueOrAddHeader(), then split up in
Bence Békye5438512017-11-22 23:07:424334 // HpackEncoder, then joined with \0 separator when
Ryan Hamilton0239aac2018-05-19 00:03:134335 // spdy::HpackDecoderAdapter::ListenerAdapter::OnHeader() calls
Bence Béky4c325e52020-10-22 20:48:014336 // spdy::Http2HeaderBlock.AppendValueOrAddHeader(), then split up again in
Bence Békye5438512017-11-22 23:07:424337 // HttpResponseHeaders.
4338 {2,
4339 {"content-encoding", "val1", "content-encoding", "val2"},
Yoichi Osato85350eb72020-09-11 02:14:304340 3,
4341 {"hello", "bye", "content-encoding", "val1", "content-encoding",
4342 "val2"}},
Bence Békye5438512017-11-22 23:07:424343 // Cookie header is not split up by HttpResponseHeaders.
4344 {2,
4345 {"cookie", "val1", "cookie", "val2"},
Yoichi Osato85350eb72020-09-11 02:14:304346 2,
4347 {"hello", "bye", "cookie", "val1; val2"}}};
bnc7ecc1122015-09-28 13:22:494348
Avi Drissman4365a4782018-12-28 19:26:244349 for (size_t i = 0; i < base::size(test_cases); ++i) {
Bence Békyad9eb1622020-09-17 16:29:174350 SCOPED_TRACE(i);
bncd16676a2016-07-20 16:23:014351 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:134352 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484353 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414354 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8b070372009-11-16 22:01:254355
Ryan Hamilton0239aac2018-05-19 00:03:134356 spdy::SpdySerializedFrame resp(spdy_test_util.ConstructSpdyGetReply(
Bence Békye5438512017-11-22 23:07:424357 test_cases[i].extra_headers, test_cases[i].extra_header_count, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134358 spdy::SpdySerializedFrame body(
4359 spdy_test_util.ConstructSpdyDataFrame(1, true));
[email protected]8b070372009-11-16 22:01:254360 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414361 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:524362 MockRead(ASYNC, 0, 3) // EOF
[email protected]8b070372009-11-16 22:01:254363 };
4364
Ryan Sleevib8d7ea02018-05-07 20:01:014365 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104366 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4367 nullptr);
[email protected]dd54bd82012-07-19 23:44:574368 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474369 TransactionHelperResult out = helper.output();
4370
robpercival214763f2016-07-01 23:27:014371 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024372 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8b070372009-11-16 22:01:254373 EXPECT_EQ("hello!", out.response_data);
4374
4375 scoped_refptr<HttpResponseHeaders> headers = out.response_info.headers;
Bence Békyad9eb1622020-09-17 16:29:174376 ASSERT_TRUE(headers);
4377 EXPECT_EQ("HTTP/1.1 200", headers->GetStatusLine());
olli.raula33c282f2016-01-21 12:12:494378 size_t iter = 0;
Bence Béky4e83f492018-05-13 23:14:254379 std::string name, value;
Bence Békye5438512017-11-22 23:07:424380 size_t expected_header_index = 0;
[email protected]8b070372009-11-16 22:01:254381 while (headers->EnumerateHeaderLines(&iter, &name, &value)) {
Bence Békyad9eb1622020-09-17 16:29:174382 ASSERT_LT(expected_header_index, test_cases[i].expected_header_count);
4383 EXPECT_EQ(name,
4384 test_cases[i].expected_headers[2 * expected_header_index]);
Bence Békye5438512017-11-22 23:07:424385 EXPECT_EQ(value,
Bence Békyad9eb1622020-09-17 16:29:174386 test_cases[i].expected_headers[2 * expected_header_index + 1]);
Bence Békye5438512017-11-22 23:07:424387 ++expected_header_index;
[email protected]8b070372009-11-16 22:01:254388 }
Bence Békyad9eb1622020-09-17 16:29:174389 EXPECT_EQ(expected_header_index, test_cases[i].expected_header_count);
[email protected]3f662f12010-03-25 19:56:124390 }
4391}
4392
bnc42331402016-07-25 13:36:154393// Verify that we don't crash on invalid response headers.
4394TEST_F(SpdyNetworkTransactionTest, InvalidResponseHeaders) {
4395 struct InvalidResponseHeadersTests {
[email protected]e7f75092010-07-01 22:39:134396 int num_headers;
4397 const char* headers[10];
Bence Békyad9eb1622020-09-17 16:29:174398 } test_cases[] = {// Response headers missing status header
4399 {2, {"cookie", "val1", "cookie", "val2", nullptr}},
4400 // Response headers with no headers
4401 {0, {nullptr}}};
[email protected]dd11b932009-11-30 19:39:484402
Avi Drissman4365a4782018-12-28 19:26:244403 for (size_t i = 0; i < base::size(test_cases); ++i) {
Bence Békyad9eb1622020-09-17 16:29:174404 SCOPED_TRACE(i);
bncd16676a2016-07-20 16:23:014405 SpdyTestUtil spdy_test_util;
bnc38dcd392016-02-09 23:19:494406
Ryan Hamilton0239aac2018-05-19 00:03:134407 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484408 spdy_test_util.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:134409 spdy::SpdySerializedFrame rst(spdy_test_util.ConstructSpdyRstStream(
4410 1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]dd11b932009-11-30 19:39:484411 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:414412 CreateMockWrite(req, 0), CreateMockWrite(rst, 2),
[email protected]dd11b932009-11-30 19:39:484413 };
4414
[email protected]745aa9c2014-06-27 02:21:294415 // Construct the reply.
Bence Béky4c325e52020-10-22 20:48:014416 spdy::Http2HeaderBlock reply_headers;
[email protected]745aa9c2014-06-27 02:21:294417 AppendToHeaderBlock(
4418 test_cases[i].headers, test_cases[i].num_headers, &reply_headers);
Ryan Hamilton0239aac2018-05-19 00:03:134419 spdy::SpdySerializedFrame resp(
bnc086b39e12016-06-24 13:05:264420 spdy_test_util.ConstructSpdyReply(1, std::move(reply_headers)));
[email protected]dd11b932009-11-30 19:39:484421 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414422 CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3) // EOF
[email protected]dd11b932009-11-30 19:39:484423 };
4424
Ryan Sleevib8d7ea02018-05-07 20:01:014425 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104426 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
4427 nullptr);
[email protected]dd54bd82012-07-19 23:44:574428 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474429 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184430 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]dd11b932009-11-30 19:39:484431 }
4432}
4433
bncd16676a2016-07-20 16:23:014434TEST_F(SpdyNetworkTransactionTest, CorruptFrameSessionError) {
Ryan Hamilton0239aac2018-05-19 00:03:134435 spdy::SpdySerializedFrame req(
4436 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Zhongyi Shi495af8072020-02-28 04:43:484437 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4438 0, spdy::ERROR_CODE_COMPRESSION_ERROR,
4439 "Framer error: 30 (HPACK_TRUNCATED_BLOCK)."));
bncdf80d44fd2016-07-15 20:27:414440 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]e3352df2014-03-19 05:55:424441
bnc38dcd392016-02-09 23:19:494442 // This is the length field that's too short.
Ryan Hamilton0239aac2018-05-19 00:03:134443 spdy::SpdySerializedFrame reply_wrong_length(
bnc42331402016-07-25 13:36:154444 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134445 size_t right_size = reply_wrong_length.size() - spdy::kFrameHeaderSize;
bnc38dcd392016-02-09 23:19:494446 size_t wrong_size = right_size - 4;
Ryan Hamilton0239aac2018-05-19 00:03:134447 spdy::test::SetFrameLength(&reply_wrong_length, wrong_size);
bnc38dcd392016-02-09 23:19:494448
[email protected]e3352df2014-03-19 05:55:424449 MockRead reads[] = {
bnc42331402016-07-25 13:36:154450 MockRead(ASYNC, reply_wrong_length.data(), reply_wrong_length.size() - 4,
4451 1),
[email protected]e3352df2014-03-19 05:55:424452 };
4453
Ryan Sleevib8d7ea02018-05-07 20:01:014454 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104455 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]e3352df2014-03-19 05:55:424456 helper.RunToCompletion(&data);
4457 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184458 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_COMPRESSION_ERROR));
[email protected]bdd1b222014-06-10 11:08:394459}
4460
bncd16676a2016-07-20 16:23:014461TEST_F(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
Ryan Hamilton0239aac2018-05-19 00:03:134462 spdy::SpdySerializedFrame req(
4463 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Zhongyi Shi495af8072020-02-28 04:43:484464 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4465 0, spdy::ERROR_CODE_COMPRESSION_ERROR,
4466 "Framer error: 30 (HPACK_TRUNCATED_BLOCK)."));
bncdf80d44fd2016-07-15 20:27:414467 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]bdd1b222014-06-10 11:08:394468
4469 // Read HEADERS with corrupted payload.
Ryan Hamilton0239aac2018-05-19 00:03:134470 spdy::SpdySerializedFrame resp(
4471 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncdf80d44fd2016-07-15 20:27:414472 memset(resp.data() + 12, 0xcf, resp.size() - 12);
4473 MockRead reads[] = {CreateMockRead(resp, 1)};
[email protected]bdd1b222014-06-10 11:08:394474
Ryan Sleevib8d7ea02018-05-07 20:01:014475 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104476 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdd1b222014-06-10 11:08:394477 helper.RunToCompletion(&data);
4478 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184479 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_COMPRESSION_ERROR));
[email protected]bdd1b222014-06-10 11:08:394480}
4481
bncd16676a2016-07-20 16:23:014482TEST_F(SpdyNetworkTransactionTest, GoAwayOnFrameSizeError) {
Ryan Hamilton0239aac2018-05-19 00:03:134483 spdy::SpdySerializedFrame req(
4484 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4485 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
4486 0, spdy::ERROR_CODE_FRAME_SIZE_ERROR,
dahollingsaf3796492016-05-25 19:21:354487 "Framer error: 15 (INVALID_CONTROL_FRAME_SIZE)."));
bncdf80d44fd2016-07-15 20:27:414488 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(goaway, 2)};
[email protected]bdd1b222014-06-10 11:08:394489
4490 // Read WINDOW_UPDATE with incorrectly-sized payload.
Ryan Hamilton0239aac2018-05-19 00:03:134491 spdy::SpdySerializedFrame bad_window_update(
[email protected]bdd1b222014-06-10 11:08:394492 spdy_util_.ConstructSpdyWindowUpdate(1, 1));
Ryan Hamilton0239aac2018-05-19 00:03:134493 spdy::test::SetFrameLength(&bad_window_update, bad_window_update.size() - 1);
bncdf80d44fd2016-07-15 20:27:414494 MockRead reads[] = {CreateMockRead(bad_window_update, 1)};
[email protected]bdd1b222014-06-10 11:08:394495
Ryan Sleevib8d7ea02018-05-07 20:01:014496 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104497 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]bdd1b222014-06-10 11:08:394498 helper.RunToCompletion(&data);
4499 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:184500 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_FRAME_SIZE_ERROR));
[email protected]e3352df2014-03-19 05:55:424501}
4502
[email protected]bf2491a92009-11-29 16:39:484503// Test that we shutdown correctly on write errors.
bncd16676a2016-07-20 16:23:014504TEST_F(SpdyNetworkTransactionTest, WriteError) {
Ryan Hamilton0239aac2018-05-19 00:03:134505 spdy::SpdySerializedFrame req(
4506 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:484507 MockWrite writes[] = {
[email protected]bdd1b222014-06-10 11:08:394508 // We'll write 10 bytes successfully
bncdf80d44fd2016-07-15 20:27:414509 MockWrite(ASYNC, req.data(), 10, 1),
[email protected]bdd1b222014-06-10 11:08:394510 // Followed by ERROR!
[email protected]bdd1b222014-06-10 11:08:394511 MockWrite(ASYNC, ERR_FAILED, 2),
mmenke666a6fea2015-12-19 04:16:334512 // Session drains and attempts to write a GOAWAY: Another ERROR!
4513 MockWrite(ASYNC, ERR_FAILED, 3),
[email protected]bf2491a92009-11-29 16:39:484514 };
4515
mmenke666a6fea2015-12-19 04:16:334516 MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)};
[email protected]238002d2013-10-17 02:01:404517
Ryan Sleevib8d7ea02018-05-07 20:01:014518 SequencedSocketData data(reads, writes);
[email protected]238002d2013-10-17 02:01:404519
Bence Békydb3cf652017-10-10 15:22:104520 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]238002d2013-10-17 02:01:404521 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:334522 helper.AddData(&data);
[email protected]238002d2013-10-17 02:01:404523 EXPECT_TRUE(helper.StartDefaultTest());
[email protected]238002d2013-10-17 02:01:404524 helper.FinishDefaultTest();
rch37de576c2015-05-17 20:28:174525 EXPECT_TRUE(data.AllWriteDataConsumed());
mmenke666a6fea2015-12-19 04:16:334526 EXPECT_TRUE(data.AllReadDataConsumed());
[email protected]3caf5542010-07-16 15:19:474527 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014528 EXPECT_THAT(out.rv, IsError(ERR_FAILED));
[email protected]bf2491a92009-11-29 16:39:484529}
4530
4531// Test that partial writes work.
bncd16676a2016-07-20 16:23:014532TEST_F(SpdyNetworkTransactionTest, PartialWrite) {
bnc42331402016-07-25 13:36:154533 // Chop the HEADERS frame into 5 chunks.
Ryan Hamilton0239aac2018-05-19 00:03:134534 spdy::SpdySerializedFrame req(
4535 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]bf2491a92009-11-29 16:39:484536 const int kChunks = 5;
bnc3f6a8552017-05-17 13:40:344537 std::unique_ptr<MockWrite[]> writes = ChopWriteFrame(req, kChunks);
rch08e3aa3e2015-05-16 14:27:524538 for (int i = 0; i < kChunks; ++i) {
4539 writes[i].sequence_number = i;
4540 }
[email protected]bf2491a92009-11-29 16:39:484541
Ryan Hamilton0239aac2018-05-19 00:03:134542 spdy::SpdySerializedFrame resp(
4543 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4544 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]bf2491a92009-11-29 16:39:484545 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414546 CreateMockRead(resp, kChunks), CreateMockRead(body, kChunks + 1),
rch08e3aa3e2015-05-16 14:27:524547 MockRead(ASYNC, 0, kChunks + 2) // EOF
[email protected]bf2491a92009-11-29 16:39:484548 };
4549
Ryan Sleevib8d7ea02018-05-07 20:01:014550 SequencedSocketData data(reads, base::make_span(writes.get(), kChunks));
Bence Békydb3cf652017-10-10 15:22:104551 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:574552 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474553 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014554 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024555 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]bf2491a92009-11-29 16:39:484556 EXPECT_EQ("hello!", out.response_data);
4557}
4558
[email protected]9e743cd2010-03-16 07:03:534559// Test that the NetLog contains good data for a simple GET request.
bncd16676a2016-07-20 16:23:014560TEST_F(SpdyNetworkTransactionTest, NetLog) {
[email protected]3deb9a52010-11-11 00:24:404561 static const char* const kExtraHeaders[] = {
4562 "user-agent", "Chrome",
4563 };
Ryan Hamilton0239aac2018-05-19 00:03:134564 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:484565 spdy_util_.ConstructSpdyGet(kExtraHeaders, 1, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414566 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]dac358042009-12-18 02:07:484567
Ryan Hamilton0239aac2018-05-19 00:03:134568 spdy::SpdySerializedFrame resp(
4569 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4570 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]dac358042009-12-18 02:07:484571 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414572 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:524573 MockRead(ASYNC, 0, 3) // EOF
[email protected]dac358042009-12-18 02:07:484574 };
4575
Matt Muellerd9342e3a2019-11-26 01:41:144576 RecordingBoundTestNetLog log;
[email protected]dac358042009-12-18 02:07:484577
Ryan Sleevib8d7ea02018-05-07 20:01:014578 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:104579 request_.extra_headers.SetHeader("User-Agent", "Chrome");
4580 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log.bound(),
4581 nullptr);
[email protected]dd54bd82012-07-19 23:44:574582 helper.RunToCompletion(&data);
[email protected]3caf5542010-07-16 15:19:474583 TransactionHelperResult out = helper.output();
robpercival214763f2016-07-01 23:27:014584 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024585 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]dac358042009-12-18 02:07:484586 EXPECT_EQ("hello!", out.response_data);
4587
[email protected]9e743cd2010-03-16 07:03:534588 // Check that the NetLog was filled reasonably.
[email protected]3caf5542010-07-16 15:19:474589 // This test is intentionally non-specific about the exact ordering of the
4590 // log; instead we just check to make sure that certain events exist, and that
4591 // they are in the right order.
Eric Roman79cc7552019-07-19 02:17:544592 auto entries = log.GetEntries();
[email protected]b2fcd0e2010-12-01 15:19:404593
4594 EXPECT_LT(0u, entries.size());
[email protected]dac358042009-12-18 02:07:484595 int pos = 0;
mikecirone8b85c432016-09-08 19:11:004596 pos = ExpectLogContainsSomewhere(
4597 entries, 0, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
4598 NetLogEventPhase::BEGIN);
4599 pos = ExpectLogContainsSomewhere(
4600 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_SEND_REQUEST,
4601 NetLogEventPhase::END);
4602 pos = ExpectLogContainsSomewhere(
4603 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
4604 NetLogEventPhase::BEGIN);
4605 pos = ExpectLogContainsSomewhere(
4606 entries, pos + 1, NetLogEventType::HTTP_TRANSACTION_READ_HEADERS,
4607 NetLogEventPhase::END);
bnc301745a2015-03-10 03:22:164608 pos = ExpectLogContainsSomewhere(entries, pos + 1,
mikecirone8b85c432016-09-08 19:11:004609 NetLogEventType::HTTP_TRANSACTION_READ_BODY,
4610 NetLogEventPhase::BEGIN);
bnc301745a2015-03-10 03:22:164611 pos = ExpectLogContainsSomewhere(entries, pos + 1,
mikecirone8b85c432016-09-08 19:11:004612 NetLogEventType::HTTP_TRANSACTION_READ_BODY,
4613 NetLogEventPhase::END);
[email protected]3deb9a52010-11-11 00:24:404614
4615 // Check that we logged all the headers correctly
mikecirone8b85c432016-09-08 19:11:004616 pos = ExpectLogContainsSomewhere(entries, 0,
4617 NetLogEventType::HTTP2_SESSION_SEND_HEADERS,
4618 NetLogEventPhase::NONE);
[email protected]3deb9a52010-11-11 00:24:404619
Eric Roman79cc7552019-07-19 02:17:544620 ASSERT_TRUE(entries[pos].HasParams());
4621 auto* header_list = entries[pos].params.FindKey("headers");
Bence Béky66871e32018-12-06 21:11:244622 ASSERT_TRUE(header_list);
4623 ASSERT_TRUE(header_list->is_list());
4624 ASSERT_EQ(5u, header_list->GetList().size());
[email protected]f3da152d2012-06-02 01:00:574625
Bence Béky66871e32018-12-06 21:11:244626 ASSERT_TRUE(header_list->GetList()[0].is_string());
4627 EXPECT_EQ(":method: GET", header_list->GetList()[0].GetString());
4628
4629 ASSERT_TRUE(header_list->GetList()[1].is_string());
4630 EXPECT_EQ(":authority: www.example.org",
4631 header_list->GetList()[1].GetString());
4632
4633 ASSERT_TRUE(header_list->GetList()[2].is_string());
4634 EXPECT_EQ(":scheme: https", header_list->GetList()[2].GetString());
4635
4636 ASSERT_TRUE(header_list->GetList()[3].is_string());
4637 EXPECT_EQ(":path: /", header_list->GetList()[3].GetString());
4638
4639 ASSERT_TRUE(header_list->GetList()[4].is_string());
4640 EXPECT_EQ("user-agent: Chrome", header_list->GetList()[4].GetString());
[email protected]dac358042009-12-18 02:07:484641}
4642
[email protected]79d84222010-02-26 00:01:444643// Since we buffer the IO from the stream to the renderer, this test verifies
4644// that when we read out the maximum amount of data (e.g. we received 50 bytes
4645// on the network, but issued a Read for only 5 of those bytes) that the data
4646// flow still works correctly.
bncd16676a2016-07-20 16:23:014647TEST_F(SpdyNetworkTransactionTest, BufferFull) {
Ryan Hamilton0239aac2018-05-19 00:03:134648 spdy::SpdySerializedFrame req(
4649 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414650 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]79d84222010-02-26 00:01:444651
[email protected]20d005f2010-07-02 19:55:434652 // 2 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134653 spdy::SpdySerializedFrame data_frame_1(
Bence Békyd74f4382018-02-20 18:26:194654 spdy_util_.ConstructSpdyDataFrame(1, "goodby", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134655 spdy::SpdySerializedFrame data_frame_2(
Bence Békyd74f4382018-02-20 18:26:194656 spdy_util_.ConstructSpdyDataFrame(1, "e worl", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134657 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:194658 CombineFrames({&data_frame_1, &data_frame_2});
4659
Ryan Hamilton0239aac2018-05-19 00:03:134660 spdy::SpdySerializedFrame last_frame(
Bence Békyd74f4382018-02-20 18:26:194661 spdy_util_.ConstructSpdyDataFrame(1, "d", /*fin=*/true));
[email protected]79d84222010-02-26 00:01:444662
Ryan Hamilton0239aac2018-05-19 00:03:134663 spdy::SpdySerializedFrame resp(
4664 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]79d84222010-02-26 00:01:444665 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414666 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:094667 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
bncef26b602017-06-12 22:08:194668 CreateMockRead(combined_data_frames, 3),
rch32320842015-05-16 15:57:094669 MockRead(ASYNC, ERR_IO_PENDING, 4), // Force a pause
bncdf80d44fd2016-07-15 20:27:414670 CreateMockRead(last_frame, 5),
rch32320842015-05-16 15:57:094671 MockRead(ASYNC, 0, 6) // EOF
[email protected]79d84222010-02-26 00:01:444672 };
4673
Ryan Sleevib8d7ea02018-05-07 20:01:014674 SequencedSocketData data(reads, writes);
[email protected]79d84222010-02-26 00:01:444675
[email protected]49639fa2011-12-20 23:22:414676 TestCompletionCallback callback;
[email protected]79d84222010-02-26 00:01:444677
Bence Békydb3cf652017-10-10 15:22:104678 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474679 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574680 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474681 HttpNetworkTransaction* trans = helper.trans();
Bence Békydb3cf652017-10-10 15:22:104682 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:014683 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]79d84222010-02-26 00:01:444684
[email protected]3caf5542010-07-16 15:19:474685 TransactionHelperResult out = helper.output();
[email protected]79d84222010-02-26 00:01:444686 out.rv = callback.WaitForResult();
4687 EXPECT_EQ(out.rv, OK);
4688
4689 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:524690 EXPECT_TRUE(response->headers);
[email protected]79d84222010-02-26 00:01:444691 EXPECT_TRUE(response->was_fetched_via_spdy);
4692 out.status_line = response->headers->GetStatusLine();
4693 out.response_info = *response; // Make a copy so we can verify.
4694
4695 // Read Data
[email protected]49639fa2011-12-20 23:22:414696 TestCompletionCallback read_callback;
[email protected]79d84222010-02-26 00:01:444697
Bence Béky4e83f492018-05-13 23:14:254698 std::string content;
[email protected]79d84222010-02-26 00:01:444699 do {
4700 // Read small chunks at a time.
4701 const int kSmallReadSize = 3;
Victor Costan9c7302b2018-08-27 16:39:444702 scoped_refptr<IOBuffer> buf =
4703 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:504704 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:164705 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:594706 data.Resume();
[email protected]79d84222010-02-26 00:01:444707 rv = read_callback.WaitForResult();
4708 }
4709 if (rv > 0) {
4710 content.append(buf->data(), rv);
4711 } else if (rv < 0) {
4712 NOTREACHED();
4713 }
4714 } while (rv > 0);
4715
4716 out.response_data.swap(content);
4717
[email protected]30c942b2010-07-21 16:59:594718 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:554719 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:174720 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:554721
[email protected]79d84222010-02-26 00:01:444722 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:474723 helper.VerifyDataConsumed();
[email protected]79d84222010-02-26 00:01:444724
robpercival214763f2016-07-01 23:27:014725 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024726 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]79d84222010-02-26 00:01:444727 EXPECT_EQ("goodbye world", out.response_data);
4728}
4729
[email protected]8918d282010-03-02 00:57:554730// Verify that basic buffering works; when multiple data frames arrive
4731// at the same time, ensure that we don't notify a read completion for
4732// each data frame individually.
bncd16676a2016-07-20 16:23:014733TEST_F(SpdyNetworkTransactionTest, Buffering) {
Ryan Hamilton0239aac2018-05-19 00:03:134734 spdy::SpdySerializedFrame req(
4735 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414736 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:554737
4738 // 4 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134739 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:194740 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134741 spdy::SpdySerializedFrame data_frame_fin(
Bence Békyd74f4382018-02-20 18:26:194742 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/true));
Ryan Hamilton0239aac2018-05-19 00:03:134743 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:194744 CombineFrames({&data_frame, &data_frame, &data_frame, &data_frame_fin});
[email protected]8918d282010-03-02 00:57:554745
Ryan Hamilton0239aac2018-05-19 00:03:134746 spdy::SpdySerializedFrame resp(
4747 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]8918d282010-03-02 00:57:554748 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414749 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:094750 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a pause
bncef26b602017-06-12 22:08:194751 CreateMockRead(combined_data_frames, 3), MockRead(ASYNC, 0, 4) // EOF
[email protected]8918d282010-03-02 00:57:554752 };
4753
Ryan Sleevib8d7ea02018-05-07 20:01:014754 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:554755
Bence Békydb3cf652017-10-10 15:22:104756 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474757 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574758 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474759 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:554760
[email protected]49639fa2011-12-20 23:22:414761 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:104762 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:014763 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:554764
[email protected]3caf5542010-07-16 15:19:474765 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:554766 out.rv = callback.WaitForResult();
4767 EXPECT_EQ(out.rv, OK);
4768
4769 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:524770 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:554771 EXPECT_TRUE(response->was_fetched_via_spdy);
4772 out.status_line = response->headers->GetStatusLine();
4773 out.response_info = *response; // Make a copy so we can verify.
4774
4775 // Read Data
[email protected]49639fa2011-12-20 23:22:414776 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:554777
Bence Béky4e83f492018-05-13 23:14:254778 std::string content;
[email protected]8918d282010-03-02 00:57:554779 int reads_completed = 0;
4780 do {
4781 // Read small chunks at a time.
4782 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:444783 scoped_refptr<IOBuffer> buf =
4784 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:504785 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:164786 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:594787 data.Resume();
[email protected]8918d282010-03-02 00:57:554788 rv = read_callback.WaitForResult();
4789 }
4790 if (rv > 0) {
4791 EXPECT_EQ(kSmallReadSize, rv);
4792 content.append(buf->data(), rv);
4793 } else if (rv < 0) {
4794 FAIL() << "Unexpected read error: " << rv;
4795 }
4796 reads_completed++;
4797 } while (rv > 0);
4798
4799 EXPECT_EQ(3, reads_completed); // Reads are: 14 bytes, 14 bytes, 0 bytes.
4800
4801 out.response_data.swap(content);
4802
[email protected]30c942b2010-07-21 16:59:594803 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:554804 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:174805 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:554806
4807 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:474808 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:554809
robpercival214763f2016-07-01 23:27:014810 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024811 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8918d282010-03-02 00:57:554812 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
4813}
4814
4815// Verify the case where we buffer data but read it after it has been buffered.
bncd16676a2016-07-20 16:23:014816TEST_F(SpdyNetworkTransactionTest, BufferedAll) {
Ryan Hamilton0239aac2018-05-19 00:03:134817 spdy::SpdySerializedFrame req(
4818 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414819 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:554820
[email protected]20d005f2010-07-02 19:55:434821 // 5 data frames in a single read.
Ryan Hamilton0239aac2018-05-19 00:03:134822 spdy::SpdySerializedFrame reply(
4823 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
4824 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:194825 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134826 spdy::SpdySerializedFrame data_frame_fin(
Bence Békyd74f4382018-02-20 18:26:194827 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/true));
Ryan Hamilton0239aac2018-05-19 00:03:134828 spdy::SpdySerializedFrame combined_frames = CombineFrames(
bncef26b602017-06-12 22:08:194829 {&reply, &data_frame, &data_frame, &data_frame, &data_frame_fin});
[email protected]8918d282010-03-02 00:57:554830
4831 MockRead reads[] = {
bncef26b602017-06-12 22:08:194832 CreateMockRead(combined_frames, 1), MockRead(ASYNC, 0, 2) // EOF
[email protected]8918d282010-03-02 00:57:554833 };
4834
Ryan Sleevib8d7ea02018-05-07 20:01:014835 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:554836
Bence Békydb3cf652017-10-10 15:22:104837 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474838 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574839 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474840 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:554841
[email protected]49639fa2011-12-20 23:22:414842 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:104843 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:014844 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:554845
[email protected]3caf5542010-07-16 15:19:474846 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:554847 out.rv = callback.WaitForResult();
4848 EXPECT_EQ(out.rv, OK);
4849
4850 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:524851 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:554852 EXPECT_TRUE(response->was_fetched_via_spdy);
4853 out.status_line = response->headers->GetStatusLine();
4854 out.response_info = *response; // Make a copy so we can verify.
4855
4856 // Read Data
[email protected]49639fa2011-12-20 23:22:414857 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:554858
Bence Béky4e83f492018-05-13 23:14:254859 std::string content;
[email protected]8918d282010-03-02 00:57:554860 int reads_completed = 0;
4861 do {
4862 // Read small chunks at a time.
4863 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:444864 scoped_refptr<IOBuffer> buf =
4865 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:504866 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
[email protected]8918d282010-03-02 00:57:554867 if (rv > 0) {
4868 EXPECT_EQ(kSmallReadSize, rv);
4869 content.append(buf->data(), rv);
4870 } else if (rv < 0) {
4871 FAIL() << "Unexpected read error: " << rv;
4872 }
4873 reads_completed++;
4874 } while (rv > 0);
4875
4876 EXPECT_EQ(3, reads_completed);
4877
4878 out.response_data.swap(content);
4879
[email protected]30c942b2010-07-21 16:59:594880 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:554881 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:174882 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:554883
4884 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:474885 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:554886
robpercival214763f2016-07-01 23:27:014887 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:024888 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]8918d282010-03-02 00:57:554889 EXPECT_EQ("messagemessagemessagemessage", out.response_data);
4890}
4891
4892// Verify the case where we buffer data and close the connection.
bncd16676a2016-07-20 16:23:014893TEST_F(SpdyNetworkTransactionTest, BufferedClosed) {
Ryan Hamilton0239aac2018-05-19 00:03:134894 spdy::SpdySerializedFrame req(
4895 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:414896 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]8918d282010-03-02 00:57:554897
4898 // All data frames in a single read.
[email protected]20d005f2010-07-02 19:55:434899 // NOTE: We don't FIN the stream.
Ryan Hamilton0239aac2018-05-19 00:03:134900 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:194901 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
Ryan Hamilton0239aac2018-05-19 00:03:134902 spdy::SpdySerializedFrame combined_data_frames =
bncef26b602017-06-12 22:08:194903 CombineFrames({&data_frame, &data_frame, &data_frame, &data_frame});
Ryan Hamilton0239aac2018-05-19 00:03:134904 spdy::SpdySerializedFrame resp(
4905 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]8918d282010-03-02 00:57:554906 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414907 CreateMockRead(resp, 1),
rch32320842015-05-16 15:57:094908 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
bncef26b602017-06-12 22:08:194909 CreateMockRead(combined_data_frames, 3), MockRead(ASYNC, 0, 4) // EOF
[email protected]8918d282010-03-02 00:57:554910 };
4911
Ryan Sleevib8d7ea02018-05-07 20:01:014912 SequencedSocketData data(reads, writes);
[email protected]8918d282010-03-02 00:57:554913
Bence Békydb3cf652017-10-10 15:22:104914 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474915 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574916 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474917 HttpNetworkTransaction* trans = helper.trans();
[email protected]8918d282010-03-02 00:57:554918
[email protected]49639fa2011-12-20 23:22:414919 TestCompletionCallback callback;
[email protected]8918d282010-03-02 00:57:554920
Bence Békydb3cf652017-10-10 15:22:104921 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:014922 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]8918d282010-03-02 00:57:554923
[email protected]3caf5542010-07-16 15:19:474924 TransactionHelperResult out = helper.output();
[email protected]8918d282010-03-02 00:57:554925 out.rv = callback.WaitForResult();
4926 EXPECT_EQ(out.rv, OK);
4927
4928 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:524929 EXPECT_TRUE(response->headers);
[email protected]8918d282010-03-02 00:57:554930 EXPECT_TRUE(response->was_fetched_via_spdy);
4931 out.status_line = response->headers->GetStatusLine();
4932 out.response_info = *response; // Make a copy so we can verify.
4933
4934 // Read Data
[email protected]49639fa2011-12-20 23:22:414935 TestCompletionCallback read_callback;
[email protected]8918d282010-03-02 00:57:554936
Bence Béky4e83f492018-05-13 23:14:254937 std::string content;
[email protected]8918d282010-03-02 00:57:554938 int reads_completed = 0;
4939 do {
4940 // Read small chunks at a time.
4941 const int kSmallReadSize = 14;
Victor Costan9c7302b2018-08-27 16:39:444942 scoped_refptr<IOBuffer> buf =
4943 base::MakeRefCounted<IOBuffer>(kSmallReadSize);
[email protected]90499482013-06-01 00:39:504944 rv = trans->Read(buf.get(), kSmallReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:164945 if (rv == ERR_IO_PENDING) {
mmenkee24011922015-12-17 22:12:594946 data.Resume();
[email protected]8918d282010-03-02 00:57:554947 rv = read_callback.WaitForResult();
4948 }
4949 if (rv > 0) {
4950 content.append(buf->data(), rv);
4951 } else if (rv < 0) {
4952 // This test intentionally closes the connection, and will get an error.
robpercival214763f2016-07-01 23:27:014953 EXPECT_THAT(rv, IsError(ERR_CONNECTION_CLOSED));
[email protected]8918d282010-03-02 00:57:554954 break;
4955 }
4956 reads_completed++;
4957 } while (rv > 0);
4958
4959 EXPECT_EQ(0, reads_completed);
4960
4961 out.response_data.swap(content);
4962
[email protected]30c942b2010-07-21 16:59:594963 // Flush the MessageLoop while the SpdySessionDependencies (in particular, the
[email protected]8918d282010-03-02 00:57:554964 // MockClientSocketFactory) are still alive.
[email protected]fc9d88472013-08-14 02:31:174965 base::RunLoop().RunUntilIdle();
[email protected]8918d282010-03-02 00:57:554966
4967 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:474968 helper.VerifyDataConsumed();
[email protected]8918d282010-03-02 00:57:554969}
4970
[email protected]1ed7b3dc2010-03-04 05:41:454971// Verify the case where we buffer data and cancel the transaction.
bncd16676a2016-07-20 16:23:014972TEST_F(SpdyNetworkTransactionTest, BufferedCancelled) {
Ryan Hamilton0239aac2018-05-19 00:03:134973 spdy::SpdySerializedFrame req(
4974 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
4975 spdy::SpdySerializedFrame rst(
4976 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_CANCEL));
bncdf80d44fd2016-07-15 20:27:414977 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 4)};
[email protected]1ed7b3dc2010-03-04 05:41:454978
[email protected]20d005f2010-07-02 19:55:434979 // NOTE: We don't FIN the stream.
Ryan Hamilton0239aac2018-05-19 00:03:134980 spdy::SpdySerializedFrame data_frame(
Bence Békyd74f4382018-02-20 18:26:194981 spdy_util_.ConstructSpdyDataFrame(1, "message", /*fin=*/false));
[email protected]1ed7b3dc2010-03-04 05:41:454982
Ryan Hamilton0239aac2018-05-19 00:03:134983 spdy::SpdySerializedFrame resp(
4984 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]1ed7b3dc2010-03-04 05:41:454985 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:414986 CreateMockRead(resp, 1),
4987 MockRead(ASYNC, ERR_IO_PENDING, 2), // Force a wait
4988 CreateMockRead(data_frame, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]1ed7b3dc2010-03-04 05:41:454989 };
4990
Ryan Sleevib8d7ea02018-05-07 20:01:014991 SequencedSocketData data(reads, writes);
[email protected]1ed7b3dc2010-03-04 05:41:454992
Bence Békydb3cf652017-10-10 15:22:104993 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:474994 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:574995 helper.AddData(&data);
[email protected]3caf5542010-07-16 15:19:474996 HttpNetworkTransaction* trans = helper.trans();
[email protected]49639fa2011-12-20 23:22:414997 TestCompletionCallback callback;
[email protected]1ed7b3dc2010-03-04 05:41:454998
Bence Békydb3cf652017-10-10 15:22:104999 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015000 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]1ed7b3dc2010-03-04 05:41:455001
[email protected]3caf5542010-07-16 15:19:475002 TransactionHelperResult out = helper.output();
[email protected]1ed7b3dc2010-03-04 05:41:455003 out.rv = callback.WaitForResult();
5004 EXPECT_EQ(out.rv, OK);
5005
5006 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525007 EXPECT_TRUE(response->headers);
[email protected]1ed7b3dc2010-03-04 05:41:455008 EXPECT_TRUE(response->was_fetched_via_spdy);
5009 out.status_line = response->headers->GetStatusLine();
5010 out.response_info = *response; // Make a copy so we can verify.
5011
5012 // Read Data
[email protected]49639fa2011-12-20 23:22:415013 TestCompletionCallback read_callback;
[email protected]1ed7b3dc2010-03-04 05:41:455014
[email protected]88c7b4be2014-03-19 23:04:015015 const int kReadSize = 256;
Victor Costan9c7302b2018-08-27 16:39:445016 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kReadSize);
[email protected]88c7b4be2014-03-19 23:04:015017 rv = trans->Read(buf.get(), kReadSize, read_callback.callback());
bnc301745a2015-03-10 03:22:165018 ASSERT_EQ(ERR_IO_PENDING, rv) << "Unexpected read: " << rv;
[email protected]88c7b4be2014-03-19 23:04:015019
5020 // Complete the read now, which causes buffering to start.
mmenkee24011922015-12-17 22:12:595021 data.Resume();
5022 base::RunLoop().RunUntilIdle();
[email protected]88c7b4be2014-03-19 23:04:015023 // Destroy the transaction, causing the stream to get cancelled
5024 // and orphaning the buffered IO task.
5025 helper.ResetTrans();
[email protected]1ed7b3dc2010-03-04 05:41:455026
5027 // Flush the MessageLoop; this will cause the buffered IO task
5028 // to run for the final time.
[email protected]fc9d88472013-08-14 02:31:175029 base::RunLoop().RunUntilIdle();
[email protected]3caf5542010-07-16 15:19:475030
5031 // Verify that we consumed all test data.
5032 helper.VerifyDataConsumed();
[email protected]1ed7b3dc2010-03-04 05:41:455033}
5034
bncc4769d412017-04-19 19:57:545035// Request should fail upon receiving a GOAWAY frame
5036// with Last-Stream-ID lower than the stream id corresponding to the request
5037// and with error code other than NO_ERROR.
5038TEST_F(SpdyNetworkTransactionTest, FailOnGoAway) {
Ryan Hamilton0239aac2018-05-19 00:03:135039 spdy::SpdySerializedFrame req(
5040 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415041 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]69d717bd2010-04-21 18:43:215042
Ryan Hamilton0239aac2018-05-19 00:03:135043 spdy::SpdySerializedFrame go_away(
5044 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_INTERNAL_ERROR, ""));
[email protected]69d717bd2010-04-21 18:43:215045 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415046 CreateMockRead(go_away, 1),
[email protected]58cebf8f2010-07-31 19:20:165047 };
5048
Ryan Sleevib8d7ea02018-05-07 20:01:015049 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:105050 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:575051 helper.RunToCompletion(&data);
[email protected]58cebf8f2010-07-31 19:20:165052 TransactionHelperResult out = helper.output();
Matt Menke3b52f9f2020-06-08 20:04:035053 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]69d717bd2010-04-21 18:43:215054}
5055
bncc4769d412017-04-19 19:57:545056// Request should be retried on a new connection upon receiving a GOAWAY frame
5057// with Last-Stream-ID lower than the stream id corresponding to the request
5058// and with error code NO_ERROR.
5059TEST_F(SpdyNetworkTransactionTest, RetryOnGoAway) {
Bence Békydb3cf652017-10-10 15:22:105060 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc4769d412017-04-19 19:57:545061
5062 // First connection.
Ryan Hamilton0239aac2018-05-19 00:03:135063 spdy::SpdySerializedFrame req(
5064 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncc4769d412017-04-19 19:57:545065 MockWrite writes1[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135066 spdy::SpdySerializedFrame go_away(
5067 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_NO_ERROR, ""));
bncc4769d412017-04-19 19:57:545068 MockRead reads1[] = {CreateMockRead(go_away, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015069 SequencedSocketData data1(reads1, writes1);
bncc4769d412017-04-19 19:57:545070 helper.AddData(&data1);
5071
5072 // Second connection.
5073 MockWrite writes2[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135074 spdy::SpdySerializedFrame resp(
5075 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5076 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncc4769d412017-04-19 19:57:545077 MockRead reads2[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
5078 MockRead(ASYNC, 0, 3)};
Ryan Sleevib8d7ea02018-05-07 20:01:015079 SequencedSocketData data2(reads2, writes2);
bncc4769d412017-04-19 19:57:545080 helper.AddData(&data2);
5081
5082 helper.RunPreTestSetup();
5083 helper.RunDefaultTest();
5084
5085 TransactionHelperResult out = helper.output();
5086 EXPECT_THAT(out.rv, IsOk());
5087
5088 helper.VerifyDataConsumed();
5089}
5090
bnc1fc7b352017-01-12 17:51:025091// A server can gracefully shut down by sending a GOAWAY frame
5092// with maximum last-stream-id value.
5093// Transactions started before receiving such a GOAWAY frame should succeed,
5094// but SpdySession should be unavailable for new streams.
5095TEST_F(SpdyNetworkTransactionTest, GracefulGoaway) {
Ryan Hamilton0239aac2018-05-19 00:03:135096 spdy::SpdySerializedFrame req1(
5097 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bnc1fc7b352017-01-12 17:51:025098 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:135099 spdy::SpdySerializedFrame req2(
bnc1fc7b352017-01-12 17:51:025100 spdy_util_.ConstructSpdyGet("https://www.example.org/foo", 3, LOWEST));
5101 MockWrite writes[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 3)};
5102
Ryan Hamilton0239aac2018-05-19 00:03:135103 spdy::SpdySerializedFrame resp1(
5104 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5105 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
5106 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
5107 0x7fffffff, spdy::ERROR_CODE_NO_ERROR, "Graceful shutdown."));
5108 spdy::SpdySerializedFrame resp2(
5109 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
5110 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
bnc1fc7b352017-01-12 17:51:025111 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
5112 CreateMockRead(goaway, 4), CreateMockRead(resp2, 5),
5113 CreateMockRead(body2, 6), MockRead(ASYNC, 0, 7)};
5114
5115 // Run first transaction.
Ryan Sleevib8d7ea02018-05-07 20:01:015116 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:105117 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1fc7b352017-01-12 17:51:025118 helper.RunPreTestSetup();
5119 helper.AddData(&data);
5120 helper.RunDefaultTest();
5121
5122 // Verify first response.
5123 TransactionHelperResult out = helper.output();
5124 EXPECT_THAT(out.rv, IsOk());
5125 EXPECT_EQ("HTTP/1.1 200", out.status_line);
5126 EXPECT_EQ("hello!", out.response_data);
5127
5128 // GOAWAY frame has not yet been received, SpdySession should be available.
5129 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
5130 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:115131 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:345132 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
5133 NetworkIsolationKey(), false /* disable_secure_dns */);
bnc1fc7b352017-01-12 17:51:025134 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:155135 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:315136 key, /* enable_ip_based_pooling = */ true,
5137 /* is_websocket = */ false, log_);
bnc1fc7b352017-01-12 17:51:025138 EXPECT_TRUE(spdy_session);
5139
5140 // Start second transaction.
5141 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
5142 TestCompletionCallback callback;
5143 HttpRequestInfo request2;
5144 request2.method = "GET";
5145 request2.url = GURL("https://www.example.org/foo");
Ramin Halavatib5e433e62018-02-07 07:41:105146 request2.traffic_annotation =
5147 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Békyd3dde832017-09-19 19:02:315148 int rv = trans2.Start(&request2, callback.callback(), log_);
bnc1fc7b352017-01-12 17:51:025149 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
5150 rv = callback.WaitForResult();
5151 EXPECT_THAT(rv, IsOk());
5152
5153 // Verify second response.
5154 const HttpResponseInfo* response = trans2.GetResponseInfo();
5155 ASSERT_TRUE(response);
5156 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2, response->connection_info);
5157 ASSERT_TRUE(response->headers);
5158 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
5159 EXPECT_TRUE(response->was_fetched_via_spdy);
5160 EXPECT_TRUE(response->was_alpn_negotiated);
Tsuyoshi Horo01faed62019-02-20 22:11:375161 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5162 EXPECT_EQ(443, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255163 std::string response_data;
bnc1fc7b352017-01-12 17:51:025164 rv = ReadTransaction(&trans2, &response_data);
5165 EXPECT_THAT(rv, IsOk());
5166 EXPECT_EQ("hello!", response_data);
5167
5168 // Graceful GOAWAY was received, SpdySession should be unavailable.
bnc9ead3ae2017-03-16 00:48:155169 spdy_session = spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:315170 key, /* enable_ip_based_pooling = */ true,
5171 /* is_websocket = */ false, log_);
bnc1fc7b352017-01-12 17:51:025172 EXPECT_FALSE(spdy_session);
5173
5174 helper.VerifyDataConsumed();
5175}
5176
bncd16676a2016-07-20 16:23:015177TEST_F(SpdyNetworkTransactionTest, CloseWithActiveStream) {
Ryan Hamilton0239aac2018-05-19 00:03:135178 spdy::SpdySerializedFrame req(
5179 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:415180 MockWrite writes[] = {CreateMockWrite(req, 0)};
[email protected]f5ed21552010-05-04 18:39:545181
Ryan Hamilton0239aac2018-05-19 00:03:135182 spdy::SpdySerializedFrame resp(
5183 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]f5ed21552010-05-04 18:39:545184 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415185 CreateMockRead(resp, 1), MockRead(SYNCHRONOUS, 0, 2) // EOF
[email protected]f5ed21552010-05-04 18:39:545186 };
5187
Ryan Sleevib8d7ea02018-05-07 20:01:015188 SequencedSocketData data(reads, writes);
bnc4d782f492016-08-18 13:50:005189
Bence Békydb3cf652017-10-10 15:22:105190 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]3caf5542010-07-16 15:19:475191 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575192 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:005193 helper.StartDefaultTest();
5194 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
[email protected]f5ed21552010-05-04 18:39:545195
bnc4d782f492016-08-18 13:50:005196 helper.WaitForCallbackToComplete();
5197 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
[email protected]3caf5542010-07-16 15:19:475198
bnc4d782f492016-08-18 13:50:005199 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525200 EXPECT_TRUE(response->headers);
[email protected]f5ed21552010-05-04 18:39:545201 EXPECT_TRUE(response->was_fetched_via_spdy);
[email protected]f5ed21552010-05-04 18:39:545202
5203 // Verify that we consumed all test data.
[email protected]3caf5542010-07-16 15:19:475204 helper.VerifyDataConsumed();
[email protected]f5ed21552010-05-04 18:39:545205}
[email protected]58cebf8f2010-07-31 19:20:165206
Bence Békyc2d37952017-11-20 16:58:165207TEST_F(SpdyNetworkTransactionTest, GoAwayImmediately) {
Ryan Hamilton0239aac2018-05-19 00:03:135208 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(1));
Bence Békyc2d37952017-11-20 16:58:165209 MockRead reads[] = {CreateMockRead(goaway, 0, SYNCHRONOUS)};
Ryan Sleevib8d7ea02018-05-07 20:01:015210 SequencedSocketData data(reads, base::span<MockWrite>());
Bence Békyc2d37952017-11-20 16:58:165211
5212 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
5213 helper.RunPreTestSetup();
5214 helper.AddData(&data);
5215 helper.StartDefaultTest();
5216 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
5217
5218 helper.WaitForCallbackToComplete();
5219 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
5220
5221 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
5222 EXPECT_FALSE(response->headers);
5223 EXPECT_TRUE(response->was_fetched_via_spdy);
5224
5225 // Verify that we consumed all test data.
5226 helper.VerifyDataConsumed();
5227}
5228
bncfacdd852015-01-09 19:22:545229// Retry with HTTP/1.1 when receiving HTTP_1_1_REQUIRED. Note that no actual
5230// protocol negotiation happens, instead this test forces protocols for both
5231// sockets.
bncd16676a2016-07-20 16:23:015232TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredRetry) {
Bence Békydb3cf652017-10-10 15:22:105233 request_.method = "GET";
bncfacdd852015-01-09 19:22:545234 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
Bence Békydb3cf652017-10-10 15:22:105235 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncfacdd852015-01-09 19:22:545236
5237 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
Bence Béky4c325e52020-10-22 20:48:015238 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:135239 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
5240 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:155241 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bncdf80d44fd2016-07-15 20:27:415242 MockWrite writes0[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135243 spdy::SpdySerializedFrame rst(
5244 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
Bence Békycb3613122017-09-19 17:06:575245 MockRead reads0[] = {CreateMockRead(rst, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015246 SequencedSocketData data0(reads0, writes0);
bncfacdd852015-01-09 19:22:545247
Jeremy Roman0579ed62017-08-29 15:56:195248 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545249 // Expect HTTP/2 protocols too in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365250 ssl_provider0->next_protos_expected_in_ssl_config =
5251 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
bncfacdd852015-01-09 19:22:545252 // Force SPDY.
bnc3cf2a592016-08-11 14:48:365253 ssl_provider0->next_proto = kProtoHTTP2;
dchengc7eeda422015-12-26 03:56:485254 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
bncfacdd852015-01-09 19:22:545255
5256 // Second socket: falling back to HTTP/1.1.
rch08e3aa3e2015-05-16 14:27:525257 MockWrite writes1[] = {MockWrite(ASYNC, 0,
5258 "GET / HTTP/1.1\r\n"
5259 "Host: www.example.org\r\n"
5260 "Connection: keep-alive\r\n\r\n")};
5261 MockRead reads1[] = {MockRead(ASYNC, 1,
5262 "HTTP/1.1 200 OK\r\n"
5263 "Content-Length: 5\r\n\r\n"
5264 "hello")};
Ryan Sleevib8d7ea02018-05-07 20:01:015265 SequencedSocketData data1(reads1, writes1);
bncfacdd852015-01-09 19:22:545266
Jeremy Roman0579ed62017-08-29 15:56:195267 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545268 // Expect only HTTP/1.1 protocol in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365269 ssl_provider1->next_protos_expected_in_ssl_config =
5270 NextProtoVector{kProtoHTTP11};
bncfacdd852015-01-09 19:22:545271 // Force HTTP/1.1.
bnc3cf2a592016-08-11 14:48:365272 ssl_provider1->next_proto = kProtoHTTP11;
dchengc7eeda422015-12-26 03:56:485273 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
bncfacdd852015-01-09 19:22:545274
bnc525e175a2016-06-20 12:36:405275 HttpServerProperties* http_server_properties =
bncfacdd852015-01-09 19:22:545276 helper.session()->spdy_session_pool()->http_server_properties();
Matt Menkef2ee07c2019-08-29 02:10:365277 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5278 url::SchemeHostPort(request_.url), NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545279
5280 helper.RunPreTestSetup();
5281 helper.StartDefaultTest();
5282 helper.FinishDefaultTestWithoutVerification();
5283 helper.VerifyDataConsumed();
Matt Menkef2ee07c2019-08-29 02:10:365284 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5285 url::SchemeHostPort(request_.url), NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545286
5287 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525288 ASSERT_TRUE(response);
5289 ASSERT_TRUE(response->headers);
bncfacdd852015-01-09 19:22:545290 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5291 EXPECT_FALSE(response->was_fetched_via_spdy);
mmenke8210acc2016-07-11 16:34:525292 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5293 response->connection_info);
bnc94c92842016-09-21 15:22:525294 EXPECT_TRUE(response->was_alpn_negotiated);
Bence Békydb3cf652017-10-10 15:22:105295 EXPECT_TRUE(request_.url.SchemeIs("https"));
Tsuyoshi Horo01faed62019-02-20 22:11:375296 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5297 EXPECT_EQ(443, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255298 std::string response_data;
robpercival214763f2016-07-01 23:27:015299 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
bncfacdd852015-01-09 19:22:545300 EXPECT_EQ("hello", response_data);
5301}
5302
Matt Menkef2ee07c2019-08-29 02:10:365303// Same as above test, but checks that NetworkIsolationKeys are respected.
5304TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredRetryWithNetworkIsolationKey) {
5305 const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/"));
5306 const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/"));
5307 const NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1);
5308 const NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2);
5309
5310 const NetworkIsolationKey kNetworkIsolationKeys[] = {
5311 kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
5312
5313 base::test::ScopedFeatureList feature_list;
5314 feature_list.InitWithFeatures(
5315 // enabled_features
5316 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
5317 // Need to partition connections by NetworkIsolationKey for
5318 // SpdySessionKeys to include NetworkIsolationKeys.
5319 features::kPartitionConnectionsByNetworkIsolationKey},
5320 // disabled_features
5321 {});
5322
5323 // Do not force SPDY so that sockets can negotiate HTTP/1.1.
5324 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
5325
5326 // For each server, set up and tear down a QUIC session cleanly, and check
5327 // that stats have been added to HttpServerProperties using the correct
5328 // NetworkIsolationKey.
5329 for (size_t i = 0; i < base::size(kNetworkIsolationKeys); ++i) {
5330 SCOPED_TRACE(i);
5331
5332 request_.method = "GET";
5333 request_.network_isolation_key = kNetworkIsolationKeys[i];
5334
5335 // First socket: HTTP/2 request rejected with HTTP_1_1_REQUIRED.
5336 SpdyTestUtil spdy_util;
Bence Béky4c325e52020-10-22 20:48:015337 spdy::Http2HeaderBlock headers(
Matt Menkef2ee07c2019-08-29 02:10:365338 spdy_util.ConstructGetHeaderBlock(kDefaultUrl));
5339 spdy::SpdySerializedFrame req(
5340 spdy_util.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
5341 MockWrite writes0[] = {CreateMockWrite(req, 0)};
5342 spdy::SpdySerializedFrame rst(spdy_util.ConstructSpdyRstStream(
5343 1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
5344 MockRead reads0[] = {CreateMockRead(rst, 1)};
5345 SequencedSocketData data0(reads0, writes0);
5346
5347 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5348 // Expect HTTP/2 protocols too in SSLConfig.
5349 ssl_provider0->next_protos_expected_in_ssl_config =
5350 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
5351 // Force SPDY.
5352 ssl_provider0->next_proto = kProtoHTTP2;
5353 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
5354
5355 // Second socket: falling back to HTTP/1.1.
5356 MockWrite writes1[] = {MockWrite(ASYNC, 0,
5357 "GET / HTTP/1.1\r\n"
5358 "Host: www.example.org\r\n"
5359 "Connection: keep-alive\r\n\r\n")};
5360 MockRead reads1[] = {MockRead(ASYNC, 1,
5361 "HTTP/1.1 200 OK\r\n"
5362 "Content-Length: 5\r\n\r\n"
5363 "hello")};
5364 SequencedSocketData data1(reads1, writes1);
5365
5366 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5367 // Expect only HTTP/1.1 protocol in SSLConfig.
5368 ssl_provider1->next_protos_expected_in_ssl_config =
5369 NextProtoVector{kProtoHTTP11};
5370 // Force HTTP/1.1.
5371 ssl_provider1->next_proto = kProtoHTTP11;
5372 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
5373
5374 HttpServerProperties* http_server_properties =
5375 helper.session()->spdy_session_pool()->http_server_properties();
5376 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5377 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[i]));
5378
5379 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
5380
5381 TestCompletionCallback callback;
5382 int rv = trans.Start(&request_, callback.callback(), log_);
5383 EXPECT_THAT(callback.GetResult(rv), IsOk());
5384
5385 const HttpResponseInfo* response = trans.GetResponseInfo();
5386 ASSERT_TRUE(response);
5387 ASSERT_TRUE(response->headers);
5388 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5389 EXPECT_FALSE(response->was_fetched_via_spdy);
5390 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5391 response->connection_info);
5392 EXPECT_TRUE(response->was_alpn_negotiated);
5393 EXPECT_TRUE(request_.url.SchemeIs("https"));
5394 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5395 EXPECT_EQ(443, response->remote_endpoint.port());
5396 std::string response_data;
5397 ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
5398 EXPECT_EQ("hello", response_data);
5399
5400 for (size_t j = 0; j < base::size(kNetworkIsolationKeys); ++j) {
5401 // NetworkIsolationKeys up to kNetworkIsolationKeys[j] are known to
5402 // require HTTP/1.1, others are not.
5403 if (j <= i) {
5404 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5405 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[j]));
5406 } else {
5407 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5408 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[j]));
5409 }
5410 }
5411 }
5412}
5413
bncfacdd852015-01-09 19:22:545414// Retry with HTTP/1.1 to the proxy when receiving HTTP_1_1_REQUIRED from the
5415// proxy. Note that no actual protocol negotiation happens, instead this test
5416// forces protocols for both sockets.
bncd16676a2016-07-20 16:23:015417TEST_F(SpdyNetworkTransactionTest, HTTP11RequiredProxyRetry) {
Bence Békydb3cf652017-10-10 15:22:105418 request_.method = "GET";
Jeremy Roman0579ed62017-08-29 15:56:195419 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565420 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495421 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
bncfacdd852015-01-09 19:22:545422 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
Bence Békydb3cf652017-10-10 15:22:105423 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:315424 std::move(session_deps));
bncfacdd852015-01-09 19:22:545425
5426 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
Ryan Hamilton0239aac2018-05-19 00:03:135427 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:045428 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
5429 HostPortPair("www.example.org", 443)));
bncdf80d44fd2016-07-15 20:27:415430 MockWrite writes0[] = {CreateMockWrite(req, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:135431 spdy::SpdySerializedFrame rst(
5432 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
Bence Békycb3613122017-09-19 17:06:575433 MockRead reads0[] = {CreateMockRead(rst, 1)};
Ryan Sleevib8d7ea02018-05-07 20:01:015434 SequencedSocketData data0(reads0, writes0);
bncfacdd852015-01-09 19:22:545435
Jeremy Roman0579ed62017-08-29 15:56:195436 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545437 // Expect HTTP/2 protocols too in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365438 ssl_provider0->next_protos_expected_in_ssl_config =
5439 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
bncfacdd852015-01-09 19:22:545440 // Force SPDY.
bnc3cf2a592016-08-11 14:48:365441 ssl_provider0->next_proto = kProtoHTTP2;
dchengc7eeda422015-12-26 03:56:485442 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
bncfacdd852015-01-09 19:22:545443
5444 // Second socket: retry using HTTP/1.1.
5445 MockWrite writes1[] = {
rch08e3aa3e2015-05-16 14:27:525446 MockWrite(ASYNC, 0,
bncce36dca22015-04-21 22:11:235447 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175448 "Host: www.example.org:443\r\n"
bncfacdd852015-01-09 19:22:545449 "Proxy-Connection: keep-alive\r\n\r\n"),
rch08e3aa3e2015-05-16 14:27:525450 MockWrite(ASYNC, 2,
bncfacdd852015-01-09 19:22:545451 "GET / HTTP/1.1\r\n"
bncce36dca22015-04-21 22:11:235452 "Host: www.example.org\r\n"
bncfacdd852015-01-09 19:22:545453 "Connection: keep-alive\r\n\r\n"),
5454 };
5455
5456 MockRead reads1[] = {
rch08e3aa3e2015-05-16 14:27:525457 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
5458 MockRead(ASYNC, 3,
bncfacdd852015-01-09 19:22:545459 "HTTP/1.1 200 OK\r\n"
5460 "Content-Length: 5\r\n\r\n"
5461 "hello"),
5462 };
Ryan Sleevib8d7ea02018-05-07 20:01:015463 SequencedSocketData data1(reads1, writes1);
bncfacdd852015-01-09 19:22:545464
Jeremy Roman0579ed62017-08-29 15:56:195465 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545466 // Expect only HTTP/1.1 protocol in SSLConfig.
Bence Béky27a19b82018-01-30 14:58:365467 ssl_provider1->next_protos_expected_in_ssl_config =
5468 NextProtoVector{kProtoHTTP11};
bncfacdd852015-01-09 19:22:545469 // Force HTTP/1.1.
bnc3cf2a592016-08-11 14:48:365470 ssl_provider1->next_proto = kProtoHTTP11;
dchengc7eeda422015-12-26 03:56:485471 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
bncfacdd852015-01-09 19:22:545472
5473 // A third socket is needed for the tunnelled connection.
Jeremy Roman0579ed62017-08-29 15:56:195474 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
bncfacdd852015-01-09 19:22:545475 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
5476 ssl_provider2.get());
5477
bnc525e175a2016-06-20 12:36:405478 HttpServerProperties* http_server_properties =
bncfacdd852015-01-09 19:22:545479 helper.session()->spdy_session_pool()->http_server_properties();
Matt Menkef2ee07c2019-08-29 02:10:365480 url::SchemeHostPort proxy_scheme_host_port(url::kHttpsScheme, "myproxy", 70);
5481 EXPECT_FALSE(http_server_properties->RequiresHTTP11(proxy_scheme_host_port,
5482 NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545483
5484 helper.RunPreTestSetup();
5485 helper.StartDefaultTest();
5486 helper.FinishDefaultTestWithoutVerification();
5487 helper.VerifyDataConsumed();
Matt Menkef2ee07c2019-08-29 02:10:365488 EXPECT_TRUE(http_server_properties->RequiresHTTP11(proxy_scheme_host_port,
5489 NetworkIsolationKey()));
bncfacdd852015-01-09 19:22:545490
5491 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
wezca1070932016-05-26 20:30:525492 ASSERT_TRUE(response);
5493 ASSERT_TRUE(response->headers);
bncfacdd852015-01-09 19:22:545494 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5495 EXPECT_FALSE(response->was_fetched_via_spdy);
mmenke8210acc2016-07-11 16:34:525496 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5497 response->connection_info);
bnc94c92842016-09-21 15:22:525498 EXPECT_FALSE(response->was_alpn_negotiated);
Bence Békydb3cf652017-10-10 15:22:105499 EXPECT_TRUE(request_.url.SchemeIs("https"));
Tsuyoshi Horo01faed62019-02-20 22:11:375500 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5501 EXPECT_EQ(70, response->remote_endpoint.port());
Bence Béky4e83f492018-05-13 23:14:255502 std::string response_data;
robpercival214763f2016-07-01 23:27:015503 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
bncfacdd852015-01-09 19:22:545504 EXPECT_EQ("hello", response_data);
5505}
5506
Matt Menkef2ee07c2019-08-29 02:10:365507// Same as above, but also test that NetworkIsolationKeys are respected.
5508TEST_F(SpdyNetworkTransactionTest,
5509 HTTP11RequiredProxyRetryWithNetworkIsolationKey) {
5510 const url::Origin kOrigin1 = url::Origin::Create(GURL("https://foo.test/"));
5511 const url::Origin kOrigin2 = url::Origin::Create(GURL("https://bar.test/"));
5512 const NetworkIsolationKey kNetworkIsolationKey1(kOrigin1, kOrigin1);
5513 const NetworkIsolationKey kNetworkIsolationKey2(kOrigin2, kOrigin2);
5514
5515 const NetworkIsolationKey kNetworkIsolationKeys[] = {
5516 kNetworkIsolationKey1, kNetworkIsolationKey2, NetworkIsolationKey()};
5517
5518 base::test::ScopedFeatureList feature_list;
5519 feature_list.InitWithFeatures(
5520 // enabled_features
5521 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
5522 // Need to partition connections by NetworkIsolationKey for
5523 // SpdySessionKeys to include NetworkIsolationKeys.
5524 features::kPartitionConnectionsByNetworkIsolationKey},
5525 // disabled_features
5526 {});
5527
5528 request_.method = "GET";
5529 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565530 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Matt Menkef2ee07c2019-08-29 02:10:365531 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
5532 // Do not force SPDY so that second socket can negotiate HTTP/1.1.
5533 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
5534 std::move(session_deps));
5535 helper.RunPreTestSetup();
5536
5537 for (size_t i = 0; i < base::size(kNetworkIsolationKeys); ++i) {
5538 // First socket: HTTP/2 CONNECT rejected with HTTP_1_1_REQUIRED.
5539
5540 SpdyTestUtil spdy_util;
5541 spdy::SpdySerializedFrame req(spdy_util.ConstructSpdyConnect(
5542 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
5543 HostPortPair("www.example.org", 443)));
5544 MockWrite writes0[] = {CreateMockWrite(req, 0)};
5545 spdy::SpdySerializedFrame rst(spdy_util.ConstructSpdyRstStream(
5546 1, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
5547 MockRead reads0[] = {CreateMockRead(rst, 1)};
5548 SequencedSocketData data0(reads0, writes0);
5549
5550 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5551 // Expect HTTP/2 protocols too in SSLConfig.
5552 ssl_provider0->next_protos_expected_in_ssl_config =
5553 NextProtoVector{kProtoHTTP2, kProtoHTTP11};
5554 // Force SPDY.
5555 ssl_provider0->next_proto = kProtoHTTP2;
5556 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
5557
5558 // Second socket: retry using HTTP/1.1.
5559 MockWrite writes1[] = {
5560 MockWrite(ASYNC, 0,
5561 "CONNECT www.example.org:443 HTTP/1.1\r\n"
5562 "Host: www.example.org:443\r\n"
5563 "Proxy-Connection: keep-alive\r\n\r\n"),
5564 MockWrite(ASYNC, 2,
5565 "GET / HTTP/1.1\r\n"
5566 "Host: www.example.org\r\n"
5567 "Connection: keep-alive\r\n\r\n"),
5568 };
5569
5570 MockRead reads1[] = {
5571 MockRead(ASYNC, 1, "HTTP/1.1 200 OK\r\n\r\n"),
5572 MockRead(ASYNC, 3,
5573 "HTTP/1.1 200 OK\r\n"
5574 "Content-Length: 5\r\n\r\n"
5575 "hello"),
5576 };
5577 SequencedSocketData data1(reads1, writes1);
5578
5579 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5580 // Expect only HTTP/1.1 protocol in SSLConfig.
5581 ssl_provider1->next_protos_expected_in_ssl_config =
5582 NextProtoVector{kProtoHTTP11};
5583 // Force HTTP/1.1.
5584 ssl_provider1->next_proto = kProtoHTTP11;
5585 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
5586
5587 // A third socket is needed for the tunnelled connection.
5588 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
5589 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
5590 ssl_provider2.get());
5591
5592 HttpServerProperties* http_server_properties =
5593 helper.session()->spdy_session_pool()->http_server_properties();
5594 url::SchemeHostPort proxy_scheme_host_port(url::kHttpsScheme, "myproxy",
5595 70);
5596 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5597 proxy_scheme_host_port, kNetworkIsolationKeys[i]));
5598
5599 request_.network_isolation_key = kNetworkIsolationKeys[i];
5600 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
5601 TestCompletionCallback callback;
5602 int rv = trans.Start(&request_, callback.callback(), log_);
5603 EXPECT_THAT(callback.GetResult(rv), IsOk());
5604 helper.VerifyDataConsumed();
5605
5606 const HttpResponseInfo* response = trans.GetResponseInfo();
5607 ASSERT_TRUE(response);
5608 ASSERT_TRUE(response->headers);
5609 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
5610 EXPECT_FALSE(response->was_fetched_via_spdy);
5611 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
5612 response->connection_info);
5613 EXPECT_FALSE(response->was_alpn_negotiated);
5614 EXPECT_TRUE(request_.url.SchemeIs("https"));
5615 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
5616 EXPECT_EQ(70, response->remote_endpoint.port());
5617 std::string response_data;
5618 ASSERT_THAT(ReadTransaction(&trans, &response_data), IsOk());
5619 EXPECT_EQ("hello", response_data);
5620
5621 for (size_t j = 0; j < base::size(kNetworkIsolationKeys); ++j) {
5622 // The proxy SchemeHostPort URL should not be marked as requiring HTTP/1.1
5623 // using the current NetworkIsolationKey, and the state of others should
5624 // be unchanged since the last loop iteration..
5625 if (j <= i) {
5626 EXPECT_TRUE(http_server_properties->RequiresHTTP11(
5627 proxy_scheme_host_port, kNetworkIsolationKeys[j]));
5628 } else {
5629 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5630 proxy_scheme_host_port, kNetworkIsolationKeys[j]));
5631 }
5632 }
5633
5634 // The destination SchemeHostPort should not be marked as requiring
5635 // HTTP/1.1.
5636 EXPECT_FALSE(http_server_properties->RequiresHTTP11(
5637 url::SchemeHostPort(request_.url), kNetworkIsolationKeys[i]));
5638 }
5639}
5640
[email protected]b261d0e2010-08-02 19:13:245641// Test to make sure we can correctly connect through a proxy.
bncd16676a2016-07-20 16:23:015642TEST_F(SpdyNetworkTransactionTest, ProxyConnect) {
Jeremy Roman0579ed62017-08-29 15:56:195643 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565644 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495645 "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:105646 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
tfarina428341112016-09-22 13:38:205647 std::move(session_deps));
[email protected]b261d0e2010-08-02 19:13:245648 helper.RunPreTestSetup();
5649 HttpNetworkTransaction* trans = helper.trans();
5650
rchebf12982015-04-10 01:15:005651 const char kConnect443[] = {
bncce36dca22015-04-21 22:11:235652 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175653 "Host: www.example.org:443\r\n"
rchcb934f562015-04-07 16:25:125654 "Proxy-Connection: keep-alive\r\n\r\n"};
[email protected]b261d0e2010-08-02 19:13:245655 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
Ryan Hamilton0239aac2018-05-19 00:03:135656 spdy::SpdySerializedFrame req(
5657 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
5658 spdy::SpdySerializedFrame resp(
5659 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5660 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245661
rchebf12982015-04-10 01:15:005662 MockWrite writes[] = {
Avi Drissman4365a4782018-12-28 19:26:245663 MockWrite(SYNCHRONOUS, kConnect443, base::size(kConnect443) - 1, 0),
bncdf80d44fd2016-07-15 20:27:415664 CreateMockWrite(req, 2),
[email protected]b261d0e2010-08-02 19:13:245665 };
rchebf12982015-04-10 01:15:005666 MockRead reads[] = {
Avi Drissman4365a4782018-12-28 19:26:245667 MockRead(SYNCHRONOUS, kHTTP200, base::size(kHTTP200) - 1, 1),
5668 CreateMockRead(resp, 3),
5669 CreateMockRead(body, 4),
Raul Tambre94493c652019-03-11 17:18:355670 MockRead(ASYNC, nullptr, 0, 5),
[email protected]b261d0e2010-08-02 19:13:245671 };
Ryan Sleevib8d7ea02018-05-07 20:01:015672 SequencedSocketData data(reads, writes);
[email protected]b261d0e2010-08-02 19:13:245673
Bence Béky53a5aef2018-03-29 21:54:125674 helper.AddData(&data);
[email protected]49639fa2011-12-20 23:22:415675 TestCompletionCallback callback;
[email protected]b261d0e2010-08-02 19:13:245676
Bence Békydb3cf652017-10-10 15:22:105677 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015678 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b261d0e2010-08-02 19:13:245679
5680 rv = callback.WaitForResult();
5681 EXPECT_EQ(0, rv);
5682
bnc42331402016-07-25 13:36:155683 // Verify the response headers.
[email protected]b261d0e2010-08-02 19:13:245684 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525685 ASSERT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:025686 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]b261d0e2010-08-02 19:13:245687
Bence Béky4e83f492018-05-13 23:14:255688 std::string response_data;
robpercival214763f2016-07-01 23:27:015689 ASSERT_THAT(ReadTransaction(trans, &response_data), IsOk());
[email protected]b261d0e2010-08-02 19:13:245690 EXPECT_EQ("hello!", response_data);
5691 helper.VerifyDataConsumed();
5692}
5693
bncce36dca22015-04-21 22:11:235694// Test to make sure we can correctly connect through a proxy to
5695// www.example.org, if there already exists a direct spdy connection to
5696// www.example.org. See https://crbug.com/49874.
bncd16676a2016-07-20 16:23:015697TEST_F(SpdyNetworkTransactionTest, DirectConnectProxyReconnect) {
[email protected]733b7a6d2010-08-25 01:38:435698 // Use a proxy service which returns a proxy fallback list from DIRECT to
5699 // myproxy:70. For this test there will be no fallback, so it is equivalent
5700 // to simply DIRECT. The reason for appending the second proxy is to verify
5701 // that the session pool key used does is just "DIRECT".
Jeremy Roman0579ed62017-08-29 15:56:195702 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565703 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495704 "DIRECT; PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
bncd16676a2016-07-20 16:23:015705 // When setting up the first transaction, we store the SpdySessionPool so that
5706 // we can use the same pool in the second transaction.
Bence Békydb3cf652017-10-10 15:22:105707 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
tfarina428341112016-09-22 13:38:205708 std::move(session_deps));
[email protected]733b7a6d2010-08-25 01:38:435709
[email protected]87bfa3f2010-09-30 14:54:565710 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
[email protected]b261d0e2010-08-02 19:13:245711 helper.RunPreTestSetup();
5712
5713 // Construct and send a simple GET request.
Ryan Hamilton0239aac2018-05-19 00:03:135714 spdy::SpdySerializedFrame req(
5715 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
[email protected]b261d0e2010-08-02 19:13:245716 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:415717 CreateMockWrite(req, 0),
[email protected]b261d0e2010-08-02 19:13:245718 };
5719
Ryan Hamilton0239aac2018-05-19 00:03:135720 spdy::SpdySerializedFrame resp(
5721 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5722 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245723 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415724 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch08e3aa3e2015-05-16 14:27:525725 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3), // Force a pause
[email protected]b261d0e2010-08-02 19:13:245726 };
Ryan Sleevib8d7ea02018-05-07 20:01:015727 SequencedSocketData data(reads, writes);
[email protected]dd54bd82012-07-19 23:44:575728 helper.AddData(&data);
[email protected]b261d0e2010-08-02 19:13:245729 HttpNetworkTransaction* trans = helper.trans();
5730
[email protected]49639fa2011-12-20 23:22:415731 TestCompletionCallback callback;
[email protected]b261d0e2010-08-02 19:13:245732 TransactionHelperResult out;
Bence Békydb3cf652017-10-10 15:22:105733 out.rv = trans->Start(&request_, callback.callback(), log_);
[email protected]b261d0e2010-08-02 19:13:245734
5735 EXPECT_EQ(out.rv, ERR_IO_PENDING);
5736 out.rv = callback.WaitForResult();
5737 EXPECT_EQ(out.rv, OK);
5738
5739 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525740 EXPECT_TRUE(response->headers);
[email protected]b261d0e2010-08-02 19:13:245741 EXPECT_TRUE(response->was_fetched_via_spdy);
5742 out.rv = ReadTransaction(trans, &out.response_data);
robpercival214763f2016-07-01 23:27:015743 EXPECT_THAT(out.rv, IsOk());
[email protected]b261d0e2010-08-02 19:13:245744 out.status_line = response->headers->GetStatusLine();
bnc84e7fb52015-12-02 11:50:025745 EXPECT_EQ("HTTP/1.1 200", out.status_line);
[email protected]b261d0e2010-08-02 19:13:245746 EXPECT_EQ("hello!", out.response_data);
5747
5748 // Check that the SpdySession is still in the SpdySessionPool.
Matt Menke2436b2f2018-12-11 18:07:115749 SpdySessionKey session_pool_key_direct(
5750 host_port_pair_, ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:345751 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
5752 NetworkIsolationKey(), false /* disable_secure_dns */);
[email protected]41d64e82013-07-03 22:44:265753 EXPECT_TRUE(HasSpdySession(spdy_session_pool, session_pool_key_direct));
[email protected]e6d017652013-05-17 18:01:405754 SpdySessionKey session_pool_key_proxy(
bncb26024382016-06-29 02:39:455755 host_port_pair_,
[email protected]e6d017652013-05-17 18:01:405756 ProxyServer::FromURI("www.foo.com", ProxyServer::SCHEME_HTTP),
Matt Menke2436b2f2018-12-11 18:07:115757 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
dalyk51ab46b2019-10-15 15:14:345758 SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
[email protected]41d64e82013-07-03 22:44:265759 EXPECT_FALSE(HasSpdySession(spdy_session_pool, session_pool_key_proxy));
[email protected]b261d0e2010-08-02 19:13:245760
rdsmithebb50aa2015-11-12 03:44:385761 // New SpdyTestUtil instance for the session that will be used for the
5762 // proxy connection.
bncd16676a2016-07-20 16:23:015763 SpdyTestUtil spdy_util_2;
rdsmithebb50aa2015-11-12 03:44:385764
[email protected]b261d0e2010-08-02 19:13:245765 // Set up data for the proxy connection.
bncce36dca22015-04-21 22:11:235766 const char kConnect443[] = {
5767 "CONNECT www.example.org:443 HTTP/1.1\r\n"
rsleevidb16bb02015-11-12 23:47:175768 "Host: www.example.org:443\r\n"
bncce36dca22015-04-21 22:11:235769 "Proxy-Connection: keep-alive\r\n\r\n"};
[email protected]b261d0e2010-08-02 19:13:245770 const char kHTTP200[] = {"HTTP/1.1 200 OK\r\n\r\n"};
Ryan Hamilton0239aac2018-05-19 00:03:135771 spdy::SpdySerializedFrame req2(
5772 spdy_util_2.ConstructSpdyGet(kPushedUrl, 1, LOWEST));
5773 spdy::SpdySerializedFrame resp2(
5774 spdy_util_2.ConstructSpdyGetReply(nullptr, 0, 1));
5775 spdy::SpdySerializedFrame body2(spdy_util_2.ConstructSpdyDataFrame(1, true));
[email protected]b261d0e2010-08-02 19:13:245776
rchebf12982015-04-10 01:15:005777 MockWrite writes2[] = {
Avi Drissman4365a4782018-12-28 19:26:245778 MockWrite(SYNCHRONOUS, kConnect443, base::size(kConnect443) - 1, 0),
bncdf80d44fd2016-07-15 20:27:415779 CreateMockWrite(req2, 2),
[email protected]b261d0e2010-08-02 19:13:245780 };
rchebf12982015-04-10 01:15:005781 MockRead reads2[] = {
Avi Drissman4365a4782018-12-28 19:26:245782 MockRead(SYNCHRONOUS, kHTTP200, base::size(kHTTP200) - 1, 1),
bncdf80d44fd2016-07-15 20:27:415783 CreateMockRead(resp2, 3), CreateMockRead(body2, 4),
rchebf12982015-04-10 01:15:005784 MockRead(ASYNC, 0, 5) // EOF
[email protected]b261d0e2010-08-02 19:13:245785 };
5786
Ryan Sleevib8d7ea02018-05-07 20:01:015787 SequencedSocketData data_proxy(reads2, writes2);
[email protected]b261d0e2010-08-02 19:13:245788
bncce36dca22015-04-21 22:11:235789 // Create another request to www.example.org, but this time through a proxy.
Bence Békydb3cf652017-10-10 15:22:105790 request_.method = "GET";
Bence Békyd2df6c1c82018-04-20 22:52:015791 request_.url = GURL(kPushedUrl);
Jeremy Roman0579ed62017-08-29 15:56:195792 auto session_deps_proxy = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:565793 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:495794 "PROXY myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:105795 NormalSpdyTransactionHelper helper_proxy(request_, DEFAULT_PRIORITY, log_,
5796 std::move(session_deps_proxy));
5797
[email protected]b261d0e2010-08-02 19:13:245798 helper_proxy.RunPreTestSetup();
Bence Béky53a5aef2018-03-29 21:54:125799 helper_proxy.AddData(&data_proxy);
[email protected]b261d0e2010-08-02 19:13:245800
5801 HttpNetworkTransaction* trans_proxy = helper_proxy.trans();
[email protected]49639fa2011-12-20 23:22:415802 TestCompletionCallback callback_proxy;
Bence Békydb3cf652017-10-10 15:22:105803 int rv = trans_proxy->Start(&request_, callback_proxy.callback(), log_);
robpercival214763f2016-07-01 23:27:015804 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]b261d0e2010-08-02 19:13:245805 rv = callback_proxy.WaitForResult();
5806 EXPECT_EQ(0, rv);
5807
5808 HttpResponseInfo response_proxy = *trans_proxy->GetResponseInfo();
wezca1070932016-05-26 20:30:525809 ASSERT_TRUE(response_proxy.headers);
bnc84e7fb52015-12-02 11:50:025810 EXPECT_EQ("HTTP/1.1 200", response_proxy.headers->GetStatusLine());
[email protected]b261d0e2010-08-02 19:13:245811
Bence Béky4e83f492018-05-13 23:14:255812 std::string response_data;
robpercival214763f2016-07-01 23:27:015813 ASSERT_THAT(ReadTransaction(trans_proxy, &response_data), IsOk());
[email protected]b261d0e2010-08-02 19:13:245814 EXPECT_EQ("hello!", response_data);
5815
[email protected]b261d0e2010-08-02 19:13:245816 helper_proxy.VerifyDataConsumed();
5817}
5818
[email protected]58cebf8f2010-07-31 19:20:165819// When we get a TCP-level RST, we need to retry a HttpNetworkTransaction
5820// on a new connection, if the connection was previously known to be good.
5821// This can happen when a server reboots without saying goodbye, or when
5822// we're behind a NAT that masked the RST.
bncd16676a2016-07-20 16:23:015823TEST_F(SpdyNetworkTransactionTest, VerifyRetryOnConnectionReset) {
Ryan Hamilton0239aac2018-05-19 00:03:135824 spdy::SpdySerializedFrame resp(
5825 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
5826 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]58cebf8f2010-07-31 19:20:165827 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:415828 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch32320842015-05-16 15:57:095829 MockRead(ASYNC, ERR_IO_PENDING, 3),
5830 MockRead(ASYNC, ERR_CONNECTION_RESET, 4),
[email protected]58cebf8f2010-07-31 19:20:165831 };
5832
5833 MockRead reads2[] = {
bncdf80d44fd2016-07-15 20:27:415834 CreateMockRead(resp, 1), CreateMockRead(body, 2),
rch32320842015-05-16 15:57:095835 MockRead(ASYNC, 0, 3) // EOF
[email protected]58cebf8f2010-07-31 19:20:165836 };
5837
Ryan Hamilton0239aac2018-05-19 00:03:135838 spdy::SpdySerializedFrame req(
5839 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:385840 // In all cases the connection will be reset before req3 can be
5841 // dispatched, destroying both streams.
5842 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:135843 spdy::SpdySerializedFrame req3(
5844 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
bncdf80d44fd2016-07-15 20:27:415845 MockWrite writes1[] = {CreateMockWrite(req, 0), CreateMockWrite(req3, 5)};
5846 MockWrite writes2[] = {CreateMockWrite(req, 0)};
rchacdcbdc2015-05-16 17:16:005847
[email protected]58cebf8f2010-07-31 19:20:165848 // This test has a couple of variants.
5849 enum {
5850 // Induce the RST while waiting for our transaction to send.
rchacdcbdc2015-05-16 17:16:005851 VARIANT_RST_DURING_SEND_COMPLETION = 0,
[email protected]58cebf8f2010-07-31 19:20:165852 // Induce the RST while waiting for our transaction to read.
5853 // In this case, the send completed - everything copied into the SNDBUF.
rchacdcbdc2015-05-16 17:16:005854 VARIANT_RST_DURING_READ_COMPLETION = 1
[email protected]58cebf8f2010-07-31 19:20:165855 };
5856
5857 for (int variant = VARIANT_RST_DURING_SEND_COMPLETION;
5858 variant <= VARIANT_RST_DURING_READ_COMPLETION;
5859 ++variant) {
Ryan Sleevib8d7ea02018-05-07 20:01:015860 SequencedSocketData data1(reads,
5861 base::make_span(writes1).first(1 + variant));
[email protected]58cebf8f2010-07-31 19:20:165862
Ryan Sleevib8d7ea02018-05-07 20:01:015863 SequencedSocketData data2(reads2, writes2);
[email protected]58cebf8f2010-07-31 19:20:165864
Bence Békydb3cf652017-10-10 15:22:105865 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
5866 nullptr);
[email protected]dd54bd82012-07-19 23:44:575867 helper.AddData(&data1);
5868 helper.AddData(&data2);
[email protected]58cebf8f2010-07-31 19:20:165869 helper.RunPreTestSetup();
5870
5871 for (int i = 0; i < 2; ++i) {
bnc691fda62016-08-12 00:43:165872 HttpNetworkTransaction trans(DEFAULT_PRIORITY, helper.session());
[email protected]58cebf8f2010-07-31 19:20:165873
[email protected]49639fa2011-12-20 23:22:415874 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:105875 int rv = trans.Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:015876 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]58cebf8f2010-07-31 19:20:165877 // On the second transaction, we trigger the RST.
5878 if (i == 1) {
5879 if (variant == VARIANT_RST_DURING_READ_COMPLETION) {
5880 // Writes to the socket complete asynchronously on SPDY by running
5881 // through the message loop. Complete the write here.
[email protected]fc9d88472013-08-14 02:31:175882 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:165883 }
5884
5885 // Now schedule the ERR_CONNECTION_RESET.
mmenkee24011922015-12-17 22:12:595886 data1.Resume();
[email protected]58cebf8f2010-07-31 19:20:165887 }
5888 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:015889 EXPECT_THAT(rv, IsOk());
[email protected]58cebf8f2010-07-31 19:20:165890
bnc691fda62016-08-12 00:43:165891 const HttpResponseInfo* response = trans.GetResponseInfo();
wezca1070932016-05-26 20:30:525892 ASSERT_TRUE(response);
5893 EXPECT_TRUE(response->headers);
[email protected]58cebf8f2010-07-31 19:20:165894 EXPECT_TRUE(response->was_fetched_via_spdy);
Bence Béky4e83f492018-05-13 23:14:255895 std::string response_data;
bnc691fda62016-08-12 00:43:165896 rv = ReadTransaction(&trans, &response_data);
robpercival214763f2016-07-01 23:27:015897 EXPECT_THAT(rv, IsOk());
bnc84e7fb52015-12-02 11:50:025898 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]58cebf8f2010-07-31 19:20:165899 EXPECT_EQ("hello!", response_data);
rchacdcbdc2015-05-16 17:16:005900 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:165901 }
5902
5903 helper.VerifyDataConsumed();
rchacdcbdc2015-05-16 17:16:005904 base::RunLoop().RunUntilIdle();
[email protected]58cebf8f2010-07-31 19:20:165905 }
5906}
[email protected]1f418ee2010-10-16 19:46:565907
[email protected]018aabc2010-10-29 16:16:595908// Tests that Basic authentication works over SPDY
bncd16676a2016-07-20 16:23:015909TEST_F(SpdyNetworkTransactionTest, SpdyBasicAuth) {
[email protected]018aabc2010-10-29 16:16:595910 // The first request will be a bare GET, the second request will be a
5911 // GET with an Authorization header.
Ryan Hamilton0239aac2018-05-19 00:03:135912 spdy::SpdySerializedFrame req_get(
Bence Béky27ad0a12018-02-08 00:35:485913 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:385914 // Will be refused for lack of auth.
5915 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]018aabc2010-10-29 16:16:595916 const char* const kExtraAuthorizationHeaders[] = {
[email protected]cdf8f7e72013-05-23 10:56:465917 "authorization", "Basic Zm9vOmJhcg=="
[email protected]018aabc2010-10-29 16:16:595918 };
Ryan Hamilton0239aac2018-05-19 00:03:135919 spdy::SpdySerializedFrame req_get_authorization(spdy_util_.ConstructSpdyGet(
Avi Drissman4365a4782018-12-28 19:26:245920 kExtraAuthorizationHeaders, base::size(kExtraAuthorizationHeaders) / 2, 3,
Bence Béky27ad0a12018-02-08 00:35:485921 LOWEST));
[email protected]018aabc2010-10-29 16:16:595922 MockWrite spdy_writes[] = {
bncdf80d44fd2016-07-15 20:27:415923 CreateMockWrite(req_get, 0), CreateMockWrite(req_get_authorization, 3),
[email protected]018aabc2010-10-29 16:16:595924 };
5925
5926 // The first response is a 401 authentication challenge, and the second
5927 // response will be a 200 response since the second request includes a valid
5928 // Authorization header.
5929 const char* const kExtraAuthenticationHeaders[] = {
[email protected]fb9e4312012-02-17 06:27:265930 "www-authenticate",
[email protected]018aabc2010-10-29 16:16:595931 "Basic realm=\"MyRealm\""
5932 };
Ryan Hamilton0239aac2018-05-19 00:03:135933 spdy::SpdySerializedFrame resp_authentication(
5934 spdy_util_.ConstructSpdyReplyError(
5935 "401", kExtraAuthenticationHeaders,
Avi Drissman4365a4782018-12-28 19:26:245936 base::size(kExtraAuthenticationHeaders) / 2, 1));
Ryan Hamilton0239aac2018-05-19 00:03:135937 spdy::SpdySerializedFrame body_authentication(
bncdf80d44fd2016-07-15 20:27:415938 spdy_util_.ConstructSpdyDataFrame(1, true));
Ryan Hamilton0239aac2018-05-19 00:03:135939 spdy::SpdySerializedFrame resp_data(
tombergan5d22c182017-01-11 02:05:355940 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Ryan Hamilton0239aac2018-05-19 00:03:135941 spdy::SpdySerializedFrame body_data(
5942 spdy_util_.ConstructSpdyDataFrame(3, true));
tombergan5d22c182017-01-11 02:05:355943
[email protected]018aabc2010-10-29 16:16:595944 MockRead spdy_reads[] = {
bncdf80d44fd2016-07-15 20:27:415945 CreateMockRead(resp_authentication, 1),
bnceb9aa7112017-01-05 01:03:465946 CreateMockRead(body_authentication, 2, SYNCHRONOUS),
bncdf80d44fd2016-07-15 20:27:415947 CreateMockRead(resp_data, 4),
5948 CreateMockRead(body_data, 5),
rch08e3aa3e2015-05-16 14:27:525949 MockRead(ASYNC, 0, 6),
[email protected]018aabc2010-10-29 16:16:595950 };
5951
Ryan Sleevib8d7ea02018-05-07 20:01:015952 SequencedSocketData data(spdy_reads, spdy_writes);
Bence Békydb3cf652017-10-10 15:22:105953 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]018aabc2010-10-29 16:16:595954
5955 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:575956 helper.AddData(&data);
bnc4d782f492016-08-18 13:50:005957 helper.StartDefaultTest();
5958 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
5959
5960 helper.WaitForCallbackToComplete();
5961 EXPECT_THAT(helper.output().rv, IsOk());
[email protected]018aabc2010-10-29 16:16:595962
5963 // Make sure the response has an auth challenge.
bnc4d782f492016-08-18 13:50:005964 HttpNetworkTransaction* trans = helper.trans();
[email protected]018aabc2010-10-29 16:16:595965 const HttpResponseInfo* const response_start = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525966 ASSERT_TRUE(response_start);
5967 ASSERT_TRUE(response_start->headers);
[email protected]018aabc2010-10-29 16:16:595968 EXPECT_EQ(401, response_start->headers->response_code());
5969 EXPECT_TRUE(response_start->was_fetched_via_spdy);
Emily Starkf2c9bbd2019-04-09 17:08:585970 const base::Optional<AuthChallengeInfo>& auth_challenge =
5971 response_start->auth_challenge;
wezca1070932016-05-26 20:30:525972 ASSERT_TRUE(auth_challenge);
[email protected]79cb5c12011-09-12 13:12:045973 EXPECT_FALSE(auth_challenge->is_proxy);
aberentbba302d2015-12-03 10:20:195974 EXPECT_EQ(kBasicAuthScheme, auth_challenge->scheme);
[email protected]79cb5c12011-09-12 13:12:045975 EXPECT_EQ("MyRealm", auth_challenge->realm);
[email protected]018aabc2010-10-29 16:16:595976
5977 // Restart with a username/password.
[email protected]ad65a3e2013-12-25 18:18:015978 AuthCredentials credentials(base::ASCIIToUTF16("foo"),
5979 base::ASCIIToUTF16("bar"));
[email protected]49639fa2011-12-20 23:22:415980 TestCompletionCallback callback_restart;
5981 const int rv_restart = trans->RestartWithAuth(
5982 credentials, callback_restart.callback());
robpercival214763f2016-07-01 23:27:015983 EXPECT_THAT(rv_restart, IsError(ERR_IO_PENDING));
[email protected]018aabc2010-10-29 16:16:595984 const int rv_restart_complete = callback_restart.WaitForResult();
robpercival214763f2016-07-01 23:27:015985 EXPECT_THAT(rv_restart_complete, IsOk());
[email protected]018aabc2010-10-29 16:16:595986 // TODO(cbentzel): This is actually the same response object as before, but
5987 // data has changed.
5988 const HttpResponseInfo* const response_restart = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:525989 ASSERT_TRUE(response_restart);
5990 ASSERT_TRUE(response_restart->headers);
[email protected]018aabc2010-10-29 16:16:595991 EXPECT_EQ(200, response_restart->headers->response_code());
Emily Starkf2c9bbd2019-04-09 17:08:585992 EXPECT_FALSE(response_restart->auth_challenge);
[email protected]018aabc2010-10-29 16:16:595993}
5994
Bence Békye7023f82018-05-14 01:53:035995struct PushHeaderTestParams {
Victor Vasiliev502ba582020-09-15 23:16:155996 std::vector<std::pair<std::string, std::string>> extra_request_headers;
5997 std::vector<std::pair<std::string, std::string>> extra_pushed_request_headers;
5998 std::vector<std::pair<std::string, std::string>>
Bence Béky49db0e22018-05-11 00:54:055999 extra_pushed_response_headers;
Victor Vasiliev502ba582020-09-15 23:16:156000 std::string pushed_status_code;
Bence Béky49db0e22018-05-11 00:54:056001 bool push_accepted;
Bence Békyeacd48f2018-05-14 11:34:336002 SpdyPushedStreamFate expected_fate;
Bence Békye7023f82018-05-14 01:53:036003} push_header_test_cases[] = {
Bence Béky49db0e22018-05-11 00:54:056004 // Base case: no extra headers.
Bence Békyeacd48f2018-05-14 11:34:336005 {{}, {}, {}, "200", true, SpdyPushedStreamFate::kAcceptedNoVary},
Bence Béky49db0e22018-05-11 00:54:056006 // Cookie headers match.
6007 {{{"cookie", "value=foo"}},
6008 {{"cookie", "value=foo"}},
6009 {{"vary", "Cookie"}},
6010 "200",
Bence Békyeacd48f2018-05-14 11:34:336011 true,
6012 SpdyPushedStreamFate::kAcceptedMatchingVary},
Bence Béky49db0e22018-05-11 00:54:056013 // Cookie headers mismatch.
6014 {{{"cookie", "value=foo"}},
6015 {{"cookie", "value=bar"}},
6016 {{"vary", "Cookie"}},
6017 "200",
Bence Békyeacd48f2018-05-14 11:34:336018 false,
6019 SpdyPushedStreamFate::kVaryMismatch},
Bence Béky49db0e22018-05-11 00:54:056020 // Partial Content response, no Range headers.
Bence Békyeacd48f2018-05-14 11:34:336021 {{}, {}, {}, "206", false, SpdyPushedStreamFate::kClientRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056022 // Partial Content response, no Range headers in pushed request.
Bence Békyeacd48f2018-05-14 11:34:336023 {{{"range", "0-42"}},
6024 {},
6025 {},
6026 "206",
6027 false,
6028 SpdyPushedStreamFate::kPushedRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056029 // Partial Content response, no Range headers in client request.
Bence Békyeacd48f2018-05-14 11:34:336030 {{},
6031 {{"range", "0-42"}},
6032 {},
6033 "206",
6034 false,
6035 SpdyPushedStreamFate::kClientRequestNotRange},
Bence Béky49db0e22018-05-11 00:54:056036 // Partial Content response, mismatching Range headers.
Bence Békyeacd48f2018-05-14 11:34:336037 {{{"range", "0-42"}},
6038 {{"range", "10-42"}},
6039 {},
6040 "206",
6041 false,
6042 SpdyPushedStreamFate::kRangeMismatch},
Bence Béky49db0e22018-05-11 00:54:056043 // Partial Content response, matching Range headers.
Bence Békyeacd48f2018-05-14 11:34:336044 {{{"range", "0-42"}},
6045 {{"range", "0-42"}},
6046 {},
6047 "206",
6048 true,
6049 SpdyPushedStreamFate::kAcceptedNoVary},
6050};
[email protected]d08358502010-12-03 22:04:036051
Bence Békye7023f82018-05-14 01:53:036052class SpdyNetworkTransactionPushHeaderTest
Bence Béky49db0e22018-05-11 00:54:056053 : public SpdyNetworkTransactionTest,
Bence Békye7023f82018-05-14 01:53:036054 public ::testing::WithParamInterface<PushHeaderTestParams> {
Bence Béky49db0e22018-05-11 00:54:056055 protected:
6056 void RunTest(bool pushed_response_headers_received_before_request) {
Bence Békyeacd48f2018-05-14 11:34:336057 base::HistogramTester histogram_tester;
6058
Bence Békyc4caf072018-04-20 22:27:306059 int seq = 0;
6060 std::vector<MockWrite> writes;
6061 std::vector<MockRead> reads;
bnc38dcd392016-02-09 23:19:496062
Ryan Hamilton0239aac2018-05-19 00:03:136063 spdy::SpdySerializedFrame req1(
Bence Béky49db0e22018-05-11 00:54:056064 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
Bence Békyc4caf072018-04-20 22:27:306065 writes.push_back(CreateMockWrite(req1, seq++));
[email protected]513963e2013-06-15 01:53:046066
Bence Béky4c325e52020-10-22 20:48:016067 spdy::Http2HeaderBlock pushed_request_headers;
Ryan Hamilton0239aac2018-05-19 00:03:136068 pushed_request_headers[spdy::kHttp2MethodHeader] = "GET";
Bence Béky49db0e22018-05-11 00:54:056069 for (const auto& header : GetParam().extra_pushed_request_headers) {
Bence Békyc4caf072018-04-20 22:27:306070 pushed_request_headers.insert(header);
6071 }
Bence Béky49db0e22018-05-11 00:54:056072 spdy_util_.AddUrlToHeaderBlock(kPushedUrl, &pushed_request_headers);
Ryan Hamilton0239aac2018-05-19 00:03:136073 spdy::SpdySerializedFrame pushed_request(
6074 spdy_util_.ConstructSpdyPushPromise(1, 2,
6075 std::move(pushed_request_headers)));
Bence Békyc4caf072018-04-20 22:27:306076 reads.push_back(CreateMockRead(pushed_request, seq++));
[email protected]d08358502010-12-03 22:04:036077
Ryan Hamilton0239aac2018-05-19 00:03:136078 spdy::SpdySerializedFrame priority(
Bence Béky49db0e22018-05-11 00:54:056079 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
Bence Békyc4caf072018-04-20 22:27:306080 writes.push_back(CreateMockWrite(priority, seq++));
bnc38dcd392016-02-09 23:19:496081
Bence Béky49db0e22018-05-11 00:54:056082 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, seq++));
6083
Bence Béky4c325e52020-10-22 20:48:016084 spdy::Http2HeaderBlock pushed_response_headers;
Ryan Hamilton0239aac2018-05-19 00:03:136085 pushed_response_headers[spdy::kHttp2StatusHeader] =
6086 GetParam().pushed_status_code;
Bence Béky49db0e22018-05-11 00:54:056087 for (const auto& header : GetParam().extra_pushed_response_headers) {
Bence Békyc4caf072018-04-20 22:27:306088 pushed_response_headers.insert(header);
6089 }
Ryan Hamilton0239aac2018-05-19 00:03:136090 spdy::SpdySerializedFrame pushed_response(
Bence Béky49db0e22018-05-11 00:54:056091 spdy_util_.ConstructSpdyReply(2, std::move(pushed_response_headers)));
Bence Békyc4caf072018-04-20 22:27:306092 reads.push_back(CreateMockRead(pushed_response, seq++));
bnc38dcd392016-02-09 23:19:496093
Ryan Hamilton0239aac2018-05-19 00:03:136094 spdy::SpdySerializedFrame resp1(
6095 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Békyc4caf072018-04-20 22:27:306096 reads.push_back(CreateMockRead(resp1, seq++));
[email protected]d08358502010-12-03 22:04:036097
Ryan Hamilton0239aac2018-05-19 00:03:136098 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Békyc4caf072018-04-20 22:27:306099 reads.push_back(CreateMockRead(body1, seq++));
Bence Béky49db0e22018-05-11 00:54:056100 spdy_util_.UpdateWithStreamDestruction(1);
[email protected]d08358502010-12-03 22:04:036101
Ryan Hamilton0239aac2018-05-19 00:03:136102 spdy::SpdySerializedFrame pushed_body(
Bence Béky49db0e22018-05-11 00:54:056103 spdy_util_.ConstructSpdyDataFrame(2, "This is pushed.", true));
Bence Békyc4caf072018-04-20 22:27:306104 reads.push_back(CreateMockRead(pushed_body, seq++));
[email protected]d08358502010-12-03 22:04:036105
Bence Békyc4caf072018-04-20 22:27:306106 // If push is not accepted, a new request is sent on the wire.
Ryan Hamilton0239aac2018-05-19 00:03:136107 spdy::SpdySerializedFrame rst;
6108 spdy::SpdySerializedFrame req2;
6109 spdy::SpdySerializedFrame resp2;
6110 spdy::SpdySerializedFrame body2;
Bence Béky49db0e22018-05-11 00:54:056111 if (!GetParam().push_accepted) {
Ryan Hamilton0239aac2018-05-19 00:03:136112 rst = spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL);
Bence Béky49db0e22018-05-11 00:54:056113 writes.push_back(CreateMockWrite(rst, seq++));
6114
Bence Béky4c325e52020-10-22 20:48:016115 spdy::Http2HeaderBlock request_headers2(
Bence Béky49db0e22018-05-11 00:54:056116 spdy_util_.ConstructGetHeaderBlock(kPushedUrl));
6117 for (const auto& header : GetParam().extra_request_headers) {
Bence Békyc4caf072018-04-20 22:27:306118 request_headers2.insert(header);
6119 }
Bence Béky49db0e22018-05-11 00:54:056120 req2 = spdy_util_.ConstructSpdyHeaders(3, std::move(request_headers2),
6121 LOWEST, true);
Bence Békyc4caf072018-04-20 22:27:306122 writes.push_back(CreateMockWrite(req2, seq++));
[email protected]d08358502010-12-03 22:04:036123
Bence Béky49db0e22018-05-11 00:54:056124 resp2 = spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3);
Bence Békyc4caf072018-04-20 22:27:306125 reads.push_back(CreateMockRead(resp2, seq++));
Bence Béky04268b022018-04-19 01:17:416126
Bence Béky49db0e22018-05-11 00:54:056127 body2 = spdy_util_.ConstructSpdyDataFrame(3, "This is not pushed.", true);
Bence Békyc4caf072018-04-20 22:27:306128 reads.push_back(CreateMockRead(body2, seq++));
6129 }
Bence Béky04268b022018-04-19 01:17:416130
Bence Békyc4caf072018-04-20 22:27:306131 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, seq++));
Bence Béky04268b022018-04-19 01:17:416132
Bence Békyc4caf072018-04-20 22:27:306133 reads.push_back(MockRead(ASYNC, 0, seq++));
Bence Béky04268b022018-04-19 01:17:416134
Ryan Sleevib8d7ea02018-05-07 20:01:016135 SequencedSocketData data(reads, writes);
Bence Béky04268b022018-04-19 01:17:416136
Bence Békyc4caf072018-04-20 22:27:306137 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
6138 nullptr);
6139 helper.RunPreTestSetup();
6140 helper.AddData(&data);
Bence Béky04268b022018-04-19 01:17:416141
Bence Békyc4caf072018-04-20 22:27:306142 HttpNetworkTransaction* trans = helper.trans();
6143 TestCompletionCallback callback1;
6144 int rv = trans->Start(&request_, callback1.callback(), log_);
6145 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky49db0e22018-05-11 00:54:056146
6147 // Open connection.
6148 base::RunLoop().RunUntilIdle();
6149
6150 if (pushed_response_headers_received_before_request) {
6151 // Read pushed response headers.
6152 data.Resume();
6153 base::RunLoop().RunUntilIdle();
6154 }
6155
6156 HttpRequestInfo request2 = CreateGetPushRequest();
6157 for (const auto& header : GetParam().extra_request_headers) {
6158 request2.extra_headers.SetHeader(header.first, header.second);
6159 }
6160 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
6161 TestCompletionCallback callback2;
6162 rv = trans2.Start(&request2, callback2.callback(), log_);
6163 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
6164 base::RunLoop().RunUntilIdle();
6165
6166 if (!pushed_response_headers_received_before_request) {
6167 // Read pushed response headers.
6168 data.Resume();
6169 base::RunLoop().RunUntilIdle();
6170 }
6171
Bence Békyc4caf072018-04-20 22:27:306172 rv = callback1.WaitForResult();
6173 EXPECT_THAT(rv, IsOk());
Bence Béky04268b022018-04-19 01:17:416174
Bence Békyc4caf072018-04-20 22:27:306175 const HttpResponseInfo* const response1 = trans->GetResponseInfo();
6176 EXPECT_TRUE(response1->headers);
6177 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
Bence Béky04268b022018-04-19 01:17:416178
Bence Béky4e83f492018-05-13 23:14:256179 std::string result1;
Bence Békyc4caf072018-04-20 22:27:306180 ReadResult(trans, &result1);
6181 EXPECT_EQ(result1, "hello!");
Bence Béky04268b022018-04-19 01:17:416182
Bence Békyc4caf072018-04-20 22:27:306183 rv = callback2.WaitForResult();
6184 EXPECT_THAT(rv, IsOk());
Bence Béky04268b022018-04-19 01:17:416185
Bence Béky4e83f492018-05-13 23:14:256186 std::string result2;
Bence Békyc4caf072018-04-20 22:27:306187 ReadResult(&trans2, &result2);
Bence Béky49db0e22018-05-11 00:54:056188 EXPECT_EQ(result2, GetParam().push_accepted ? "This is pushed."
6189 : "This is not pushed.");
Bence Béky04268b022018-04-19 01:17:416190
Bence Békyc4caf072018-04-20 22:27:306191 data.Resume();
6192 base::RunLoop().RunUntilIdle();
6193 helper.VerifyDataConsumed();
Bence Békyeacd48f2018-05-14 11:34:336194
6195 histogram_tester.ExpectBucketCount(
6196 "Net.SpdyPushedStreamFate", static_cast<int>(GetParam().expected_fate),
6197 1);
6198 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
Bence Békyc4caf072018-04-20 22:27:306199 }
Bence Béky49db0e22018-05-11 00:54:056200};
6201
Ilia Samsonov958c9fef2019-11-20 21:37:316202INSTANTIATE_TEST_SUITE_P(All,
Victor Costan2309ea02019-02-13 21:35:476203 SpdyNetworkTransactionPushHeaderTest,
6204 ::testing::ValuesIn(push_header_test_cases));
Bence Béky49db0e22018-05-11 00:54:056205
Bence Békye7023f82018-05-14 01:53:036206TEST_P(SpdyNetworkTransactionPushHeaderTest,
Bence Béky49db0e22018-05-11 00:54:056207 PushedResponseHeadersReceivedBeforeRequest) {
6208 RunTest(/* pushed_response_headers_received_before_request = */ true);
Bence Béky04268b022018-04-19 01:17:416209}
6210
Bence Békye7023f82018-05-14 01:53:036211TEST_P(SpdyNetworkTransactionPushHeaderTest,
Bence Béky49db0e22018-05-11 00:54:056212 PushedResponseHeadersReceivedAfterRequest) {
6213 RunTest(/* pushed_response_headers_received_before_request = */ false);
[email protected]d08358502010-12-03 22:04:036214}
6215
bnc42331402016-07-25 13:36:156216TEST_F(SpdyNetworkTransactionTest, ResponseHeadersTwice) {
Ryan Hamilton0239aac2018-05-19 00:03:136217 spdy::SpdySerializedFrame req(
6218 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6219 spdy::SpdySerializedFrame rst(
6220 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b771bb72013-06-24 09:55:416221 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416222 CreateMockWrite(req, 0), CreateMockWrite(rst, 4),
[email protected]745aa9c2014-06-27 02:21:296223 };
[email protected]d08358502010-12-03 22:04:036224
Ryan Hamilton0239aac2018-05-19 00:03:136225 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:356226 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
[email protected]513963e2013-06-15 01:53:046227
Bence Béky4c325e52020-10-22 20:48:016228 spdy::Http2HeaderBlock late_headers;
bnc38dcd392016-02-09 23:19:496229 late_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:136230 spdy::SpdySerializedFrame stream1_headers(
6231 spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
6232 false));
6233 spdy::SpdySerializedFrame stream1_body(
6234 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d08358502010-12-03 22:04:036235 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416236 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_headers, 2),
6237 CreateMockRead(stream1_body, 3), MockRead(ASYNC, 0, 5) // EOF
[email protected]d08358502010-12-03 22:04:036238 };
6239
Ryan Sleevib8d7ea02018-05-07 20:01:016240 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106241 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:576242 helper.RunToCompletion(&data);
[email protected]d08358502010-12-03 22:04:036243 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:186244 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]d08358502010-12-03 22:04:036245}
6246
xunjieli294da722015-08-11 19:15:026247// Tests that receiving HEADERS, DATA, HEADERS, and DATA in that sequence will
Bence Békyd0d69502019-06-25 19:47:186248// trigger a ERR_HTTP2_PROTOCOL_ERROR because trailing HEADERS must not be
xunjieli294da722015-08-11 19:15:026249// followed by any DATA frames.
bncd16676a2016-07-20 16:23:016250TEST_F(SpdyNetworkTransactionTest, SyncReplyDataAfterTrailers) {
Ryan Hamilton0239aac2018-05-19 00:03:136251 spdy::SpdySerializedFrame req(
6252 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6253 spdy::SpdySerializedFrame rst(
6254 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
[email protected]b771bb72013-06-24 09:55:416255 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416256 CreateMockWrite(req, 0), CreateMockWrite(rst, 5),
[email protected]b771bb72013-06-24 09:55:416257 };
[email protected]d08358502010-12-03 22:04:036258
Ryan Hamilton0239aac2018-05-19 00:03:136259 spdy::SpdySerializedFrame stream1_reply(
tombergan5d22c182017-01-11 02:05:356260 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136261 spdy::SpdySerializedFrame stream1_body(
6262 spdy_util_.ConstructSpdyDataFrame(1, false));
bnc38dcd392016-02-09 23:19:496263
Bence Béky4c325e52020-10-22 20:48:016264 spdy::Http2HeaderBlock late_headers;
bnc38dcd392016-02-09 23:19:496265 late_headers["hello"] = "bye";
Ryan Hamilton0239aac2018-05-19 00:03:136266 spdy::SpdySerializedFrame stream1_headers(
6267 spdy_util_.ConstructSpdyResponseHeaders(1, std::move(late_headers),
6268 false));
6269 spdy::SpdySerializedFrame stream1_body2(
6270 spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d08358502010-12-03 22:04:036271 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416272 CreateMockRead(stream1_reply, 1), CreateMockRead(stream1_body, 2),
6273 CreateMockRead(stream1_headers, 3), CreateMockRead(stream1_body2, 4),
rch08e3aa3e2015-05-16 14:27:526274 MockRead(ASYNC, 0, 6) // EOF
[email protected]d08358502010-12-03 22:04:036275 };
6276
Ryan Sleevib8d7ea02018-05-07 20:01:016277 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106278 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]dd54bd82012-07-19 23:44:576279 helper.RunToCompletion(&data);
[email protected]d08358502010-12-03 22:04:036280 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:186281 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
[email protected]d08358502010-12-03 22:04:036282}
6283
Bence Békye7023f82018-05-14 01:53:036284struct PushUrlTestParams {
6285 const char* url_to_fetch;
6286 const char* url_to_push;
Bence Békyb2f76672018-06-11 21:10:136287 bool client_cert_sent;
Matt Menkec74a9262020-06-09 15:49:216288 bool expect_ct_error;
Bence Békyeacd48f2018-05-14 11:34:336289 SpdyPushedStreamFate expected_fate;
Bence Békye7023f82018-05-14 01:53:036290} push_url_test_cases[] = {
6291 // http scheme cannot be pushed (except by trusted proxy).
Matt Menkec74a9262020-06-09 15:49:216292 {"https://www.example.org/foo.html", "http://www.example.org/foo.js",
6293 false /* client_cert_sent */, false /* expect_ct_error */,
Bence Békyeacd48f2018-05-14 11:34:336294 SpdyPushedStreamFate::kNonHttpsPushedScheme},
Bence Békye7023f82018-05-14 01:53:036295 // ftp scheme cannot be pushed.
Matt Menkec74a9262020-06-09 15:49:216296 {"https://www.example.org/foo.html", "ftp://www.example.org/foo.js",
6297 false /* client_cert_sent */, false /* expect_ct_error */,
Bence Békyeacd48f2018-05-14 11:34:336298 SpdyPushedStreamFate::kInvalidUrl},
Bence Békye7023f82018-05-14 01:53:036299 // Cross subdomain, certificate not valid.
Bence Békyeacd48f2018-05-14 11:34:336300 {"https://www.example.org/foo.html", "https://blat.www.example.org/foo.js",
Matt Menkec74a9262020-06-09 15:49:216301 false /* client_cert_sent */, false /* expect_ct_error */,
6302 SpdyPushedStreamFate::kCertificateMismatch},
Bence Békye7023f82018-05-14 01:53:036303 // Cross domain, certificate not valid.
Matt Menkec74a9262020-06-09 15:49:216304 {"https://www.example.org/foo.html", "https://www.foo.com/foo.js",
6305 false /* client_cert_sent */, false /* expect_ct_error */,
Bence Békyb2f76672018-06-11 21:10:136306 SpdyPushedStreamFate::kCertificateMismatch},
6307 // Cross domain, certificate valid, but cross-origin push is rejected on a
6308 // connection with client certificate.
6309 {"https://www.example.org/foo.html", "https://mail.example.org/foo.js",
Matt Menkec74a9262020-06-09 15:49:216310 true /* client_cert_sent */, false /* expect_ct_error */,
6311 SpdyPushedStreamFate::kCertificateMismatch},
6312 // Cross domain, certificate valid, but cross-origin push is rejected on a
6313 // connection with an Expect-CT error.
6314 {"https://www.example.org/foo.html", "https://mail.example.org/foo.js",
6315 false /* client_cert_sent */, true /* expect_ct_error */,
6316 SpdyPushedStreamFate::kCertificateMismatch}};
Bence Békye7023f82018-05-14 01:53:036317
6318class SpdyNetworkTransactionPushUrlTest
6319 : public SpdyNetworkTransactionTest,
6320 public ::testing::WithParamInterface<PushUrlTestParams> {
Matt Menkec74a9262020-06-09 15:49:216321 public:
6322 SpdyNetworkTransactionPushUrlTest() {
6323 // Set features needed for the |expect_ct_error| case, where it's important
6324 // to check that NetworkIsolationKeys are respected.
6325 feature_list_.InitWithFeatures(
6326 /* enabled_features */
6327 {TransportSecurityState::kDynamicExpectCTFeature,
6328 features::kPartitionExpectCTStateByNetworkIsolationKey,
6329 features::kPartitionConnectionsByNetworkIsolationKey,
6330 features::kPartitionSSLSessionsByNetworkIsolationKey},
6331 /* disabled_features */
6332 {});
6333 }
6334
Bence Békye7023f82018-05-14 01:53:036335 protected:
[email protected]a7a265ef2010-12-08 18:05:576336 // In this test we want to verify that we can't accidentally push content
6337 // which can't be pushed by this content server.
6338 // This test assumes that:
6339 // - if we're requesting http://www.foo.com/barbaz
6340 // - the browser has made a connection to "www.foo.com".
Bence Békye7023f82018-05-14 01:53:036341 void RunTest() {
Bence Békyeacd48f2018-05-14 11:34:336342 base::HistogramTester histogram_tester;
6343
bncd16676a2016-07-20 16:23:016344 SpdyTestUtil spdy_test_util;
Ryan Hamilton0239aac2018-05-19 00:03:136345 spdy::SpdySerializedFrame stream1_syn(
Bence Békye7023f82018-05-14 01:53:036346 spdy_test_util.ConstructSpdyGet(GetParam().url_to_fetch, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136347 spdy::SpdySerializedFrame stream1_body(
bncdf80d44fd2016-07-15 20:27:416348 spdy_test_util.ConstructSpdyDataFrame(1, true));
Ryan Hamilton0239aac2018-05-19 00:03:136349 spdy::SpdySerializedFrame push_rst(spdy_test_util.ConstructSpdyRstStream(
6350 2, spdy::ERROR_CODE_REFUSED_STREAM));
[email protected]a7a265ef2010-12-08 18:05:576351 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416352 CreateMockWrite(stream1_syn, 0), CreateMockWrite(push_rst, 3),
[email protected]a7a265ef2010-12-08 18:05:576353 };
6354
Ryan Hamilton0239aac2018-05-19 00:03:136355 spdy::SpdySerializedFrame stream1_reply(
bnc42331402016-07-25 13:36:156356 spdy_test_util.ConstructSpdyGetReply(nullptr, 0, 1));
Ryan Hamilton0239aac2018-05-19 00:03:136357 spdy::SpdySerializedFrame stream2_syn(spdy_test_util.ConstructSpdyPush(
Bence Békye7023f82018-05-14 01:53:036358 nullptr, 0, 2, 1, GetParam().url_to_push));
[email protected]8a0fc822013-06-27 20:52:436359 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:136360 spdy::SpdySerializedFrame stream2_body(
Bence Békyd74f4382018-02-20 18:26:196361 spdy_test_util.ConstructSpdyDataFrame(2, kPushedData, true));
Ryan Hamilton0239aac2018-05-19 00:03:136362 spdy::SpdySerializedFrame rst(
6363 spdy_test_util.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
[email protected]a7a265ef2010-12-08 18:05:576364
6365 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416366 CreateMockRead(stream1_reply, 1),
6367 CreateMockRead(stream2_syn, 2),
6368 CreateMockRead(stream1_body, 4),
6369 CreateMockRead(stream2_body, 5),
rch08e3aa3e2015-05-16 14:27:526370 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6), // Force a pause
[email protected]a7a265ef2010-12-08 18:05:576371 };
6372
6373 HttpResponseInfo response;
Ryan Sleevib8d7ea02018-05-07 20:01:016374 SequencedSocketData data(reads, writes);
[email protected]a7a265ef2010-12-08 18:05:576375
Bence Békye7023f82018-05-14 01:53:036376 request_.url = GURL(GetParam().url_to_fetch);
Matt Menkec74a9262020-06-09 15:49:216377 // Set a NetworkIsolationKey for the |expect_ct_error| case, to make sure
6378 // NetworkIsolationKeys are respected.
6379 request_.network_isolation_key = NetworkIsolationKey::CreateTransient();
[email protected]a7a265ef2010-12-08 18:05:576380
[email protected]7c6f7ba2012-04-03 04:09:296381 // Enable cross-origin push. Since we are not using a proxy, this should
6382 // not actually enable cross-origin SPDY push.
Jeremy Roman0579ed62017-08-29 15:56:196383 auto session_deps = std::make_unique<SpdySessionDependencies>();
6384 auto proxy_delegate = std::make_unique<TestProxyDelegate>();
tbansal28e68f82016-02-04 02:56:156385 proxy_delegate->set_trusted_spdy_proxy(net::ProxyServer::FromURI(
6386 "https://123.45.67.89:443", net::ProxyServer::SCHEME_HTTP));
Eric Roman3d8546a2018-09-10 17:00:526387 session_deps->proxy_resolution_service->SetProxyDelegate(
6388 proxy_delegate.get());
Bence Békyb2f76672018-06-11 21:10:136389
6390 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
6391 ssl_provider->ssl_info.client_cert_sent = GetParam().client_cert_sent;
6392 ssl_provider->ssl_info.cert =
6393 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Matt Menkec74a9262020-06-09 15:49:216394 if (GetParam().expect_ct_error) {
6395 ssl_provider->ssl_info.ct_policy_compliance =
6396 ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
6397 ssl_provider->ssl_info.is_issued_by_known_root = true;
6398
6399 session_deps->transport_security_state->AddExpectCT(
6400 "mail.example.org",
6401 base::Time::Now() + base::TimeDelta::FromDays(1) /* expiry */, true,
6402 GURL(), request_.network_isolation_key);
6403 }
6404
6405 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
6406 std::move(session_deps));
6407
6408 helper.RunPreTestSetup();
6409
6410 if (GetParam().expect_ct_error) {
6411 ssl_provider->ssl_info.ct_policy_compliance =
6412 ct::CTPolicyCompliance::CT_POLICY_NOT_ENOUGH_SCTS;
6413 ssl_provider->ssl_info.is_issued_by_known_root = true;
6414 }
6415
Bence Békyb2f76672018-06-11 21:10:136416 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
[email protected]7c6f7ba2012-04-03 04:09:296417
[email protected]a7a265ef2010-12-08 18:05:576418 HttpNetworkTransaction* trans = helper.trans();
6419
6420 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:416421 TestCompletionCallback callback;
[email protected]a7a265ef2010-12-08 18:05:576422
Bence Békydb3cf652017-10-10 15:22:106423 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:016424 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]a7a265ef2010-12-08 18:05:576425 rv = callback.WaitForResult();
6426
bnceb9aa7112017-01-05 01:03:466427 // Finish async network reads/writes.
6428 base::RunLoop().RunUntilIdle();
6429
[email protected]a7a265ef2010-12-08 18:05:576430 // Read the response body.
Bence Béky4e83f492018-05-13 23:14:256431 std::string result;
rch0aecfd82015-05-19 17:22:326432 ReadResult(trans, &result);
[email protected]a7a265ef2010-12-08 18:05:576433
6434 // Verify that we consumed all test data.
rch37de576c2015-05-17 20:28:176435 EXPECT_TRUE(data.AllReadDataConsumed());
6436 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]a7a265ef2010-12-08 18:05:576437
bnc42331402016-07-25 13:36:156438 // Verify the response headers.
[email protected]a7a265ef2010-12-08 18:05:576439 // Copy the response info, because trans goes away.
6440 response = *trans->GetResponseInfo();
6441
6442 VerifyStreamsClosed(helper);
6443
bnc42331402016-07-25 13:36:156444 // Verify the response headers.
wezca1070932016-05-26 20:30:526445 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:026446 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
Bence Békyeacd48f2018-05-14 11:34:336447
6448 histogram_tester.ExpectBucketCount(
6449 "Net.SpdyPushedStreamFate", static_cast<int>(GetParam().expected_fate),
6450 1);
6451 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
[email protected]a7a265ef2010-12-08 18:05:576452 }
Matt Menkec74a9262020-06-09 15:49:216453
6454 base::test::ScopedFeatureList feature_list_;
Bence Békye7023f82018-05-14 01:53:036455};
6456
Ilia Samsonov958c9fef2019-11-20 21:37:316457INSTANTIATE_TEST_SUITE_P(All,
Victor Costan2309ea02019-02-13 21:35:476458 SpdyNetworkTransactionPushUrlTest,
6459 ::testing::ValuesIn(push_url_test_cases));
Bence Békye7023f82018-05-14 01:53:036460
6461TEST_P(SpdyNetworkTransactionPushUrlTest, PushUrlTest) {
6462 RunTest();
[email protected]a7a265ef2010-12-08 18:05:576463}
6464
bnc3e79387f2016-03-15 14:49:206465// Verify that push works cross origin as long as the certificate is valid for
6466// the pushed authority.
bncd16676a2016-07-20 16:23:016467TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOrigin) {
bnc3e79387f2016-03-15 14:49:206468 // "spdy_pooling.pem" is valid for both www.example.org and mail.example.org.
6469 const char* url_to_fetch = "https://www.example.org";
6470 const char* url_to_push = "https://mail.example.org";
6471
Ryan Hamilton0239aac2018-05-19 00:03:136472 spdy::SpdySerializedFrame headers(
bnc3e79387f2016-03-15 14:49:206473 spdy_util_.ConstructSpdyGet(url_to_fetch, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136474 spdy::SpdySerializedFrame push_priority(
tombergan5d22c182017-01-11 02:05:356475 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
bnc3e79387f2016-03-15 14:49:206476 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:356477 CreateMockWrite(headers, 0), CreateMockWrite(push_priority, 3),
bnc3e79387f2016-03-15 14:49:206478 };
6479
Ryan Hamilton0239aac2018-05-19 00:03:136480 spdy::SpdySerializedFrame reply(
6481 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6482 spdy::SpdySerializedFrame push(
bnc3e79387f2016-03-15 14:49:206483 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
Ryan Hamilton0239aac2018-05-19 00:03:136484 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc3e79387f2016-03-15 14:49:206485 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:136486 spdy::SpdySerializedFrame pushed_body(
Bence Békyd74f4382018-02-20 18:26:196487 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
bnc3e79387f2016-03-15 14:49:206488 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416489 CreateMockRead(reply, 1),
bnceb9aa7112017-01-05 01:03:466490 CreateMockRead(push, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:356491 CreateMockRead(body, 4),
6492 CreateMockRead(pushed_body, 5, SYNCHRONOUS),
6493 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
bnc3e79387f2016-03-15 14:49:206494 };
6495
Ryan Sleevib8d7ea02018-05-07 20:01:016496 SequencedSocketData data(reads, writes);
bnc3e79387f2016-03-15 14:49:206497
Bence Békydb3cf652017-10-10 15:22:106498 request_.url = GURL(url_to_fetch);
bnc3e79387f2016-03-15 14:49:206499
Bence Békydb3cf652017-10-10 15:22:106500 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc3e79387f2016-03-15 14:49:206501 helper.RunPreTestSetup();
6502 helper.AddData(&data);
6503
6504 HttpNetworkTransaction* trans0 = helper.trans();
6505 TestCompletionCallback callback0;
Bence Békydb3cf652017-10-10 15:22:106506 int rv = trans0->Start(&request_, callback0.callback(), log_);
bnc3e79387f2016-03-15 14:49:206507 rv = callback0.GetResult(rv);
robpercival214763f2016-07-01 23:27:016508 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206509
6510 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
bncb26024382016-06-29 02:39:456511 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:116512 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:346513 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
6514 NetworkIsolationKey(), false /* disable_secure_dns */);
bnc3e79387f2016-03-15 14:49:206515 base::WeakPtr<SpdySession> spdy_session =
bnc9ead3ae2017-03-16 00:48:156516 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:316517 key, /* enable_ip_based_pooling = */ true,
6518 /* is_websocket = */ false, log_);
bnc3e79387f2016-03-15 14:49:206519
Bence Béky285e7d42017-12-04 20:22:116520 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
Bence Béky3b609012017-12-04 15:19:356521 EXPECT_TRUE(
Bence Béky285e7d42017-12-04 20:22:116522 has_unclaimed_pushed_stream_for_url(spdy_session, GURL(url_to_push)));
bnc3e79387f2016-03-15 14:49:206523
bnc691fda62016-08-12 00:43:166524 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
bnc3e79387f2016-03-15 14:49:206525 HttpRequestInfo push_request;
6526 push_request.method = "GET";
6527 push_request.url = GURL(url_to_push);
Ramin Halavatib5e433e62018-02-07 07:41:106528 push_request.traffic_annotation =
6529 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
bnc3e79387f2016-03-15 14:49:206530 TestCompletionCallback callback1;
Bence Békyd3dde832017-09-19 19:02:316531 rv = trans1.Start(&push_request, callback1.callback(), log_);
bnc3e79387f2016-03-15 14:49:206532 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:016533 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206534
Bence Béky285e7d42017-12-04 20:22:116535 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
bnc3e79387f2016-03-15 14:49:206536
bnc3e79387f2016-03-15 14:49:206537 HttpResponseInfo response = *trans0->GetResponseInfo();
wezca1070932016-05-26 20:30:526538 EXPECT_TRUE(response.headers);
bnc3e79387f2016-03-15 14:49:206539 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
6540
Bence Béky4e83f492018-05-13 23:14:256541 std::string result0;
bnc3e79387f2016-03-15 14:49:206542 ReadResult(trans0, &result0);
6543 EXPECT_EQ("hello!", result0);
6544
bnc691fda62016-08-12 00:43:166545 HttpResponseInfo push_response = *trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:526546 EXPECT_TRUE(push_response.headers);
bnc3e79387f2016-03-15 14:49:206547 EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
6548
Bence Béky4e83f492018-05-13 23:14:256549 std::string result1;
bnc691fda62016-08-12 00:43:166550 ReadResult(&trans1, &result1);
bnc3e79387f2016-03-15 14:49:206551 EXPECT_EQ(kPushedData, result1);
tombergan5d22c182017-01-11 02:05:356552
6553 base::RunLoop().RunUntilIdle();
6554 helper.VerifyDataConsumed();
6555 VerifyStreamsClosed(helper);
bnc3e79387f2016-03-15 14:49:206556}
6557
Matt Menkedf93ff72020-07-16 02:23:036558// Verify that push does not work cross origin when NetworkIsolationKeys don't
6559// match.
6560TEST_F(SpdyNetworkTransactionTest,
6561 ServerPushCrossOriginNetworkIsolationKeyMistmatch) {
6562 base::test::ScopedFeatureList feature_list;
6563 feature_list.InitWithFeatures(
6564 // enabled_features
6565 {features::kPartitionHttpServerPropertiesByNetworkIsolationKey,
6566 // Need to partition connections by NetworkIsolationKey for
6567 // SpdySessionKeys to include NetworkIsolationKeys.
6568 features::kPartitionConnectionsByNetworkIsolationKey},
6569 // disabled_features
6570 {});
6571
6572 // "spdy_pooling.pem" is valid for both www.example.org and mail.example.org.
6573 const char* url_to_fetch = "https://www.example.org";
6574 const char* url_to_push = "https://mail.example.org";
6575
6576 spdy::SpdySerializedFrame headers(
6577 spdy_util_.ConstructSpdyGet(url_to_fetch, 1, LOWEST));
6578 spdy::SpdySerializedFrame push_priority(
6579 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
6580 MockWrite writes[] = {
6581 CreateMockWrite(headers, 0),
6582 CreateMockWrite(push_priority, 3),
6583 };
6584
6585 spdy::SpdySerializedFrame reply(
6586 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6587 spdy::SpdySerializedFrame push(
6588 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
6589 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
6590 const char kPushedData[] = "pushed";
6591 spdy::SpdySerializedFrame pushed_body(
6592 spdy_util_.ConstructSpdyDataFrame(2, kPushedData, true));
6593 MockRead reads[] = {
6594 CreateMockRead(reply, 1),
6595 CreateMockRead(push, 2, SYNCHRONOUS),
6596 CreateMockRead(body, 4),
6597 CreateMockRead(pushed_body, 5, SYNCHRONOUS),
6598 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
6599 };
6600
6601 SequencedSocketData data(reads, writes);
6602
6603 request_.url = GURL(url_to_fetch);
6604
6605 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
6606 helper.RunPreTestSetup();
6607 helper.AddData(&data);
6608
6609 SequencedSocketData data2(net::MockConnect(ASYNC, net::ERR_FAILED),
6610 base::span<MockRead>(), base::span<MockWrite>());
6611 helper.AddData(&data2);
6612
6613 HttpNetworkTransaction* trans0 = helper.trans();
6614 TestCompletionCallback callback0;
6615 int rv = trans0->Start(&request_, callback0.callback(), log_);
6616 rv = callback0.GetResult(rv);
6617 EXPECT_THAT(rv, IsOk());
6618
6619 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
6620 SpdySessionKey key(host_port_pair_, ProxyServer::Direct(),
6621 PRIVACY_MODE_DISABLED,
6622 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
6623 NetworkIsolationKey(), false /* disable_secure_dns */);
6624 base::WeakPtr<SpdySession> spdy_session =
6625 spdy_session_pool->FindAvailableSession(
6626 key, /* enable_ip_based_pooling = */ true,
6627 /* is_websocket = */ false, log_);
6628
6629 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
6630 EXPECT_TRUE(
6631 has_unclaimed_pushed_stream_for_url(spdy_session, GURL(url_to_push)));
6632
6633 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
6634 HttpRequestInfo push_request;
6635 // Use a different NetworkIsolationKey than |spdy_session| (which uses an
6636 // empty one).
6637 push_request.network_isolation_key = NetworkIsolationKey::CreateTransient();
6638 push_request.method = "GET";
6639 push_request.url = GURL(url_to_push);
6640 push_request.traffic_annotation =
6641 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
6642 TestCompletionCallback callback1;
6643 rv = trans1.Start(&push_request, callback1.callback(), log_);
6644 // This transaction should try and use a new socket, which fails.
6645 EXPECT_THAT(callback1.GetResult(rv), IsError(net::ERR_FAILED));
6646
6647 // The pushed stream should still be pending.
6648 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
6649
6650 // Try again, this time with an empty NetworkIsolationKey, matching the
6651 // SpdySession's. This request should successfully get the pushed stream.
6652 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
6653 push_request.network_isolation_key = NetworkIsolationKey();
6654 TestCompletionCallback callback2;
6655 rv = trans1.Start(&push_request, callback2.callback(), log_);
6656 EXPECT_THAT(callback2.GetResult(rv), IsOk());
6657
6658 HttpResponseInfo response = *trans0->GetResponseInfo();
6659 EXPECT_TRUE(response.headers);
6660 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
6661
6662 std::string result0;
6663 ReadResult(trans0, &result0);
6664 EXPECT_EQ("hello!", result0);
6665
6666 HttpResponseInfo push_response = *trans1.GetResponseInfo();
6667 EXPECT_TRUE(push_response.headers);
6668 EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
6669
6670 std::string result1;
6671 ReadResult(&trans1, &result1);
6672 EXPECT_EQ(kPushedData, result1);
6673
6674 base::RunLoop().RunUntilIdle();
6675 helper.VerifyDataConsumed();
6676 VerifyStreamsClosed(helper);
6677}
6678
Bence Békyb2f76672018-06-11 21:10:136679// Regression test for https://crbug.com/832859: Server push is accepted on a
6680// connection with client certificate, as long as SpdySessionKey matches.
6681TEST_F(SpdyNetworkTransactionTest, ServerPushWithClientCert) {
6682 spdy::SpdySerializedFrame req(
6683 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
6684 spdy::SpdySerializedFrame priority(
6685 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
6686 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3)};
6687
6688 spdy::SpdySerializedFrame resp(
6689 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6690 spdy::SpdySerializedFrame push(
6691 spdy_util_.ConstructSpdyPush(nullptr, 0, 2, 1, kPushedUrl));
6692 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
6693 spdy::SpdySerializedFrame body2(
6694 spdy_util_.ConstructSpdyDataFrame(2, "pushed", true));
6695 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(push, 2),
6696 CreateMockRead(body1, 4), CreateMockRead(body2, 5),
6697 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6)};
6698
6699 SequencedSocketData data(reads, writes);
6700
6701 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
6702 ssl_provider->ssl_info.client_cert_sent = true;
6703 ssl_provider->ssl_info.cert =
6704 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
6705
6706 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
6707 helper.RunPreTestSetup();
6708 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
6709
6710 EXPECT_TRUE(helper.StartDefaultTest());
6711 helper.FinishDefaultTest();
6712
6713 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
6714 HttpRequestInfo request = CreateGetPushRequest();
6715 TestCompletionCallback callback;
6716 int rv = trans2.Start(&request, callback.callback(), log_);
6717 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
6718
6719 rv = callback.WaitForResult();
6720 EXPECT_THAT(rv, IsOk());
6721
6722 const HttpResponseInfo* const response = trans2.GetResponseInfo();
6723 EXPECT_TRUE(response->headers);
6724 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
6725
6726 std::string result;
6727 ReadResult(&trans2, &result);
6728 EXPECT_EQ("pushed", result);
6729
6730 EXPECT_TRUE(data.AllReadDataConsumed());
6731 EXPECT_TRUE(data.AllWriteDataConsumed());
6732
6733 VerifyStreamsClosed(helper);
6734}
6735
bnc3e79387f2016-03-15 14:49:206736// Verify that push works cross origin, even if there is already a connection
6737// open to origin of pushed resource.
bncd16676a2016-07-20 16:23:016738TEST_F(SpdyNetworkTransactionTest, ServerPushValidCrossOriginWithOpenSession) {
bnc3e79387f2016-03-15 14:49:206739 const char* url_to_fetch0 = "https://mail.example.org/foo";
6740 const char* url_to_fetch1 = "https://docs.example.org";
6741 const char* url_to_push = "https://mail.example.org/bar";
6742
bncd16676a2016-07-20 16:23:016743 SpdyTestUtil spdy_util_0;
bnc3e79387f2016-03-15 14:49:206744
Ryan Hamilton0239aac2018-05-19 00:03:136745 spdy::SpdySerializedFrame headers0(
bnc3e79387f2016-03-15 14:49:206746 spdy_util_0.ConstructSpdyGet(url_to_fetch0, 1, LOWEST));
6747 MockWrite writes0[] = {
bncdf80d44fd2016-07-15 20:27:416748 CreateMockWrite(headers0, 0),
bnc3e79387f2016-03-15 14:49:206749 };
6750
Ryan Hamilton0239aac2018-05-19 00:03:136751 spdy::SpdySerializedFrame reply0(
6752 spdy_util_0.ConstructSpdyGetReply(nullptr, 0, 1));
bnc3e79387f2016-03-15 14:49:206753 const char kData0[] = "first";
Ryan Hamilton0239aac2018-05-19 00:03:136754 spdy::SpdySerializedFrame body0(
Bence Békyd74f4382018-02-20 18:26:196755 spdy_util_0.ConstructSpdyDataFrame(1, kData0, true));
bncdf80d44fd2016-07-15 20:27:416756 MockRead reads0[] = {CreateMockRead(reply0, 1), CreateMockRead(body0, 2),
6757 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
bnc3e79387f2016-03-15 14:49:206758
Ryan Sleevib8d7ea02018-05-07 20:01:016759 SequencedSocketData data0(reads0, writes0);
bnc3e79387f2016-03-15 14:49:206760
bncd16676a2016-07-20 16:23:016761 SpdyTestUtil spdy_util_1;
bnc3e79387f2016-03-15 14:49:206762
Ryan Hamilton0239aac2018-05-19 00:03:136763 spdy::SpdySerializedFrame headers1(
bnc3e79387f2016-03-15 14:49:206764 spdy_util_1.ConstructSpdyGet(url_to_fetch1, 1, LOWEST));
Ryan Hamilton0239aac2018-05-19 00:03:136765 spdy::SpdySerializedFrame push_priority(
tombergan5d22c182017-01-11 02:05:356766 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
bnc3e79387f2016-03-15 14:49:206767 MockWrite writes1[] = {
bncdf80d44fd2016-07-15 20:27:416768 CreateMockWrite(headers1, 0),
tombergan5d22c182017-01-11 02:05:356769 CreateMockWrite(push_priority, 3, SYNCHRONOUS),
bnc3e79387f2016-03-15 14:49:206770 };
6771
Ryan Hamilton0239aac2018-05-19 00:03:136772 spdy::SpdySerializedFrame reply1(
6773 spdy_util_1.ConstructSpdyGetReply(nullptr, 0, 1));
6774 spdy::SpdySerializedFrame push(
bnc3e79387f2016-03-15 14:49:206775 spdy_util_1.ConstructSpdyPush(nullptr, 0, 2, 1, url_to_push));
6776 const char kData1[] = "second";
Ryan Hamilton0239aac2018-05-19 00:03:136777 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:196778 spdy_util_1.ConstructSpdyDataFrame(1, kData1, true));
bnc3e79387f2016-03-15 14:49:206779 const char kPushedData[] = "pushed";
Ryan Hamilton0239aac2018-05-19 00:03:136780 spdy::SpdySerializedFrame pushed_body(
Bence Békyd74f4382018-02-20 18:26:196781 spdy_util_1.ConstructSpdyDataFrame(2, kPushedData, true));
bnc3e79387f2016-03-15 14:49:206782
6783 MockRead reads1[] = {
bncdf80d44fd2016-07-15 20:27:416784 CreateMockRead(reply1, 1),
bnceb9aa7112017-01-05 01:03:466785 CreateMockRead(push, 2, SYNCHRONOUS),
tombergan5d22c182017-01-11 02:05:356786 CreateMockRead(body1, 4),
6787 CreateMockRead(pushed_body, 5, SYNCHRONOUS),
6788 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 6),
bnc3e79387f2016-03-15 14:49:206789 };
6790
Ryan Sleevib8d7ea02018-05-07 20:01:016791 SequencedSocketData data1(reads1, writes1);
bnc3e79387f2016-03-15 14:49:206792
6793 // Request |url_to_fetch0| to open connection to mail.example.org.
Bence Békydb3cf652017-10-10 15:22:106794 request_.url = GURL(url_to_fetch0);
bnc3e79387f2016-03-15 14:49:206795
Bence Békydb3cf652017-10-10 15:22:106796 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc3e79387f2016-03-15 14:49:206797 helper.RunPreTestSetup();
6798
6799 // "spdy_pooling.pem" is valid for www.example.org, but not for
6800 // docs.example.org.
Jeremy Roman0579ed62017-08-29 15:56:196801 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:496802 ssl_provider0->ssl_info.cert =
bnc3e79387f2016-03-15 14:49:206803 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
Ryan Sleevi4f832092017-11-21 23:25:496804 ASSERT_TRUE(ssl_provider0->ssl_info.cert);
bnc3e79387f2016-03-15 14:49:206805 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
6806
6807 // "wildcard.pem" is valid for both www.example.org and docs.example.org.
Jeremy Roman0579ed62017-08-29 15:56:196808 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Ryan Sleevi4f832092017-11-21 23:25:496809 ssl_provider1->ssl_info.cert =
bnc3e79387f2016-03-15 14:49:206810 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
Ryan Sleevi4f832092017-11-21 23:25:496811 ASSERT_TRUE(ssl_provider1->ssl_info.cert);
bnc3e79387f2016-03-15 14:49:206812 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
6813
6814 HttpNetworkTransaction* trans0 = helper.trans();
6815 TestCompletionCallback callback0;
Bence Békydb3cf652017-10-10 15:22:106816 int rv = trans0->Start(&request_, callback0.callback(), log_);
bnc3e79387f2016-03-15 14:49:206817 rv = callback0.GetResult(rv);
robpercival214763f2016-07-01 23:27:016818 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206819
6820 // Request |url_to_fetch1|, during which docs.example.org pushes
6821 // |url_to_push|, which happens to be for www.example.org, to which there is
6822 // already an open connection.
bnc691fda62016-08-12 00:43:166823 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
bnc3e79387f2016-03-15 14:49:206824 HttpRequestInfo request1;
6825 request1.method = "GET";
6826 request1.url = GURL(url_to_fetch1);
Ramin Halavatib5e433e62018-02-07 07:41:106827 request1.traffic_annotation =
6828 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
bnc3e79387f2016-03-15 14:49:206829 TestCompletionCallback callback1;
Bence Békyd3dde832017-09-19 19:02:316830 rv = trans1.Start(&request1, callback1.callback(), log_);
bnc3e79387f2016-03-15 14:49:206831 rv = callback1.GetResult(rv);
robpercival214763f2016-07-01 23:27:016832 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206833
6834 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
6835 HostPortPair host_port_pair0("mail.example.org", 443);
6836 SpdySessionKey key0(host_port_pair0, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:116837 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:346838 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
6839 NetworkIsolationKey(), false /* disable_secure_dns */);
bnc3e79387f2016-03-15 14:49:206840 base::WeakPtr<SpdySession> spdy_session0 =
bnc9ead3ae2017-03-16 00:48:156841 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:316842 key0, /* enable_ip_based_pooling = */ true,
6843 /* is_websocket = */ false, log_);
bnc3e79387f2016-03-15 14:49:206844
Bence Béky285e7d42017-12-04 20:22:116845 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session0));
bnc3e79387f2016-03-15 14:49:206846
6847 HostPortPair host_port_pair1("docs.example.org", 443);
6848 SpdySessionKey key1(host_port_pair1, ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:116849 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:346850 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
6851 NetworkIsolationKey(), false /* disable_secure_dns */);
bnc3e79387f2016-03-15 14:49:206852 base::WeakPtr<SpdySession> spdy_session1 =
bnc9ead3ae2017-03-16 00:48:156853 spdy_session_pool->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:316854 key1, /* enable_ip_based_pooling = */ true,
6855 /* is_websocket = */ false, log_);
bnc3e79387f2016-03-15 14:49:206856
Bence Béky285e7d42017-12-04 20:22:116857 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session1));
Bence Béky3b609012017-12-04 15:19:356858 EXPECT_TRUE(
Bence Béky285e7d42017-12-04 20:22:116859 has_unclaimed_pushed_stream_for_url(spdy_session1, GURL(url_to_push)));
bnc3e79387f2016-03-15 14:49:206860
6861 // Request |url_to_push|, which should be served from the pushed resource.
bnc691fda62016-08-12 00:43:166862 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
bnc3e79387f2016-03-15 14:49:206863 HttpRequestInfo push_request;
6864 push_request.method = "GET";
6865 push_request.url = GURL(url_to_push);
Ramin Halavatib5e433e62018-02-07 07:41:106866 push_request.traffic_annotation =
6867 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
bnc3e79387f2016-03-15 14:49:206868 TestCompletionCallback callback2;
Bence Békyd3dde832017-09-19 19:02:316869 rv = trans2.Start(&push_request, callback2.callback(), log_);
bnc3e79387f2016-03-15 14:49:206870 rv = callback2.GetResult(rv);
robpercival214763f2016-07-01 23:27:016871 EXPECT_THAT(rv, IsOk());
bnc3e79387f2016-03-15 14:49:206872
Bence Béky285e7d42017-12-04 20:22:116873 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session0));
6874 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session1));
bnc3e79387f2016-03-15 14:49:206875
bnc3e79387f2016-03-15 14:49:206876 HttpResponseInfo response0 = *trans0->GetResponseInfo();
wezca1070932016-05-26 20:30:526877 EXPECT_TRUE(response0.headers);
bnc3e79387f2016-03-15 14:49:206878 EXPECT_EQ("HTTP/1.1 200", response0.headers->GetStatusLine());
6879
Bence Béky4e83f492018-05-13 23:14:256880 std::string result0;
bnc3e79387f2016-03-15 14:49:206881 ReadResult(trans0, &result0);
6882 EXPECT_EQ(kData0, result0);
6883
bnc691fda62016-08-12 00:43:166884 HttpResponseInfo response1 = *trans1.GetResponseInfo();
wezca1070932016-05-26 20:30:526885 EXPECT_TRUE(response1.headers);
bnc3e79387f2016-03-15 14:49:206886 EXPECT_EQ("HTTP/1.1 200", response1.headers->GetStatusLine());
6887
Bence Béky4e83f492018-05-13 23:14:256888 std::string result1;
bnc691fda62016-08-12 00:43:166889 ReadResult(&trans1, &result1);
bnc3e79387f2016-03-15 14:49:206890 EXPECT_EQ(kData1, result1);
6891
bnc691fda62016-08-12 00:43:166892 HttpResponseInfo push_response = *trans2.GetResponseInfo();
wezca1070932016-05-26 20:30:526893 EXPECT_TRUE(push_response.headers);
bnc3e79387f2016-03-15 14:49:206894 EXPECT_EQ("HTTP/1.1 200", push_response.headers->GetStatusLine());
6895
Bence Béky4e83f492018-05-13 23:14:256896 std::string result2;
bnc691fda62016-08-12 00:43:166897 ReadResult(&trans2, &result2);
bnc3e79387f2016-03-15 14:49:206898 EXPECT_EQ(kPushedData, result2);
tombergan5d22c182017-01-11 02:05:356899
6900 base::RunLoop().RunUntilIdle();
6901 helper.VerifyDataConsumed();
6902 VerifyStreamsClosed(helper);
bnc3e79387f2016-03-15 14:49:206903}
6904
bncd16676a2016-07-20 16:23:016905TEST_F(SpdyNetworkTransactionTest, RetryAfterRefused) {
[email protected]721c0ce2011-10-13 02:41:006906 // Construct the request.
Ryan Hamilton0239aac2018-05-19 00:03:136907 spdy::SpdySerializedFrame req(
6908 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
rdsmithebb50aa2015-11-12 03:44:386909 // Will be destroyed by the RST before stream 3 starts.
6910 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:136911 spdy::SpdySerializedFrame req2(
6912 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
[email protected]721c0ce2011-10-13 02:41:006913 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416914 CreateMockWrite(req, 0), CreateMockWrite(req2, 2),
[email protected]721c0ce2011-10-13 02:41:006915 };
6916
Ryan Hamilton0239aac2018-05-19 00:03:136917 spdy::SpdySerializedFrame refused(
6918 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_REFUSED_STREAM));
6919 spdy::SpdySerializedFrame resp(
6920 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
6921 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(3, true));
[email protected]721c0ce2011-10-13 02:41:006922 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416923 CreateMockRead(refused, 1), CreateMockRead(resp, 3),
6924 CreateMockRead(body, 4), MockRead(ASYNC, 0, 5) // EOF
[email protected]721c0ce2011-10-13 02:41:006925 };
6926
Ryan Sleevib8d7ea02018-05-07 20:01:016927 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:106928 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]721c0ce2011-10-13 02:41:006929
6930 helper.RunPreTestSetup();
[email protected]dd54bd82012-07-19 23:44:576931 helper.AddData(&data);
[email protected]721c0ce2011-10-13 02:41:006932
6933 HttpNetworkTransaction* trans = helper.trans();
6934
6935 // Start the transaction with basic parameters.
[email protected]49639fa2011-12-20 23:22:416936 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:106937 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:016938 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]721c0ce2011-10-13 02:41:006939 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:016940 EXPECT_THAT(rv, IsOk());
[email protected]721c0ce2011-10-13 02:41:006941
bnceb9aa7112017-01-05 01:03:466942 // Finish async network reads.
6943 base::RunLoop().RunUntilIdle();
6944
[email protected]721c0ce2011-10-13 02:41:006945 // Verify that we consumed all test data.
rch08e3aa3e2015-05-16 14:27:526946 EXPECT_TRUE(data.AllReadDataConsumed());
6947 EXPECT_TRUE(data.AllWriteDataConsumed());
[email protected]721c0ce2011-10-13 02:41:006948
bnc42331402016-07-25 13:36:156949 // Verify the response headers.
[email protected]721c0ce2011-10-13 02:41:006950 HttpResponseInfo response = *trans->GetResponseInfo();
wezca1070932016-05-26 20:30:526951 EXPECT_TRUE(response.headers);
bnc84e7fb52015-12-02 11:50:026952 EXPECT_EQ("HTTP/1.1 200", response.headers->GetStatusLine());
[email protected]721c0ce2011-10-13 02:41:006953}
6954
bnc42331402016-07-25 13:36:156955TEST_F(SpdyNetworkTransactionTest, OutOfOrderHeaders) {
[email protected]e1f58efa2012-05-15 18:23:406956 // This first request will start to establish the SpdySession.
6957 // Then we will start the second (MEDIUM priority) and then third
6958 // (HIGHEST priority) request in such a way that the third will actually
[email protected]c92f4b4542012-07-26 23:53:216959 // start before the second, causing the second to be numbered differently
[email protected]513963e2013-06-15 01:53:046960 // than the order they were created.
rdsmithebb50aa2015-11-12 03:44:386961 //
6962 // Note that the requests and responses created below are expectations
6963 // of what the above will produce on the wire, and hence are in the
6964 // initial->HIGHEST->LOWEST priority.
6965 //
6966 // Frames are created by SpdySession just before the write associated
6967 // with the frame is attempted, so stream dependencies will be based
6968 // on the streams alive at the point of the request write attempt. Thus
6969 // req1 is alive when req2 is attempted (during but not after the
6970 // |data.RunFor(2);| statement below) but not when req3 is attempted.
6971 // The call to spdy_util_.UpdateWithStreamDestruction() reflects this.
Ryan Hamilton0239aac2018-05-19 00:03:136972 spdy::SpdySerializedFrame req1(
6973 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
6974 spdy::SpdySerializedFrame req2(
6975 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, HIGHEST));
rdsmithebb50aa2015-11-12 03:44:386976 spdy_util_.UpdateWithStreamDestruction(1);
Ryan Hamilton0239aac2018-05-19 00:03:136977 spdy::SpdySerializedFrame req3(
6978 spdy_util_.ConstructSpdyGet(nullptr, 0, 5, MEDIUM));
[email protected]e1f58efa2012-05-15 18:23:406979 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:416980 MockWrite(ASYNC, ERR_IO_PENDING, 0), CreateMockWrite(req1, 1),
6981 CreateMockWrite(req2, 5), CreateMockWrite(req3, 6),
[email protected]e1f58efa2012-05-15 18:23:406982 };
6983
Ryan Hamilton0239aac2018-05-19 00:03:136984 spdy::SpdySerializedFrame resp1(
6985 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
6986 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
6987 spdy::SpdySerializedFrame resp2(
6988 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
6989 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
6990 spdy::SpdySerializedFrame resp3(
6991 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 5));
6992 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(5, true));
[email protected]e1f58efa2012-05-15 18:23:406993 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:416994 CreateMockRead(resp1, 2), MockRead(ASYNC, ERR_IO_PENDING, 3),
6995 CreateMockRead(body1, 4), CreateMockRead(resp2, 7),
6996 CreateMockRead(body2, 8), CreateMockRead(resp3, 9),
6997 CreateMockRead(body3, 10), MockRead(ASYNC, 0, 11) // EOF
[email protected]e1f58efa2012-05-15 18:23:406998 };
6999
Ryan Sleevib8d7ea02018-05-07 20:01:017000 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107001 NormalSpdyTransactionHelper helper(request_, LOWEST, log_, nullptr);
[email protected]e1f58efa2012-05-15 18:23:407002 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337003 helper.AddData(&data);
[email protected]e1f58efa2012-05-15 18:23:407004
7005 // Start the first transaction to set up the SpdySession
7006 HttpNetworkTransaction* trans = helper.trans();
7007 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107008 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017009 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]e1f58efa2012-05-15 18:23:407010
7011 // Run the message loop, but do not allow the write to complete.
7012 // This leaves the SpdySession with a write pending, which prevents
7013 // SpdySession from attempting subsequent writes until this write completes.
[email protected]fc9d88472013-08-14 02:31:177014 base::RunLoop().RunUntilIdle();
[email protected]e1f58efa2012-05-15 18:23:407015
7016 // Now, start both new transactions
[email protected]e1f58efa2012-05-15 18:23:407017 TestCompletionCallback callback2;
bnc691fda62016-08-12 00:43:167018 HttpNetworkTransaction trans2(MEDIUM, helper.session());
Bence Békydb3cf652017-10-10 15:22:107019 rv = trans2.Start(&request_, callback2.callback(), log_);
robpercival214763f2016-07-01 23:27:017020 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:177021 base::RunLoop().RunUntilIdle();
[email protected]e1f58efa2012-05-15 18:23:407022
[email protected]e1f58efa2012-05-15 18:23:407023 TestCompletionCallback callback3;
bnc691fda62016-08-12 00:43:167024 HttpNetworkTransaction trans3(HIGHEST, helper.session());
Bence Békydb3cf652017-10-10 15:22:107025 rv = trans3.Start(&request_, callback3.callback(), log_);
robpercival214763f2016-07-01 23:27:017026 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]fc9d88472013-08-14 02:31:177027 base::RunLoop().RunUntilIdle();
[email protected]e1f58efa2012-05-15 18:23:407028
bnc42331402016-07-25 13:36:157029 // We now have two HEADERS frames queued up which will be
[email protected]e1f58efa2012-05-15 18:23:407030 // dequeued only once the first write completes, which we
7031 // now allow to happen.
mmenke666a6fea2015-12-19 04:16:337032 ASSERT_TRUE(data.IsPaused());
7033 data.Resume();
robpercival214763f2016-07-01 23:27:017034 EXPECT_THAT(callback.WaitForResult(), IsOk());
[email protected]e1f58efa2012-05-15 18:23:407035
7036 // And now we can allow everything else to run to completion.
mmenke666a6fea2015-12-19 04:16:337037 data.Resume();
7038 base::RunLoop().RunUntilIdle();
robpercival214763f2016-07-01 23:27:017039 EXPECT_THAT(callback2.WaitForResult(), IsOk());
7040 EXPECT_THAT(callback3.WaitForResult(), IsOk());
[email protected]e1f58efa2012-05-15 18:23:407041
7042 helper.VerifyDataConsumed();
krasin0bfeb6b2017-01-13 21:48:047043
7044 // At this point the test is completed and we need to safely destroy
7045 // all allocated structures. Helper stores a transaction that has a
7046 // reference to a stack allocated request, which has a short lifetime,
7047 // and is accessed during the transaction destruction. We need to delete
7048 // the transaction while the request is still a valid object.
7049 helper.ResetTrans();
[email protected]e1f58efa2012-05-15 18:23:407050}
7051
[email protected]d11b6912013-06-27 23:07:327052// Test that sent data frames and received WINDOW_UPDATE frames change
7053// the send_window_size_ correctly.
7054
7055// WINDOW_UPDATE is different than most other frames in that it can arrive
7056// while the client is still sending the request body. In order to enforce
7057// this scenario, we feed a couple of dummy frames and give a delay of 0 to
7058// socket data provider, so that initial read that is done as soon as the
7059// stream is created, succeeds and schedules another read. This way reads
7060// and writes are interleaved; after doing a full frame write, SpdyStream
7061// will break out of DoLoop and will read and process a WINDOW_UPDATE.
bnc42331402016-07-25 13:36:157062// Once our WINDOW_UPDATE is read, we cannot send HEADERS right away
[email protected]d11b6912013-06-27 23:07:327063// since request has not been completely written, therefore we feed
7064// enough number of WINDOW_UPDATEs to finish the first read and cause a
7065// write, leading to a complete write of request body; after that we send
7066// a reply with a body, to cause a graceful shutdown.
7067
7068// TODO(agayev): develop a socket data provider where both, reads and
7069// writes are ordered so that writing tests like these are easy and rewrite
7070// all these tests using it. Right now we are working around the
7071// limitations as described above and it's not deterministic, tests may
7072// fail under specific circumstances.
bncd16676a2016-07-20 16:23:017073TEST_F(SpdyNetworkTransactionTest, WindowUpdateReceived) {
[email protected]d11b6912013-06-27 23:07:327074 static int kFrameCount = 2;
Bence Békyd74f4382018-02-20 18:26:197075 std::string content(kMaxSpdyFrameChunkSize, 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137076 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:357077 kDefaultUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, nullptr,
7078 0));
Ryan Hamilton0239aac2018-05-19 00:03:137079 spdy::SpdySerializedFrame body(
Bence Békyd74f4382018-02-20 18:26:197080 spdy_util_.ConstructSpdyDataFrame(1, content, false));
Ryan Hamilton0239aac2018-05-19 00:03:137081 spdy::SpdySerializedFrame body_end(
Bence Békyd74f4382018-02-20 18:26:197082 spdy_util_.ConstructSpdyDataFrame(1, content, true));
[email protected]d11b6912013-06-27 23:07:327083
7084 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417085 CreateMockWrite(req, 0), CreateMockWrite(body, 1),
7086 CreateMockWrite(body_end, 2),
[email protected]d11b6912013-06-27 23:07:327087 };
7088
Avi Drissman13fc8932015-12-20 04:40:467089 static const int32_t kDeltaWindowSize = 0xff;
[email protected]d11b6912013-06-27 23:07:327090 static const int kDeltaCount = 4;
Ryan Hamilton0239aac2018-05-19 00:03:137091 spdy::SpdySerializedFrame window_update(
[email protected]d11b6912013-06-27 23:07:327092 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
Ryan Hamilton0239aac2018-05-19 00:03:137093 spdy::SpdySerializedFrame window_update_dummy(
[email protected]d11b6912013-06-27 23:07:327094 spdy_util_.ConstructSpdyWindowUpdate(2, kDeltaWindowSize));
Ryan Hamilton0239aac2018-05-19 00:03:137095 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327096 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:417097 CreateMockRead(window_update_dummy, 3),
7098 CreateMockRead(window_update_dummy, 4),
7099 CreateMockRead(window_update_dummy, 5),
7100 CreateMockRead(window_update, 6), // Four updates, therefore window
7101 CreateMockRead(window_update, 7), // size should increase by
7102 CreateMockRead(window_update, 8), // kDeltaWindowSize * 4
7103 CreateMockRead(window_update, 9),
7104 CreateMockRead(resp, 10),
7105 MockRead(ASYNC, ERR_IO_PENDING, 11),
7106 CreateMockRead(body_end, 12),
mmenke666a6fea2015-12-19 04:16:337107 MockRead(ASYNC, 0, 13) // EOF
[email protected]d11b6912013-06-27 23:07:327108 };
7109
Ryan Sleevib8d7ea02018-05-07 20:01:017110 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327111
danakjaee3e1ec2016-04-16 00:23:187112 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
[email protected]d11b6912013-06-27 23:07:327113 for (int i = 0; i < kFrameCount; ++i) {
Jeremy Roman0579ed62017-08-29 15:56:197114 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
Bence Békyd74f4382018-02-20 18:26:197115 content.data(), content.size()));
[email protected]d11b6912013-06-27 23:07:327116 }
olli.raula6df48b2a2015-11-26 07:40:227117 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327118
Bence Békydb3cf652017-10-10 15:22:107119 // Setup the request.
7120 request_.method = "POST";
7121 request_.upload_data_stream = &upload_data_stream;
[email protected]d11b6912013-06-27 23:07:327122
Bence Békydb3cf652017-10-10 15:22:107123 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
mmenke666a6fea2015-12-19 04:16:337124 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327125 helper.RunPreTestSetup();
7126
7127 HttpNetworkTransaction* trans = helper.trans();
7128
7129 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107130 int rv = trans->Start(&request_, callback.callback(), log_);
[email protected]d11b6912013-06-27 23:07:327131
robpercival214763f2016-07-01 23:27:017132 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327133
mmenke666a6fea2015-12-19 04:16:337134 data.RunUntilPaused();
7135 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327136
7137 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527138 ASSERT_TRUE(stream);
7139 ASSERT_TRUE(stream->stream());
bncbca843ba2016-07-14 13:05:487140 EXPECT_EQ(static_cast<int>(kDefaultInitialWindowSize) +
7141 kDeltaWindowSize * kDeltaCount -
7142 kMaxSpdyFrameChunkSize * kFrameCount,
7143 stream->stream()->send_window_size());
[email protected]d11b6912013-06-27 23:07:327144
mmenke666a6fea2015-12-19 04:16:337145 data.Resume();
7146 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327147
7148 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:017149 EXPECT_THAT(rv, IsOk());
[email protected]d11b6912013-06-27 23:07:327150
7151 helper.VerifyDataConsumed();
7152}
7153
7154// Test that received data frames and sent WINDOW_UPDATE frames change
7155// the recv_window_size_ correctly.
bncd16676a2016-07-20 16:23:017156TEST_F(SpdyNetworkTransactionTest, WindowUpdateSent) {
bnc8f0f3b62015-04-08 04:37:237157 // Session level maximum window size that is more than twice the default
7158 // initial window size so that an initial window update is sent.
Avi Drissman13fc8932015-12-20 04:40:467159 const int32_t session_max_recv_window_size = 5 * 64 * 1024;
bncbca843ba2016-07-14 13:05:487160 ASSERT_LT(2 * kDefaultInitialWindowSize, session_max_recv_window_size);
bnc8f0f3b62015-04-08 04:37:237161 // Stream level maximum window size that is less than the session level
7162 // maximum window size so that we test for confusion between the two.
Avi Drissman13fc8932015-12-20 04:40:467163 const int32_t stream_max_recv_window_size = 4 * 64 * 1024;
bnc8f0f3b62015-04-08 04:37:237164 ASSERT_GT(session_max_recv_window_size, stream_max_recv_window_size);
7165 // Size of body to be sent. Has to be less than or equal to both window sizes
7166 // so that we do not run out of receiving window. Also has to be greater than
7167 // half of them so that it triggers both a session level and a stream level
7168 // window update frame.
Avi Drissman13fc8932015-12-20 04:40:467169 const int32_t kTargetSize = 3 * 64 * 1024;
bnc8f0f3b62015-04-08 04:37:237170 ASSERT_GE(session_max_recv_window_size, kTargetSize);
7171 ASSERT_GE(stream_max_recv_window_size, kTargetSize);
7172 ASSERT_LT(session_max_recv_window_size / 2, kTargetSize);
7173 ASSERT_LT(stream_max_recv_window_size / 2, kTargetSize);
7174 // Size of each DATA frame.
Avi Drissman13fc8932015-12-20 04:40:467175 const int32_t kChunkSize = 4096;
bnc8f0f3b62015-04-08 04:37:237176 // Size of window updates.
7177 ASSERT_EQ(0, session_max_recv_window_size / 2 % kChunkSize);
Avi Drissman13fc8932015-12-20 04:40:467178 const int32_t session_window_update_delta =
bnc8f0f3b62015-04-08 04:37:237179 session_max_recv_window_size / 2 + kChunkSize;
7180 ASSERT_EQ(0, stream_max_recv_window_size / 2 % kChunkSize);
Avi Drissman13fc8932015-12-20 04:40:467181 const int32_t stream_window_update_delta =
bnc8f0f3b62015-04-08 04:37:237182 stream_max_recv_window_size / 2 + kChunkSize;
[email protected]d11b6912013-06-27 23:07:327183
Ryan Hamilton0239aac2018-05-19 00:03:137184 spdy::SpdySerializedFrame preface(
7185 const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
7186 spdy::kHttp2ConnectionHeaderPrefixSize,
7187 /* owns_buffer = */ false);
bnc8abf64af2017-06-07 20:18:547188
Ryan Hamilton0239aac2018-05-19 00:03:137189 spdy::SettingsMap initial_settings;
7190 initial_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
7191 initial_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
bnc3171a2432016-12-28 18:40:267192 kSpdyMaxConcurrentPushedStreams;
Ryan Hamilton0239aac2018-05-19 00:03:137193 initial_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] =
7194 stream_max_recv_window_size;
Bence Béky6cee52f2019-10-24 16:52:337195 initial_settings[spdy::SETTINGS_MAX_HEADER_LIST_SIZE] =
7196 kSpdyMaxHeaderListSize;
Ryan Hamilton0239aac2018-05-19 00:03:137197 spdy::SpdySerializedFrame initial_settings_frame(
bnc8f0f3b62015-04-08 04:37:237198 spdy_util_.ConstructSpdySettings(initial_settings));
bnc8abf64af2017-06-07 20:18:547199
Ryan Hamilton0239aac2018-05-19 00:03:137200 spdy::SpdySerializedFrame initial_window_update(
bnc8f0f3b62015-04-08 04:37:237201 spdy_util_.ConstructSpdyWindowUpdate(
Ryan Hamilton0239aac2018-05-19 00:03:137202 spdy::kSessionFlowControlStreamId,
bncbca843ba2016-07-14 13:05:487203 session_max_recv_window_size - kDefaultInitialWindowSize));
bnc8abf64af2017-06-07 20:18:547204
Ryan Hamilton0239aac2018-05-19 00:03:137205 spdy::SpdySerializedFrame combined_frames = CombineFrames(
bncef26b602017-06-12 22:08:197206 {&preface, &initial_settings_frame, &initial_window_update});
[email protected]d11b6912013-06-27 23:07:327207
7208 std::vector<MockWrite> writes;
bncef26b602017-06-12 22:08:197209 writes.push_back(CreateMockWrite(combined_frames));
bnc8abf64af2017-06-07 20:18:547210
Ryan Hamilton0239aac2018-05-19 00:03:137211 spdy::SpdySerializedFrame req(
7212 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncdf80d44fd2016-07-15 20:27:417213 writes.push_back(CreateMockWrite(req, writes.size()));
[email protected]d11b6912013-06-27 23:07:327214
[email protected]251029e2014-03-19 06:04:407215 std::vector<MockRead> reads;
Ryan Hamilton0239aac2018-05-19 00:03:137216 spdy::SpdySerializedFrame resp(
7217 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
bncdf80d44fd2016-07-15 20:27:417218 reads.push_back(CreateMockRead(resp, writes.size() + reads.size()));
[email protected]d11b6912013-06-27 23:07:327219
Ryan Hamilton0239aac2018-05-19 00:03:137220 std::vector<spdy::SpdySerializedFrame> body_frames;
Bence Béky4e83f492018-05-13 23:14:257221 const std::string body_data(kChunkSize, 'x');
[email protected]251029e2014-03-19 06:04:407222 for (size_t remaining = kTargetSize; remaining != 0;) {
7223 size_t frame_size = std::min(remaining, body_data.size());
Bence Békyd74f4382018-02-20 18:26:197224 body_frames.push_back(spdy_util_.ConstructSpdyDataFrame(
7225 1, base::StringPiece(body_data.data(), frame_size), false));
rchacdcbdc2015-05-16 17:16:007226 reads.push_back(
bncdf80d44fd2016-07-15 20:27:417227 CreateMockRead(body_frames.back(), writes.size() + reads.size()));
[email protected]251029e2014-03-19 06:04:407228 remaining -= frame_size;
7229 }
mmenkee24011922015-12-17 22:12:597230 // Yield.
rchacdcbdc2015-05-16 17:16:007231 reads.push_back(
mmenkee24011922015-12-17 22:12:597232 MockRead(SYNCHRONOUS, ERR_IO_PENDING, writes.size() + reads.size()));
[email protected]251029e2014-03-19 06:04:407233
Ryan Hamilton0239aac2018-05-19 00:03:137234 spdy::SpdySerializedFrame session_window_update(
bnc8abf64af2017-06-07 20:18:547235 spdy_util_.ConstructSpdyWindowUpdate(0, session_window_update_delta));
rchacdcbdc2015-05-16 17:16:007236 writes.push_back(
bncdf80d44fd2016-07-15 20:27:417237 CreateMockWrite(session_window_update, writes.size() + reads.size()));
Ryan Hamilton0239aac2018-05-19 00:03:137238 spdy::SpdySerializedFrame stream_window_update(
bnc8abf64af2017-06-07 20:18:547239 spdy_util_.ConstructSpdyWindowUpdate(1, stream_window_update_delta));
rchacdcbdc2015-05-16 17:16:007240 writes.push_back(
bncdf80d44fd2016-07-15 20:27:417241 CreateMockWrite(stream_window_update, writes.size() + reads.size()));
rchacdcbdc2015-05-16 17:16:007242
Ryan Sleevib8d7ea02018-05-07 20:01:017243 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327244
Jeremy Roman0579ed62017-08-29 15:56:197245 auto session_deps = std::make_unique<SpdySessionDependencies>();
bnc903e8c12016-12-09 20:50:057246 session_deps->session_max_recv_window_size = session_max_recv_window_size;
Ryan Hamilton0239aac2018-05-19 00:03:137247 session_deps->http2_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] =
bnc3171a2432016-12-28 18:40:267248 stream_max_recv_window_size;
bnc903e8c12016-12-09 20:50:057249
Bence Békydb3cf652017-10-10 15:22:107250 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
bnc903e8c12016-12-09 20:50:057251 std::move(session_deps));
[email protected]d11b6912013-06-27 23:07:327252 helper.AddData(&data);
7253 helper.RunPreTestSetup();
[email protected]d11b6912013-06-27 23:07:327254
bnc8f0f3b62015-04-08 04:37:237255 SpdySessionPool* spdy_session_pool = helper.session()->spdy_session_pool();
7256 SpdySessionPoolPeer pool_peer(spdy_session_pool);
7257 pool_peer.SetEnableSendingInitialData(true);
bnc8f0f3b62015-04-08 04:37:237258
7259 HttpNetworkTransaction* trans = helper.trans();
[email protected]d11b6912013-06-27 23:07:327260 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107261 int rv = trans->Start(&request_, callback.callback(), log_);
[email protected]d11b6912013-06-27 23:07:327262
robpercival214763f2016-07-01 23:27:017263 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327264 rv = callback.WaitForResult();
robpercival214763f2016-07-01 23:27:017265 EXPECT_THAT(rv, IsOk());
[email protected]d11b6912013-06-27 23:07:327266
bnceb9aa7112017-01-05 01:03:467267 // Finish async network reads.
7268 base::RunLoop().RunUntilIdle();
7269
[email protected]d11b6912013-06-27 23:07:327270 SpdyHttpStream* stream =
7271 static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527272 ASSERT_TRUE(stream);
7273 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327274
[email protected]251029e2014-03-19 06:04:407275 // All data has been read, but not consumed. The window reflects this.
bnc8f0f3b62015-04-08 04:37:237276 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size - kTargetSize),
[email protected]251029e2014-03-19 06:04:407277 stream->stream()->recv_window_size());
[email protected]d11b6912013-06-27 23:07:327278
7279 const HttpResponseInfo* response = trans->GetResponseInfo();
wezca1070932016-05-26 20:30:527280 ASSERT_TRUE(response);
7281 ASSERT_TRUE(response->headers);
bnc84e7fb52015-12-02 11:50:027282 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
[email protected]d11b6912013-06-27 23:07:327283 EXPECT_TRUE(response->was_fetched_via_spdy);
7284
7285 // Issue a read which will cause a WINDOW_UPDATE to be sent and window
7286 // size increased to default.
Victor Costan9c7302b2018-08-27 16:39:447287 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kTargetSize);
[email protected]251029e2014-03-19 06:04:407288 EXPECT_EQ(static_cast<int>(kTargetSize),
Bence Békybdbb0e72018-08-07 21:42:597289 trans->Read(buf.get(), kTargetSize, CompletionOnceCallback()));
bnc8f0f3b62015-04-08 04:37:237290 EXPECT_EQ(static_cast<int>(stream_max_recv_window_size),
[email protected]251029e2014-03-19 06:04:407291 stream->stream()->recv_window_size());
Bence Béky4e83f492018-05-13 23:14:257292 EXPECT_THAT(base::StringPiece(buf->data(), kTargetSize), Each(Eq('x')));
[email protected]d11b6912013-06-27 23:07:327293
[email protected]251029e2014-03-19 06:04:407294 // Allow scheduled WINDOW_UPDATE frames to write.
[email protected]fc9d88472013-08-14 02:31:177295 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327296 helper.VerifyDataConsumed();
7297}
7298
7299// Test that WINDOW_UPDATE frame causing overflow is handled correctly.
bncd16676a2016-07-20 16:23:017300TEST_F(SpdyNetworkTransactionTest, WindowUpdateOverflow) {
[email protected]d11b6912013-06-27 23:07:327301 // Number of full frames we hope to write (but will not, used to
7302 // set content-length header correctly)
7303 static int kFrameCount = 3;
7304
Bence Békyd74f4382018-02-20 18:26:197305 std::string content(kMaxSpdyFrameChunkSize, 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137306 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
tombergan5d22c182017-01-11 02:05:357307 kDefaultUrl, 1, kMaxSpdyFrameChunkSize * kFrameCount, LOWEST, nullptr,
7308 0));
Ryan Hamilton0239aac2018-05-19 00:03:137309 spdy::SpdySerializedFrame body(
Bence Békyd74f4382018-02-20 18:26:197310 spdy_util_.ConstructSpdyDataFrame(1, content, false));
Ryan Hamilton0239aac2018-05-19 00:03:137311 spdy::SpdySerializedFrame rst(spdy_util_.ConstructSpdyRstStream(
7312 1, spdy::ERROR_CODE_FLOW_CONTROL_ERROR));
[email protected]d11b6912013-06-27 23:07:327313
7314 // We're not going to write a data frame with FIN, we'll receive a bad
7315 // WINDOW_UPDATE while sending a request and will send a RST_STREAM frame.
7316 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417317 CreateMockWrite(req, 0), CreateMockWrite(body, 2),
7318 CreateMockWrite(rst, 3),
[email protected]d11b6912013-06-27 23:07:327319 };
7320
Avi Drissman13fc8932015-12-20 04:40:467321 static const int32_t kDeltaWindowSize = 0x7fffffff; // cause an overflow
Ryan Hamilton0239aac2018-05-19 00:03:137322 spdy::SpdySerializedFrame window_update(
[email protected]d11b6912013-06-27 23:07:327323 spdy_util_.ConstructSpdyWindowUpdate(1, kDeltaWindowSize));
7324 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:417325 CreateMockRead(window_update, 1), MockRead(ASYNC, 0, 4) // EOF
[email protected]d11b6912013-06-27 23:07:327326 };
7327
Ryan Sleevib8d7ea02018-05-07 20:01:017328 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327329
danakjaee3e1ec2016-04-16 00:23:187330 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
[email protected]d11b6912013-06-27 23:07:327331 for (int i = 0; i < kFrameCount; ++i) {
Jeremy Roman0579ed62017-08-29 15:56:197332 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
Bence Békyd74f4382018-02-20 18:26:197333 content.data(), content.size()));
[email protected]d11b6912013-06-27 23:07:327334 }
olli.raula6df48b2a2015-11-26 07:40:227335 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327336
Bence Békydb3cf652017-10-10 15:22:107337 // Setup the request.
7338 request_.method = "POST";
7339 request_.upload_data_stream = &upload_data_stream;
[email protected]d11b6912013-06-27 23:07:327340
Bence Békydb3cf652017-10-10 15:22:107341 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
[email protected]d11b6912013-06-27 23:07:327342 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337343 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327344 HttpNetworkTransaction* trans = helper.trans();
7345
7346 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107347 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017348 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327349
mmenke666a6fea2015-12-19 04:16:337350 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327351 ASSERT_TRUE(callback.have_result());
Bence Békyd0d69502019-06-25 19:47:187352 EXPECT_THAT(callback.WaitForResult(), IsError(ERR_HTTP2_FLOW_CONTROL_ERROR));
[email protected]d11b6912013-06-27 23:07:327353 helper.VerifyDataConsumed();
7354}
7355
Bence Béky05dcb0382017-09-15 20:07:587356// Regression test for https://crbug.com/732019.
Ryan Hamilton0239aac2018-05-19 00:03:137357// RFC7540 Section 6.9.2: A spdy::SETTINGS_INITIAL_WINDOW_SIZE change that
7358// causes any stream flow control window to overflow MUST be treated as a
7359// connection error.
Bence Béky05dcb0382017-09-15 20:07:587360TEST_F(SpdyNetworkTransactionTest, InitialWindowSizeOverflow) {
Ryan Hamilton0239aac2018-05-19 00:03:137361 spdy::SpdySerializedFrame window_update(
Bence Béky05dcb0382017-09-15 20:07:587362 spdy_util_.ConstructSpdyWindowUpdate(1, 0x60000000));
Ryan Hamilton0239aac2018-05-19 00:03:137363 spdy::SettingsMap settings;
7364 settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 0x60000000;
7365 spdy::SpdySerializedFrame settings_frame(
Bence Béky05dcb0382017-09-15 20:07:587366 spdy_util_.ConstructSpdySettings(settings));
7367 MockRead reads[] = {CreateMockRead(window_update, 1),
7368 CreateMockRead(settings_frame, 2)};
7369
Ryan Hamilton0239aac2018-05-19 00:03:137370 spdy::SpdySerializedFrame req(
7371 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7372 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
7373 spdy::SpdySerializedFrame goaway(
7374 spdy_util_.ConstructSpdyGoAway(0, spdy::ERROR_CODE_FLOW_CONTROL_ERROR,
7375 "New spdy::SETTINGS_INITIAL_WINDOW_SIZE "
7376 "value overflows flow control window of "
7377 "stream 1."));
Bence Béky05dcb0382017-09-15 20:07:587378 MockWrite writes[] = {CreateMockWrite(req, 0),
7379 CreateMockWrite(settings_ack, 3),
7380 CreateMockWrite(goaway, 4)};
7381
Ryan Sleevib8d7ea02018-05-07 20:01:017382 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107383 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
Bence Béky05dcb0382017-09-15 20:07:587384 helper.RunToCompletion(&data);
7385 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:187386 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_FLOW_CONTROL_ERROR));
Bence Béky05dcb0382017-09-15 20:07:587387}
7388
David Schinazi410676a2019-08-13 22:31:057389// Tests that we close the connection if we try to enqueue more frames than
7390// the cap allows.
7391TEST_F(SpdyNetworkTransactionTest, SessionMaxQueuedCappedFramesExceeded) {
7392 const int kTestSessionMaxQueuedCappedFrames = 5;
7393 const int kTestNumPings = kTestSessionMaxQueuedCappedFrames + 1;
7394 spdy::SettingsMap settings;
7395 settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = 0xffff;
7396 spdy::SpdySerializedFrame settings_frame(
7397 spdy_util_.ConstructSpdySettings(settings));
7398 std::vector<spdy::SpdySerializedFrame> ping_frames;
7399
7400 spdy::SpdySerializedFrame req(
7401 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7402 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
7403
7404 std::vector<MockWrite> writes;
7405 std::vector<MockRead> reads;
7406 // Send request, receive SETTINGS and send a SETTINGS ACK.
7407 writes.push_back(CreateMockWrite(req, writes.size() + reads.size()));
7408 reads.push_back(CreateMockRead(settings_frame, writes.size() + reads.size()));
7409 writes.push_back(CreateMockWrite(settings_ack, writes.size() + reads.size()));
7410 // Receive more pings than our limit allows.
7411 for (int i = 1; i <= kTestNumPings; ++i) {
7412 ping_frames.push_back(
7413 spdy_util_.ConstructSpdyPing(/*ping_id=*/i, /*is_ack=*/false));
7414 reads.push_back(
7415 CreateMockRead(ping_frames.back(), writes.size() + reads.size()));
7416 }
7417 // Only write PING ACKs after receiving all of them to ensure they are all in
7418 // the write queue.
7419 for (int i = 1; i <= kTestNumPings; ++i) {
7420 ping_frames.push_back(
7421 spdy_util_.ConstructSpdyPing(/*ping_id=*/i, /*is_ack=*/true));
7422 writes.push_back(
7423 CreateMockWrite(ping_frames.back(), writes.size() + reads.size()));
7424 }
7425 // Stop reading.
7426 reads.push_back(MockRead(ASYNC, 0, writes.size() + reads.size()));
7427
7428 SequencedSocketData data(reads, writes);
7429 auto session_deps = std::make_unique<SpdySessionDependencies>();
7430 session_deps->session_max_queued_capped_frames =
7431 kTestSessionMaxQueuedCappedFrames;
7432 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
7433 std::move(session_deps));
7434 helper.RunToCompletion(&data);
7435 TransactionHelperResult out = helper.output();
7436 EXPECT_THAT(out.rv, IsError(ERR_CONNECTION_CLOSED));
7437}
7438
[email protected]d11b6912013-06-27 23:07:327439// Test that after hitting a send window size of 0, the write process
7440// stalls and upon receiving WINDOW_UPDATE frame write resumes.
7441
7442// This test constructs a POST request followed by enough data frames
7443// containing 'a' that would make the window size 0, followed by another
7444// data frame containing default content (which is "hello!") and this frame
rchacdcbdc2015-05-16 17:16:007445// also contains a FIN flag. SequencedSocketData is used to enforce all
7446// writes, save the last, go through before a read could happen. The last frame
7447// ("hello!") is not permitted to go through since by the time its turn
[email protected]d11b6912013-06-27 23:07:327448// arrives, window size is 0. At this point MessageLoop::Run() called via
7449// callback would block. Therefore we call MessageLoop::RunUntilIdle()
7450// which returns after performing all possible writes. We use DCHECKS to
7451// ensure that last data frame is still there and stream has stalled.
7452// After that, next read is artifically enforced, which causes a
7453// WINDOW_UPDATE to be read and I/O process resumes.
bncd16676a2016-07-20 16:23:017454TEST_F(SpdyNetworkTransactionTest, FlowControlStallResume) {
bncbca843ba2016-07-14 13:05:487455 const int32_t initial_window_size = kDefaultInitialWindowSize;
xunjieli179a6e72016-04-26 19:47:457456 // Number of upload data buffers we need to send to zero out the window size
7457 // is the minimal number of upload buffers takes to be bigger than
7458 // |initial_window_size|.
7459 size_t num_upload_buffers =
7460 ceil(static_cast<double>(initial_window_size) / kBufferSize);
7461 // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
7462 // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
7463 // which has kBufferSize % kMaxSpdyChunkSize bytes.
7464 size_t num_frames_in_one_upload_buffer =
7465 ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
[email protected]d11b6912013-06-27 23:07:327466
7467 // Construct content for a data frame of maximum size.
Bence Béky4e83f492018-05-13 23:14:257468 std::string content(kMaxSpdyFrameChunkSize, 'a');
[email protected]d11b6912013-06-27 23:07:327469
Ryan Hamilton0239aac2018-05-19 00:03:137470 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bncb26024382016-06-29 02:39:457471 kDefaultUrl, 1,
xunjieli179a6e72016-04-26 19:47:457472 /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
tombergan5d22c182017-01-11 02:05:357473 LOWEST, nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327474
7475 // Full frames.
Ryan Hamilton0239aac2018-05-19 00:03:137476 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:197477 spdy_util_.ConstructSpdyDataFrame(1, content, false));
[email protected]d11b6912013-06-27 23:07:327478
xunjieli179a6e72016-04-26 19:47:457479 // Last frame in each upload data buffer.
Ryan Hamilton0239aac2018-05-19 00:03:137480 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197481 1,
7482 base::StringPiece(content.data(), kBufferSize % kMaxSpdyFrameChunkSize),
7483 false));
[email protected]d11b6912013-06-27 23:07:327484
xunjieli179a6e72016-04-26 19:47:457485 // The very last frame before the stalled frames.
Ryan Hamilton0239aac2018-05-19 00:03:137486 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197487 1,
7488 base::StringPiece(content.data(), initial_window_size % kBufferSize %
7489 kMaxSpdyFrameChunkSize),
7490 false));
xunjieli179a6e72016-04-26 19:47:457491
7492 // Data frames to be sent once WINDOW_UPDATE frame is received.
7493
7494 // If kBufferSize * num_upload_buffers > initial_window_size,
7495 // we need one additional frame to send the rest of 'a'.
Bence Béky4e83f492018-05-13 23:14:257496 std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
7497 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137498 spdy::SpdySerializedFrame body4(
Bence Békyd74f4382018-02-20 18:26:197499 spdy_util_.ConstructSpdyDataFrame(1, last_body, false));
xunjieli179a6e72016-04-26 19:47:457500
7501 // Also send a "hello!" after WINDOW_UPDATE.
Ryan Hamilton0239aac2018-05-19 00:03:137502 spdy::SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d11b6912013-06-27 23:07:327503
7504 // Fill in mock writes.
[email protected]d11b6912013-06-27 23:07:327505 size_t i = 0;
xunjieli179a6e72016-04-26 19:47:457506 std::vector<MockWrite> writes;
bncdf80d44fd2016-07-15 20:27:417507 writes.push_back(CreateMockWrite(req, i++));
xunjieli179a6e72016-04-26 19:47:457508 for (size_t j = 0; j < num_upload_buffers; j++) {
7509 for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
7510 if (k == num_frames_in_one_upload_buffer - 1 &&
7511 kBufferSize % kMaxSpdyFrameChunkSize != 0) {
7512 if (j == num_upload_buffers - 1 &&
7513 (initial_window_size % kBufferSize != 0)) {
bncdf80d44fd2016-07-15 20:27:417514 writes.push_back(CreateMockWrite(body3, i++));
xunjieli179a6e72016-04-26 19:47:457515 } else {
bncdf80d44fd2016-07-15 20:27:417516 writes.push_back(CreateMockWrite(body2, i++));
xunjieli179a6e72016-04-26 19:47:457517 }
7518 } else {
bncdf80d44fd2016-07-15 20:27:417519 writes.push_back(CreateMockWrite(body1, i++));
xunjieli179a6e72016-04-26 19:47:457520 }
7521 }
7522 }
[email protected]d11b6912013-06-27 23:07:327523
xunjieli179a6e72016-04-26 19:47:457524 // Fill in mock reads.
7525 std::vector<MockRead> reads;
7526 // Force a pause.
7527 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
7528 // Construct read frame for window updates that gives enough space to upload
7529 // the rest of the data.
Ryan Hamilton0239aac2018-05-19 00:03:137530 spdy::SpdySerializedFrame session_window_update(
xunjieli179a6e72016-04-26 19:47:457531 spdy_util_.ConstructSpdyWindowUpdate(0,
7532 kUploadDataSize + last_body.size()));
Ryan Hamilton0239aac2018-05-19 00:03:137533 spdy::SpdySerializedFrame window_update(spdy_util_.ConstructSpdyWindowUpdate(
bncdf80d44fd2016-07-15 20:27:417534 1, kUploadDataSize + last_body.size()));
xunjieli179a6e72016-04-26 19:47:457535
bncdf80d44fd2016-07-15 20:27:417536 reads.push_back(CreateMockRead(session_window_update, i++));
7537 reads.push_back(CreateMockRead(window_update, i++));
xunjieli179a6e72016-04-26 19:47:457538
7539 // Stalled frames which can be sent after receiving window updates.
7540 if (last_body.size() > 0)
bncdf80d44fd2016-07-15 20:27:417541 writes.push_back(CreateMockWrite(body4, i++));
7542 writes.push_back(CreateMockWrite(body5, i++));
xunjieli179a6e72016-04-26 19:47:457543
Ryan Hamilton0239aac2018-05-19 00:03:137544 spdy::SpdySerializedFrame reply(
7545 spdy_util_.ConstructSpdyPostReply(nullptr, 0));
bncdf80d44fd2016-07-15 20:27:417546 reads.push_back(CreateMockRead(reply, i++));
7547 reads.push_back(CreateMockRead(body2, i++));
7548 reads.push_back(CreateMockRead(body5, i++));
xunjieli179a6e72016-04-26 19:47:457549 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
[email protected]d11b6912013-06-27 23:07:327550
Ryan Sleevib8d7ea02018-05-07 20:01:017551 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327552
danakjaee3e1ec2016-04-16 00:23:187553 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Bence Béky4e83f492018-05-13 23:14:257554 std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
[email protected]d11b6912013-06-27 23:07:327555 upload_data_string.append(kUploadData, kUploadDataSize);
Jeremy Roman0579ed62017-08-29 15:56:197556 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
bnc3f6a8552017-05-17 13:40:347557 upload_data_string.c_str(), upload_data_string.size()));
olli.raula6df48b2a2015-11-26 07:40:227558 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327559
Bence Békydb3cf652017-10-10 15:22:107560 request_.method = "POST";
7561 request_.upload_data_stream = &upload_data_stream;
7562 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
7563
[email protected]d11b6912013-06-27 23:07:327564 helper.AddData(&data);
7565 helper.RunPreTestSetup();
7566
7567 HttpNetworkTransaction* trans = helper.trans();
7568
7569 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107570 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017571 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327572
[email protected]fc9d88472013-08-14 02:31:177573 base::RunLoop().RunUntilIdle(); // Write as much as we can.
[email protected]d11b6912013-06-27 23:07:327574
7575 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527576 ASSERT_TRUE(stream);
7577 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327578 EXPECT_EQ(0, stream->stream()->send_window_size());
xunjieli179a6e72016-04-26 19:47:457579 if (initial_window_size % kBufferSize != 0) {
7580 // If it does not take whole number of full upload buffer to zero out
7581 // initial window size, then the upload data is not at EOF, because the
7582 // last read must be stalled.
7583 EXPECT_FALSE(upload_data_stream.IsEOF());
7584 } else {
7585 // All the body data should have been read.
7586 // TODO(satorux): This is because of the weirdness in reading the request
7587 // body in OnSendBodyComplete(). See crbug.com/113107.
7588 EXPECT_TRUE(upload_data_stream.IsEOF());
7589 }
[email protected]d11b6912013-06-27 23:07:327590 // But the body is not yet fully sent (kUploadData is not yet sent)
7591 // since we're send-stalled.
7592 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
7593
mmenkee24011922015-12-17 22:12:597594 data.Resume(); // Read in WINDOW_UPDATE frame.
[email protected]d11b6912013-06-27 23:07:327595 rv = callback.WaitForResult();
bnceb9aa7112017-01-05 01:03:467596 EXPECT_THAT(rv, IsOk());
7597
7598 // Finish async network reads.
7599 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327600 helper.VerifyDataConsumed();
7601}
7602
7603// Test we correctly handle the case where the SETTINGS frame results in
7604// unstalling the send window.
bncd16676a2016-07-20 16:23:017605TEST_F(SpdyNetworkTransactionTest, FlowControlStallResumeAfterSettings) {
bncbca843ba2016-07-14 13:05:487606 const int32_t initial_window_size = kDefaultInitialWindowSize;
xunjieli179a6e72016-04-26 19:47:457607 // Number of upload data buffers we need to send to zero out the window size
7608 // is the minimal number of upload buffers takes to be bigger than
7609 // |initial_window_size|.
7610 size_t num_upload_buffers =
7611 ceil(static_cast<double>(initial_window_size) / kBufferSize);
7612 // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
7613 // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
7614 // which has kBufferSize % kMaxSpdyChunkSize bytes.
7615 size_t num_frames_in_one_upload_buffer =
7616 ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
[email protected]d11b6912013-06-27 23:07:327617
7618 // Construct content for a data frame of maximum size.
Bence Béky4e83f492018-05-13 23:14:257619 std::string content(kMaxSpdyFrameChunkSize, 'a');
[email protected]d11b6912013-06-27 23:07:327620
Ryan Hamilton0239aac2018-05-19 00:03:137621 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bncb26024382016-06-29 02:39:457622 kDefaultUrl, 1,
xunjieli179a6e72016-04-26 19:47:457623 /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
tombergan5d22c182017-01-11 02:05:357624 LOWEST, nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327625
7626 // Full frames.
Ryan Hamilton0239aac2018-05-19 00:03:137627 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:197628 spdy_util_.ConstructSpdyDataFrame(1, content, false));
[email protected]d11b6912013-06-27 23:07:327629
xunjieli179a6e72016-04-26 19:47:457630 // Last frame in each upload data buffer.
Ryan Hamilton0239aac2018-05-19 00:03:137631 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197632 1,
7633 base::StringPiece(content.data(), kBufferSize % kMaxSpdyFrameChunkSize),
7634 false));
[email protected]d11b6912013-06-27 23:07:327635
xunjieli179a6e72016-04-26 19:47:457636 // The very last frame before the stalled frames.
Ryan Hamilton0239aac2018-05-19 00:03:137637 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197638 1,
7639 base::StringPiece(content.data(), initial_window_size % kBufferSize %
7640 kMaxSpdyFrameChunkSize),
7641 false));
xunjieli179a6e72016-04-26 19:47:457642
7643 // Data frames to be sent once WINDOW_UPDATE frame is received.
7644
7645 // If kBufferSize * num_upload_buffers > initial_window_size,
7646 // we need one additional frame to send the rest of 'a'.
Bence Béky4e83f492018-05-13 23:14:257647 std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
7648 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137649 spdy::SpdySerializedFrame body4(
Bence Békyd74f4382018-02-20 18:26:197650 spdy_util_.ConstructSpdyDataFrame(1, last_body, false));
xunjieli179a6e72016-04-26 19:47:457651
7652 // Also send a "hello!" after WINDOW_UPDATE.
Ryan Hamilton0239aac2018-05-19 00:03:137653 spdy::SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d11b6912013-06-27 23:07:327654
xunjieli179a6e72016-04-26 19:47:457655 // Fill in mock writes.
[email protected]d11b6912013-06-27 23:07:327656 size_t i = 0;
xunjieli179a6e72016-04-26 19:47:457657 std::vector<MockWrite> writes;
bncdf80d44fd2016-07-15 20:27:417658 writes.push_back(CreateMockWrite(req, i++));
xunjieli179a6e72016-04-26 19:47:457659 for (size_t j = 0; j < num_upload_buffers; j++) {
7660 for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
7661 if (k == num_frames_in_one_upload_buffer - 1 &&
7662 kBufferSize % kMaxSpdyFrameChunkSize != 0) {
7663 if (j == num_upload_buffers - 1 &&
7664 (initial_window_size % kBufferSize != 0)) {
bncdf80d44fd2016-07-15 20:27:417665 writes.push_back(CreateMockWrite(body3, i++));
xunjieli179a6e72016-04-26 19:47:457666 } else {
bncdf80d44fd2016-07-15 20:27:417667 writes.push_back(CreateMockWrite(body2, i++));
xunjieli179a6e72016-04-26 19:47:457668 }
7669 } else {
bncdf80d44fd2016-07-15 20:27:417670 writes.push_back(CreateMockWrite(body1, i++));
xunjieli179a6e72016-04-26 19:47:457671 }
7672 }
7673 }
[email protected]d11b6912013-06-27 23:07:327674
xunjieli179a6e72016-04-26 19:47:457675 // Fill in mock reads.
7676 std::vector<MockRead> reads;
7677 // Force a pause.
mmenke666a6fea2015-12-19 04:16:337678 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
7679
[email protected]d11b6912013-06-27 23:07:327680 // Construct read frame for SETTINGS that gives enough space to upload the
7681 // rest of the data.
Ryan Hamilton0239aac2018-05-19 00:03:137682 spdy::SettingsMap settings;
7683 settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = initial_window_size * 2;
7684 spdy::SpdySerializedFrame settings_frame_large(
[email protected]d11b6912013-06-27 23:07:327685 spdy_util_.ConstructSpdySettings(settings));
7686
bncdf80d44fd2016-07-15 20:27:417687 reads.push_back(CreateMockRead(settings_frame_large, i++));
[email protected]d11b6912013-06-27 23:07:327688
Ryan Hamilton0239aac2018-05-19 00:03:137689 spdy::SpdySerializedFrame session_window_update(
xunjieli179a6e72016-04-26 19:47:457690 spdy_util_.ConstructSpdyWindowUpdate(0,
7691 last_body.size() + kUploadDataSize));
bncdf80d44fd2016-07-15 20:27:417692 reads.push_back(CreateMockRead(session_window_update, i++));
[email protected]d11b6912013-06-27 23:07:327693
Ryan Hamilton0239aac2018-05-19 00:03:137694 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
bncdf80d44fd2016-07-15 20:27:417695 writes.push_back(CreateMockWrite(settings_ack, i++));
[email protected]d4a77c12014-05-15 20:45:217696
xunjieli179a6e72016-04-26 19:47:457697 // Stalled frames which can be sent after |settings_ack|.
7698 if (last_body.size() > 0)
bncdf80d44fd2016-07-15 20:27:417699 writes.push_back(CreateMockWrite(body4, i++));
7700 writes.push_back(CreateMockWrite(body5, i++));
[email protected]d11b6912013-06-27 23:07:327701
Ryan Hamilton0239aac2018-05-19 00:03:137702 spdy::SpdySerializedFrame reply(
7703 spdy_util_.ConstructSpdyPostReply(nullptr, 0));
bncdf80d44fd2016-07-15 20:27:417704 reads.push_back(CreateMockRead(reply, i++));
7705 reads.push_back(CreateMockRead(body2, i++));
7706 reads.push_back(CreateMockRead(body5, i++));
[email protected]d11b6912013-06-27 23:07:327707 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
7708
7709 // Force all writes to happen before any read, last write will not
7710 // actually queue a frame, due to window size being 0.
Ryan Sleevib8d7ea02018-05-07 20:01:017711 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327712
danakjaee3e1ec2016-04-16 00:23:187713 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Bence Béky4e83f492018-05-13 23:14:257714 std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
[email protected]d11b6912013-06-27 23:07:327715 upload_data_string.append(kUploadData, kUploadDataSize);
Jeremy Roman0579ed62017-08-29 15:56:197716 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
bnc3f6a8552017-05-17 13:40:347717 upload_data_string.c_str(), upload_data_string.size()));
olli.raula6df48b2a2015-11-26 07:40:227718 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327719
Bence Békydb3cf652017-10-10 15:22:107720 request_.method = "POST";
7721 request_.upload_data_stream = &upload_data_stream;
7722 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
7723
[email protected]d11b6912013-06-27 23:07:327724 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337725 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327726
7727 HttpNetworkTransaction* trans = helper.trans();
7728
7729 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107730 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017731 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327732
mmenke666a6fea2015-12-19 04:16:337733 data.RunUntilPaused(); // Write as much as we can.
7734 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327735
7736 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527737 ASSERT_TRUE(stream);
7738 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327739 EXPECT_EQ(0, stream->stream()->send_window_size());
7740
xunjieli179a6e72016-04-26 19:47:457741 if (initial_window_size % kBufferSize != 0) {
7742 // If it does not take whole number of full upload buffer to zero out
7743 // initial window size, then the upload data is not at EOF, because the
7744 // last read must be stalled.
7745 EXPECT_FALSE(upload_data_stream.IsEOF());
7746 } else {
7747 // All the body data should have been read.
7748 // TODO(satorux): This is because of the weirdness in reading the request
7749 // body in OnSendBodyComplete(). See crbug.com/113107.
7750 EXPECT_TRUE(upload_data_stream.IsEOF());
7751 }
[email protected]d11b6912013-06-27 23:07:327752 // But the body is not yet fully sent (kUploadData is not yet sent)
7753 // since we're send-stalled.
7754 EXPECT_TRUE(stream->stream()->send_stalled_by_flow_control());
7755
mmenke666a6fea2015-12-19 04:16:337756 // Read in SETTINGS frame to unstall.
7757 data.Resume();
7758 base::RunLoop().RunUntilIdle();
7759
[email protected]d11b6912013-06-27 23:07:327760 rv = callback.WaitForResult();
7761 helper.VerifyDataConsumed();
tombergan5d22c182017-01-11 02:05:357762 // If stream is nullptr, that means it was unstalled and closed.
7763 EXPECT_TRUE(stream->stream() == nullptr);
[email protected]d11b6912013-06-27 23:07:327764}
7765
7766// Test we correctly handle the case where the SETTINGS frame results in a
7767// negative send window size.
bncd16676a2016-07-20 16:23:017768TEST_F(SpdyNetworkTransactionTest, FlowControlNegativeSendWindowSize) {
bncbca843ba2016-07-14 13:05:487769 const int32_t initial_window_size = kDefaultInitialWindowSize;
xunjieli179a6e72016-04-26 19:47:457770 // Number of upload data buffers we need to send to zero out the window size
7771 // is the minimal number of upload buffers takes to be bigger than
7772 // |initial_window_size|.
7773 size_t num_upload_buffers =
7774 ceil(static_cast<double>(initial_window_size) / kBufferSize);
7775 // Each upload data buffer consists of |num_frames_in_one_upload_buffer|
7776 // frames, each with |kMaxSpdyFrameChunkSize| bytes except the last frame,
7777 // which has kBufferSize % kMaxSpdyChunkSize bytes.
7778 size_t num_frames_in_one_upload_buffer =
7779 ceil(static_cast<double>(kBufferSize) / kMaxSpdyFrameChunkSize);
[email protected]d11b6912013-06-27 23:07:327780
7781 // Construct content for a data frame of maximum size.
Bence Béky4e83f492018-05-13 23:14:257782 std::string content(kMaxSpdyFrameChunkSize, 'a');
[email protected]d11b6912013-06-27 23:07:327783
Ryan Hamilton0239aac2018-05-19 00:03:137784 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
bncb26024382016-06-29 02:39:457785 kDefaultUrl, 1,
xunjieli179a6e72016-04-26 19:47:457786 /*content_length=*/kBufferSize * num_upload_buffers + kUploadDataSize,
tombergan5d22c182017-01-11 02:05:357787 LOWEST, nullptr, 0));
[email protected]d11b6912013-06-27 23:07:327788
7789 // Full frames.
Ryan Hamilton0239aac2018-05-19 00:03:137790 spdy::SpdySerializedFrame body1(
Bence Békyd74f4382018-02-20 18:26:197791 spdy_util_.ConstructSpdyDataFrame(1, content, false));
[email protected]d11b6912013-06-27 23:07:327792
xunjieli179a6e72016-04-26 19:47:457793 // Last frame in each upload data buffer.
Ryan Hamilton0239aac2018-05-19 00:03:137794 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197795 1,
7796 base::StringPiece(content.data(), kBufferSize % kMaxSpdyFrameChunkSize),
7797 false));
[email protected]d11b6912013-06-27 23:07:327798
xunjieli179a6e72016-04-26 19:47:457799 // The very last frame before the stalled frames.
Ryan Hamilton0239aac2018-05-19 00:03:137800 spdy::SpdySerializedFrame body3(spdy_util_.ConstructSpdyDataFrame(
Bence Békyd74f4382018-02-20 18:26:197801 1,
7802 base::StringPiece(content.data(), initial_window_size % kBufferSize %
7803 kMaxSpdyFrameChunkSize),
7804 false));
xunjieli179a6e72016-04-26 19:47:457805
7806 // Data frames to be sent once WINDOW_UPDATE frame is received.
7807
7808 // If kBufferSize * num_upload_buffers > initial_window_size,
7809 // we need one additional frame to send the rest of 'a'.
Bence Béky4e83f492018-05-13 23:14:257810 std::string last_body(kBufferSize * num_upload_buffers - initial_window_size,
7811 'a');
Ryan Hamilton0239aac2018-05-19 00:03:137812 spdy::SpdySerializedFrame body4(
Bence Békyd74f4382018-02-20 18:26:197813 spdy_util_.ConstructSpdyDataFrame(1, last_body, false));
xunjieli179a6e72016-04-26 19:47:457814
7815 // Also send a "hello!" after WINDOW_UPDATE.
Ryan Hamilton0239aac2018-05-19 00:03:137816 spdy::SpdySerializedFrame body5(spdy_util_.ConstructSpdyDataFrame(1, true));
[email protected]d11b6912013-06-27 23:07:327817
xunjieli179a6e72016-04-26 19:47:457818 // Fill in mock writes.
[email protected]d11b6912013-06-27 23:07:327819 size_t i = 0;
xunjieli179a6e72016-04-26 19:47:457820 std::vector<MockWrite> writes;
bncdf80d44fd2016-07-15 20:27:417821 writes.push_back(CreateMockWrite(req, i++));
xunjieli179a6e72016-04-26 19:47:457822 for (size_t j = 0; j < num_upload_buffers; j++) {
7823 for (size_t k = 0; k < num_frames_in_one_upload_buffer; k++) {
7824 if (k == num_frames_in_one_upload_buffer - 1 &&
7825 kBufferSize % kMaxSpdyFrameChunkSize != 0) {
7826 if (j == num_upload_buffers - 1 &&
7827 (initial_window_size % kBufferSize != 0)) {
bncdf80d44fd2016-07-15 20:27:417828 writes.push_back(CreateMockWrite(body3, i++));
xunjieli179a6e72016-04-26 19:47:457829 } else {
bncdf80d44fd2016-07-15 20:27:417830 writes.push_back(CreateMockWrite(body2, i++));
xunjieli179a6e72016-04-26 19:47:457831 }
7832 } else {
bncdf80d44fd2016-07-15 20:27:417833 writes.push_back(CreateMockWrite(body1, i++));
xunjieli179a6e72016-04-26 19:47:457834 }
7835 }
7836 }
[email protected]d11b6912013-06-27 23:07:327837
xunjieli179a6e72016-04-26 19:47:457838 // Fill in mock reads.
7839 std::vector<MockRead> reads;
7840 // Force a pause.
mmenke666a6fea2015-12-19 04:16:337841 reads.push_back(MockRead(ASYNC, ERR_IO_PENDING, i++));
[email protected]d11b6912013-06-27 23:07:327842 // Construct read frame for SETTINGS that makes the send_window_size
7843 // negative.
Ryan Hamilton0239aac2018-05-19 00:03:137844 spdy::SettingsMap new_settings;
7845 new_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] = initial_window_size / 2;
7846 spdy::SpdySerializedFrame settings_frame_small(
[email protected]d11b6912013-06-27 23:07:327847 spdy_util_.ConstructSpdySettings(new_settings));
7848 // Construct read frames for WINDOW_UPDATE that makes the send_window_size
7849 // positive.
Ryan Hamilton0239aac2018-05-19 00:03:137850 spdy::SpdySerializedFrame session_window_update_init_size(
bnc2f54c832014-12-01 13:31:197851 spdy_util_.ConstructSpdyWindowUpdate(0, initial_window_size));
Ryan Hamilton0239aac2018-05-19 00:03:137852 spdy::SpdySerializedFrame window_update_init_size(
bnc2f54c832014-12-01 13:31:197853 spdy_util_.ConstructSpdyWindowUpdate(1, initial_window_size));
[email protected]d11b6912013-06-27 23:07:327854
bncdf80d44fd2016-07-15 20:27:417855 reads.push_back(CreateMockRead(settings_frame_small, i++));
7856 reads.push_back(CreateMockRead(session_window_update_init_size, i++));
7857 reads.push_back(CreateMockRead(window_update_init_size, i++));
[email protected]d11b6912013-06-27 23:07:327858
Ryan Hamilton0239aac2018-05-19 00:03:137859 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
bncdf80d44fd2016-07-15 20:27:417860 writes.push_back(CreateMockWrite(settings_ack, i++));
[email protected]d4a77c12014-05-15 20:45:217861
xunjieli179a6e72016-04-26 19:47:457862 // Stalled frames which can be sent after |settings_ack|.
7863 if (last_body.size() > 0)
bncdf80d44fd2016-07-15 20:27:417864 writes.push_back(CreateMockWrite(body4, i++));
7865 writes.push_back(CreateMockWrite(body5, i++));
[email protected]d11b6912013-06-27 23:07:327866
Ryan Hamilton0239aac2018-05-19 00:03:137867 spdy::SpdySerializedFrame reply(
7868 spdy_util_.ConstructSpdyPostReply(nullptr, 0));
bncdf80d44fd2016-07-15 20:27:417869 reads.push_back(CreateMockRead(reply, i++));
7870 reads.push_back(CreateMockRead(body2, i++));
7871 reads.push_back(CreateMockRead(body5, i++));
[email protected]d11b6912013-06-27 23:07:327872 reads.push_back(MockRead(ASYNC, 0, i++)); // EOF
7873
7874 // Force all writes to happen before any read, last write will not
7875 // actually queue a frame, due to window size being 0.
Ryan Sleevib8d7ea02018-05-07 20:01:017876 SequencedSocketData data(reads, writes);
[email protected]d11b6912013-06-27 23:07:327877
danakjaee3e1ec2016-04-16 00:23:187878 std::vector<std::unique_ptr<UploadElementReader>> element_readers;
Bence Béky4e83f492018-05-13 23:14:257879 std::string upload_data_string(kBufferSize * num_upload_buffers, 'a');
[email protected]d11b6912013-06-27 23:07:327880 upload_data_string.append(kUploadData, kUploadDataSize);
Jeremy Roman0579ed62017-08-29 15:56:197881 element_readers.push_back(std::make_unique<UploadBytesElementReader>(
bnc3f6a8552017-05-17 13:40:347882 upload_data_string.c_str(), upload_data_string.size()));
olli.raula6df48b2a2015-11-26 07:40:227883 ElementsUploadDataStream upload_data_stream(std::move(element_readers), 0);
[email protected]d11b6912013-06-27 23:07:327884
Bence Békydb3cf652017-10-10 15:22:107885 request_.method = "POST";
7886 request_.upload_data_stream = &upload_data_stream;
7887 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
7888
[email protected]d11b6912013-06-27 23:07:327889 helper.RunPreTestSetup();
mmenke666a6fea2015-12-19 04:16:337890 helper.AddData(&data);
[email protected]d11b6912013-06-27 23:07:327891
7892 HttpNetworkTransaction* trans = helper.trans();
7893
7894 TestCompletionCallback callback;
Bence Békydb3cf652017-10-10 15:22:107895 int rv = trans->Start(&request_, callback.callback(), log_);
robpercival214763f2016-07-01 23:27:017896 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
[email protected]d11b6912013-06-27 23:07:327897
mmenke666a6fea2015-12-19 04:16:337898 data.RunUntilPaused(); // Write as much as we can.
7899 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327900
7901 SpdyHttpStream* stream = static_cast<SpdyHttpStream*>(trans->stream_.get());
wezca1070932016-05-26 20:30:527902 ASSERT_TRUE(stream);
7903 ASSERT_TRUE(stream->stream());
[email protected]d11b6912013-06-27 23:07:327904 EXPECT_EQ(0, stream->stream()->send_window_size());
7905
xunjieli179a6e72016-04-26 19:47:457906 if (initial_window_size % kBufferSize != 0) {
7907 // If it does not take whole number of full upload buffer to zero out
7908 // initial window size, then the upload data is not at EOF, because the
7909 // last read must be stalled.
7910 EXPECT_FALSE(upload_data_stream.IsEOF());
7911 } else {
7912 // All the body data should have been read.
7913 // TODO(satorux): This is because of the weirdness in reading the request
7914 // body in OnSendBodyComplete(). See crbug.com/113107.
7915 EXPECT_TRUE(upload_data_stream.IsEOF());
7916 }
[email protected]d11b6912013-06-27 23:07:327917
7918 // Read in WINDOW_UPDATE or SETTINGS frame.
mmenke666a6fea2015-12-19 04:16:337919 data.Resume();
7920 base::RunLoop().RunUntilIdle();
[email protected]d11b6912013-06-27 23:07:327921 rv = callback.WaitForResult();
7922 helper.VerifyDataConsumed();
7923}
7924
bncd16676a2016-07-20 16:23:017925TEST_F(SpdyNetworkTransactionTest, GoAwayOnOddPushStreamId) {
Bence Békyeacd48f2018-05-14 11:34:337926 base::HistogramTester histogram_tester;
7927
Bence Béky4c325e52020-10-22 20:48:017928 spdy::Http2HeaderBlock push_headers;
bnc086b39e12016-06-24 13:05:267929 spdy_util_.AddUrlToHeaderBlock("http://www.example.org/a.dat", &push_headers);
Ryan Hamilton0239aac2018-05-19 00:03:137930 spdy::SpdySerializedFrame push(
Bence Békyf1d78522018-01-11 01:16:507931 spdy_util_.ConstructSpdyPushPromise(1, 3, std::move(push_headers)));
bncdf80d44fd2016-07-15 20:27:417932 MockRead reads[] = {CreateMockRead(push, 1)};
baranovich212a1292014-09-02 21:45:317933
Ryan Hamilton0239aac2018-05-19 00:03:137934 spdy::SpdySerializedFrame req(
7935 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7936 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
7937 0, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:567938 "Received invalid pushed stream id 3 (must be even) on stream id 1."));
baranovich212a1292014-09-02 21:45:317939 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:417940 CreateMockWrite(req, 0), CreateMockWrite(goaway, 2),
baranovich212a1292014-09-02 21:45:317941 };
7942
Ryan Sleevib8d7ea02018-05-07 20:01:017943 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107944 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
baranovich212a1292014-09-02 21:45:317945 helper.RunToCompletion(&data);
7946 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:187947 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
Bence Békyeacd48f2018-05-14 11:34:337948
7949 histogram_tester.ExpectBucketCount(
7950 "Net.SpdyPushedStreamFate",
7951 static_cast<int>(SpdyPushedStreamFate::kPromisedStreamIdParityError), 1);
7952 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
baranovich212a1292014-09-02 21:45:317953}
7954
bncd16676a2016-07-20 16:23:017955TEST_F(SpdyNetworkTransactionTest,
baranovich212a1292014-09-02 21:45:317956 GoAwayOnPushStreamIdLesserOrEqualThanLastAccepted) {
Bence Békyeacd48f2018-05-14 11:34:337957 base::HistogramTester histogram_tester;
7958
Ryan Hamilton0239aac2018-05-19 00:03:137959 spdy::SpdySerializedFrame push_a(spdy_util_.ConstructSpdyPush(
Bence Béky3e01b532018-02-06 23:04:517960 nullptr, 0, 4, 1, "https://www.example.org/a.dat"));
Bence Béky4c325e52020-10-22 20:48:017961 spdy::Http2HeaderBlock push_b_headers;
Bence Béky3e01b532018-02-06 23:04:517962 spdy_util_.AddUrlToHeaderBlock("https://www.example.org/b.dat",
bnc086b39e12016-06-24 13:05:267963 &push_b_headers);
Ryan Hamilton0239aac2018-05-19 00:03:137964 spdy::SpdySerializedFrame push_b(
Bence Békyf1d78522018-01-11 01:16:507965 spdy_util_.ConstructSpdyPushPromise(1, 2, std::move(push_b_headers)));
baranovich212a1292014-09-02 21:45:317966 MockRead reads[] = {
tombergan5d22c182017-01-11 02:05:357967 CreateMockRead(push_a, 1), CreateMockRead(push_b, 3),
baranovich212a1292014-09-02 21:45:317968 };
7969
Ryan Hamilton0239aac2018-05-19 00:03:137970 spdy::SpdySerializedFrame req(
7971 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
7972 spdy::SpdySerializedFrame priority_a(
tombergan5d22c182017-01-11 02:05:357973 spdy_util_.ConstructSpdyPriority(4, 1, IDLE, true));
Ryan Hamilton0239aac2018-05-19 00:03:137974 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
7975 4, spdy::ERROR_CODE_PROTOCOL_ERROR,
Bence Béky602c40c2017-07-26 05:22:567976 "Received pushed stream id 2 must be larger than last accepted id 4."));
baranovich212a1292014-09-02 21:45:317977 MockWrite writes[] = {
tombergan5d22c182017-01-11 02:05:357978 CreateMockWrite(req, 0), CreateMockWrite(priority_a, 2),
7979 CreateMockWrite(goaway, 4),
baranovich212a1292014-09-02 21:45:317980 };
7981
Ryan Sleevib8d7ea02018-05-07 20:01:017982 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:107983 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
baranovich212a1292014-09-02 21:45:317984 helper.RunToCompletion(&data);
7985 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:187986 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
Bence Békyeacd48f2018-05-14 11:34:337987
7988 histogram_tester.ExpectBucketCount(
7989 "Net.SpdyPushedStreamFate",
7990 static_cast<int>(SpdyPushedStreamFate::kStreamIdOutOfOrder), 1);
7991 histogram_tester.ExpectTotalCount("Net.SpdyPushedStreamFate", 1);
baranovich212a1292014-09-02 21:45:317992}
7993
bnc76598ab2015-06-29 12:43:077994// Regression test for https://crbug.com/493348: request header exceeds 16 kB
7995// and thus sent in multiple frames when using HTTP/2.
bncd16676a2016-07-20 16:23:017996TEST_F(SpdyNetworkTransactionTest, LargeRequest) {
Bence Béky4e83f492018-05-13 23:14:257997 const std::string kKey("foo");
7998 const std::string kValue(1 << 15, 'z');
bnc76598ab2015-06-29 12:43:077999
Bence Békydb3cf652017-10-10 15:22:108000 request_.extra_headers.SetHeader(kKey, kValue);
bnc76598ab2015-06-29 12:43:078001
Bence Béky4c325e52020-10-22 20:48:018002 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:138003 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
bnc086b39e12016-06-24 13:05:268004 headers[kKey] = kValue;
Ryan Hamilton0239aac2018-05-19 00:03:138005 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:158006 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bnc76598ab2015-06-29 12:43:078007 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:418008 CreateMockWrite(req, 0),
bnc76598ab2015-06-29 12:43:078009 };
8010
Ryan Hamilton0239aac2018-05-19 00:03:138011 spdy::SpdySerializedFrame resp(
8012 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8013 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc76598ab2015-06-29 12:43:078014 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:418015 CreateMockRead(resp, 1), CreateMockRead(body, 2),
bnc76598ab2015-06-29 12:43:078016 MockRead(ASYNC, 0, 3) // EOF
8017 };
8018
Ryan Sleevib8d7ea02018-05-07 20:01:018019 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108020 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc76598ab2015-06-29 12:43:078021 helper.RunToCompletion(&data);
8022 TransactionHelperResult out = helper.output();
8023
robpercival214763f2016-07-01 23:27:018024 EXPECT_THAT(out.rv, IsOk());
bnc84e7fb52015-12-02 11:50:028025 EXPECT_EQ("HTTP/1.1 200", out.status_line);
bnc76598ab2015-06-29 12:43:078026 EXPECT_EQ("hello!", out.response_data);
8027}
8028
bncd67383342016-01-08 21:58:438029// Regression test for https://crbug.com/535629: response header exceeds 16 kB.
bncd16676a2016-07-20 16:23:018030TEST_F(SpdyNetworkTransactionTest, LargeResponseHeader) {
Bence Béky4c325e52020-10-22 20:48:018031 spdy::Http2HeaderBlock headers(
Ryan Hamilton0239aac2018-05-19 00:03:138032 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
8033 spdy::SpdySerializedFrame req(
bnc42331402016-07-25 13:36:158034 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), LOWEST, true));
bncd67383342016-01-08 21:58:438035 MockWrite writes[] = {
bncdf80d44fd2016-07-15 20:27:418036 CreateMockWrite(req, 0),
bncd67383342016-01-08 21:58:438037 };
8038
8039 // HPACK decoder implementation limits string literal length to 16 kB.
8040 const char* response_headers[2];
Bence Béky4e83f492018-05-13 23:14:258041 const std::string kKey(16 * 1024, 'a');
bncd67383342016-01-08 21:58:438042 response_headers[0] = kKey.data();
Bence Béky4e83f492018-05-13 23:14:258043 const std::string kValue(16 * 1024, 'b');
bncd67383342016-01-08 21:58:438044 response_headers[1] = kValue.data();
8045
Ryan Hamilton0239aac2018-05-19 00:03:138046 spdy::SpdySerializedFrame resp(
bnc42331402016-07-25 13:36:158047 spdy_util_.ConstructSpdyGetReply(response_headers, 1, 1));
Ryan Hamilton0239aac2018-05-19 00:03:138048 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncd67383342016-01-08 21:58:438049 MockRead reads[] = {
bncdf80d44fd2016-07-15 20:27:418050 CreateMockRead(resp, 1), CreateMockRead(body, 2),
bncd67383342016-01-08 21:58:438051 MockRead(ASYNC, 0, 3) // EOF
8052 };
8053
Bence Békydb3cf652017-10-10 15:22:108054 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncd67383342016-01-08 21:58:438055
Ryan Sleevib8d7ea02018-05-07 20:01:018056 SequencedSocketData data(reads, writes);
bncd67383342016-01-08 21:58:438057 helper.RunToCompletion(&data);
8058 TransactionHelperResult out = helper.output();
8059
robpercival214763f2016-07-01 23:27:018060 EXPECT_THAT(out.rv, IsOk());
bncd67383342016-01-08 21:58:438061 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8062 EXPECT_EQ("hello!", out.response_data);
8063 ASSERT_TRUE(out.response_info.headers->HasHeaderValue(kKey, kValue));
8064}
8065
bnc204a6d02016-08-01 14:34:278066// End of line delimiter is forbidden according to RFC 7230 Section 3.2.
8067TEST_F(SpdyNetworkTransactionTest, CRLFInHeaderValue) {
Ryan Hamilton0239aac2018-05-19 00:03:138068 spdy::SpdySerializedFrame req(
8069 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
8070 spdy::SpdySerializedFrame rst(
8071 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_PROTOCOL_ERROR));
bnc204a6d02016-08-01 14:34:278072 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(rst, 2)};
8073
8074 const char* response_headers[] = {"folded", "foo\r\nbar"};
Ryan Hamilton0239aac2018-05-19 00:03:138075 spdy::SpdySerializedFrame resp(
bnc204a6d02016-08-01 14:34:278076 spdy_util_.ConstructSpdyGetReply(response_headers, 1, 1));
8077 MockRead reads[] = {CreateMockRead(resp, 1), MockRead(ASYNC, 0, 3)};
8078
Ryan Sleevib8d7ea02018-05-07 20:01:018079 SequencedSocketData data(reads, writes);
bnc204a6d02016-08-01 14:34:278080
Bence Békydb3cf652017-10-10 15:22:108081 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc204a6d02016-08-01 14:34:278082 helper.RunToCompletion(&data);
8083 TransactionHelperResult out = helper.output();
8084
Bence Békyd0d69502019-06-25 19:47:188085 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
bnc204a6d02016-08-01 14:34:278086}
8087
bncc22b581e82016-10-27 04:45:428088// Regression test for https://crbug.com/603182.
8089// No response headers received before RST_STREAM: error.
8090TEST_F(SpdyNetworkTransactionTest, RstStreamNoError) {
Ryan Hamilton0239aac2018-05-19 00:03:138091 spdy::SpdySerializedFrame req(
8092 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bncc22b581e82016-10-27 04:45:428093 MockWrite writes[] = {CreateMockWrite(req, 0, ASYNC)};
8094
Ryan Hamilton0239aac2018-05-19 00:03:138095 spdy::SpdySerializedFrame rst(
8096 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
bncc22b581e82016-10-27 04:45:428097 MockRead reads[] = {CreateMockRead(rst, 1), MockRead(ASYNC, 0, 2)};
8098
Ryan Sleevib8d7ea02018-05-07 20:01:018099 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108100 UseChunkedPostRequest();
8101 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc22b581e82016-10-27 04:45:428102 helper.RunToCompletion(&data);
8103 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188104 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_PROTOCOL_ERROR));
bncc22b581e82016-10-27 04:45:428105}
8106
8107// Regression test for https://crbug.com/603182.
8108// Response headers and data, then RST_STREAM received,
8109// before request body is sent: success.
8110TEST_F(SpdyNetworkTransactionTest, RstStreamNoErrorAfterResponse) {
Ryan Hamilton0239aac2018-05-19 00:03:138111 spdy::SpdySerializedFrame req(
8112 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bncc22b581e82016-10-27 04:45:428113 MockWrite writes[] = {CreateMockWrite(req, 0, ASYNC)};
8114
Ryan Hamilton0239aac2018-05-19 00:03:138115 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
8116 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
8117 spdy::SpdySerializedFrame rst(
8118 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
bncc22b581e82016-10-27 04:45:428119 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8120 CreateMockRead(rst, 3), MockRead(ASYNC, 0, 4)};
8121
Ryan Sleevib8d7ea02018-05-07 20:01:018122 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108123 UseChunkedPostRequest();
8124 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc22b581e82016-10-27 04:45:428125 helper.RunToCompletion(&data);
8126 TransactionHelperResult out = helper.output();
8127 EXPECT_THAT(out.rv, IsOk());
8128 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8129 EXPECT_EQ("hello!", out.response_data);
8130}
8131
bncc9f762a2016-12-06 20:38:238132TEST_F(SpdyNetworkTransactionTest, 100Continue) {
Ryan Hamilton0239aac2018-05-19 00:03:138133 spdy::SpdySerializedFrame req(
8134 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bncc9f762a2016-12-06 20:38:238135 MockWrite writes[] = {CreateMockWrite(req, 0)};
8136
Bence Béky4c325e52020-10-22 20:48:018137 spdy::Http2HeaderBlock informational_headers;
Ryan Hamilton0239aac2018-05-19 00:03:138138 informational_headers[spdy::kHttp2StatusHeader] = "100";
8139 spdy::SpdySerializedFrame informational_response(
bncc9f762a2016-12-06 20:38:238140 spdy_util_.ConstructSpdyReply(1, std::move(informational_headers)));
Ryan Hamilton0239aac2018-05-19 00:03:138141 spdy::SpdySerializedFrame resp(
8142 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8143 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bncc9f762a2016-12-06 20:38:238144 MockRead reads[] = {
8145 CreateMockRead(informational_response, 1), CreateMockRead(resp, 2),
8146 CreateMockRead(body, 3), MockRead(ASYNC, 0, 4) // EOF
8147 };
8148
Ryan Sleevib8d7ea02018-05-07 20:01:018149 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108150 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bncc9f762a2016-12-06 20:38:238151 helper.RunToCompletion(&data);
8152 TransactionHelperResult out = helper.output();
8153 EXPECT_THAT(out.rv, IsOk());
8154 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8155 EXPECT_EQ("hello!", out.response_data);
8156}
8157
bnc1ff80872016-12-16 20:57:578158// "A server can send a complete response prior to the client sending an entire
8159// request if the response does not depend on any portion of the request that
8160// has not been sent and received." (RFC7540 Section 8.1)
8161// Regression test for https://crbug.com/606990. Server responds before POST
8162// data are sent and closes connection: this must result in
Bence Békyd0d69502019-06-25 19:47:188163// ERR_CONNECTION_CLOSED (as opposed to ERR_HTTP2_PROTOCOL_ERROR).
bnc1ff80872016-12-16 20:57:578164TEST_F(SpdyNetworkTransactionTest, ResponseBeforePostDataSent) {
Ryan Hamilton0239aac2018-05-19 00:03:138165 spdy::SpdySerializedFrame req(
8166 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bnc1ff80872016-12-16 20:57:578167 MockWrite writes[] = {CreateMockWrite(req, 0)};
8168
Ryan Hamilton0239aac2018-05-19 00:03:138169 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
8170 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc1ff80872016-12-16 20:57:578171 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8172 MockRead(ASYNC, 0, 3)};
8173
Ryan Sleevib8d7ea02018-05-07 20:01:018174 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108175 UseChunkedPostRequest();
8176 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1ff80872016-12-16 20:57:578177
8178 helper.RunPreTestSetup();
8179 helper.AddData(&data);
8180 helper.StartDefaultTest();
8181 EXPECT_THAT(helper.output().rv, IsError(ERR_IO_PENDING));
8182 helper.WaitForCallbackToComplete();
8183 EXPECT_THAT(helper.output().rv, IsError(ERR_CONNECTION_CLOSED));
8184}
8185
8186// Regression test for https://crbug.com/606990.
8187// Server responds before POST data are sent and resets stream with NO_ERROR.
8188TEST_F(SpdyNetworkTransactionTest, ResponseAndRstStreamBeforePostDataSent) {
Ryan Hamilton0239aac2018-05-19 00:03:138189 spdy::SpdySerializedFrame req(
8190 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
bnc1ff80872016-12-16 20:57:578191 MockWrite writes[] = {CreateMockWrite(req, 0)};
8192
Ryan Hamilton0239aac2018-05-19 00:03:138193 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
8194 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
8195 spdy::SpdySerializedFrame rst(
8196 spdy_util_.ConstructSpdyRstStream(1, spdy::ERROR_CODE_NO_ERROR));
bnc1ff80872016-12-16 20:57:578197 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8198 CreateMockRead(rst, 3), MockRead(ASYNC, 0, 4)};
8199
Ryan Sleevib8d7ea02018-05-07 20:01:018200 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108201 UseChunkedPostRequest();
8202 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc1ff80872016-12-16 20:57:578203
8204 helper.RunToCompletion(&data);
8205
8206 TransactionHelperResult out = helper.output();
8207 EXPECT_THAT(out.rv, IsOk());
8208 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8209 EXPECT_EQ("hello!", out.response_data);
8210}
8211
bnc96487ec2017-03-29 19:40:238212// Unsupported frames must be ignored. This is especially important for frame
8213// type 0xb, which used to be the BLOCKED frame in previous versions of SPDY,
8214// but is going to be used for the ORIGIN frame.
8215// TODO(bnc): Implement ORIGIN frame support. https://crbug.com/697333
8216TEST_F(SpdyNetworkTransactionTest, IgnoreUnsupportedOriginFrame) {
Ryan Hamilton0239aac2018-05-19 00:03:138217 spdy::SpdySerializedFrame req(
8218 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
bnc96487ec2017-03-29 19:40:238219 MockWrite writes[] = {CreateMockWrite(req, 0)};
8220
8221 const char origin_frame_on_stream_zero[] = {
8222 0x00, 0x00, 0x05, // Length
8223 0x0b, // Type
8224 0x00, // Flags
8225 0x00, 0x00, 0x00, 0x00, // Stream ID
8226 0x00, 0x03, // Origin-Len
8227 'f', 'o', 'o' // ASCII-Origin
8228 };
8229
8230 const char origin_frame_on_stream_one[] = {
8231 0x00, 0x00, 0x05, // Length
8232 0x0b, // Type
8233 0x00, // Flags
8234 0x00, 0x00, 0x00, 0x01, // Stream ID
8235 0x00, 0x03, // Origin-Len
8236 'b', 'a', 'r' // ASCII-Origin
8237 };
8238
Ryan Hamilton0239aac2018-05-19 00:03:138239 spdy::SpdySerializedFrame resp(
8240 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8241 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
bnc96487ec2017-03-29 19:40:238242 MockRead reads[] = {MockRead(ASYNC, origin_frame_on_stream_zero,
Avi Drissman4365a4782018-12-28 19:26:248243 base::size(origin_frame_on_stream_zero), 1),
bnc96487ec2017-03-29 19:40:238244 CreateMockRead(resp, 2),
8245 MockRead(ASYNC, origin_frame_on_stream_one,
Avi Drissman4365a4782018-12-28 19:26:248246 base::size(origin_frame_on_stream_one), 3),
bnc96487ec2017-03-29 19:40:238247 CreateMockRead(body, 4), MockRead(ASYNC, 0, 5)};
8248
Ryan Sleevib8d7ea02018-05-07 20:01:018249 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108250 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
bnc96487ec2017-03-29 19:40:238251 helper.RunToCompletion(&data);
8252 TransactionHelperResult out = helper.output();
8253 EXPECT_THAT(out.rv, IsOk());
8254 EXPECT_EQ("HTTP/1.1 200", out.status_line);
8255 EXPECT_EQ("hello!", out.response_data);
8256}
8257
[email protected]514aeaf2014-05-23 10:31:518258class SpdyNetworkTransactionTLSUsageCheckTest
8259 : public SpdyNetworkTransactionTest {
8260 protected:
danakjaee3e1ec2016-04-16 00:23:188261 void RunTLSUsageCheckTest(
8262 std::unique_ptr<SSLSocketDataProvider> ssl_provider) {
Ryan Hamilton0239aac2018-05-19 00:03:138263 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
8264 0, spdy::ERROR_CODE_INADEQUATE_SECURITY, ""));
bncdf80d44fd2016-07-15 20:27:418265 MockWrite writes[] = {CreateMockWrite(goaway)};
[email protected]514aeaf2014-05-23 10:31:518266
Ryan Sleevib8d7ea02018-05-07 20:01:018267 StaticSocketDataProvider data(base::span<MockRead>(), writes);
Bence Békydb3cf652017-10-10 15:22:108268 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:318269 nullptr);
dchengc7eeda422015-12-26 03:56:488270 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:518271 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188272 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY));
[email protected]514aeaf2014-05-23 10:31:518273 }
8274};
8275
bncd16676a2016-07-20 16:23:018276TEST_F(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
Jeremy Roman0579ed62017-08-29 15:56:198277 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
[email protected]514aeaf2014-05-23 10:31:518278 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
Ryan Sleevi4f832092017-11-21 23:25:498279 &ssl_provider->ssl_info.connection_status);
[email protected]514aeaf2014-05-23 10:31:518280
dchengc7eeda422015-12-26 03:56:488281 RunTLSUsageCheckTest(std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:518282}
8283
bncd16676a2016-07-20 16:23:018284TEST_F(SpdyNetworkTransactionTLSUsageCheckTest, TLSCipherSuiteSucky) {
Jeremy Roman0579ed62017-08-29 15:56:198285 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
[email protected]514aeaf2014-05-23 10:31:518286 // Set to TLS_RSA_WITH_NULL_MD5
Ryan Sleevi4f832092017-11-21 23:25:498287 SSLConnectionStatusSetCipherSuite(0x1,
8288 &ssl_provider->ssl_info.connection_status);
[email protected]514aeaf2014-05-23 10:31:518289
dchengc7eeda422015-12-26 03:56:488290 RunTLSUsageCheckTest(std::move(ssl_provider));
[email protected]514aeaf2014-05-23 10:31:518291}
8292
Bence Béky306378f2017-06-30 12:09:568293// Regression test for https://crbug.com/737143.
8294// This test sets up an old TLS version just like in TLSVersionTooOld,
Ryan Hamilton0239aac2018-05-19 00:03:138295// and makes sure that it results in an spdy::ERROR_CODE_INADEQUATE_SECURITY
Bence Béky306378f2017-06-30 12:09:568296// even for a non-secure request URL.
8297TEST_F(SpdyNetworkTransactionTest, InsecureUrlCreatesSecureSpdySession) {
Jeremy Roman0579ed62017-08-29 15:56:198298 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
Bence Béky306378f2017-06-30 12:09:568299 SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_SSL3,
Ryan Sleevi4f832092017-11-21 23:25:498300 &ssl_provider->ssl_info.connection_status);
Bence Béky306378f2017-06-30 12:09:568301
Ryan Hamilton0239aac2018-05-19 00:03:138302 spdy::SpdySerializedFrame goaway(spdy_util_.ConstructSpdyGoAway(
8303 0, spdy::ERROR_CODE_INADEQUATE_SECURITY, ""));
Bence Béky306378f2017-06-30 12:09:568304 MockWrite writes[] = {CreateMockWrite(goaway)};
Ryan Sleevib8d7ea02018-05-07 20:01:018305 StaticSocketDataProvider data(base::span<MockRead>(), writes);
Bence Béky306378f2017-06-30 12:09:568306
Bence Békydb3cf652017-10-10 15:22:108307 request_.url = GURL("http://www.example.org/");
Bence Béky306378f2017-06-30 12:09:568308
8309 // Need secure proxy so that insecure URL can use HTTP/2.
Jeremy Roman0579ed62017-08-29 15:56:198310 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:568311 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Ramin Halavatica8d5252018-03-12 05:33:498312 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Békydb3cf652017-10-10 15:22:108313 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
Bence Békyd3dde832017-09-19 19:02:318314 std::move(session_deps));
Bence Béky306378f2017-06-30 12:09:568315
8316 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
8317 TransactionHelperResult out = helper.output();
Bence Békyd0d69502019-06-25 19:47:188318 EXPECT_THAT(out.rv, IsError(ERR_HTTP2_INADEQUATE_TRANSPORT_SECURITY));
Bence Békydb3cf652017-10-10 15:22:108319}
Bence Béky306378f2017-06-30 12:09:568320
Andrey Kosyakov83a6eee2017-08-14 19:20:048321TEST_F(SpdyNetworkTransactionTest, RequestHeadersCallback) {
Ryan Hamilton0239aac2018-05-19 00:03:138322 spdy::SpdySerializedFrame req(
Bence Béky27ad0a12018-02-08 00:35:488323 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
Andrey Kosyakov83a6eee2017-08-14 19:20:048324 MockWrite writes[] = {CreateMockWrite(req, 0)};
8325
Ryan Hamilton0239aac2018-05-19 00:03:138326 spdy::SpdySerializedFrame resp(
8327 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8328 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Andrey Kosyakov83a6eee2017-08-14 19:20:048329 MockRead reads[] = {
8330 CreateMockRead(resp, 1), CreateMockRead(body, 2),
8331 MockRead(ASYNC, 0, 3) // EOF
8332 };
8333
8334 HttpRawRequestHeaders raw_headers;
8335
Ryan Sleevib8d7ea02018-05-07 20:01:018336 SequencedSocketData data(reads, writes);
Bence Békydb3cf652017-10-10 15:22:108337 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
Andrey Kosyakov83a6eee2017-08-14 19:20:048338 helper.RunPreTestSetup();
8339 helper.AddData(&data);
Steve Kobes530eb142020-07-08 18:15:518340 helper.trans()->SetRequestHeadersCallback(base::BindRepeating(
Andrey Kosyakov83a6eee2017-08-14 19:20:048341 &HttpRawRequestHeaders::Assign, base::Unretained(&raw_headers)));
8342 helper.StartDefaultTest();
8343 helper.FinishDefaultTestWithoutVerification();
8344 EXPECT_FALSE(raw_headers.headers().empty());
8345 std::string value;
8346 EXPECT_TRUE(raw_headers.FindHeaderForTest(":path", &value));
8347 EXPECT_EQ("/", value);
8348 EXPECT_TRUE(raw_headers.FindHeaderForTest(":method", &value));
8349 EXPECT_EQ("GET", value);
8350 EXPECT_TRUE(raw_headers.request_line().empty());
8351}
8352
Yoav Weiss9693572f2018-01-04 09:37:348353// A request that has adopted a push promise and later got reset by the server
8354// should be retried on a new stream.
8355// Regression test for https://crbug.com/798508.
8356TEST_F(SpdyNetworkTransactionTest, PushCanceledByServerAfterClaimed) {
8357 const char pushed_url[] = "https://www.example.org/a.dat";
8358 // Construct a request to the default URL on stream 1.
Ryan Hamilton0239aac2018-05-19 00:03:138359 spdy::SpdySerializedFrame req(
8360 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
8361 spdy::SpdySerializedFrame req2(
8362 spdy_util_.ConstructSpdyGet(pushed_url, 3, LOWEST));
Yoav Weiss9693572f2018-01-04 09:37:348363 // Construct a priority frame for stream 2.
Ryan Hamilton0239aac2018-05-19 00:03:138364 spdy::SpdySerializedFrame priority(
Yoav Weiss9693572f2018-01-04 09:37:348365 spdy_util_.ConstructSpdyPriority(2, 1, IDLE, true));
8366 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(priority, 3),
8367 CreateMockWrite(req2, 6)};
8368
8369 // Construct a Push Promise frame, with no response.
Ryan Hamilton0239aac2018-05-19 00:03:138370 spdy::SpdySerializedFrame push_promise(spdy_util_.ConstructSpdyPushPromise(
Bence Békyf1d78522018-01-11 01:16:508371 1, 2, spdy_util_.ConstructGetHeaderBlock(pushed_url)));
Yoav Weiss9693572f2018-01-04 09:37:348372 // Construct a RST frame, canceling stream 2.
Ryan Hamilton0239aac2018-05-19 00:03:138373 spdy::SpdySerializedFrame rst_server(
8374 spdy_util_.ConstructSpdyRstStream(2, spdy::ERROR_CODE_CANCEL));
Yoav Weiss9693572f2018-01-04 09:37:348375 // Construct response headers and bodies.
Ryan Hamilton0239aac2018-05-19 00:03:138376 spdy::SpdySerializedFrame resp1(
8377 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8378 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8379 spdy::SpdySerializedFrame resp2(
8380 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
8381 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
Yoav Weiss9693572f2018-01-04 09:37:348382 MockRead reads[] = {
8383 CreateMockRead(push_promise, 1), MockRead(ASYNC, ERR_IO_PENDING, 2),
8384 CreateMockRead(rst_server, 4), MockRead(ASYNC, ERR_IO_PENDING, 5),
8385 CreateMockRead(resp1, 7), CreateMockRead(body1, 8),
8386 CreateMockRead(resp2, 9), CreateMockRead(body2, 10),
8387 MockRead(ASYNC, 0, 11)};
8388
Ryan Sleevib8d7ea02018-05-07 20:01:018389 SequencedSocketData data(reads, writes);
Yoav Weiss9693572f2018-01-04 09:37:348390
8391 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
8392
8393 helper.RunPreTestSetup();
8394 helper.AddData(&data);
8395
8396 HttpNetworkTransaction* trans = helper.trans();
8397
8398 // First request to start the connection.
8399 TestCompletionCallback callback1;
8400 int rv = trans->Start(&request_, callback1.callback(), log_);
8401 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
8402
8403 data.RunUntilPaused();
8404
8405 // Get a SpdySession.
8406 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:118407 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348408 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
8409 NetworkIsolationKey(), false /* disable_secure_dns */);
Yoav Weiss9693572f2018-01-04 09:37:348410 HttpNetworkSession* session = helper.session();
8411 base::WeakPtr<SpdySession> spdy_session =
8412 session->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:318413 key, /* enable_ip_based_pooling = */ true,
8414 /* is_websocket = */ false, log_);
Yoav Weiss9693572f2018-01-04 09:37:348415
8416 // Verify that there is one unclaimed push stream.
8417 EXPECT_EQ(1u, num_unclaimed_pushed_streams(spdy_session));
8418
8419 // Claim the pushed stream.
8420 HttpNetworkTransaction transaction2(DEFAULT_PRIORITY, session);
8421 TestCompletionCallback callback2;
8422 HttpRequestInfo request2;
8423 request2.method = "GET";
8424 request2.url = GURL(pushed_url);
Ramin Halavatib5e433e62018-02-07 07:41:108425 request2.traffic_annotation =
8426 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Yoav Weiss9693572f2018-01-04 09:37:348427 transaction2.Start(&request2, callback2.callback(), log_);
8428 base::RunLoop().RunUntilIdle();
8429 EXPECT_EQ(3u, spdy_stream_hi_water_mark(spdy_session));
8430
8431 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
8432
8433 // Continue reading and get the RST.
8434 data.Resume();
8435 base::RunLoop().RunUntilIdle();
8436
8437 // Make sure we got the RST and retried the request.
8438 EXPECT_EQ(2u, num_active_streams(spdy_session));
8439 EXPECT_EQ(0u, num_unclaimed_pushed_streams(spdy_session));
8440 EXPECT_EQ(5u, spdy_stream_hi_water_mark(spdy_session));
8441
8442 data.Resume();
8443
8444 // Test that transactions succeeded.
8445 rv = callback1.WaitForResult();
8446 ASSERT_THAT(rv, IsOk());
8447
8448 rv = callback2.WaitForResult();
8449 ASSERT_THAT(rv, IsOk());
8450
8451 // Read EOF.
8452 base::RunLoop().RunUntilIdle();
8453
8454 // Verify that all data was read and written.
8455 helper.VerifyDataConsumed();
8456}
8457
Bence Béky0ca719f2018-01-31 13:41:198458#if BUILDFLAG(ENABLE_WEBSOCKETS)
Bence Béky8bfacd42018-02-23 13:05:138459
8460TEST_F(SpdyNetworkTransactionTest, WebSocketOpensNewConnection) {
Bence Békyb09dddf12018-07-31 18:52:048461 base::HistogramTester histogram_tester;
Bence Béky0ca719f2018-01-31 13:41:198462 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
8463 helper.RunPreTestSetup();
8464
8465 // First request opens up an HTTP/2 connection.
Ryan Hamilton0239aac2018-05-19 00:03:138466 spdy::SpdySerializedFrame req(
Bence Béky8bfacd42018-02-23 13:05:138467 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
Bence Béky0ca719f2018-01-31 13:41:198468 MockWrite writes1[] = {CreateMockWrite(req, 0)};
8469
Ryan Hamilton0239aac2018-05-19 00:03:138470 spdy::SpdySerializedFrame resp(
8471 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8472 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
Bence Béky0ca719f2018-01-31 13:41:198473 MockRead reads1[] = {CreateMockRead(resp, 1), CreateMockRead(body, 2),
8474 MockRead(ASYNC, ERR_IO_PENDING, 3),
8475 MockRead(ASYNC, 0, 4)};
8476
Ryan Sleevib8d7ea02018-05-07 20:01:018477 SequencedSocketData data1(reads1, writes1);
Bence Béky0ca719f2018-01-31 13:41:198478 helper.AddData(&data1);
8479
Bence Béky8bfacd42018-02-23 13:05:138480 // WebSocket request opens a new connection with HTTP/2 disabled.
Bence Béky0ca719f2018-01-31 13:41:198481 MockWrite writes2[] = {
8482 MockWrite("GET / HTTP/1.1\r\n"
8483 "Host: www.example.org\r\n"
8484 "Connection: Upgrade\r\n"
8485 "Upgrade: websocket\r\n"
8486 "Origin: http://www.example.org\r\n"
8487 "Sec-WebSocket-Version: 13\r\n"
Bence Béky8d1c6052018-02-07 12:48:158488 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
8489 "Sec-WebSocket-Extensions: permessage-deflate; "
8490 "client_max_window_bits\r\n\r\n")};
Bence Béky0ca719f2018-01-31 13:41:198491
Bence Béky8d1c6052018-02-07 12:48:158492 MockRead reads2[] = {
8493 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
8494 "Upgrade: websocket\r\n"
8495 "Connection: Upgrade\r\n"
8496 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
8497
Ryan Sleevib8d7ea02018-05-07 20:01:018498 StaticSocketDataProvider data2(reads2, writes2);
Bence Béky0ca719f2018-01-31 13:41:198499
8500 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
8501 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
8502 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
8503 // Force socket to use HTTP/1.1, the default protocol without ALPN.
8504 ssl_provider2->next_proto = kProtoHTTP11;
8505 ssl_provider2->ssl_info.cert =
8506 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
8507 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
8508
8509 TestCompletionCallback callback1;
8510 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
8511 int rv = trans1.Start(&request_, callback1.callback(), log_);
8512 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8513 rv = callback1.WaitForResult();
8514 ASSERT_THAT(rv, IsOk());
8515
8516 const HttpResponseInfo* response = trans1.GetResponseInfo();
8517 ASSERT_TRUE(response->headers);
8518 EXPECT_TRUE(response->was_fetched_via_spdy);
8519 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8520
8521 std::string response_data;
8522 rv = ReadTransaction(&trans1, &response_data);
8523 EXPECT_THAT(rv, IsOk());
8524 EXPECT_EQ("hello!", response_data);
8525
8526 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:118527 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348528 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
8529 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky0ca719f2018-01-31 13:41:198530 base::WeakPtr<SpdySession> spdy_session =
8531 helper.session()->spdy_session_pool()->FindAvailableSession(
Bence Békyd885b2b2018-02-03 00:58:318532 key, /* enable_ip_based_pooling = */ true,
8533 /* is_websocket = */ false, log_);
Bence Béky0ca719f2018-01-31 13:41:198534 ASSERT_TRUE(spdy_session);
Bence Békyd885b2b2018-02-03 00:58:318535 EXPECT_FALSE(spdy_session->support_websocket());
Bence Béky0ca719f2018-01-31 13:41:198536
8537 HttpRequestInfo request2;
8538 request2.method = "GET";
8539 request2.url = GURL("wss://www.example.org/");
Ramin Halavatib5e433e62018-02-07 07:41:108540 request2.traffic_annotation =
8541 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
Bence Béky0ca719f2018-01-31 13:41:198542 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8543 .Equals(HostPortPair::FromURL(request2.url)));
8544 request2.extra_headers.SetHeader("Connection", "Upgrade");
8545 request2.extra_headers.SetHeader("Upgrade", "websocket");
8546 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8547 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
Bence Béky8d1c6052018-02-07 12:48:158548
8549 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
Bence Béky0ca719f2018-01-31 13:41:198550
8551 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
Bence Béky0ca719f2018-01-31 13:41:198552 trans2.SetWebSocketHandshakeStreamCreateHelper(
8553 &websocket_stream_create_helper);
8554
8555 TestCompletionCallback callback2;
8556 rv = trans2.Start(&request2, callback2.callback(), log_);
8557 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8558 rv = callback2.WaitForResult();
8559 ASSERT_THAT(rv, IsOk());
8560
Bence Béky8bfacd42018-02-23 13:05:138561 // HTTP/2 connection is still open, but WebSocket request did not pool to it.
Bence Béky0ca719f2018-01-31 13:41:198562 ASSERT_TRUE(spdy_session);
8563
Bence Béky0ca719f2018-01-31 13:41:198564 data1.Resume();
Bence Békyb09dddf12018-07-31 18:52:048565 base::RunLoop().RunUntilIdle();
Bence Béky0ca719f2018-01-31 13:41:198566 helper.VerifyDataConsumed();
Bence Békyb09dddf12018-07-31 18:52:048567
8568 // Server did not advertise WebSocket support.
8569 histogram_tester.ExpectUniqueSample("Net.SpdySession.ServerSupportsWebSocket",
8570 /* support_websocket = false */ 0,
8571 /* expected_count = */ 1);
Bence Béky0ca719f2018-01-31 13:41:198572}
Bence Béky8bfacd42018-02-23 13:05:138573
Matt Menke77173952019-04-18 17:42:148574// Make sure that a WebSocket job doesn't pick up a newly created SpdySession
8575// that doesn't support WebSockets through
8576// HttpStreamFactory::Job::OnSpdySessionAvailable().
8577TEST_F(SpdyNetworkTransactionTest,
8578 WebSocketDoesUseNewH2SessionWithoutWebSocketSupport) {
8579 base::HistogramTester histogram_tester;
8580 auto session_deps = std::make_unique<SpdySessionDependencies>();
8581 session_deps->enable_websocket_over_http2 = true;
8582 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
8583 std::move(session_deps));
8584 helper.RunPreTestSetup();
8585
8586 spdy::SpdySerializedFrame req(
8587 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8588
8589 MockWrite writes[] = {CreateMockWrite(req, 0)};
8590
8591 spdy::SpdySerializedFrame resp1(
8592 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8593 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8594 MockRead reads[] = {CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
8595 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 3)};
8596
8597 SequencedSocketData data(
8598 // Just as with other operations, this means to pause during connection
8599 // establishment.
8600 MockConnect(ASYNC, ERR_IO_PENDING), reads, writes);
8601 helper.AddData(&data);
8602
8603 MockWrite writes2[] = {
8604 MockWrite(SYNCHRONOUS, 0,
8605 "GET / HTTP/1.1\r\n"
8606 "Host: www.example.org\r\n"
8607 "Connection: Upgrade\r\n"
8608 "Upgrade: websocket\r\n"
8609 "Origin: http://www.example.org\r\n"
8610 "Sec-WebSocket-Version: 13\r\n"
8611 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
8612 "Sec-WebSocket-Extensions: permessage-deflate; "
8613 "client_max_window_bits\r\n\r\n")};
8614
8615 MockRead reads2[] = {
8616 MockRead(SYNCHRONOUS, 1,
8617 "HTTP/1.1 101 Switching Protocols\r\n"
8618 "Upgrade: websocket\r\n"
8619 "Connection: Upgrade\r\n"
8620 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
8621 SequencedSocketData data2(MockConnect(ASYNC, ERR_IO_PENDING), reads2,
8622 writes2);
8623 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
8624 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
8625 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
8626 // Force socket to use HTTP/1.1, the default protocol without ALPN.
8627 ssl_provider2->next_proto = kProtoHTTP11;
Matt Menke77173952019-04-18 17:42:148628 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
8629
8630 TestCompletionCallback callback1;
8631 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
8632 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8633
8634 // Create HTTP/2 connection.
8635 base::RunLoop().RunUntilIdle();
8636
8637 HttpRequestInfo request2;
8638 request2.method = "GET";
8639 request2.url = GURL("wss://www.example.org/");
8640 request2.traffic_annotation =
8641 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
8642 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8643 .Equals(HostPortPair::FromURL(request2.url)));
8644 request2.extra_headers.SetHeader("Connection", "Upgrade");
8645 request2.extra_headers.SetHeader("Upgrade", "websocket");
8646 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8647 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
8648
8649 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
8650
8651 HttpNetworkTransaction trans2(MEDIUM, helper.session());
8652 trans2.SetWebSocketHandshakeStreamCreateHelper(
8653 &websocket_stream_create_helper);
8654
8655 TestCompletionCallback callback2;
8656 rv = trans2.Start(&request2, callback2.callback(), log_);
8657 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8658
8659 // Run until waiting on both connections.
8660 base::RunLoop().RunUntilIdle();
8661
8662 // The H2 connection completes.
8663 data.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8664 EXPECT_EQ(OK, callback1.WaitForResult());
8665 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
8666 ASSERT_TRUE(response->headers);
8667 EXPECT_TRUE(response->was_fetched_via_spdy);
8668 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8669 std::string response_data;
8670 rv = ReadTransaction(helper.trans(), &response_data);
8671 EXPECT_THAT(rv, IsOk());
8672 EXPECT_EQ("hello!", response_data);
8673
8674 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
8675 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348676 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
8677 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke77173952019-04-18 17:42:148678
8679 base::WeakPtr<SpdySession> spdy_session =
8680 helper.session()->spdy_session_pool()->FindAvailableSession(
8681 key, /* enable_ip_based_pooling = */ true,
8682 /* is_websocket = */ false, log_);
8683 ASSERT_TRUE(spdy_session);
8684 EXPECT_FALSE(spdy_session->support_websocket());
8685
8686 EXPECT_FALSE(callback2.have_result());
8687
8688 // Create WebSocket stream.
8689 data2.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8690
8691 rv = callback2.WaitForResult();
8692 ASSERT_THAT(rv, IsOk());
8693 helper.VerifyDataConsumed();
8694}
8695
Bence Béky8bfacd42018-02-23 13:05:138696TEST_F(SpdyNetworkTransactionTest, WebSocketOverHTTP2) {
Bence Békyb09dddf12018-07-31 18:52:048697 base::HistogramTester histogram_tester;
Bence Béky8bfacd42018-02-23 13:05:138698 auto session_deps = std::make_unique<SpdySessionDependencies>();
8699 session_deps->enable_websocket_over_http2 = true;
Bence Béky7a4836c2018-05-08 03:52:488700 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
Bence Béky8bfacd42018-02-23 13:05:138701 std::move(session_deps));
8702 helper.RunPreTestSetup();
8703
Ryan Hamilton0239aac2018-05-19 00:03:138704 spdy::SpdySerializedFrame req(
8705 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8706 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
Bence Béky8bfacd42018-02-23 13:05:138707
Bence Béky4c325e52020-10-22 20:48:018708 spdy::Http2HeaderBlock websocket_request_headers;
Ryan Hamilton0239aac2018-05-19 00:03:138709 websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
8710 websocket_request_headers[spdy::kHttp2AuthorityHeader] = "www.example.org";
8711 websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
8712 websocket_request_headers[spdy::kHttp2PathHeader] = "/";
8713 websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
Bence Béky8bfacd42018-02-23 13:05:138714 websocket_request_headers["origin"] = "http://www.example.org";
8715 websocket_request_headers["sec-websocket-version"] = "13";
8716 websocket_request_headers["sec-websocket-extensions"] =
8717 "permessage-deflate; client_max_window_bits";
Ryan Hamilton0239aac2018-05-19 00:03:138718 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
Bence Béky7a4836c2018-05-08 03:52:488719 3, std::move(websocket_request_headers), MEDIUM, false));
8720
Bence Béky73b85292018-06-14 04:56:438721 spdy::SpdySerializedFrame priority1(
8722 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
8723 spdy::SpdySerializedFrame priority2(
8724 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
8725
8726 MockWrite writes[] = {
8727 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 2),
8728 CreateMockWrite(websocket_request, 4), CreateMockWrite(priority1, 5),
8729 CreateMockWrite(priority2, 6)};
Bence Béky8bfacd42018-02-23 13:05:138730
Ryan Hamilton0239aac2018-05-19 00:03:138731 spdy::SettingsMap settings;
8732 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
8733 spdy::SpdySerializedFrame settings_frame(
Bence Béky8bfacd42018-02-23 13:05:138734 spdy_util_.ConstructSpdySettings(settings));
Ryan Hamilton0239aac2018-05-19 00:03:138735 spdy::SpdySerializedFrame resp1(
8736 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8737 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8738 spdy::SpdySerializedFrame websocket_response(
Bence Béky8bfacd42018-02-23 13:05:138739 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
Bence Béky73b85292018-06-14 04:56:438740 MockRead reads[] = {CreateMockRead(settings_frame, 1),
8741 CreateMockRead(resp1, 3), CreateMockRead(body1, 7),
8742 CreateMockRead(websocket_response, 8),
8743 MockRead(ASYNC, 0, 9)};
Bence Béky8bfacd42018-02-23 13:05:138744
Ryan Sleevib8d7ea02018-05-07 20:01:018745 SequencedSocketData data(reads, writes);
Bence Béky8bfacd42018-02-23 13:05:138746 helper.AddData(&data);
8747
8748 TestCompletionCallback callback1;
Bence Béky7a4836c2018-05-08 03:52:488749 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
Bence Béky8bfacd42018-02-23 13:05:138750 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky8bfacd42018-02-23 13:05:138751
Bence Béky7a4836c2018-05-08 03:52:488752 // Create HTTP/2 connection.
8753 base::RunLoop().RunUntilIdle();
Bence Béky8bfacd42018-02-23 13:05:138754
8755 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
Matt Menke2436b2f2018-12-11 18:07:118756 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:348757 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
8758 NetworkIsolationKey(), false /* disable_secure_dns */);
Bence Béky8bfacd42018-02-23 13:05:138759 base::WeakPtr<SpdySession> spdy_session =
8760 helper.session()->spdy_session_pool()->FindAvailableSession(
8761 key, /* enable_ip_based_pooling = */ true,
8762 /* is_websocket = */ true, log_);
8763 ASSERT_TRUE(spdy_session);
8764 EXPECT_TRUE(spdy_session->support_websocket());
8765
8766 HttpRequestInfo request2;
8767 request2.method = "GET";
8768 request2.url = GURL("wss://www.example.org/");
8769 request2.traffic_annotation =
8770 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
8771 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8772 .Equals(HostPortPair::FromURL(request2.url)));
8773 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8774 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
8775 // The following two headers must be removed by WebSocketHttp2HandshakeStream.
8776 request2.extra_headers.SetHeader("Connection", "Upgrade");
8777 request2.extra_headers.SetHeader("Upgrade", "websocket");
8778
8779 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
8780
Bence Béky7a4836c2018-05-08 03:52:488781 HttpNetworkTransaction trans2(MEDIUM, helper.session());
Bence Béky8bfacd42018-02-23 13:05:138782 trans2.SetWebSocketHandshakeStreamCreateHelper(
8783 &websocket_stream_create_helper);
8784
8785 TestCompletionCallback callback2;
8786 rv = trans2.Start(&request2, callback2.callback(), log_);
8787 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
Bence Béky7a4836c2018-05-08 03:52:488788
8789 // Create WebSocket stream.
8790 base::RunLoop().RunUntilIdle();
Bence Béky73b85292018-06-14 04:56:438791 ASSERT_TRUE(spdy_session);
8792
8793 // First request has HIGHEST priority, WebSocket request has MEDIUM priority.
8794 // Changing the priority of the first request to LOWEST changes their order,
8795 // and therefore triggers sending PRIORITY frames.
8796 helper.trans()->SetPriority(LOWEST);
Bence Béky7a4836c2018-05-08 03:52:488797
8798 rv = callback1.WaitForResult();
8799 ASSERT_THAT(rv, IsOk());
8800
8801 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
8802 ASSERT_TRUE(response->headers);
8803 EXPECT_TRUE(response->was_fetched_via_spdy);
8804 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8805
8806 std::string response_data;
8807 rv = ReadTransaction(helper.trans(), &response_data);
8808 EXPECT_THAT(rv, IsOk());
8809 EXPECT_EQ("hello!", response_data);
8810
Bence Béky8bfacd42018-02-23 13:05:138811 rv = callback2.WaitForResult();
8812 ASSERT_THAT(rv, IsOk());
8813
Bence Béky8bfacd42018-02-23 13:05:138814 helper.VerifyDataConsumed();
Bence Békyb09dddf12018-07-31 18:52:048815
8816 // Server advertised WebSocket support.
8817 histogram_tester.ExpectUniqueSample("Net.SpdySession.ServerSupportsWebSocket",
8818 /* support_websocket = true */ 1,
8819 /* expected_count = */ 1);
Bence Béky8bfacd42018-02-23 13:05:138820}
8821
Matt Menke7269f352019-10-03 17:05:298822// Make sure that a WebSocket job doesn't pick up a newly created SpdySession
8823// that supports WebSockets through an HTTPS proxy when an H2 server doesn't
8824// support websockets and |enable_websocket_over_http2| is false. See
8825// https://crbug.com/1010491.
8826TEST_F(SpdyNetworkTransactionTest,
8827 WebSocketDoesNotUseNewH2SessionWithoutWebSocketSupportOverHttpsProxy) {
8828 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:568829 ConfiguredProxyResolutionService::CreateFixed(
8830 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Matt Menke7269f352019-10-03 17:05:298831
8832 // Note: Once WebSocket over H2 is enabled by default, this line can be
8833 // deleted, and this test will still be useful to keep, though its description
8834 // will need to be updated.
8835 session_deps->enable_websocket_over_http2 = false;
8836
8837 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
8838 std::move(session_deps));
8839 helper.RunPreTestSetup();
8840
8841 spdy::SpdySerializedFrame req(
8842 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8843
8844 MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0,
8845 "CONNECT www.example.org:443 HTTP/1.1\r\n"
8846 "Host: www.example.org:443\r\n"
8847 "Proxy-Connection: keep-alive\r\n\r\n"),
8848 CreateMockWrite(req, 2)};
8849
8850 spdy::SpdySerializedFrame resp1(
8851 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
8852 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
8853 MockRead reads[] = {MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
8854 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
8855 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
8856
8857 // SSL data for the proxy.
8858 SSLSocketDataProvider tunnel_ssl_data(ASYNC, OK);
8859 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
8860 &tunnel_ssl_data);
8861
8862 SequencedSocketData data(
8863 // Just as with other operations, this means to pause during connection
8864 // establishment.
8865 MockConnect(ASYNC, ERR_IO_PENDING), reads, writes);
8866 helper.AddData(&data);
8867
8868 MockWrite writes2[] = {
8869 MockWrite(SYNCHRONOUS, 0,
8870 "CONNECT www.example.org:443 HTTP/1.1\r\n"
8871 "Host: www.example.org:443\r\n"
8872 "Proxy-Connection: keep-alive\r\n\r\n"),
8873 MockWrite(SYNCHRONOUS, 2,
8874 "GET / HTTP/1.1\r\n"
8875 "Host: www.example.org\r\n"
8876 "Connection: Upgrade\r\n"
8877 "Upgrade: websocket\r\n"
8878 "Origin: http://www.example.org\r\n"
8879 "Sec-WebSocket-Version: 13\r\n"
8880 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
8881 "Sec-WebSocket-Extensions: permessage-deflate; "
8882 "client_max_window_bits\r\n\r\n")};
8883
8884 MockRead reads2[] = {
8885 MockRead(SYNCHRONOUS, 1, "HTTP/1.1 200 OK\r\n\r\n"),
8886 MockRead(SYNCHRONOUS, 3,
8887 "HTTP/1.1 101 Switching Protocols\r\n"
8888 "Upgrade: websocket\r\n"
8889 "Connection: Upgrade\r\n"
8890 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
8891 SequencedSocketData data2(MockConnect(ASYNC, ERR_IO_PENDING), reads2,
8892 writes2);
8893
8894 // SSL data for the proxy.
8895 SSLSocketDataProvider tunnel_ssl_data2(ASYNC, OK);
8896 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
8897 &tunnel_ssl_data2);
8898
8899 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
8900 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
8901 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
8902 // Force socket to use HTTP/1.1, the default protocol without ALPN.
8903 ssl_provider2->next_proto = kProtoHTTP11;
8904 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
8905
8906 TestCompletionCallback callback1;
8907 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
8908 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8909
8910 // Create HTTP/2 connection.
8911 base::RunLoop().RunUntilIdle();
8912
8913 HttpRequestInfo request2;
8914 request2.method = "GET";
8915 request2.url = GURL("wss://www.example.org/");
8916 request2.traffic_annotation =
8917 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
8918 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
8919 .Equals(HostPortPair::FromURL(request2.url)));
8920 request2.extra_headers.SetHeader("Connection", "Upgrade");
8921 request2.extra_headers.SetHeader("Upgrade", "websocket");
8922 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
8923 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
8924
8925 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
8926
8927 HttpNetworkTransaction trans2(MEDIUM, helper.session());
8928 trans2.SetWebSocketHandshakeStreamCreateHelper(
8929 &websocket_stream_create_helper);
8930
8931 TestCompletionCallback callback2;
8932 rv = trans2.Start(&request2, callback2.callback(), log_);
8933 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
8934
8935 // Run until waiting on both connections.
8936 base::RunLoop().RunUntilIdle();
8937
8938 // The H2 connection completes.
8939 data.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8940 EXPECT_EQ(OK, callback1.WaitForResult());
8941 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
8942 ASSERT_TRUE(response->headers);
8943 EXPECT_TRUE(response->was_fetched_via_spdy);
8944 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
8945 std::string response_data;
8946 rv = ReadTransaction(helper.trans(), &response_data);
8947 EXPECT_THAT(rv, IsOk());
8948 EXPECT_EQ("hello!", response_data);
8949
8950 SpdySessionKey key(
8951 HostPortPair::FromURL(request_.url),
8952 ProxyServer::FromURI("https://proxy:70", ProxyServer::SCHEME_HTTPS),
8953 PRIVACY_MODE_DISABLED, SpdySessionKey::IsProxySession::kFalse,
dalyk51ab46b2019-10-15 15:14:348954 SocketTag(), NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke7269f352019-10-03 17:05:298955
8956 base::WeakPtr<SpdySession> spdy_session =
8957 helper.session()->spdy_session_pool()->FindAvailableSession(
8958 key, /* enable_ip_based_pooling = */ true,
8959 /* is_websocket = */ false, log_);
8960 ASSERT_TRUE(spdy_session);
8961 EXPECT_FALSE(spdy_session->support_websocket());
8962
8963 EXPECT_FALSE(callback2.have_result());
8964
8965 // Create WebSocket stream.
8966 data2.socket()->OnConnectComplete(MockConnect(SYNCHRONOUS, OK));
8967
8968 rv = callback2.WaitForResult();
8969 ASSERT_THAT(rv, IsOk());
8970 helper.VerifyDataConsumed();
8971}
8972
Matt Menke5062be22019-05-01 17:50:248973// Same as above, but checks that a WebSocket connection avoids creating a new
8974// socket if it detects an H2 session when host resolution completes, and
8975// requests also use different hostnames.
8976TEST_F(SpdyNetworkTransactionTest,
8977 WebSocketOverHTTP2DetectsNewSessionWithAliasing) {
8978 base::HistogramTester histogram_tester;
8979 auto session_deps = std::make_unique<SpdySessionDependencies>();
8980 session_deps->enable_websocket_over_http2 = true;
8981 session_deps->host_resolver->set_ondemand_mode(true);
8982 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
8983 std::move(session_deps));
8984 helper.RunPreTestSetup();
8985
8986 spdy::SpdySerializedFrame req(
8987 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
8988 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
8989
Bence Béky4c325e52020-10-22 20:48:018990 spdy::Http2HeaderBlock websocket_request_headers;
Matt Menke5062be22019-05-01 17:50:248991 websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
8992 websocket_request_headers[spdy::kHttp2AuthorityHeader] = "example.test";
8993 websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
8994 websocket_request_headers[spdy::kHttp2PathHeader] = "/";
8995 websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
8996 websocket_request_headers["origin"] = "http://example.test";
8997 websocket_request_headers["sec-websocket-version"] = "13";
8998 websocket_request_headers["sec-websocket-extensions"] =
8999 "permessage-deflate; client_max_window_bits";
9000 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
9001 3, std::move(websocket_request_headers), MEDIUM, false));
9002
9003 spdy::SpdySerializedFrame priority1(
9004 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
9005 spdy::SpdySerializedFrame priority2(
9006 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
9007
9008 MockWrite writes[] = {
9009 CreateMockWrite(req, 0), CreateMockWrite(settings_ack, 2),
9010 CreateMockWrite(websocket_request, 4), CreateMockWrite(priority1, 5),
9011 CreateMockWrite(priority2, 6)};
9012
9013 spdy::SettingsMap settings;
9014 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
9015 spdy::SpdySerializedFrame settings_frame(
9016 spdy_util_.ConstructSpdySettings(settings));
9017 spdy::SpdySerializedFrame resp1(
9018 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9019 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9020 spdy::SpdySerializedFrame websocket_response(
9021 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9022 MockRead reads[] = {CreateMockRead(settings_frame, 1),
9023 CreateMockRead(resp1, 3), CreateMockRead(body1, 7),
9024 CreateMockRead(websocket_response, 8),
9025 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 9)};
9026
9027 SequencedSocketData data(reads, writes);
9028 helper.AddData(&data);
9029
9030 TestCompletionCallback callback1;
9031 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
9032 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9033
9034 HttpRequestInfo request2;
9035 request2.method = "GET";
9036 request2.url = GURL("wss://example.test/");
9037 request2.traffic_annotation =
9038 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9039 request2.extra_headers.SetHeader("Origin", "http://example.test");
9040 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9041 // The following two headers must be removed by WebSocketHttp2HandshakeStream.
9042 request2.extra_headers.SetHeader("Connection", "Upgrade");
9043 request2.extra_headers.SetHeader("Upgrade", "websocket");
9044
9045 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9046
9047 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9048 trans2.SetWebSocketHandshakeStreamCreateHelper(
9049 &websocket_stream_create_helper);
9050
9051 TestCompletionCallback callback2;
9052 rv = trans2.Start(&request2, callback2.callback(), log_);
9053 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9054
9055 // Make sure both requests are blocked on host resolution.
9056 base::RunLoop().RunUntilIdle();
9057
9058 EXPECT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
9059 // Complete the first DNS lookup, which should result in the first transaction
9060 // creating an H2 session (And completing successfully).
9061 helper.session_deps()->host_resolver->ResolveNow(1);
9062 base::RunLoop().RunUntilIdle();
9063
9064 SpdySessionKey key1(HostPortPair::FromURL(request_.url),
9065 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349066 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9067 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:249068 base::WeakPtr<SpdySession> spdy_session1 =
9069 helper.session()->spdy_session_pool()->FindAvailableSession(
9070 key1, /* enable_ip_based_pooling = */ true,
9071 /* is_websocket = */ false, log_);
9072 ASSERT_TRUE(spdy_session1);
9073 EXPECT_TRUE(spdy_session1->support_websocket());
9074
9075 // Second DNS lookup completes, which results in creating a WebSocket stream.
9076 helper.session_deps()->host_resolver->ResolveNow(2);
9077 ASSERT_TRUE(spdy_session1);
9078
9079 SpdySessionKey key2(HostPortPair::FromURL(request2.url),
9080 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349081 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9082 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:249083 base::WeakPtr<SpdySession> spdy_session2 =
9084 helper.session()->spdy_session_pool()->FindAvailableSession(
9085 key1, /* enable_ip_based_pooling = */ true,
9086 /* is_websocket = */ true, log_);
9087 ASSERT_TRUE(spdy_session2);
9088 EXPECT_EQ(spdy_session1.get(), spdy_session2.get());
9089
9090 base::RunLoop().RunUntilIdle();
9091
9092 // First request has HIGHEST priority, WebSocket request has MEDIUM priority.
9093 // Changing the priority of the first request to LOWEST changes their order,
9094 // and therefore triggers sending PRIORITY frames.
9095 helper.trans()->SetPriority(LOWEST);
9096
9097 rv = callback1.WaitForResult();
9098 ASSERT_THAT(rv, IsOk());
9099
9100 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
9101 ASSERT_TRUE(response->headers);
9102 EXPECT_TRUE(response->was_fetched_via_spdy);
9103 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
9104
9105 std::string response_data;
9106 rv = ReadTransaction(helper.trans(), &response_data);
9107 EXPECT_THAT(rv, IsOk());
9108 EXPECT_EQ("hello!", response_data);
9109
9110 rv = callback2.WaitForResult();
9111 ASSERT_THAT(rv, IsOk());
9112
9113 helper.VerifyDataConsumed();
9114}
9115
9116// Same as above, but the SpdySession is closed just before use, so the
9117// WebSocket is sent over a new HTTP/1.x connection instead.
9118TEST_F(SpdyNetworkTransactionTest,
9119 WebSocketOverDetectsNewSessionWithAliasingButClosedBeforeUse) {
9120 base::HistogramTester histogram_tester;
9121 auto session_deps = std::make_unique<SpdySessionDependencies>();
9122 session_deps->enable_websocket_over_http2 = true;
9123 session_deps->host_resolver->set_ondemand_mode(true);
9124 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
9125 std::move(session_deps));
9126 helper.RunPreTestSetup();
9127
9128 spdy::SpdySerializedFrame req(
9129 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
9130 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
9131
9132 MockWrite writes[] = {CreateMockWrite(req, 0),
9133 CreateMockWrite(settings_ack, 2)};
9134
9135 spdy::SettingsMap settings;
9136 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
9137 spdy::SpdySerializedFrame settings_frame(
9138 spdy_util_.ConstructSpdySettings(settings));
9139 spdy::SpdySerializedFrame resp1(
9140 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9141 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9142 MockRead reads[] = {CreateMockRead(settings_frame, 1),
9143 CreateMockRead(resp1, 3), CreateMockRead(body1, 4),
9144 MockRead(SYNCHRONOUS, ERR_IO_PENDING, 5)};
9145
9146 SequencedSocketData data(reads, writes);
9147 helper.AddData(&data);
9148
9149 MockWrite writes2[] = {
9150 MockWrite("GET / HTTP/1.1\r\n"
9151 "Host: example.test\r\n"
9152 "Connection: Upgrade\r\n"
9153 "Upgrade: websocket\r\n"
9154 "Origin: http://example.test\r\n"
9155 "Sec-WebSocket-Version: 13\r\n"
9156 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9157 "Sec-WebSocket-Extensions: permessage-deflate; "
9158 "client_max_window_bits\r\n\r\n")};
9159 MockRead reads2[] = {
9160 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
9161 "Upgrade: websocket\r\n"
9162 "Connection: Upgrade\r\n"
9163 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
9164 StaticSocketDataProvider data2(reads2, writes2);
9165 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9166 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9167 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
9168 // Force socket to use HTTP/1.1, the default protocol without ALPN.
9169 ssl_provider2->next_proto = kProtoHTTP11;
9170 ssl_provider2->ssl_info.cert =
9171 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
9172 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9173
9174 TestCompletionCallback callback1;
9175 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
9176 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9177
9178 HttpRequestInfo request2;
9179 request2.method = "GET";
9180 request2.url = GURL("wss://example.test/");
9181 request2.traffic_annotation =
9182 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9183 request2.extra_headers.SetHeader("Connection", "Upgrade");
9184 request2.extra_headers.SetHeader("Upgrade", "websocket");
9185 request2.extra_headers.SetHeader("Origin", "http://example.test");
9186 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9187
9188 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9189
9190 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9191 trans2.SetWebSocketHandshakeStreamCreateHelper(
9192 &websocket_stream_create_helper);
9193
9194 TestCompletionCallback callback2;
9195 rv = trans2.Start(&request2, callback2.callback(), log_);
9196 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9197
9198 // Make sure both requests are blocked on host resolution.
9199 base::RunLoop().RunUntilIdle();
9200
9201 EXPECT_TRUE(helper.session_deps()->host_resolver->has_pending_requests());
9202 // Complete the first DNS lookup, which should result in the first transaction
9203 // creating an H2 session (And completing successfully).
9204 helper.session_deps()->host_resolver->ResolveNow(1);
9205
9206 // Complete first request.
9207 rv = callback1.WaitForResult();
9208 ASSERT_THAT(rv, IsOk());
9209 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
9210 ASSERT_TRUE(response->headers);
9211 EXPECT_TRUE(response->was_fetched_via_spdy);
9212 EXPECT_EQ("HTTP/1.1 200", response->headers->GetStatusLine());
9213 std::string response_data;
9214 rv = ReadTransaction(helper.trans(), &response_data);
9215 EXPECT_THAT(rv, IsOk());
9216 EXPECT_EQ("hello!", response_data);
9217
9218 SpdySessionKey key1(HostPortPair::FromURL(request_.url),
9219 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349220 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9221 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:249222 base::WeakPtr<SpdySession> spdy_session1 =
9223 helper.session()->spdy_session_pool()->FindAvailableSession(
9224 key1, /* enable_ip_based_pooling = */ true,
9225 /* is_websocket = */ false, log_);
9226 ASSERT_TRUE(spdy_session1);
9227 EXPECT_TRUE(spdy_session1->support_websocket());
9228
9229 // Second DNS lookup completes, which results in creating an alias for the
9230 // SpdySession immediately, and a task is posted asynchronously to use the
9231 // alias..
9232 helper.session_deps()->host_resolver->ResolveNow(2);
9233
9234 SpdySessionKey key2(HostPortPair::FromURL(request2.url),
9235 ProxyServer::Direct(), PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349236 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9237 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menke5062be22019-05-01 17:50:249238 base::WeakPtr<SpdySession> spdy_session2 =
9239 helper.session()->spdy_session_pool()->FindAvailableSession(
9240 key1, /* enable_ip_based_pooling = */ true,
9241 /* is_websocket = */ true, log_);
9242 ASSERT_TRUE(spdy_session2);
9243 EXPECT_EQ(spdy_session1.get(), spdy_session2.get());
9244
9245 // But the session is closed before it can be used.
9246 helper.session()->spdy_session_pool()->CloseAllSessions();
9247
9248 // The second request establishes another connection (without even doing
9249 // another DNS lookup) instead, and uses HTTP/1.x.
9250 rv = callback2.WaitForResult();
9251 ASSERT_THAT(rv, IsOk());
9252
9253 helper.VerifyDataConsumed();
9254}
9255
Bence Békyfbeb8832018-04-05 23:19:569256TEST_F(SpdyNetworkTransactionTest, WebSocketNegotiatesHttp2) {
9257 HttpRequestInfo request;
9258 request.method = "GET";
9259 request.url = GURL("wss://www.example.org/");
9260 request.traffic_annotation =
9261 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9262 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
9263 .Equals(HostPortPair::FromURL(request.url)));
9264 request.extra_headers.SetHeader("Connection", "Upgrade");
9265 request.extra_headers.SetHeader("Upgrade", "websocket");
9266 request.extra_headers.SetHeader("Origin", "http://www.example.org");
9267 request.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9268
9269 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
9270 helper.RunPreTestSetup();
9271
Ryan Sleevib8d7ea02018-05-07 20:01:019272 StaticSocketDataProvider data;
Bence Békyfbeb8832018-04-05 23:19:569273
9274 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9275 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9276 ssl_provider->next_protos_expected_in_ssl_config = NextProtoVector{};
Bence Békyb4a07f8f2018-05-17 14:31:559277 // Force socket to use HTTP/2, which should never happen (TLS implementation
9278 // should fail TLS handshake if server chooses HTTP/2 without client
9279 // advertising support).
Bence Békyfbeb8832018-04-05 23:19:569280 ssl_provider->next_proto = kProtoHTTP2;
9281 ssl_provider->ssl_info.cert =
9282 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
9283 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
9284
9285 HttpNetworkTransaction* trans = helper.trans();
9286 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9287 trans->SetWebSocketHandshakeStreamCreateHelper(
9288 &websocket_stream_create_helper);
9289
9290 TestCompletionCallback callback;
9291 int rv = trans->Start(&request, callback.callback(), log_);
9292 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9293 rv = callback.WaitForResult();
9294 ASSERT_THAT(rv, IsError(ERR_NOT_IMPLEMENTED));
9295
9296 helper.VerifyDataConsumed();
9297}
9298
Matt Menkef2ee07c2019-08-29 02:10:369299TEST_F(SpdyNetworkTransactionTest, WebSocketHttp11Required) {
9300 base::HistogramTester histogram_tester;
9301 auto session_deps = std::make_unique<SpdySessionDependencies>();
9302 session_deps->enable_websocket_over_http2 = true;
9303 NormalSpdyTransactionHelper helper(request_, HIGHEST, log_,
9304 std::move(session_deps));
9305 helper.RunPreTestSetup();
9306
9307 spdy::SpdySerializedFrame req(
9308 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, HIGHEST));
9309 spdy::SpdySerializedFrame settings_ack(spdy_util_.ConstructSpdySettingsAck());
9310
Bence Béky4c325e52020-10-22 20:48:019311 spdy::Http2HeaderBlock websocket_request_headers;
Matt Menkef2ee07c2019-08-29 02:10:369312 websocket_request_headers[spdy::kHttp2MethodHeader] = "CONNECT";
9313 websocket_request_headers[spdy::kHttp2AuthorityHeader] = "www.example.org";
9314 websocket_request_headers[spdy::kHttp2SchemeHeader] = "https";
9315 websocket_request_headers[spdy::kHttp2PathHeader] = "/";
9316 websocket_request_headers[spdy::kHttp2ProtocolHeader] = "websocket";
9317 websocket_request_headers["origin"] = "http://www.example.org";
9318 websocket_request_headers["sec-websocket-version"] = "13";
9319 websocket_request_headers["sec-websocket-extensions"] =
9320 "permessage-deflate; client_max_window_bits";
9321 spdy::SpdySerializedFrame websocket_request(spdy_util_.ConstructSpdyHeaders(
9322 3, std::move(websocket_request_headers), MEDIUM, false));
9323
9324 spdy::SpdySerializedFrame priority1(
9325 spdy_util_.ConstructSpdyPriority(3, 0, MEDIUM, true));
9326 spdy::SpdySerializedFrame priority2(
9327 spdy_util_.ConstructSpdyPriority(1, 3, LOWEST, true));
9328
9329 MockWrite writes1[] = {CreateMockWrite(req, 0),
9330 CreateMockWrite(settings_ack, 2),
9331 CreateMockWrite(websocket_request, 4)};
9332
9333 spdy::SettingsMap settings;
9334 settings[spdy::SETTINGS_ENABLE_CONNECT_PROTOCOL] = 1;
9335 spdy::SpdySerializedFrame settings_frame(
9336 spdy_util_.ConstructSpdySettings(settings));
9337 spdy::SpdySerializedFrame resp1(
9338 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9339 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9340 spdy::SpdySerializedFrame websocket_response_http11_required(
9341 spdy_util_.ConstructSpdyRstStream(3, spdy::ERROR_CODE_HTTP_1_1_REQUIRED));
9342 MockRead reads1[] = {CreateMockRead(settings_frame, 1),
9343 CreateMockRead(resp1, 3),
9344 CreateMockRead(websocket_response_http11_required, 5)};
9345
9346 SequencedSocketData data1(reads1, writes1);
9347 helper.AddData(&data1);
9348
9349 MockWrite writes2[] = {
9350 MockWrite("GET / HTTP/1.1\r\n"
9351 "Host: www.example.org\r\n"
9352 "Connection: Upgrade\r\n"
9353 "Origin: http://www.example.org\r\n"
9354 "Sec-WebSocket-Version: 13\r\n"
9355 "Upgrade: websocket\r\n"
9356 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9357 "Sec-WebSocket-Extensions: permessage-deflate; "
9358 "client_max_window_bits\r\n\r\n")};
9359 MockRead reads2[] = {
9360 MockRead("HTTP/1.1 101 Switching Protocols\r\n"
9361 "Upgrade: websocket\r\n"
9362 "Connection: Upgrade\r\n"
9363 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n")};
9364 StaticSocketDataProvider data2(reads2, writes2);
9365 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9366 // Test that request has empty |alpn_protos|, that is, HTTP/2 is disabled.
9367 ssl_provider2->next_protos_expected_in_ssl_config = NextProtoVector{};
9368 // Force socket to use HTTP/1.1, the default protocol without ALPN.
9369 ssl_provider2->next_proto = kProtoHTTP11;
9370 ssl_provider2->ssl_info.cert =
9371 ImportCertFromFile(GetTestCertsDirectory(), "spdy_pooling.pem");
9372 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9373
9374 // Create HTTP/2 connection.
9375 TestCompletionCallback callback1;
9376 int rv = helper.trans()->Start(&request_, callback1.callback(), log_);
9377 ASSERT_THAT(rv, IsError(ERR_IO_PENDING));
9378
9379 // Create HTTP/2 connection.
9380 base::RunLoop().RunUntilIdle();
9381
9382 SpdySessionKey key(HostPortPair::FromURL(request_.url), ProxyServer::Direct(),
9383 PRIVACY_MODE_DISABLED,
dalyk51ab46b2019-10-15 15:14:349384 SpdySessionKey::IsProxySession::kFalse, SocketTag(),
9385 NetworkIsolationKey(), false /* disable_secure_dns */);
Matt Menkef2ee07c2019-08-29 02:10:369386 base::WeakPtr<SpdySession> spdy_session =
9387 helper.session()->spdy_session_pool()->FindAvailableSession(
9388 key, /* enable_ip_based_pooling = */ true,
9389 /* is_websocket = */ true, log_);
9390 ASSERT_TRUE(spdy_session);
9391 EXPECT_TRUE(spdy_session->support_websocket());
9392
9393 HttpRequestInfo request2;
9394 request2.method = "GET";
9395 request2.url = GURL("wss://www.example.org/");
9396 request2.traffic_annotation =
9397 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9398 EXPECT_TRUE(HostPortPair::FromURL(request_.url)
9399 .Equals(HostPortPair::FromURL(request2.url)));
9400 request2.extra_headers.SetHeader("Origin", "http://www.example.org");
9401 request2.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9402 // The following two headers must be removed by WebSocketHttp2HandshakeStream.
9403 request2.extra_headers.SetHeader("Connection", "Upgrade");
9404 request2.extra_headers.SetHeader("Upgrade", "websocket");
9405
9406 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9407
9408 HttpNetworkTransaction trans2(MEDIUM, helper.session());
9409 trans2.SetWebSocketHandshakeStreamCreateHelper(
9410 &websocket_stream_create_helper);
9411
9412 TestCompletionCallback callback2;
9413 rv = trans2.Start(&request2, callback2.callback(), log_);
9414 EXPECT_THAT(callback2.GetResult(rv), IsOk());
9415
9416 helper.VerifyDataConsumed();
9417
9418 // Server advertised WebSocket support.
9419 histogram_tester.ExpectUniqueSample("Net.SpdySession.ServerSupportsWebSocket",
9420 /* support_websocket = true */ 1,
9421 /* expected_count = */ 1);
9422}
9423
Bence Béky420bb2d2018-03-30 17:25:269424// Plaintext WebSocket over HTTP/2 is not implemented, see
9425// https://crbug.com/684681.
9426TEST_F(SpdyNetworkTransactionTest, PlaintextWebSocketOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139427 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049428 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9429 HostPortPair("www.example.org", 80)));
Bence Béky420bb2d2018-03-30 17:25:269430 MockWrite writes[] = {CreateMockWrite(req, 0)};
9431
Ryan Hamilton0239aac2018-05-19 00:03:139432 spdy::SpdySerializedFrame resp(
9433 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Béky420bb2d2018-03-30 17:25:269434 MockRead reads[] = {CreateMockRead(resp, 1), MockRead(ASYNC, 0, 2)};
9435
Ryan Sleevib8d7ea02018-05-07 20:01:019436 SequencedSocketData data(reads, writes);
Bence Béky420bb2d2018-03-30 17:25:269437
9438 request_.url = GURL("ws://www.example.org/");
9439 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569440 ConfiguredProxyResolutionService::CreateFixed(
9441 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky420bb2d2018-03-30 17:25:269442 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9443 std::move(session_deps));
9444 helper.RunPreTestSetup();
9445 helper.AddData(&data);
9446
9447 HttpNetworkTransaction* trans = helper.trans();
9448 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9449 trans->SetWebSocketHandshakeStreamCreateHelper(
9450 &websocket_stream_create_helper);
9451
9452 EXPECT_TRUE(helper.StartDefaultTest());
9453 helper.WaitForCallbackToComplete();
9454 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9455
9456 helper.VerifyDataConsumed();
9457}
9458
Bence Béky6434d5e2018-04-03 13:43:119459// Regression test for https://crbug.com/819101. Open two identical plaintext
Xida Chen9bfe0b62018-04-24 19:52:219460// websocket requests over proxy. The HttpStreamFactory::Job for the second
Bence Béky6434d5e2018-04-03 13:43:119461// request should reuse the first connection.
9462TEST_F(SpdyNetworkTransactionTest, TwoWebSocketRequestsOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139463 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049464 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9465 HostPortPair("www.example.org", 80)));
Bence Béky6434d5e2018-04-03 13:43:119466 MockWrite writes[] = {CreateMockWrite(req, 0)};
9467
Ryan Hamilton0239aac2018-05-19 00:03:139468 spdy::SpdySerializedFrame resp(
9469 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
Bence Béky6434d5e2018-04-03 13:43:119470 MockRead reads[] = {CreateMockRead(resp, 1),
9471 MockRead(ASYNC, ERR_IO_PENDING, 2),
9472 MockRead(ASYNC, 0, 3)};
9473
Ryan Sleevib8d7ea02018-05-07 20:01:019474 SequencedSocketData data(reads, writes);
Bence Béky6434d5e2018-04-03 13:43:119475
9476 request_.url = GURL("ws://www.example.org/");
9477 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569478 ConfiguredProxyResolutionService::CreateFixed(
9479 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky6434d5e2018-04-03 13:43:119480 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9481 std::move(session_deps));
9482 helper.RunPreTestSetup();
9483 helper.AddData(&data);
9484
9485 HttpNetworkTransaction* trans1 = helper.trans();
9486 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9487 trans1->SetWebSocketHandshakeStreamCreateHelper(
9488 &websocket_stream_create_helper);
9489
9490 EXPECT_TRUE(helper.StartDefaultTest());
9491 helper.WaitForCallbackToComplete();
9492 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9493
9494 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9495 trans2.SetWebSocketHandshakeStreamCreateHelper(
9496 &websocket_stream_create_helper);
9497
9498 TestCompletionCallback callback2;
9499 int rv = trans2.Start(&request_, callback2.callback(), log_);
9500 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9501
9502 rv = callback2.WaitForResult();
9503 EXPECT_THAT(rv, IsError(ERR_NOT_IMPLEMENTED));
9504
9505 data.Resume();
9506 base::RunLoop().RunUntilIdle();
9507
9508 helper.VerifyDataConsumed();
9509}
9510
Bence Béky420bb2d2018-03-30 17:25:269511TEST_F(SpdyNetworkTransactionTest, SecureWebSocketOverHttp2Proxy) {
Ryan Hamilton0239aac2018-05-19 00:03:139512 spdy::SpdySerializedFrame connect_request(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049513 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9514 HostPortPair("www.example.org", 443)));
Bence Béky420bb2d2018-03-30 17:25:269515 const char kWebSocketRequest[] =
9516 "GET / HTTP/1.1\r\n"
9517 "Host: www.example.org\r\n"
9518 "Connection: Upgrade\r\n"
9519 "Upgrade: websocket\r\n"
9520 "Origin: http://www.example.org\r\n"
9521 "Sec-WebSocket-Version: 13\r\n"
9522 "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
9523 "Sec-WebSocket-Extensions: permessage-deflate; "
9524 "client_max_window_bits\r\n\r\n";
Ryan Hamilton0239aac2018-05-19 00:03:139525 spdy::SpdySerializedFrame websocket_request(
Bence Béky420bb2d2018-03-30 17:25:269526 spdy_util_.ConstructSpdyDataFrame(1, kWebSocketRequest, false));
9527 MockWrite writes[] = {CreateMockWrite(connect_request, 0),
9528 CreateMockWrite(websocket_request, 2)};
9529
Ryan Hamilton0239aac2018-05-19 00:03:139530 spdy::SpdySerializedFrame connect_response(
Bence Béky420bb2d2018-03-30 17:25:269531 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9532 const char kWebSocketResponse[] =
9533 "HTTP/1.1 101 Switching Protocols\r\n"
9534 "Upgrade: websocket\r\n"
9535 "Connection: Upgrade\r\n"
9536 "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n\r\n";
Ryan Hamilton0239aac2018-05-19 00:03:139537 spdy::SpdySerializedFrame websocket_response(
Bence Béky420bb2d2018-03-30 17:25:269538 spdy_util_.ConstructSpdyDataFrame(1, kWebSocketResponse, false));
9539 MockRead reads[] = {CreateMockRead(connect_response, 1),
9540 CreateMockRead(websocket_response, 3),
9541 MockRead(ASYNC, 0, 4)};
9542
Ryan Sleevib8d7ea02018-05-07 20:01:019543 SequencedSocketData data(reads, writes);
Bence Béky420bb2d2018-03-30 17:25:269544
9545 request_.url = GURL("wss://www.example.org/");
9546 request_.extra_headers.SetHeader("Connection", "Upgrade");
9547 request_.extra_headers.SetHeader("Upgrade", "websocket");
9548 request_.extra_headers.SetHeader("Origin", "http://www.example.org");
9549 request_.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9550 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569551 ConfiguredProxyResolutionService::CreateFixed(
9552 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky420bb2d2018-03-30 17:25:269553 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9554 std::move(session_deps));
9555 helper.RunPreTestSetup();
9556 helper.AddData(&data);
9557
9558 // Add SSL data for the tunneled connection.
9559 SSLSocketDataProvider ssl_provider(ASYNC, OK);
9560 ssl_provider.ssl_info.cert =
9561 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
Bence Béky12943c62018-04-05 19:16:509562 // A WebSocket request should not advertise HTTP/2 support.
9563 ssl_provider.next_protos_expected_in_ssl_config = NextProtoVector{};
Bence Béky420bb2d2018-03-30 17:25:269564 // This test uses WebSocket over HTTP/1.1.
9565 ssl_provider.next_proto = kProtoHTTP11;
9566 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9567 &ssl_provider);
9568
9569 HttpNetworkTransaction* trans = helper.trans();
9570 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9571 trans->SetWebSocketHandshakeStreamCreateHelper(
9572 &websocket_stream_create_helper);
9573
9574 EXPECT_TRUE(helper.StartDefaultTest());
9575 helper.WaitForCallbackToComplete();
9576 EXPECT_THAT(helper.output().rv, IsOk());
9577 const HttpResponseInfo* response = trans->GetResponseInfo();
9578 ASSERT_TRUE(response);
9579 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
9580 response->connection_info);
9581 EXPECT_TRUE(response->was_alpn_negotiated);
9582 EXPECT_FALSE(response->was_fetched_via_spdy);
Tsuyoshi Horo01faed62019-02-20 22:11:379583 EXPECT_EQ(70, response->remote_endpoint.port());
Bence Béky420bb2d2018-03-30 17:25:269584 ASSERT_TRUE(response->headers);
9585 EXPECT_EQ("HTTP/1.1 101 Switching Protocols",
9586 response->headers->GetStatusLine());
9587
9588 base::RunLoop().RunUntilIdle();
9589 helper.VerifyDataConsumed();
9590}
9591
Bence Béky12943c62018-04-05 19:16:509592// Regression test for https://crbug.com/828865.
9593TEST_F(SpdyNetworkTransactionTest,
9594 SecureWebSocketOverHttp2ProxyNegotiatesHttp2) {
Ryan Hamilton0239aac2018-05-19 00:03:139595 spdy::SpdySerializedFrame connect_request(spdy_util_.ConstructSpdyConnect(
Matt Menke6e879bd2019-03-18 17:26:049596 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
9597 HostPortPair("www.example.org", 443)));
Bence Béky12943c62018-04-05 19:16:509598 MockWrite writes[] = {CreateMockWrite(connect_request, 0)};
Ryan Hamilton0239aac2018-05-19 00:03:139599 spdy::SpdySerializedFrame connect_response(
Bence Béky12943c62018-04-05 19:16:509600 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9601 MockRead reads[] = {CreateMockRead(connect_response, 1),
9602 MockRead(ASYNC, 0, 2)};
Ryan Sleevib8d7ea02018-05-07 20:01:019603 SequencedSocketData data(reads, writes);
Bence Béky12943c62018-04-05 19:16:509604
9605 request_.url = GURL("wss://www.example.org/");
9606 request_.extra_headers.SetHeader("Connection", "Upgrade");
9607 request_.extra_headers.SetHeader("Upgrade", "websocket");
9608 request_.extra_headers.SetHeader("Origin", "http://www.example.org");
9609 request_.extra_headers.SetHeader("Sec-WebSocket-Version", "13");
9610 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:569611 ConfiguredProxyResolutionService::CreateFixed(
9612 "https://proxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
Bence Béky12943c62018-04-05 19:16:509613 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9614 std::move(session_deps));
9615 helper.RunPreTestSetup();
9616 helper.AddData(&data);
9617
9618 // Add SSL data for the tunneled connection.
9619 SSLSocketDataProvider ssl_provider(ASYNC, OK);
9620 ssl_provider.ssl_info.cert =
9621 ImportCertFromFile(GetTestCertsDirectory(), "wildcard.pem");
9622 // A WebSocket request should not advertise HTTP/2 support.
9623 ssl_provider.next_protos_expected_in_ssl_config = NextProtoVector{};
9624 // The server should not negotiate HTTP/2 over the tunnelled connection,
9625 // but it must be handled gracefully if it does.
9626 ssl_provider.next_proto = kProtoHTTP2;
9627 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
9628 &ssl_provider);
9629
9630 HttpNetworkTransaction* trans = helper.trans();
9631 TestWebSocketHandshakeStreamCreateHelper websocket_stream_create_helper;
9632 trans->SetWebSocketHandshakeStreamCreateHelper(
9633 &websocket_stream_create_helper);
9634
9635 EXPECT_TRUE(helper.StartDefaultTest());
9636 helper.WaitForCallbackToComplete();
9637 EXPECT_THAT(helper.output().rv, IsError(ERR_NOT_IMPLEMENTED));
9638
9639 base::RunLoop().RunUntilIdle();
9640 helper.VerifyDataConsumed();
9641}
9642
Bence Béky0ca719f2018-01-31 13:41:199643#endif // BUILDFLAG(ENABLE_WEBSOCKETS)
9644
Steven Valdez1c1859172019-04-10 15:33:289645TEST_F(SpdyNetworkTransactionTest, ZeroRTTDoesntConfirm) {
David Benjaminbae08ba2019-10-18 21:06:159646 static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:289647 spdy::SpdySerializedFrame req(
9648 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
9649 MockWrite writes[] = {CreateMockWrite(req, 0)};
9650
9651 spdy::SpdySerializedFrame resp(
9652 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9653 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
9654 MockRead reads[] = {
9655 CreateMockRead(resp, 1), CreateMockRead(body, 2),
9656 MockRead(ASYNC, 0, 3) // EOF
9657 };
9658
9659 SequencedSocketData data(reads, writes);
9660 auto session_deps = std::make_unique<SpdySessionDependencies>();
9661 session_deps->enable_early_data = true;
9662 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9663 std::move(session_deps));
9664 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:159665 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:289666 // Configure |ssl_provider| to fail if ConfirmHandshake is called. The request
9667 // should still succeed.
9668 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
David Benjaminbae08ba2019-10-18 21:06:159669 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
9670 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:289671 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
9672 TransactionHelperResult out = helper.output();
9673 EXPECT_THAT(out.rv, IsOk());
9674 EXPECT_EQ("HTTP/1.1 200", out.status_line);
9675 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:159676
9677 // The handshake time should include the time it took to run Connect(), but
9678 // not ConfirmHandshake().
9679 LoadTimingInfo load_timing_info;
9680 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
9681 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
9682 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
9683 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
9684 EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
Steven Valdez1c1859172019-04-10 15:33:289685}
9686
9687// Run multiple concurrent streams that don't require handshake confirmation.
9688TEST_F(SpdyNetworkTransactionTest, ZeroRTTNoConfirmMultipleStreams) {
9689 spdy::SpdySerializedFrame req1(
9690 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, LOWEST));
9691 spdy::SpdySerializedFrame req2(
9692 spdy_util_.ConstructSpdyGet(nullptr, 0, 3, LOWEST));
9693 MockWrite writes1[] = {CreateMockWrite(req1, 0), CreateMockWrite(req2, 3)};
9694
9695 spdy::SpdySerializedFrame resp1(
9696 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9697 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9698 spdy::SpdySerializedFrame resp2(
9699 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9700 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9701 MockRead reads1[] = {
9702 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9703 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9704 MockRead(ASYNC, 0, 6) // EOF
9705 };
9706
9707 SequencedSocketData data1(reads1, writes1);
9708 SequencedSocketData data2({}, {});
9709 auto session_deps = std::make_unique<SpdySessionDependencies>();
9710 session_deps->enable_early_data = true;
9711 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9712 std::move(session_deps));
9713 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9714 ssl_provider1->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
9715 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9716 ssl_provider2->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
9717
9718 helper.RunPreTestSetup();
9719 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9720 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9721 EXPECT_TRUE(helper.StartDefaultTest());
9722
9723 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9724 HttpRequestInfo request2;
9725 request2.method = "GET";
9726 request2.url = GURL(kDefaultUrl);
9727 request2.traffic_annotation =
9728 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9729 TestCompletionCallback callback2;
9730 int rv = trans2.Start(&request2, callback2.callback(), log_);
9731 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9732
9733 helper.FinishDefaultTest();
9734 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9735 helper.VerifyDataConsumed();
9736
9737 TransactionHelperResult out = helper.output();
9738 EXPECT_THAT(out.rv, IsOk());
9739 EXPECT_EQ("HTTP/1.1 200", out.status_line);
9740 EXPECT_EQ("hello!", out.response_data);
9741}
9742
9743// Run multiple concurrent streams that require handshake confirmation.
9744TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmMultipleStreams) {
Bence Béky4c325e52020-10-22 20:48:019745 spdy::Http2HeaderBlock req_block1(
Steven Valdez1c1859172019-04-10 15:33:289746 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9747 spdy::SpdySerializedFrame req1(
9748 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
Bence Béky4c325e52020-10-22 20:48:019749 spdy::Http2HeaderBlock req_block2(
Steven Valdez1c1859172019-04-10 15:33:289750 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9751 spdy::SpdySerializedFrame req2(
9752 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
9753 MockWrite writes[] = {
9754 CreateMockWrite(req1, 0),
9755 CreateMockWrite(req2, 3),
9756 };
9757 spdy::SpdySerializedFrame resp1(
9758 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9759 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9760 spdy::SpdySerializedFrame resp2(
9761 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9762 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9763 MockRead reads[] = {
9764 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9765 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9766 MockRead(ASYNC, 0, 6) // EOF
9767 };
9768
9769 SequencedSocketData data1(reads, writes);
9770 SequencedSocketData data2({}, {});
9771 UsePostRequest();
9772 auto session_deps = std::make_unique<SpdySessionDependencies>();
9773 session_deps->enable_early_data = true;
9774 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9775 std::move(session_deps));
9776 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9777 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
9778 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9779 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
9780
9781 helper.RunPreTestSetup();
9782 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9783 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9784
9785 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
9786 HttpRequestInfo request1;
9787 request1.method = "POST";
9788 request1.url = GURL(kDefaultUrl);
9789 request1.traffic_annotation =
9790 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9791 TestCompletionCallback callback1;
9792 int rv = trans1.Start(&request1, callback1.callback(), log_);
9793 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9794
9795 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9796 HttpRequestInfo request2;
9797 request2.method = "POST";
9798 request2.url = GURL(kDefaultUrl);
9799 request2.traffic_annotation =
9800 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9801 TestCompletionCallback callback2;
9802 rv = trans2.Start(&request2, callback2.callback(), log_);
9803 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9804
9805 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
9806 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9807
9808 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
9809 ASSERT_TRUE(response1);
9810 ASSERT_TRUE(response1->headers);
9811 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9812 response1->connection_info);
9813 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
9814 std::string response_data;
9815 ReadTransaction(&trans1, &response_data);
9816 EXPECT_EQ("hello!", response_data);
9817
9818 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
9819 ASSERT_TRUE(response2);
9820 ASSERT_TRUE(response2->headers);
9821 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9822 response2->connection_info);
9823 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
9824 ReadTransaction(&trans2, &response_data);
9825 EXPECT_EQ("hello!", response_data);
9826
9827 helper.VerifyDataConsumed();
9828}
9829
9830// Run multiple concurrent streams, the first require a confirmation and the
9831// second not requiring confirmation.
9832TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmNoConfirmStreams) {
9833 // This test orders the writes such that the GET (no confirmation) is written
9834 // before the POST (confirmation required).
Bence Béky4c325e52020-10-22 20:48:019835 spdy::Http2HeaderBlock req_block1(
Steven Valdez1c1859172019-04-10 15:33:289836 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
9837 spdy::SpdySerializedFrame req1(
9838 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
Bence Béky4c325e52020-10-22 20:48:019839 spdy::Http2HeaderBlock req_block2(
Steven Valdez1c1859172019-04-10 15:33:289840 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9841 spdy::SpdySerializedFrame req2(
9842 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
9843 MockWrite writes[] = {
9844 CreateMockWrite(req1, 0),
9845 CreateMockWrite(req2, 3),
9846 };
9847 spdy::SpdySerializedFrame resp1(
9848 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9849 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9850 spdy::SpdySerializedFrame resp2(
9851 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9852 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9853 MockRead reads[] = {
9854 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9855 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9856 MockRead(ASYNC, 0, 6) // EOF
9857 };
9858
9859 SequencedSocketData data1(reads, writes);
9860 SequencedSocketData data2({}, {});
9861 UsePostRequest();
9862 auto session_deps = std::make_unique<SpdySessionDependencies>();
9863 session_deps->enable_early_data = true;
9864 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9865 std::move(session_deps));
9866 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9867 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
9868 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9869 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
9870
9871 helper.RunPreTestSetup();
9872 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9873 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9874
9875 // TODO(https://crbug.com/949724): Explicitly verify the ordering of
9876 // ConfirmHandshake and the second stream.
9877
9878 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
9879 HttpRequestInfo request1;
9880 request1.method = "POST";
9881 request1.url = GURL(kDefaultUrl);
9882 request1.traffic_annotation =
9883 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9884 TestCompletionCallback callback1;
9885 int rv = trans1.Start(&request1, callback1.callback(), log_);
9886 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9887
9888 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9889 HttpRequestInfo request2;
9890 request2.method = "GET";
9891 request2.url = GURL(kDefaultUrl);
9892 request2.traffic_annotation =
9893 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9894 TestCompletionCallback callback2;
9895 rv = trans2.Start(&request2, callback2.callback(), log_);
9896 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9897
9898 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
9899 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9900
9901 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
9902 ASSERT_TRUE(response1);
9903 ASSERT_TRUE(response1->headers);
9904 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9905 response1->connection_info);
9906 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
9907 std::string response_data;
9908 ReadTransaction(&trans1, &response_data);
9909 EXPECT_EQ("hello!", response_data);
9910
9911 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
9912 ASSERT_TRUE(response2);
9913 ASSERT_TRUE(response2->headers);
9914 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9915 response2->connection_info);
9916 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
9917 ReadTransaction(&trans2, &response_data);
9918 EXPECT_EQ("hello!", response_data);
9919
9920 helper.VerifyDataConsumed();
9921}
9922
9923// Run multiple concurrent streams, the first not requiring confirmation and the
9924// second requiring confirmation.
9925TEST_F(SpdyNetworkTransactionTest, ZeroRTTNoConfirmConfirmStreams) {
9926 // This test orders the writes such that the GET (no confirmation) is written
9927 // before the POST (confirmation required).
Bence Béky4c325e52020-10-22 20:48:019928 spdy::Http2HeaderBlock req_block1(
Steven Valdez1c1859172019-04-10 15:33:289929 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
9930 spdy::SpdySerializedFrame req1(
9931 spdy_util_.ConstructSpdyHeaders(1, std::move(req_block1), LOWEST, true));
Bence Béky4c325e52020-10-22 20:48:019932 spdy::Http2HeaderBlock req_block2(
Steven Valdez1c1859172019-04-10 15:33:289933 spdy_util_.ConstructPostHeaderBlock(kDefaultUrl, 0));
9934 spdy::SpdySerializedFrame req2(
9935 spdy_util_.ConstructSpdyHeaders(3, std::move(req_block2), LOWEST, true));
9936 MockWrite writes[] = {
9937 CreateMockWrite(req1, 0),
9938 CreateMockWrite(req2, 3),
9939 };
9940 spdy::SpdySerializedFrame resp1(
9941 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
9942 spdy::SpdySerializedFrame body1(spdy_util_.ConstructSpdyDataFrame(1, true));
9943 spdy::SpdySerializedFrame resp2(
9944 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 3));
9945 spdy::SpdySerializedFrame body2(spdy_util_.ConstructSpdyDataFrame(3, true));
9946 MockRead reads[] = {
9947 CreateMockRead(resp1, 1), CreateMockRead(body1, 2),
9948 CreateMockRead(resp2, 4), CreateMockRead(body2, 5),
9949 MockRead(ASYNC, 0, 6) // EOF
9950 };
9951
9952 SequencedSocketData data1(reads, writes);
9953 SequencedSocketData data2({}, {});
9954 UsePostRequest();
9955 auto session_deps = std::make_unique<SpdySessionDependencies>();
9956 session_deps->enable_early_data = true;
9957 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
9958 std::move(session_deps));
9959 auto ssl_provider1 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9960 ssl_provider1->confirm = MockConfirm(ASYNC, OK);
9961 auto ssl_provider2 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
9962 ssl_provider2->confirm = MockConfirm(ASYNC, OK);
9963
9964 helper.RunPreTestSetup();
9965 helper.AddDataWithSSLSocketDataProvider(&data1, std::move(ssl_provider1));
9966 helper.AddDataWithSSLSocketDataProvider(&data2, std::move(ssl_provider2));
9967
9968 // TODO(https://crbug.com/949724): Explicitly verify the ordering of
9969 // ConfirmHandshake and the second stream.
9970
9971 HttpNetworkTransaction trans1(DEFAULT_PRIORITY, helper.session());
9972 HttpRequestInfo request1;
9973 request1.method = "GET";
9974 request1.url = GURL(kDefaultUrl);
9975 request1.traffic_annotation =
9976 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9977 TestCompletionCallback callback1;
9978 int rv = trans1.Start(&request1, callback1.callback(), log_);
9979 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9980
9981 HttpNetworkTransaction trans2(DEFAULT_PRIORITY, helper.session());
9982 HttpRequestInfo request2;
9983 request2.method = "POST";
9984 request2.url = GURL(kDefaultUrl);
9985 request2.traffic_annotation =
9986 net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS);
9987 TestCompletionCallback callback2;
9988 rv = trans2.Start(&request2, callback2.callback(), log_);
9989 EXPECT_THAT(rv, IsError(ERR_IO_PENDING));
9990
9991 EXPECT_THAT(callback1.GetResult(ERR_IO_PENDING), IsOk());
9992 EXPECT_THAT(callback2.GetResult(ERR_IO_PENDING), IsOk());
9993
9994 const HttpResponseInfo* response1 = trans1.GetResponseInfo();
9995 ASSERT_TRUE(response1);
9996 ASSERT_TRUE(response1->headers);
9997 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
9998 response1->connection_info);
9999 EXPECT_EQ("HTTP/1.1 200", response1->headers->GetStatusLine());
10000 std::string response_data;
10001 ReadTransaction(&trans1, &response_data);
10002 EXPECT_EQ("hello!", response_data);
10003
10004 const HttpResponseInfo* response2 = trans2.GetResponseInfo();
10005 ASSERT_TRUE(response2);
10006 ASSERT_TRUE(response2->headers);
10007 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP2,
10008 response2->connection_info);
10009 EXPECT_EQ("HTTP/1.1 200", response2->headers->GetStatusLine());
10010 ReadTransaction(&trans2, &response_data);
10011 EXPECT_EQ("hello!", response_data);
10012
10013 helper.VerifyDataConsumed();
10014}
10015
10016TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmSyncWrite) {
David Benjaminbae08ba2019-10-18 21:06:1510017 static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:2810018 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10019 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10020 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10021 MockWrite writes[] = {
10022 CreateMockWrite(req, 0, SYNCHRONOUS),
10023 CreateMockWrite(body, 1), // POST upload frame
10024 };
10025
10026 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10027 MockRead reads[] = {
10028 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10029 MockRead(ASYNC, 0, 4) // EOF
10030 };
10031
10032 SequencedSocketData data(reads, writes);
10033 UsePostRequest();
10034 auto session_deps = std::make_unique<SpdySessionDependencies>();
10035 session_deps->enable_early_data = true;
10036 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10037 std::move(session_deps));
10038 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510039 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810040 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, OK);
David Benjaminbae08ba2019-10-18 21:06:1510041 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
10042 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:2810043 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10044 TransactionHelperResult out = helper.output();
10045 EXPECT_THAT(out.rv, IsOk());
10046 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10047 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:1510048
10049 // The handshake time should include the time it took to run Connect(), but
10050 // not ConfirmHandshake(). If ConfirmHandshake() returns synchronously, we
10051 // assume the connection did not negotiate 0-RTT or the handshake was already
10052 // confirmed.
10053 LoadTimingInfo load_timing_info;
10054 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
10055 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
10056 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
10057 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + kDelay);
10058 EXPECT_EQ(load_timing_info.connect_timing.connect_end, start_time + kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810059}
10060
10061TEST_F(SpdyNetworkTransactionTest, ZeroRTTSyncConfirmAsyncWrite) {
10062 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10063 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10064 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10065 MockWrite writes[] = {
10066 CreateMockWrite(req, 0, ASYNC),
10067 CreateMockWrite(body, 1), // POST upload frame
10068 };
10069
10070 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10071 MockRead reads[] = {
10072 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10073 MockRead(ASYNC, 0, 4) // EOF
10074 };
10075
10076 SequencedSocketData data(reads, writes);
10077 UsePostRequest();
10078 auto session_deps = std::make_unique<SpdySessionDependencies>();
10079 session_deps->enable_early_data = true;
10080 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10081 std::move(session_deps));
10082 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10083 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, OK);
10084 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10085 TransactionHelperResult out = helper.output();
10086 EXPECT_THAT(out.rv, IsOk());
10087 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10088 EXPECT_EQ("hello!", out.response_data);
10089}
10090
10091TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmSyncWrite) {
David Benjaminbae08ba2019-10-18 21:06:1510092 static const base::TimeDelta kDelay = base::TimeDelta::FromMilliseconds(10);
Steven Valdez1c1859172019-04-10 15:33:2810093 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10094 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10095 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10096 MockWrite writes[] = {
10097 CreateMockWrite(req, 0, SYNCHRONOUS),
10098 CreateMockWrite(body, 1), // POST upload frame
10099 };
10100
10101 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10102 MockRead reads[] = {
10103 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10104 MockRead(ASYNC, 0, 4) // EOF
10105 };
10106
10107 SequencedSocketData data(reads, writes);
10108 UsePostRequest();
10109 auto session_deps = std::make_unique<SpdySessionDependencies>();
10110 session_deps->enable_early_data = true;
10111 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10112 std::move(session_deps));
10113 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510114 ssl_provider->connect_callback = FastForwardByCallback(kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810115 ssl_provider->confirm = MockConfirm(ASYNC, OK);
David Benjaminbae08ba2019-10-18 21:06:1510116 ssl_provider->confirm_callback = FastForwardByCallback(kDelay);
10117 base::TimeTicks start_time = base::TimeTicks::Now();
Steven Valdez1c1859172019-04-10 15:33:2810118 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10119 TransactionHelperResult out = helper.output();
10120 EXPECT_THAT(out.rv, IsOk());
10121 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10122 EXPECT_EQ("hello!", out.response_data);
David Benjaminbae08ba2019-10-18 21:06:1510123
10124 // The handshake time should include the time it took to run Connect() and
10125 // ConfirmHandshake().
10126 LoadTimingInfo load_timing_info;
10127 EXPECT_TRUE(helper.trans()->GetLoadTimingInfo(&load_timing_info));
10128 EXPECT_EQ(load_timing_info.connect_timing.connect_start, start_time);
10129 EXPECT_EQ(load_timing_info.connect_timing.ssl_start, start_time);
10130 EXPECT_EQ(load_timing_info.connect_timing.ssl_end, start_time + 2 * kDelay);
10131 EXPECT_EQ(load_timing_info.connect_timing.connect_end,
10132 start_time + 2 * kDelay);
Steven Valdez1c1859172019-04-10 15:33:2810133}
10134
10135TEST_F(SpdyNetworkTransactionTest, ZeroRTTAsyncConfirmAsyncWrite) {
10136 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10137 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10138 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10139 MockWrite writes[] = {
10140 CreateMockWrite(req, 0, ASYNC),
10141 CreateMockWrite(body, 1), // POST upload frame
10142 };
10143
10144 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10145 MockRead reads[] = {
10146 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10147 MockRead(ASYNC, 0, 4) // EOF
10148 };
10149
10150 SequencedSocketData data(reads, writes);
10151 UsePostRequest();
10152 auto session_deps = std::make_unique<SpdySessionDependencies>();
10153 session_deps->enable_early_data = true;
10154 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10155 std::move(session_deps));
10156 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10157 ssl_provider->confirm = MockConfirm(ASYNC, OK);
10158 helper.RunToCompletionWithSSLData(&data, std::move(ssl_provider));
10159 TransactionHelperResult out = helper.output();
10160 EXPECT_THAT(out.rv, IsOk());
10161 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10162 EXPECT_EQ("hello!", out.response_data);
10163}
10164
10165TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmErrorSync) {
10166 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10167 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10168 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10169 MockWrite writes[] = {
10170 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10171 };
10172
10173 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10174 MockRead reads[] = {
10175 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10176 MockRead(ASYNC, 0, 4) // EOF
10177 };
10178
10179 SequencedSocketData data(reads, writes);
10180 UsePostRequest();
10181 auto session_deps = std::make_unique<SpdySessionDependencies>();
10182 session_deps->enable_early_data = true;
10183 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10184 std::move(session_deps));
10185 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10186 ssl_provider->confirm = MockConfirm(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
10187 helper.RunPreTestSetup();
10188 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
10189 helper.RunDefaultTest();
10190 TransactionHelperResult out = helper.output();
10191 EXPECT_THAT(out.rv, IsError(ERR_SSL_PROTOCOL_ERROR));
10192}
10193
10194TEST_F(SpdyNetworkTransactionTest, ZeroRTTConfirmErrorAsync) {
10195 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10196 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10197 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10198 MockWrite writes[] = {
10199 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10200 };
10201
10202 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10203 MockRead reads[] = {
10204 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10205 MockRead(ASYNC, 0, 4) // EOF
10206 };
10207
10208 SequencedSocketData data(reads, writes);
10209 UsePostRequest();
10210 auto session_deps = std::make_unique<SpdySessionDependencies>();
10211 session_deps->enable_early_data = true;
10212 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10213 std::move(session_deps));
10214 auto ssl_provider = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10215 ssl_provider->confirm = MockConfirm(ASYNC, ERR_SSL_PROTOCOL_ERROR);
10216 helper.RunPreTestSetup();
10217 helper.AddDataWithSSLSocketDataProvider(&data, std::move(ssl_provider));
10218 helper.RunDefaultTest();
10219 TransactionHelperResult out = helper.output();
10220 EXPECT_THAT(out.rv, IsError(ERR_SSL_PROTOCOL_ERROR));
10221}
10222
Bence Békycb4be9e2020-07-09 11:18:1410223// If |http2_end_stream_with_data_frame| is false, then the HEADERS frame of a
10224// GET request will close the stream using the END_STREAM flag. Test that
10225// |greased_http2_frame| is ignored and no reserved frames are sent on a closed
10226// stream.
10227TEST_F(SpdyNetworkTransactionTest,
10228 DoNotGreaseFrameTypeWithGetRequestIfHeadersFrameClosesStream) {
10229 auto session_deps = std::make_unique<SpdySessionDependencies>();
10230
10231 const uint8_t type = 0x0b;
10232 const uint8_t flags = 0xcc;
10233 const std::string payload("foo");
10234 session_deps->greased_http2_frame =
10235 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10236 {type, flags, payload});
10237 session_deps->http2_end_stream_with_data_frame = false;
10238
10239 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10240 std::move(session_deps));
10241
10242 spdy::SpdySerializedFrame req(
10243 spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
10244 MockWrite writes[] = {CreateMockWrite(req, 0)};
10245
10246 spdy::SpdySerializedFrame resp(
10247 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10248 spdy::SpdySerializedFrame response_body(
10249 spdy_util_.ConstructSpdyDataFrame(1, true));
10250
10251 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(response_body, 2),
10252 MockRead(ASYNC, 0, 3)};
10253
10254 SequencedSocketData data(reads, writes);
10255 helper.RunPreTestSetup();
10256 helper.AddData(&data);
10257
10258 TestCompletionCallback callback;
10259 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10260 EXPECT_THAT(callback.GetResult(rv), IsOk());
10261
10262 base::RunLoop().RunUntilIdle();
10263
10264 helper.VerifyDataConsumed();
10265}
10266
10267// Test that if |http2_end_stream_with_data_frame| and |greased_http2_frame| are
10268// both set, then the HEADERS frame does not have the END_STREAM flag set, it is
10269// followed by a greased frame, and then by an empty DATA frame with END_STREAM
10270// set.
Bence Béky9eb57f62019-11-13 14:47:2510271TEST_F(SpdyNetworkTransactionTest, GreaseFrameTypeWithGetRequest) {
10272 auto session_deps = std::make_unique<SpdySessionDependencies>();
10273
10274 const uint8_t type = 0x0b;
10275 const uint8_t flags = 0xcc;
10276 const std::string payload("foo");
10277 session_deps->greased_http2_frame =
10278 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10279 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410280 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky9eb57f62019-11-13 14:47:2510281
10282 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10283 std::move(session_deps));
10284
Bence Béky4c325e52020-10-22 20:48:0110285 spdy::Http2HeaderBlock headers(
Bence Béky9eb57f62019-11-13 14:47:2510286 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10287 spdy::SpdySerializedFrame req(
10288 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), DEFAULT_PRIORITY,
10289 /* fin = */ false));
10290
10291 const char kRawFrameData[] = {
10292 0x00, 0x00, 0x03, // length
10293 0x0b, // type
10294 0xcc, // flags
10295 0x00, 0x00, 0x00, 0x01, // stream ID
10296 'f', 'o', 'o' // payload
10297 };
10298 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10299 base::size(kRawFrameData),
10300 /* owns_buffer = */ false);
10301 spdy::SpdySerializedFrame empty_body(
10302 spdy_util_.ConstructSpdyDataFrame(1, "", true));
10303
10304 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10305 CreateMockWrite(empty_body, 2)};
10306
10307 spdy::SpdySerializedFrame resp(
10308 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10309 spdy::SpdySerializedFrame response_body(
10310 spdy_util_.ConstructSpdyDataFrame(1, true));
10311
10312 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10313 MockRead(ASYNC, 0, 5)};
10314
10315 SequencedSocketData data(reads, writes);
10316 helper.RunPreTestSetup();
10317 helper.AddData(&data);
10318
10319 TestCompletionCallback callback;
10320 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10321 EXPECT_THAT(callback.GetResult(rv), IsOk());
10322
10323 base::RunLoop().RunUntilIdle();
10324
10325 helper.VerifyDataConsumed();
10326}
10327
Bence Békycb4be9e2020-07-09 11:18:1410328// Test sending a greased frame before DATA frame that closes the stream when
10329// |http2_end_stream_with_data_frame| is false.
10330TEST_F(SpdyNetworkTransactionTest,
10331 GreaseFrameTypeWithPostRequestWhenHeadersFrameClosesStream) {
Bence Béky9eb57f62019-11-13 14:47:2510332 UsePostRequest();
10333
10334 auto session_deps = std::make_unique<SpdySessionDependencies>();
10335
10336 const uint8_t type = 0x0b;
10337 const uint8_t flags = 0xcc;
10338 const std::string payload("foo");
10339 session_deps->greased_http2_frame =
10340 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10341 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410342 session_deps->http2_end_stream_with_data_frame = true;
10343
10344 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10345 std::move(session_deps));
10346
10347 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10348 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10349
10350 const char kRawFrameData[] = {
10351 0x00, 0x00, 0x03, // length
10352 0x0b, // type
10353 0xcc, // flags
10354 0x00, 0x00, 0x00, 0x01, // stream ID
10355 'f', 'o', 'o' // payload
10356 };
10357 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10358 base::size(kRawFrameData),
10359 /* owns_buffer = */ false);
10360 spdy::SpdySerializedFrame request_body(
10361 spdy_util_.ConstructSpdyDataFrame(1, true));
10362
10363 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10364 CreateMockWrite(request_body, 2)};
10365
10366 spdy::SpdySerializedFrame resp(
10367 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10368 spdy::SpdySerializedFrame response_body(
10369 spdy_util_.ConstructSpdyDataFrame(1, true));
10370
10371 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10372 MockRead(ASYNC, 0, 5)};
10373
10374 SequencedSocketData data(reads, writes);
10375 helper.RunPreTestSetup();
10376 helper.AddData(&data);
10377
10378 TestCompletionCallback callback;
10379 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10380 EXPECT_THAT(callback.GetResult(rv), IsOk());
10381
10382 base::RunLoop().RunUntilIdle();
10383
10384 helper.VerifyDataConsumed();
10385}
10386
10387// Test sending a greased frame before DATA frame that closes the stream.
10388// |http2_end_stream_with_data_frame| is true but should make no difference,
10389// because the stream is already closed by a DATA frame.
10390TEST_F(SpdyNetworkTransactionTest,
10391 GreaseFrameTypeWithPostRequestWhenEmptyDataFrameClosesStream) {
10392 UsePostRequest();
10393
10394 auto session_deps = std::make_unique<SpdySessionDependencies>();
10395
10396 const uint8_t type = 0x0b;
10397 const uint8_t flags = 0xcc;
10398 const std::string payload("foo");
10399 session_deps->greased_http2_frame =
10400 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10401 {type, flags, payload});
10402 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky9eb57f62019-11-13 14:47:2510403
10404 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10405 std::move(session_deps));
10406
10407 spdy::SpdySerializedFrame req(spdy_util_.ConstructSpdyPost(
10408 kDefaultUrl, 1, kUploadDataSize, LOWEST, nullptr, 0));
10409
10410 const char kRawFrameData[] = {
10411 0x00, 0x00, 0x03, // length
10412 0x0b, // type
10413 0xcc, // flags
10414 0x00, 0x00, 0x00, 0x01, // stream ID
10415 'f', 'o', 'o' // payload
10416 };
10417 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10418 base::size(kRawFrameData),
10419 /* owns_buffer = */ false);
10420 spdy::SpdySerializedFrame request_body(
10421 spdy_util_.ConstructSpdyDataFrame(1, true));
10422
10423 MockWrite writes[] = {CreateMockWrite(req, 0), CreateMockWrite(grease, 1),
10424 CreateMockWrite(request_body, 2)};
10425
10426 spdy::SpdySerializedFrame resp(
10427 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10428 spdy::SpdySerializedFrame response_body(
10429 spdy_util_.ConstructSpdyDataFrame(1, true));
10430
10431 MockRead reads[] = {CreateMockRead(resp, 3), CreateMockRead(response_body, 4),
10432 MockRead(ASYNC, 0, 5)};
10433
10434 SequencedSocketData data(reads, writes);
10435 helper.RunPreTestSetup();
10436 helper.AddData(&data);
10437
10438 TestCompletionCallback callback;
10439 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10440 EXPECT_THAT(callback.GetResult(rv), IsOk());
10441
10442 base::RunLoop().RunUntilIdle();
10443
10444 helper.VerifyDataConsumed();
10445}
10446
Bence Béky21755dd62019-11-19 13:47:3510447// According to https://httpwg.org/specs/rfc7540.html#CONNECT, "frame types
10448// other than DATA or stream management frames (RST_STREAM, WINDOW_UPDATE, and
10449// PRIORITY) MUST NOT be sent on a connected stream".
Bence Békycb4be9e2020-07-09 11:18:1410450// Also test that |http2_end_stream_with_data_frame| has no effect on proxy
10451// streams.
Bence Béky21755dd62019-11-19 13:47:3510452TEST_F(SpdyNetworkTransactionTest, DoNotGreaseFrameTypeWithConnect) {
10453 auto session_deps = std::make_unique<SpdySessionDependencies>(
Nicolas Arciniegad2013f92020-02-07 23:00:5610454 ConfiguredProxyResolutionService::CreateFixedFromPacResult(
Bence Béky21755dd62019-11-19 13:47:3510455 "HTTPS myproxy:70", TRAFFIC_ANNOTATION_FOR_TESTS));
10456
10457 const uint8_t type = 0x0b;
10458 const uint8_t flags = 0xcc;
10459 const std::string payload("foo");
10460 session_deps->greased_http2_frame =
10461 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10462 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410463 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky21755dd62019-11-19 13:47:3510464
10465 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10466 std::move(session_deps));
10467
10468 // CONNECT to proxy.
10469 spdy::SpdySerializedFrame connect_req(spdy_util_.ConstructSpdyConnect(
10470 nullptr, 0, 1, HttpProxyConnectJob::kH2QuicTunnelPriority,
10471 HostPortPair("www.example.org", 443)));
10472 spdy::SpdySerializedFrame connect_response(
10473 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10474
10475 // Tunneled transaction wrapped in DATA frames.
10476 const char req[] =
10477 "GET / HTTP/1.1\r\n"
10478 "Host: www.example.org\r\n"
10479 "Connection: keep-alive\r\n\r\n";
10480 spdy::SpdySerializedFrame tunneled_req(
10481 spdy_util_.ConstructSpdyDataFrame(1, req, false));
10482
10483 const char resp[] =
10484 "HTTP/1.1 200 OK\r\n"
10485 "Content-Length: 5\r\n\r\n"
10486 "hello";
10487 spdy::SpdySerializedFrame tunneled_response(
10488 spdy_util_.ConstructSpdyDataFrame(1, resp, false));
10489
10490 MockWrite writes[] = {CreateMockWrite(connect_req, 0),
10491 CreateMockWrite(tunneled_req, 2)};
10492
10493 MockRead reads[] = {CreateMockRead(connect_response, 1),
10494 CreateMockRead(tunneled_response, 3),
10495 MockRead(ASYNC, 0, 4)};
10496
10497 SequencedSocketData data0(reads, writes);
10498
10499 // HTTP/2 connection to proxy.
10500 auto ssl_provider0 = std::make_unique<SSLSocketDataProvider>(ASYNC, OK);
10501 ssl_provider0->next_proto = kProtoHTTP2;
10502 helper.AddDataWithSSLSocketDataProvider(&data0, std::move(ssl_provider0));
10503
10504 // HTTP/1.1 to destination.
10505 SSLSocketDataProvider ssl_provider1(ASYNC, OK);
10506 ssl_provider1.next_proto = kProtoHTTP11;
10507 helper.session_deps()->socket_factory->AddSSLSocketDataProvider(
10508 &ssl_provider1);
10509
10510 helper.RunPreTestSetup();
10511 helper.StartDefaultTest();
10512 helper.FinishDefaultTestWithoutVerification();
10513 helper.VerifyDataConsumed();
10514
10515 const HttpResponseInfo* response = helper.trans()->GetResponseInfo();
10516 ASSERT_TRUE(response);
10517 ASSERT_TRUE(response->headers);
10518 EXPECT_EQ("HTTP/1.1 200 OK", response->headers->GetStatusLine());
10519 EXPECT_FALSE(response->was_fetched_via_spdy);
10520 EXPECT_EQ(HttpResponseInfo::CONNECTION_INFO_HTTP1_1,
10521 response->connection_info);
10522 EXPECT_TRUE(response->was_alpn_negotiated);
10523 EXPECT_TRUE(request_.url.SchemeIs("https"));
10524 EXPECT_EQ("127.0.0.1", response->remote_endpoint.ToStringWithoutPort());
10525 EXPECT_EQ(70, response->remote_endpoint.port());
10526 std::string response_data;
10527 ASSERT_THAT(ReadTransaction(helper.trans(), &response_data), IsOk());
10528 EXPECT_EQ("hello", response_data);
10529}
10530
Bence Béky087d4ba2020-05-13 23:10:2810531// Regression test for https://crbug.com/1081955.
10532// Greasing frame types is enabled, the outgoing HEADERS frame is followed by a
10533// frame of reserved type, then an empty DATA frame to close the stream.
10534// Response arrives before reserved frame and DATA frame can be sent.
10535// SpdyHttpStream::OnDataSent() must not crash.
10536TEST_F(SpdyNetworkTransactionTest, OnDataSentDoesNotCrashWithGreasedFrameType) {
10537 auto session_deps = std::make_unique<SpdySessionDependencies>();
10538
10539 const uint8_t type = 0x0b;
10540 const uint8_t flags = 0xcc;
10541 const std::string payload("foo");
10542 session_deps->greased_http2_frame =
10543 base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
10544 {type, flags, payload});
Bence Békycb4be9e2020-07-09 11:18:1410545 session_deps->http2_end_stream_with_data_frame = true;
Bence Béky087d4ba2020-05-13 23:10:2810546
10547 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_,
10548 std::move(session_deps));
10549
Bence Béky4c325e52020-10-22 20:48:0110550 spdy::Http2HeaderBlock headers(
Bence Béky087d4ba2020-05-13 23:10:2810551 spdy_util_.ConstructGetHeaderBlock(kDefaultUrl));
10552 spdy::SpdySerializedFrame req(
10553 spdy_util_.ConstructSpdyHeaders(1, std::move(headers), DEFAULT_PRIORITY,
10554 /* fin = */ false));
10555
10556 const char kRawFrameData[] = {
10557 0x00, 0x00, 0x03, // length
10558 0x0b, // type
10559 0xcc, // flags
10560 0x00, 0x00, 0x00, 0x01, // stream ID
10561 'f', 'o', 'o' // payload
10562 };
10563 spdy::SpdySerializedFrame grease(const_cast<char*>(kRawFrameData),
10564 base::size(kRawFrameData),
10565 /* owns_buffer = */ false);
10566 spdy::SpdySerializedFrame empty_body(
10567 spdy_util_.ConstructSpdyDataFrame(1, "", true));
10568
10569 MockWrite writes[] = {
10570 CreateMockWrite(req, 0), MockWrite(ASYNC, ERR_IO_PENDING, 2),
10571 CreateMockWrite(grease, 3), CreateMockWrite(empty_body, 4)};
10572
10573 spdy::SpdySerializedFrame resp(
10574 spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
10575 spdy::SpdySerializedFrame response_body(
10576 spdy_util_.ConstructSpdyDataFrame(1, true));
10577
10578 MockRead reads[] = {CreateMockRead(resp, 1), CreateMockRead(response_body, 5),
10579 MockRead(ASYNC, 0, 6)};
10580
10581 SequencedSocketData data(reads, writes);
10582 helper.RunPreTestSetup();
10583 helper.AddData(&data);
10584
10585 TestCompletionCallback callback;
10586 int rv = helper.trans()->Start(&request_, callback.callback(), log_);
10587 base::RunLoop().RunUntilIdle();
10588
10589 // Response headers received. Resume sending |grease| and |empty_body|.
10590 data.Resume();
10591 EXPECT_THAT(callback.GetResult(rv), IsOk());
10592
10593 base::RunLoop().RunUntilIdle();
10594
10595 helper.VerifyDataConsumed();
10596}
10597
Yoichi Osato4c75c0c2020-06-24 08:03:5710598TEST_F(SpdyNetworkTransactionTest, NotAllowHTTP1NotBlockH2Post) {
10599 spdy::SpdySerializedFrame req(
10600 spdy_util_.ConstructChunkedSpdyPost(nullptr, 0));
10601 spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
10602 MockWrite writes[] = {
10603 CreateMockWrite(req, 0), CreateMockWrite(body, 1), // POST upload frame
10604 };
10605 spdy::SpdySerializedFrame resp(spdy_util_.ConstructSpdyPostReply(nullptr, 0));
10606 MockRead reads[] = {
10607 CreateMockRead(resp, 2), CreateMockRead(body, 3),
10608 MockRead(ASYNC, 0, 4) // EOF
10609 };
10610 SequencedSocketData data(reads, writes);
10611
10612 request_.method = "POST";
10613 UploadDataStreamNotAllowHTTP1 upload_data(kUploadData);
10614 request_.upload_data_stream = &upload_data;
10615
10616 NormalSpdyTransactionHelper helper(request_, DEFAULT_PRIORITY, log_, nullptr);
10617 helper.RunToCompletion(&data);
10618 TransactionHelperResult out = helper.output();
10619 EXPECT_THAT(out.rv, IsOk());
10620 EXPECT_EQ("HTTP/1.1 200", out.status_line);
10621 EXPECT_EQ("hello!", out.response_data);
10622}
10623
[email protected]aea80602009-09-18 00:55:0810624} // namespace net