xref: /aosp_15_r20/external/cronet/net/spdy/spdy_test_util_common.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "net/spdy/spdy_test_util_common.h"
6 
7 #include <cstddef>
8 #include <optional>
9 #include <string_view>
10 #include <utility>
11 
12 #include "base/base64.h"
13 #include "base/check_op.h"
14 #include "base/compiler_specific.h"
15 #include "base/containers/span.h"
16 #include "base/functional/bind.h"
17 #include "base/notreached.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_split.h"
20 #include "build/build_config.h"
21 #include "net/base/features.h"
22 #include "net/base/host_port_pair.h"
23 #include "net/base/http_user_agent_settings.h"
24 #include "net/base/proxy_delegate.h"
25 #include "net/cert/ct_policy_status.h"
26 #include "net/cert/mock_cert_verifier.h"
27 #include "net/cert/signed_certificate_timestamp_and_status.h"
28 #include "net/dns/host_resolver.h"
29 #include "net/dns/public/secure_dns_policy.h"
30 #include "net/http/http_cache.h"
31 #include "net/http/http_network_transaction.h"
32 #include "net/http/http_proxy_connect_job.h"
33 #include "net/log/net_log_with_source.h"
34 #include "net/proxy_resolution/configured_proxy_resolution_service.h"
35 #include "net/quic/quic_context.h"
36 #include "net/quic/quic_crypto_client_stream_factory.h"
37 #include "net/quic/quic_http_utils.h"
38 #include "net/socket/client_socket_handle.h"
39 #include "net/socket/next_proto.h"
40 #include "net/socket/socket_tag.h"
41 #include "net/socket/socks_connect_job.h"
42 #include "net/socket/ssl_client_socket.h"
43 #include "net/socket/transport_client_socket_pool.h"
44 #include "net/spdy/buffered_spdy_framer.h"
45 #include "net/spdy/spdy_http_utils.h"
46 #include "net/spdy/spdy_stream.h"
47 #include "net/ssl/ssl_connection_status_flags.h"
48 #include "net/test/gtest_util.h"
49 #include "net/third_party/quiche/src/quiche/spdy/core/spdy_alt_svc_wire_format.h"
50 #include "net/third_party/quiche/src/quiche/spdy/core/spdy_framer.h"
51 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
52 #include "net/url_request/static_http_user_agent_settings.h"
53 #include "net/url_request/url_request_context_builder.h"
54 #include "net/url_request/url_request_job_factory.h"
55 #include "net/url_request/url_request_test_util.h"
56 #include "testing/gmock/include/gmock/gmock.h"
57 #include "url/scheme_host_port.h"
58 #include "url/url_constants.h"
59 
60 using net::test::IsError;
61 using net::test::IsOk;
62 
63 namespace net {
64 
65 namespace {
66 
67 // Parses a URL into the scheme, host, and path components required for a
68 // SPDY request.
ParseUrl(std::string_view url,std::string * scheme,std::string * host,std::string * path)69 void ParseUrl(std::string_view url,
70               std::string* scheme,
71               std::string* host,
72               std::string* path) {
73   GURL gurl(url);
74   path->assign(gurl.PathForRequest());
75   scheme->assign(gurl.scheme());
76   host->assign(gurl.host());
77   if (gurl.has_port()) {
78     host->append(":");
79     host->append(gurl.port());
80   }
81 }
82 
83 }  // namespace
84 
85 // Chop a frame into an array of MockWrites.
86 // |frame| is the frame to chop.
87 // |num_chunks| is the number of chunks to create.
ChopWriteFrame(const spdy::SpdySerializedFrame & frame,int num_chunks)88 std::unique_ptr<MockWrite[]> ChopWriteFrame(
89     const spdy::SpdySerializedFrame& frame,
90     int num_chunks) {
91   auto chunks = std::make_unique<MockWrite[]>(num_chunks);
92   int chunk_size = frame.size() / num_chunks;
93   for (int index = 0; index < num_chunks; index++) {
94     const char* ptr = frame.data() + (index * chunk_size);
95     if (index == num_chunks - 1)
96       chunk_size +=
97           frame.size() % chunk_size;  // The last chunk takes the remainder.
98     chunks[index] = MockWrite(ASYNC, ptr, chunk_size);
99   }
100   return chunks;
101 }
102 
103 // Adds headers and values to a map.
104 // |extra_headers| is an array of { name, value } pairs, arranged as strings
105 // where the even entries are the header names, and the odd entries are the
106 // header values.
107 // |headers| gets filled in from |extra_headers|.
AppendToHeaderBlock(const char * const extra_headers[],int extra_header_count,spdy::Http2HeaderBlock * headers)108 void AppendToHeaderBlock(const char* const extra_headers[],
109                          int extra_header_count,
110                          spdy::Http2HeaderBlock* headers) {
111   if (!extra_header_count)
112     return;
113 
114   // Sanity check: Non-NULL header list.
115   DCHECK(extra_headers) << "NULL header value pair list";
116   // Sanity check: Non-NULL header map.
117   DCHECK(headers) << "NULL header map";
118 
119   // Copy in the headers.
120   for (int i = 0; i < extra_header_count; i++) {
121     std::string_view key(extra_headers[i * 2]);
122     std::string_view value(extra_headers[i * 2 + 1]);
123     DCHECK(!key.empty()) << "Header key must not be empty.";
124     headers->AppendValueOrAddHeader(key, value);
125   }
126 }
127 
128 // Create a MockWrite from the given spdy::SpdySerializedFrame.
CreateMockWrite(const spdy::SpdySerializedFrame & req)129 MockWrite CreateMockWrite(const spdy::SpdySerializedFrame& req) {
130   return MockWrite(ASYNC, req.data(), req.size());
131 }
132 
133 // Create a MockWrite from the given spdy::SpdySerializedFrame and sequence
134 // number.
CreateMockWrite(const spdy::SpdySerializedFrame & req,int seq)135 MockWrite CreateMockWrite(const spdy::SpdySerializedFrame& req, int seq) {
136   return CreateMockWrite(req, seq, ASYNC);
137 }
138 
139 // Create a MockWrite from the given spdy::SpdySerializedFrame and sequence
140 // number.
CreateMockWrite(const spdy::SpdySerializedFrame & req,int seq,IoMode mode)141 MockWrite CreateMockWrite(const spdy::SpdySerializedFrame& req,
142                           int seq,
143                           IoMode mode) {
144   return MockWrite(mode, req.data(), req.size(), seq);
145 }
146 
147 // Create a MockRead from the given spdy::SpdySerializedFrame.
CreateMockRead(const spdy::SpdySerializedFrame & resp)148 MockRead CreateMockRead(const spdy::SpdySerializedFrame& resp) {
149   return MockRead(ASYNC, resp.data(), resp.size());
150 }
151 
152 // Create a MockRead from the given spdy::SpdySerializedFrame and sequence
153 // number.
CreateMockRead(const spdy::SpdySerializedFrame & resp,int seq)154 MockRead CreateMockRead(const spdy::SpdySerializedFrame& resp, int seq) {
155   return CreateMockRead(resp, seq, ASYNC);
156 }
157 
158 // Create a MockRead from the given spdy::SpdySerializedFrame and sequence
159 // number.
CreateMockRead(const spdy::SpdySerializedFrame & resp,int seq,IoMode mode)160 MockRead CreateMockRead(const spdy::SpdySerializedFrame& resp,
161                         int seq,
162                         IoMode mode) {
163   return MockRead(mode, resp.data(), resp.size(), seq);
164 }
165 
166 // Combines the given vector of spdy::SpdySerializedFrame into a single frame.
CombineFrames(std::vector<const spdy::SpdySerializedFrame * > frames)167 spdy::SpdySerializedFrame CombineFrames(
168     std::vector<const spdy::SpdySerializedFrame*> frames) {
169   size_t total_size = 0;
170   for (const auto* frame : frames) {
171     total_size += frame->size();
172   }
173   auto data = std::make_unique<char[]>(total_size);
174   char* ptr = data.get();
175   for (const auto* frame : frames) {
176     memcpy(ptr, frame->data(), frame->size());
177     ptr += frame->size();
178   }
179   return spdy::SpdySerializedFrame(std::move(data), total_size);
180 }
181 
182 namespace {
183 
184 class PriorityGetter : public BufferedSpdyFramerVisitorInterface {
185  public:
186   PriorityGetter() = default;
187   ~PriorityGetter() override = default;
188 
priority() const189   spdy::SpdyPriority priority() const { return priority_; }
190 
OnError(http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error)191   void OnError(
192       http2::Http2DecoderAdapter::SpdyFramerError spdy_framer_error) override {}
OnStreamError(spdy::SpdyStreamId stream_id,const std::string & description)193   void OnStreamError(spdy::SpdyStreamId stream_id,
194                      const std::string& description) override {}
OnHeaders(spdy::SpdyStreamId stream_id,bool has_priority,int weight,spdy::SpdyStreamId parent_stream_id,bool exclusive,bool fin,spdy::Http2HeaderBlock headers,base::TimeTicks recv_first_byte_time)195   void OnHeaders(spdy::SpdyStreamId stream_id,
196                  bool has_priority,
197                  int weight,
198                  spdy::SpdyStreamId parent_stream_id,
199                  bool exclusive,
200                  bool fin,
201                  spdy::Http2HeaderBlock headers,
202                  base::TimeTicks recv_first_byte_time) override {
203     if (has_priority) {
204       priority_ = spdy::Http2WeightToSpdy3Priority(weight);
205     }
206   }
OnDataFrameHeader(spdy::SpdyStreamId stream_id,size_t length,bool fin)207   void OnDataFrameHeader(spdy::SpdyStreamId stream_id,
208                          size_t length,
209                          bool fin) override {}
OnStreamFrameData(spdy::SpdyStreamId stream_id,const char * data,size_t len)210   void OnStreamFrameData(spdy::SpdyStreamId stream_id,
211                          const char* data,
212                          size_t len) override {}
OnStreamEnd(spdy::SpdyStreamId stream_id)213   void OnStreamEnd(spdy::SpdyStreamId stream_id) override {}
OnStreamPadding(spdy::SpdyStreamId stream_id,size_t len)214   void OnStreamPadding(spdy::SpdyStreamId stream_id, size_t len) override {}
OnSettings()215   void OnSettings() override {}
OnSettingsAck()216   void OnSettingsAck() override {}
OnSetting(spdy::SpdySettingsId id,uint32_t value)217   void OnSetting(spdy::SpdySettingsId id, uint32_t value) override {}
OnSettingsEnd()218   void OnSettingsEnd() override {}
OnPing(spdy::SpdyPingId unique_id,bool is_ack)219   void OnPing(spdy::SpdyPingId unique_id, bool is_ack) override {}
OnRstStream(spdy::SpdyStreamId stream_id,spdy::SpdyErrorCode error_code)220   void OnRstStream(spdy::SpdyStreamId stream_id,
221                    spdy::SpdyErrorCode error_code) override {}
OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,spdy::SpdyErrorCode error_code,std::string_view debug_data)222   void OnGoAway(spdy::SpdyStreamId last_accepted_stream_id,
223                 spdy::SpdyErrorCode error_code,
224                 std::string_view debug_data) override {}
OnWindowUpdate(spdy::SpdyStreamId stream_id,int delta_window_size)225   void OnWindowUpdate(spdy::SpdyStreamId stream_id,
226                       int delta_window_size) override {}
OnPushPromise(spdy::SpdyStreamId stream_id,spdy::SpdyStreamId promised_stream_id,spdy::Http2HeaderBlock headers)227   void OnPushPromise(spdy::SpdyStreamId stream_id,
228                      spdy::SpdyStreamId promised_stream_id,
229                      spdy::Http2HeaderBlock headers) override {}
OnAltSvc(spdy::SpdyStreamId stream_id,std::string_view origin,const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector & altsvc_vector)230   void OnAltSvc(spdy::SpdyStreamId stream_id,
231                 std::string_view origin,
232                 const spdy::SpdyAltSvcWireFormat::AlternativeServiceVector&
233                     altsvc_vector) override {}
OnUnknownFrame(spdy::SpdyStreamId stream_id,uint8_t frame_type)234   bool OnUnknownFrame(spdy::SpdyStreamId stream_id,
235                       uint8_t frame_type) override {
236     return false;
237   }
238 
239  private:
240   spdy::SpdyPriority priority_ = 0;
241 };
242 
243 }  // namespace
244 
GetSpdyPriority(const spdy::SpdySerializedFrame & frame,spdy::SpdyPriority * priority)245 bool GetSpdyPriority(const spdy::SpdySerializedFrame& frame,
246                      spdy::SpdyPriority* priority) {
247   NetLogWithSource net_log;
248   BufferedSpdyFramer framer(kMaxHeaderListSizeForTest, net_log);
249   PriorityGetter priority_getter;
250   framer.set_visitor(&priority_getter);
251   size_t frame_size = frame.size();
252   if (framer.ProcessInput(frame.data(), frame_size) != frame_size) {
253     return false;
254   }
255   *priority = priority_getter.priority();
256   return true;
257 }
258 
CreateStreamSynchronously(SpdyStreamType type,const base::WeakPtr<SpdySession> & session,const GURL & url,RequestPriority priority,const NetLogWithSource & net_log,bool detect_broken_connection,base::TimeDelta heartbeat_interval)259 base::WeakPtr<SpdyStream> CreateStreamSynchronously(
260     SpdyStreamType type,
261     const base::WeakPtr<SpdySession>& session,
262     const GURL& url,
263     RequestPriority priority,
264     const NetLogWithSource& net_log,
265     bool detect_broken_connection,
266     base::TimeDelta heartbeat_interval) {
267   SpdyStreamRequest stream_request;
268   int rv = stream_request.StartRequest(
269       type, session, url, false /* no early data */, priority, SocketTag(),
270       net_log, CompletionOnceCallback(), TRAFFIC_ANNOTATION_FOR_TESTS,
271       detect_broken_connection, heartbeat_interval);
272 
273   return
274       (rv == OK) ? stream_request.ReleaseStream() : base::WeakPtr<SpdyStream>();
275 }
276 
277 StreamReleaserCallback::StreamReleaserCallback() = default;
278 
279 StreamReleaserCallback::~StreamReleaserCallback() = default;
280 
MakeCallback(SpdyStreamRequest * request)281 CompletionOnceCallback StreamReleaserCallback::MakeCallback(
282     SpdyStreamRequest* request) {
283   return base::BindOnce(&StreamReleaserCallback::OnComplete,
284                         base::Unretained(this), request);
285 }
286 
OnComplete(SpdyStreamRequest * request,int result)287 void StreamReleaserCallback::OnComplete(
288     SpdyStreamRequest* request, int result) {
289   if (result == OK)
290     request->ReleaseStream()->Cancel(ERR_ABORTED);
291   SetResult(result);
292 }
293 
SpdySessionDependencies()294 SpdySessionDependencies::SpdySessionDependencies()
295     : SpdySessionDependencies(
296           ConfiguredProxyResolutionService::CreateDirect()) {}
297 
SpdySessionDependencies(std::unique_ptr<ProxyResolutionService> proxy_resolution_service)298 SpdySessionDependencies::SpdySessionDependencies(
299     std::unique_ptr<ProxyResolutionService> proxy_resolution_service)
300     : host_resolver(std::make_unique<MockCachingHostResolver>(
301           /*cache_invalidation_num=*/0,
302           MockHostResolverBase::RuleResolver::GetLocalhostResult())),
303       cert_verifier(std::make_unique<MockCertVerifier>()),
304       transport_security_state(std::make_unique<TransportSecurityState>()),
305       proxy_resolution_service(std::move(proxy_resolution_service)),
306       ssl_config_service(std::make_unique<SSLConfigServiceDefaults>()),
307       socket_factory(std::make_unique<MockClientSocketFactory>()),
308       http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault()),
309       http_server_properties(std::make_unique<HttpServerProperties>()),
310       quic_context(std::make_unique<QuicContext>()),
311       time_func(&base::TimeTicks::Now) {
312   http2_settings[spdy::SETTINGS_INITIAL_WINDOW_SIZE] =
313       kDefaultInitialWindowSize;
314 }
315 
316 SpdySessionDependencies::SpdySessionDependencies(SpdySessionDependencies&&) =
317     default;
318 
319 SpdySessionDependencies::~SpdySessionDependencies() = default;
320 
321 SpdySessionDependencies& SpdySessionDependencies::operator=(
322     SpdySessionDependencies&&) = default;
323 
324 // static
SpdyCreateSession(SpdySessionDependencies * session_deps)325 std::unique_ptr<HttpNetworkSession> SpdySessionDependencies::SpdyCreateSession(
326     SpdySessionDependencies* session_deps) {
327   return SpdyCreateSessionWithSocketFactory(session_deps,
328                                             session_deps->socket_factory.get());
329 }
330 
331 // static
332 std::unique_ptr<HttpNetworkSession>
SpdyCreateSessionWithSocketFactory(SpdySessionDependencies * session_deps,ClientSocketFactory * factory)333 SpdySessionDependencies::SpdyCreateSessionWithSocketFactory(
334     SpdySessionDependencies* session_deps,
335     ClientSocketFactory* factory) {
336   HttpNetworkSessionParams session_params = CreateSessionParams(session_deps);
337   HttpNetworkSessionContext session_context =
338       CreateSessionContext(session_deps);
339   session_context.client_socket_factory = factory;
340   auto http_session =
341       std::make_unique<HttpNetworkSession>(session_params, session_context);
342   SpdySessionPoolPeer pool_peer(http_session->spdy_session_pool());
343   pool_peer.SetEnableSendingInitialData(false);
344   return http_session;
345 }
346 
347 // static
CreateSessionParams(SpdySessionDependencies * session_deps)348 HttpNetworkSessionParams SpdySessionDependencies::CreateSessionParams(
349     SpdySessionDependencies* session_deps) {
350   HttpNetworkSessionParams params;
351   params.host_mapping_rules = session_deps->host_mapping_rules;
352   params.enable_spdy_ping_based_connection_checking = session_deps->enable_ping;
353   params.enable_user_alternate_protocol_ports =
354       session_deps->enable_user_alternate_protocol_ports;
355   params.enable_quic = session_deps->enable_quic;
356   params.spdy_session_max_recv_window_size =
357       session_deps->session_max_recv_window_size;
358   params.spdy_session_max_queued_capped_frames =
359       session_deps->session_max_queued_capped_frames;
360   params.http2_settings = session_deps->http2_settings;
361   params.time_func = session_deps->time_func;
362   params.enable_http2_alternative_service =
363       session_deps->enable_http2_alternative_service;
364   params.enable_http2_settings_grease =
365       session_deps->enable_http2_settings_grease;
366   params.greased_http2_frame = session_deps->greased_http2_frame;
367   params.http2_end_stream_with_data_frame =
368       session_deps->http2_end_stream_with_data_frame;
369   params.disable_idle_sockets_close_on_memory_pressure =
370       session_deps->disable_idle_sockets_close_on_memory_pressure;
371   params.enable_early_data = session_deps->enable_early_data;
372   params.key_auth_cache_server_entries_by_network_anonymization_key =
373       session_deps->key_auth_cache_server_entries_by_network_anonymization_key;
374   params.enable_priority_update = session_deps->enable_priority_update;
375   params.spdy_go_away_on_ip_change = session_deps->go_away_on_ip_change;
376   params.ignore_ip_address_changes = session_deps->ignore_ip_address_changes;
377   return params;
378 }
379 
CreateSessionContext(SpdySessionDependencies * session_deps)380 HttpNetworkSessionContext SpdySessionDependencies::CreateSessionContext(
381     SpdySessionDependencies* session_deps) {
382   HttpNetworkSessionContext context;
383   context.client_socket_factory = session_deps->socket_factory.get();
384   context.host_resolver = session_deps->GetHostResolver();
385   context.cert_verifier = session_deps->cert_verifier.get();
386   context.transport_security_state =
387       session_deps->transport_security_state.get();
388   context.proxy_delegate = session_deps->proxy_delegate.get();
389   context.proxy_resolution_service =
390       session_deps->proxy_resolution_service.get();
391   context.http_user_agent_settings =
392       session_deps->http_user_agent_settings.get();
393   context.ssl_config_service = session_deps->ssl_config_service.get();
394   context.http_auth_handler_factory =
395       session_deps->http_auth_handler_factory.get();
396   context.http_server_properties = session_deps->http_server_properties.get();
397   context.quic_context = session_deps->quic_context.get();
398   context.net_log = session_deps->net_log;
399   context.quic_crypto_client_stream_factory =
400       session_deps->quic_crypto_client_stream_factory.get();
401 #if BUILDFLAG(ENABLE_REPORTING)
402   context.reporting_service = session_deps->reporting_service.get();
403   context.network_error_logging_service =
404       session_deps->network_error_logging_service.get();
405 #endif
406   return context;
407 }
408 
409 std::unique_ptr<URLRequestContextBuilder>
CreateSpdyTestURLRequestContextBuilder(ClientSocketFactory * client_socket_factory)410 CreateSpdyTestURLRequestContextBuilder(
411     ClientSocketFactory* client_socket_factory) {
412   auto builder = CreateTestURLRequestContextBuilder();
413   builder->set_client_socket_factory_for_testing(  // IN-TEST
414       client_socket_factory);
415   builder->set_host_resolver(std::make_unique<MockHostResolver>(
416       /*default_result=*/MockHostResolverBase::RuleResolver::
417           GetLocalhostResult()));
418   builder->SetCertVerifier(std::make_unique<MockCertVerifier>());
419   HttpNetworkSessionParams session_params;
420   session_params.enable_spdy_ping_based_connection_checking = false;
421   builder->set_http_network_session_params(session_params);
422   builder->set_http_user_agent_settings(
423       std::make_unique<StaticHttpUserAgentSettings>("", ""));
424   return builder;
425 }
426 
HasSpdySession(SpdySessionPool * pool,const SpdySessionKey & key)427 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key) {
428   return static_cast<bool>(pool->FindAvailableSession(
429       key, /* enable_ip_based_pooling = */ true,
430       /* is_websocket = */ false, NetLogWithSource()));
431 }
432 
433 namespace {
434 
CreateSpdySessionHelper(HttpNetworkSession * http_session,const SpdySessionKey & key,const NetLogWithSource & net_log,bool enable_ip_based_pooling)435 base::WeakPtr<SpdySession> CreateSpdySessionHelper(
436     HttpNetworkSession* http_session,
437     const SpdySessionKey& key,
438     const NetLogWithSource& net_log,
439     bool enable_ip_based_pooling) {
440   EXPECT_FALSE(http_session->spdy_session_pool()->FindAvailableSession(
441       key, enable_ip_based_pooling,
442       /*is_websocket=*/false, NetLogWithSource()));
443 
444   auto connection = std::make_unique<ClientSocketHandle>();
445   TestCompletionCallback callback;
446 
447   scoped_refptr<ClientSocketPool::SocketParams> socket_params =
448       base::MakeRefCounted<ClientSocketPool::SocketParams>(
449           /*allowed_bad_certs=*/std::vector<SSLConfig::CertAndStatus>());
450   int rv = connection->Init(
451       ClientSocketPool::GroupId(
452           url::SchemeHostPort(url::kHttpsScheme,
453                               key.host_port_pair().HostForURL(),
454                               key.host_port_pair().port()),
455           key.privacy_mode(), NetworkAnonymizationKey(),
456           SecureDnsPolicy::kAllow, /*disable_cert_network_fetches=*/false),
457       socket_params, /*proxy_annotation_tag=*/std::nullopt, MEDIUM,
458       key.socket_tag(), ClientSocketPool::RespectLimits::ENABLED,
459       callback.callback(), ClientSocketPool::ProxyAuthCallback(),
460       http_session->GetSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL,
461                                   ProxyChain::Direct()),
462       net_log);
463   rv = callback.GetResult(rv);
464   EXPECT_THAT(rv, IsOk());
465 
466   base::WeakPtr<SpdySession> spdy_session;
467   rv =
468       http_session->spdy_session_pool()->CreateAvailableSessionFromSocketHandle(
469           key, std::move(connection), net_log, &spdy_session);
470   // Failure is reported asynchronously.
471   EXPECT_THAT(rv, IsOk());
472   EXPECT_TRUE(spdy_session);
473   EXPECT_TRUE(HasSpdySession(http_session->spdy_session_pool(), key));
474   // Disable the time-based receive window updates by setting the delay to
475   // the max time interval. This prevents time-based flakiness in the tests
476   // for any test not explicitly exercising the window update buffering.
477   spdy_session->SetTimeToBufferSmallWindowUpdates(base::TimeDelta::Max());
478   return spdy_session;
479 }
480 
481 }  // namespace
482 
CreateSpdySession(HttpNetworkSession * http_session,const SpdySessionKey & key,const NetLogWithSource & net_log)483 base::WeakPtr<SpdySession> CreateSpdySession(HttpNetworkSession* http_session,
484                                              const SpdySessionKey& key,
485                                              const NetLogWithSource& net_log) {
486   return CreateSpdySessionHelper(http_session, key, net_log,
487                                  /* enable_ip_based_pooling = */ true);
488 }
489 
CreateSpdySessionWithIpBasedPoolingDisabled(HttpNetworkSession * http_session,const SpdySessionKey & key,const NetLogWithSource & net_log)490 base::WeakPtr<SpdySession> CreateSpdySessionWithIpBasedPoolingDisabled(
491     HttpNetworkSession* http_session,
492     const SpdySessionKey& key,
493     const NetLogWithSource& net_log) {
494   return CreateSpdySessionHelper(http_session, key, net_log,
495                                  /* enable_ip_based_pooling = */ false);
496 }
497 
498 namespace {
499 
500 // A ClientSocket used for CreateFakeSpdySession() below.
501 class FakeSpdySessionClientSocket : public MockClientSocket {
502  public:
FakeSpdySessionClientSocket()503   FakeSpdySessionClientSocket() : MockClientSocket(NetLogWithSource()) {}
504 
505   ~FakeSpdySessionClientSocket() override = default;
506 
Read(IOBuffer * buf,int buf_len,CompletionOnceCallback callback)507   int Read(IOBuffer* buf,
508            int buf_len,
509            CompletionOnceCallback callback) override {
510     return ERR_IO_PENDING;
511   }
512 
Write(IOBuffer * buf,int buf_len,CompletionOnceCallback callback,const NetworkTrafficAnnotationTag & traffic_annotation)513   int Write(IOBuffer* buf,
514             int buf_len,
515             CompletionOnceCallback callback,
516             const NetworkTrafficAnnotationTag& traffic_annotation) override {
517     return ERR_IO_PENDING;
518   }
519 
520   // Return kProtoUnknown to use the pool's default protocol.
GetNegotiatedProtocol() const521   NextProto GetNegotiatedProtocol() const override { return kProtoUnknown; }
522 
523   // The functions below are not expected to be called.
524 
Connect(CompletionOnceCallback callback)525   int Connect(CompletionOnceCallback callback) override {
526     ADD_FAILURE();
527     return ERR_UNEXPECTED;
528   }
529 
WasEverUsed() const530   bool WasEverUsed() const override {
531     ADD_FAILURE();
532     return false;
533   }
534 
GetSSLInfo(SSLInfo * ssl_info)535   bool GetSSLInfo(SSLInfo* ssl_info) override {
536     SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1_3,
537                                   &ssl_info->connection_status);
538     SSLConnectionStatusSetCipherSuite(0x1301 /* TLS_CHACHA20_POLY1305_SHA256 */,
539                                       &ssl_info->connection_status);
540     return true;
541   }
542 
GetTotalReceivedBytes() const543   int64_t GetTotalReceivedBytes() const override {
544     NOTIMPLEMENTED();
545     return 0;
546   }
547 };
548 
549 }  // namespace
550 
CreateFakeSpdySession(SpdySessionPool * pool,const SpdySessionKey & key)551 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool,
552                                                  const SpdySessionKey& key) {
553   EXPECT_FALSE(HasSpdySession(pool, key));
554   auto handle = std::make_unique<ClientSocketHandle>();
555   handle->SetSocket(std::make_unique<FakeSpdySessionClientSocket>());
556   base::WeakPtr<SpdySession> spdy_session;
557   int rv = pool->CreateAvailableSessionFromSocketHandle(
558       key, std::move(handle), NetLogWithSource(), &spdy_session);
559   // Failure is reported asynchronously.
560   EXPECT_THAT(rv, IsOk());
561   EXPECT_TRUE(spdy_session);
562   EXPECT_TRUE(HasSpdySession(pool, key));
563   // Disable the time-based receive window updates by setting the delay to
564   // the max time interval. This prevents time-based flakiness in the tests
565   // for any test not explicitly exercising the window update buffering.
566   spdy_session->SetTimeToBufferSmallWindowUpdates(base::TimeDelta::Max());
567   return spdy_session;
568 }
569 
SpdySessionPoolPeer(SpdySessionPool * pool)570 SpdySessionPoolPeer::SpdySessionPoolPeer(SpdySessionPool* pool) : pool_(pool) {
571 }
572 
RemoveAliases(const SpdySessionKey & key)573 void SpdySessionPoolPeer::RemoveAliases(const SpdySessionKey& key) {
574   pool_->RemoveAliases(key);
575 }
576 
SetEnableSendingInitialData(bool enabled)577 void SpdySessionPoolPeer::SetEnableSendingInitialData(bool enabled) {
578   pool_->enable_sending_initial_data_ = enabled;
579 }
580 
SpdyTestUtil(bool use_priority_header)581 SpdyTestUtil::SpdyTestUtil(bool use_priority_header)
582     : headerless_spdy_framer_(spdy::SpdyFramer::ENABLE_COMPRESSION),
583       request_spdy_framer_(spdy::SpdyFramer::ENABLE_COMPRESSION),
584       response_spdy_framer_(spdy::SpdyFramer::ENABLE_COMPRESSION),
585       default_url_(GURL(kDefaultUrl)),
586       use_priority_header_(use_priority_header) {}
587 
588 SpdyTestUtil::~SpdyTestUtil() = default;
589 
AddUrlToHeaderBlock(std::string_view url,spdy::Http2HeaderBlock * headers) const590 void SpdyTestUtil::AddUrlToHeaderBlock(std::string_view url,
591                                        spdy::Http2HeaderBlock* headers) const {
592   std::string scheme, host, path;
593   ParseUrl(url, &scheme, &host, &path);
594   (*headers)[spdy::kHttp2AuthorityHeader] = host;
595   (*headers)[spdy::kHttp2SchemeHeader] = scheme;
596   (*headers)[spdy::kHttp2PathHeader] = path;
597 }
598 
AddPriorityToHeaderBlock(RequestPriority request_priority,bool priority_incremental,spdy::Http2HeaderBlock * headers) const599 void SpdyTestUtil::AddPriorityToHeaderBlock(
600     RequestPriority request_priority,
601     bool priority_incremental,
602     spdy::Http2HeaderBlock* headers) const {
603   if (use_priority_header_ &&
604       base::FeatureList::IsEnabled(net::features::kPriorityHeader)) {
605     uint8_t urgency = ConvertRequestPriorityToQuicPriority(request_priority);
606     bool incremental = priority_incremental;
607     quic::HttpStreamPriority priority{urgency, incremental};
608     std::string serialized_priority =
609         quic::SerializePriorityFieldValue(priority);
610     if (!serialized_priority.empty()) {
611       (*headers)[kHttp2PriorityHeader] = serialized_priority;
612     }
613   }
614 }
615 
616 // static
ConstructGetHeaderBlock(std::string_view url)617 spdy::Http2HeaderBlock SpdyTestUtil::ConstructGetHeaderBlock(
618     std::string_view url) {
619   return ConstructHeaderBlock("GET", url, nullptr);
620 }
621 
622 // static
ConstructGetHeaderBlockForProxy(std::string_view url)623 spdy::Http2HeaderBlock SpdyTestUtil::ConstructGetHeaderBlockForProxy(
624     std::string_view url) {
625   return ConstructGetHeaderBlock(url);
626 }
627 
628 // static
ConstructHeadHeaderBlock(std::string_view url,int64_t content_length)629 spdy::Http2HeaderBlock SpdyTestUtil::ConstructHeadHeaderBlock(
630     std::string_view url,
631     int64_t content_length) {
632   return ConstructHeaderBlock("HEAD", url, nullptr);
633 }
634 
635 // static
ConstructPostHeaderBlock(std::string_view url,int64_t content_length)636 spdy::Http2HeaderBlock SpdyTestUtil::ConstructPostHeaderBlock(
637     std::string_view url,
638     int64_t content_length) {
639   return ConstructHeaderBlock("POST", url, &content_length);
640 }
641 
642 // static
ConstructPutHeaderBlock(std::string_view url,int64_t content_length)643 spdy::Http2HeaderBlock SpdyTestUtil::ConstructPutHeaderBlock(
644     std::string_view url,
645     int64_t content_length) {
646   return ConstructHeaderBlock("PUT", url, &content_length);
647 }
648 
ConstructSpdyReplyString(const spdy::Http2HeaderBlock & headers) const649 std::string SpdyTestUtil::ConstructSpdyReplyString(
650     const spdy::Http2HeaderBlock& headers) const {
651   std::string reply_string;
652   for (spdy::Http2HeaderBlock::const_iterator it = headers.begin();
653        it != headers.end(); ++it) {
654     auto key = std::string(it->first);
655     // Remove leading colon from pseudo headers.
656     if (key[0] == ':')
657       key = key.substr(1);
658     for (const std::string& value :
659          base::SplitString(it->second, std::string_view("\0", 1),
660                            base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) {
661       reply_string += key + ": " + value + "\n";
662     }
663   }
664   return reply_string;
665 }
666 
667 // TODO(jgraettinger): Eliminate uses of this method in tests (prefer
668 // spdy::SpdySettingsIR).
ConstructSpdySettings(const spdy::SettingsMap & settings)669 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdySettings(
670     const spdy::SettingsMap& settings) {
671   spdy::SpdySettingsIR settings_ir;
672   for (const auto& setting : settings) {
673     settings_ir.AddSetting(setting.first, setting.second);
674   }
675   return spdy::SpdySerializedFrame(
676       headerless_spdy_framer_.SerializeFrame(settings_ir));
677 }
678 
ConstructSpdySettingsAck()679 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdySettingsAck() {
680   spdy::SpdySettingsIR settings_ir;
681   settings_ir.set_is_ack(true);
682   return spdy::SpdySerializedFrame(
683       headerless_spdy_framer_.SerializeFrame(settings_ir));
684 }
685 
ConstructSpdyPing(uint32_t ping_id,bool is_ack)686 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyPing(uint32_t ping_id,
687                                                           bool is_ack) {
688   spdy::SpdyPingIR ping_ir(ping_id);
689   ping_ir.set_is_ack(is_ack);
690   return spdy::SpdySerializedFrame(
691       headerless_spdy_framer_.SerializeFrame(ping_ir));
692 }
693 
ConstructSpdyGoAway(spdy::SpdyStreamId last_good_stream_id)694 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyGoAway(
695     spdy::SpdyStreamId last_good_stream_id) {
696   spdy::SpdyGoAwayIR go_ir(last_good_stream_id, spdy::ERROR_CODE_NO_ERROR,
697                            "go away");
698   return spdy::SpdySerializedFrame(
699       headerless_spdy_framer_.SerializeFrame(go_ir));
700 }
701 
ConstructSpdyGoAway(spdy::SpdyStreamId last_good_stream_id,spdy::SpdyErrorCode error_code,const std::string & desc)702 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyGoAway(
703     spdy::SpdyStreamId last_good_stream_id,
704     spdy::SpdyErrorCode error_code,
705     const std::string& desc) {
706   spdy::SpdyGoAwayIR go_ir(last_good_stream_id, error_code, desc);
707   return spdy::SpdySerializedFrame(
708       headerless_spdy_framer_.SerializeFrame(go_ir));
709 }
710 
ConstructSpdyWindowUpdate(const spdy::SpdyStreamId stream_id,uint32_t delta_window_size)711 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyWindowUpdate(
712     const spdy::SpdyStreamId stream_id,
713     uint32_t delta_window_size) {
714   spdy::SpdyWindowUpdateIR update_ir(stream_id, delta_window_size);
715   return spdy::SpdySerializedFrame(
716       headerless_spdy_framer_.SerializeFrame(update_ir));
717 }
718 
719 // TODO(jgraettinger): Eliminate uses of this method in tests (prefer
720 // spdy::SpdyRstStreamIR).
ConstructSpdyRstStream(spdy::SpdyStreamId stream_id,spdy::SpdyErrorCode error_code)721 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyRstStream(
722     spdy::SpdyStreamId stream_id,
723     spdy::SpdyErrorCode error_code) {
724   spdy::SpdyRstStreamIR rst_ir(stream_id, error_code);
725   return spdy::SpdySerializedFrame(
726       headerless_spdy_framer_.SerializeRstStream(rst_ir));
727 }
728 
729 // TODO(jgraettinger): Eliminate uses of this method in tests (prefer
730 // spdy::SpdyPriorityIR).
ConstructSpdyPriority(spdy::SpdyStreamId stream_id,spdy::SpdyStreamId parent_stream_id,RequestPriority request_priority,bool exclusive)731 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyPriority(
732     spdy::SpdyStreamId stream_id,
733     spdy::SpdyStreamId parent_stream_id,
734     RequestPriority request_priority,
735     bool exclusive) {
736   int weight = spdy::Spdy3PriorityToHttp2Weight(
737       ConvertRequestPriorityToSpdyPriority(request_priority));
738   spdy::SpdyPriorityIR ir(stream_id, parent_stream_id, weight, exclusive);
739   return spdy::SpdySerializedFrame(
740       headerless_spdy_framer_.SerializePriority(ir));
741 }
742 
ConstructSpdyGet(const char * const url,spdy::SpdyStreamId stream_id,RequestPriority request_priority,bool priority_incremental,std::optional<RequestPriority> header_request_priority)743 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyGet(
744     const char* const url,
745     spdy::SpdyStreamId stream_id,
746     RequestPriority request_priority,
747     bool priority_incremental,
748     std::optional<RequestPriority> header_request_priority) {
749   spdy::Http2HeaderBlock block(ConstructGetHeaderBlock(url));
750   return ConstructSpdyHeaders(stream_id, std::move(block), request_priority,
751                               true, priority_incremental,
752                               header_request_priority);
753 }
754 
ConstructSpdyGet(const char * const extra_headers[],int extra_header_count,int stream_id,RequestPriority request_priority,bool priority_incremental,std::optional<RequestPriority> header_request_priority)755 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyGet(
756     const char* const extra_headers[],
757     int extra_header_count,
758     int stream_id,
759     RequestPriority request_priority,
760     bool priority_incremental,
761     std::optional<RequestPriority> header_request_priority) {
762   spdy::Http2HeaderBlock block;
763   block[spdy::kHttp2MethodHeader] = "GET";
764   AddUrlToHeaderBlock(default_url_.spec(), &block);
765   AppendToHeaderBlock(extra_headers, extra_header_count, &block);
766   return ConstructSpdyHeaders(stream_id, std::move(block), request_priority,
767                               true, priority_incremental,
768                               header_request_priority);
769 }
770 
ConstructSpdyConnect(const char * const extra_headers[],int extra_header_count,int stream_id,RequestPriority priority,const HostPortPair & host_port_pair)771 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyConnect(
772     const char* const extra_headers[],
773     int extra_header_count,
774     int stream_id,
775     RequestPriority priority,
776     const HostPortPair& host_port_pair) {
777   spdy::Http2HeaderBlock block;
778   block[spdy::kHttp2MethodHeader] = "CONNECT";
779   block[spdy::kHttp2AuthorityHeader] = host_port_pair.ToString();
780   AppendToHeaderBlock(extra_headers, extra_header_count, &block);
781   return ConstructSpdyHeaders(stream_id, std::move(block), priority, false);
782 }
783 
ConstructSpdyPushPromise(spdy::SpdyStreamId associated_stream_id,spdy::SpdyStreamId stream_id,spdy::Http2HeaderBlock headers)784 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyPushPromise(
785     spdy::SpdyStreamId associated_stream_id,
786     spdy::SpdyStreamId stream_id,
787     spdy::Http2HeaderBlock headers) {
788   spdy::SpdyPushPromiseIR push_promise(associated_stream_id, stream_id,
789                                        std::move(headers));
790   return spdy::SpdySerializedFrame(
791       response_spdy_framer_.SerializeFrame(push_promise));
792 }
793 
ConstructSpdyResponseHeaders(int stream_id,spdy::Http2HeaderBlock headers,bool fin)794 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyResponseHeaders(
795     int stream_id,
796     spdy::Http2HeaderBlock headers,
797     bool fin) {
798   spdy::SpdyHeadersIR spdy_headers(stream_id, std::move(headers));
799   spdy_headers.set_fin(fin);
800   return spdy::SpdySerializedFrame(
801       response_spdy_framer_.SerializeFrame(spdy_headers));
802 }
803 
ConstructSpdyHeaders(int stream_id,spdy::Http2HeaderBlock block,RequestPriority priority,bool fin,bool priority_incremental,std::optional<RequestPriority> header_request_priority)804 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyHeaders(
805     int stream_id,
806     spdy::Http2HeaderBlock block,
807     RequestPriority priority,
808     bool fin,
809     bool priority_incremental,
810     std::optional<RequestPriority> header_request_priority) {
811   // Get the stream id of the next highest priority request
812   // (most recent request of the same priority, or last request of
813   // an earlier priority).
814   // Note that this is a duplicate of the logic in Http2PriorityDependencies
815   // (slightly transformed as this is based on RequestPriority and that logic
816   // on spdy::SpdyPriority, but only slightly transformed) and hence tests using
817   // this function do not effectively test that logic.
818   // That logic is tested by the Http2PriorityDependencies unit tests.
819   int parent_stream_id = 0;
820   for (int q = priority; q <= HIGHEST; ++q) {
821     if (!priority_to_stream_id_list_[q].empty()) {
822       parent_stream_id = priority_to_stream_id_list_[q].back();
823       break;
824     }
825   }
826 
827   priority_to_stream_id_list_[priority].push_back(stream_id);
828 
829   if (block[spdy::kHttp2MethodHeader] != "CONNECT") {
830     RequestPriority header_priority =
831         header_request_priority.value_or(priority);
832     AddPriorityToHeaderBlock(header_priority, priority_incremental, &block);
833   }
834 
835   spdy::SpdyHeadersIR headers(stream_id, std::move(block));
836   headers.set_has_priority(true);
837   headers.set_weight(spdy::Spdy3PriorityToHttp2Weight(
838       ConvertRequestPriorityToSpdyPriority(priority)));
839   headers.set_parent_stream_id(parent_stream_id);
840   headers.set_exclusive(true);
841   headers.set_fin(fin);
842   return spdy::SpdySerializedFrame(
843       request_spdy_framer_.SerializeFrame(headers));
844 }
845 
ConstructSpdyReply(int stream_id,spdy::Http2HeaderBlock headers)846 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyReply(
847     int stream_id,
848     spdy::Http2HeaderBlock headers) {
849   spdy::SpdyHeadersIR reply(stream_id, std::move(headers));
850   return spdy::SpdySerializedFrame(response_spdy_framer_.SerializeFrame(reply));
851 }
852 
ConstructSpdyReplyError(const char * const status,const char * const * const extra_headers,int extra_header_count,int stream_id)853 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyReplyError(
854     const char* const status,
855     const char* const* const extra_headers,
856     int extra_header_count,
857     int stream_id) {
858   spdy::Http2HeaderBlock block;
859   block[spdy::kHttp2StatusHeader] = status;
860   block["hello"] = "bye";
861   AppendToHeaderBlock(extra_headers, extra_header_count, &block);
862 
863   spdy::SpdyHeadersIR reply(stream_id, std::move(block));
864   return spdy::SpdySerializedFrame(response_spdy_framer_.SerializeFrame(reply));
865 }
866 
ConstructSpdyReplyError(int stream_id)867 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyReplyError(int stream_id) {
868   return ConstructSpdyReplyError("500", nullptr, 0, stream_id);
869 }
870 
ConstructSpdyGetReply(const char * const extra_headers[],int extra_header_count,int stream_id)871 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyGetReply(
872     const char* const extra_headers[],
873     int extra_header_count,
874     int stream_id) {
875   spdy::Http2HeaderBlock block;
876   block[spdy::kHttp2StatusHeader] = "200";
877   block["hello"] = "bye";
878   AppendToHeaderBlock(extra_headers, extra_header_count, &block);
879 
880   return ConstructSpdyReply(stream_id, std::move(block));
881 }
882 
ConstructSpdyPost(const char * url,spdy::SpdyStreamId stream_id,int64_t content_length,RequestPriority request_priority,const char * const extra_headers[],int extra_header_count,bool priority_incremental)883 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyPost(
884     const char* url,
885     spdy::SpdyStreamId stream_id,
886     int64_t content_length,
887     RequestPriority request_priority,
888     const char* const extra_headers[],
889     int extra_header_count,
890     bool priority_incremental) {
891   spdy::Http2HeaderBlock block(ConstructPostHeaderBlock(url, content_length));
892   AppendToHeaderBlock(extra_headers, extra_header_count, &block);
893   return ConstructSpdyHeaders(stream_id, std::move(block), request_priority,
894                               false, priority_incremental);
895 }
896 
ConstructChunkedSpdyPost(const char * const extra_headers[],int extra_header_count,RequestPriority request_priority,bool priority_incremental)897 spdy::SpdySerializedFrame SpdyTestUtil::ConstructChunkedSpdyPost(
898     const char* const extra_headers[],
899     int extra_header_count,
900     RequestPriority request_priority,
901     bool priority_incremental) {
902   spdy::Http2HeaderBlock block;
903   block[spdy::kHttp2MethodHeader] = "POST";
904   AddUrlToHeaderBlock(default_url_.spec(), &block);
905   AppendToHeaderBlock(extra_headers, extra_header_count, &block);
906   return ConstructSpdyHeaders(1, std::move(block), request_priority, false,
907                               priority_incremental);
908 }
909 
ConstructSpdyPostReply(const char * const extra_headers[],int extra_header_count)910 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyPostReply(
911     const char* const extra_headers[],
912     int extra_header_count) {
913   // TODO(jgraettinger): Remove this method.
914   return ConstructSpdyGetReply(extra_headers, extra_header_count, 1);
915 }
916 
ConstructSpdyDataFrame(int stream_id,bool fin)917 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyDataFrame(int stream_id,
918                                                                bool fin) {
919   return ConstructSpdyDataFrame(stream_id, kUploadData, fin);
920 }
921 
ConstructSpdyDataFrame(int stream_id,std::string_view data,bool fin)922 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyDataFrame(
923     int stream_id,
924     std::string_view data,
925     bool fin) {
926   spdy::SpdyDataIR data_ir(stream_id, data);
927   data_ir.set_fin(fin);
928   return spdy::SpdySerializedFrame(
929       headerless_spdy_framer_.SerializeData(data_ir));
930 }
931 
ConstructSpdyDataFrame(int stream_id,std::string_view data,bool fin,int padding_length)932 spdy::SpdySerializedFrame SpdyTestUtil::ConstructSpdyDataFrame(
933     int stream_id,
934     std::string_view data,
935     bool fin,
936     int padding_length) {
937   spdy::SpdyDataIR data_ir(stream_id, data);
938   data_ir.set_fin(fin);
939   data_ir.set_padding_len(padding_length);
940   return spdy::SpdySerializedFrame(
941       headerless_spdy_framer_.SerializeData(data_ir));
942 }
943 
ConstructWrappedSpdyFrame(const spdy::SpdySerializedFrame & frame,int stream_id)944 spdy::SpdySerializedFrame SpdyTestUtil::ConstructWrappedSpdyFrame(
945     const spdy::SpdySerializedFrame& frame,
946     int stream_id) {
947   return ConstructSpdyDataFrame(
948       stream_id, std::string_view(frame.data(), frame.size()), false);
949 }
950 
SerializeFrame(const spdy::SpdyFrameIR & frame_ir)951 spdy::SpdySerializedFrame SpdyTestUtil::SerializeFrame(
952     const spdy::SpdyFrameIR& frame_ir) {
953   return headerless_spdy_framer_.SerializeFrame(frame_ir);
954 }
955 
UpdateWithStreamDestruction(int stream_id)956 void SpdyTestUtil::UpdateWithStreamDestruction(int stream_id) {
957   for (auto& priority_it : priority_to_stream_id_list_) {
958     for (auto stream_it = priority_it.second.begin();
959          stream_it != priority_it.second.end(); ++stream_it) {
960       if (*stream_it == stream_id) {
961         priority_it.second.erase(stream_it);
962         return;
963       }
964     }
965   }
966   NOTREACHED();
967 }
968 
969 // static
ConstructHeaderBlock(std::string_view method,std::string_view url,int64_t * content_length)970 spdy::Http2HeaderBlock SpdyTestUtil::ConstructHeaderBlock(
971     std::string_view method,
972     std::string_view url,
973     int64_t* content_length) {
974   std::string scheme, host, path;
975   ParseUrl(url, &scheme, &host, &path);
976   spdy::Http2HeaderBlock headers;
977   headers[spdy::kHttp2MethodHeader] = std::string(method);
978   headers[spdy::kHttp2AuthorityHeader] = host.c_str();
979   headers[spdy::kHttp2SchemeHeader] = scheme.c_str();
980   headers[spdy::kHttp2PathHeader] = path.c_str();
981   if (content_length) {
982     std::string length_str = base::NumberToString(*content_length);
983     headers["content-length"] = length_str;
984   }
985   return headers;
986 }
987 
988 namespace test {
GetTestHashValue(uint8_t label)989 HashValue GetTestHashValue(uint8_t label) {
990   HashValue hash_value(HASH_VALUE_SHA256);
991   memset(hash_value.data(), label, hash_value.size());
992   return hash_value;
993 }
994 
995 }  // namespace test
996 }  // namespace net
997