• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef NET_SPDY_SPDY_TEST_UTIL_COMMON_H_
6 #define NET_SPDY_SPDY_TEST_UTIL_COMMON_H_
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <map>
12 #include <memory>
13 #include <string>
14 #include <string_view>
15 #include <vector>
16 
17 #include "base/containers/span.h"
18 #include "base/memory/raw_ptr.h"
19 #include "crypto/ec_private_key.h"
20 #include "net/base/completion_once_callback.h"
21 #include "net/base/host_mapping_rules.h"
22 #include "net/base/proxy_server.h"
23 #include "net/base/request_priority.h"
24 #include "net/base/test_completion_callback.h"
25 #include "net/cert/mock_cert_verifier.h"
26 #include "net/dns/mock_host_resolver.h"
27 #include "net/http/http_auth_handler_factory.h"
28 #include "net/http/http_network_session.h"
29 #include "net/http/http_response_info.h"
30 #include "net/http/http_server_properties.h"
31 #include "net/http/transport_security_state.h"
32 #include "net/proxy_resolution/proxy_resolution_service.h"
33 #include "net/quic/quic_crypto_client_stream_factory.h"
34 #include "net/socket/socket_test_util.h"
35 #include "net/spdy/spdy_session.h"
36 #include "net/spdy/spdy_session_pool.h"
37 #include "net/ssl/ssl_config_service_defaults.h"
38 #include "net/third_party/quiche/src/quiche/common/http/http_header_block.h"
39 #include "net/third_party/quiche/src/quiche/http2/core/spdy_protocol.h"
40 #include "testing/gtest/include/gtest/gtest.h"
41 
42 #if BUILDFLAG(ENABLE_REPORTING)
43 #include "net/network_error_logging/network_error_logging_service.h"
44 #include "net/reporting/reporting_service.h"
45 #endif
46 
47 class GURL;
48 
49 namespace net {
50 
51 class ClientSocketFactory;
52 class HashValue;
53 class HostPortPair;
54 class HostResolver;
55 class QuicContext;
56 class HttpUserAgentSettings;
57 class NetLogWithSource;
58 class SpdySessionKey;
59 class SpdyStream;
60 class SpdyStreamRequest;
61 class TransportSecurityState;
62 class URLRequestContextBuilder;
63 class ProxyDelegate;
64 
65 // Default upload data used by both, mock objects and framer when creating
66 // data frames.
67 const char kDefaultUrl[] = "https://www.example.org/";
68 const char kUploadData[] = "hello!";
69 const int kUploadDataSize = std::size(kUploadData) - 1;
70 
71 // While HTTP/2 protocol defines default SETTINGS_MAX_HEADER_LIST_SIZE_FOR_TEST
72 // to be unlimited, BufferedSpdyFramer constructor requires a value.
73 const uint32_t kMaxHeaderListSizeForTest = 1024;
74 
75 // Chop a spdy::SpdySerializedFrame into an array of MockWrites.
76 // |frame| is the frame to chop.
77 // |num_chunks| is the number of chunks to create.
78 std::unique_ptr<MockWrite[]> ChopWriteFrame(
79     const spdy::SpdySerializedFrame& frame,
80     int num_chunks);
81 
82 // Adds headers and values to a map.
83 // |extra_headers| is an array of { name, value } pairs, arranged as strings
84 // where the even entries are the header names, and the odd entries are the
85 // header values.
86 // |headers| gets filled in from |extra_headers|.
87 void AppendToHeaderBlock(const char* const extra_headers[],
88                          int extra_header_count,
89                          quiche::HttpHeaderBlock* headers);
90 
91 // Create an async MockWrite from the given spdy::SpdySerializedFrame.
92 MockWrite CreateMockWrite(const spdy::SpdySerializedFrame& req);
93 
94 // Create an async MockWrite from the given spdy::SpdySerializedFrame and
95 // sequence number.
96 MockWrite CreateMockWrite(const spdy::SpdySerializedFrame& req, int seq);
97 
98 MockWrite CreateMockWrite(const spdy::SpdySerializedFrame& req,
99                           int seq,
100                           IoMode mode);
101 
102 // Create a MockRead from the given spdy::SpdySerializedFrame.
103 MockRead CreateMockRead(const spdy::SpdySerializedFrame& resp);
104 
105 // Create a MockRead from the given spdy::SpdySerializedFrame and sequence
106 // number.
107 MockRead CreateMockRead(const spdy::SpdySerializedFrame& resp, int seq);
108 
109 MockRead CreateMockRead(const spdy::SpdySerializedFrame& resp,
110                         int seq,
111                         IoMode mode);
112 
113 // Combines the given vector of spdy::SpdySerializedFrame into a single frame.
114 spdy::SpdySerializedFrame CombineFrames(
115     std::vector<const spdy::SpdySerializedFrame*> frames);
116 
117 // Returns the spdy::SpdyPriority embedded in the given frame.  Returns true
118 // and fills in |priority| on success.
119 bool GetSpdyPriority(const spdy::SpdySerializedFrame& frame,
120                      spdy::SpdyPriority* priority);
121 
122 // Tries to create a stream in |session| synchronously. Returns NULL
123 // on failure.
124 base::WeakPtr<SpdyStream> CreateStreamSynchronously(
125     SpdyStreamType type,
126     const base::WeakPtr<SpdySession>& session,
127     const GURL& url,
128     RequestPriority priority,
129     const NetLogWithSource& net_log,
130     bool detect_broken_connection = false,
131     base::TimeDelta heartbeat_interval = base::Seconds(0));
132 
133 // Helper class used by some tests to release a stream as soon as it's
134 // created.
135 class StreamReleaserCallback : public TestCompletionCallbackBase {
136  public:
137   StreamReleaserCallback();
138 
139   ~StreamReleaserCallback() override;
140 
141   // Returns a callback that releases |request|'s stream.
142   CompletionOnceCallback MakeCallback(SpdyStreamRequest* request);
143 
144  private:
145   void OnComplete(SpdyStreamRequest* request, int result);
146 };
147 
148 // Helper to manage the lifetimes of the dependencies for a
149 // HttpNetworkTransaction.
150 struct SpdySessionDependencies {
151   // Default set of dependencies -- "null" proxy service.
152   SpdySessionDependencies();
153 
154   // Custom proxy service dependency.
155   explicit SpdySessionDependencies(
156       std::unique_ptr<ProxyResolutionService> proxy_resolution_service);
157 
158   SpdySessionDependencies(SpdySessionDependencies&&);
159 
160   ~SpdySessionDependencies();
161 
162   SpdySessionDependencies& operator=(SpdySessionDependencies&&);
163 
GetHostResolverSpdySessionDependencies164   HostResolver* GetHostResolver() {
165     return alternate_host_resolver ? alternate_host_resolver.get()
166                                    : host_resolver.get();
167   }
168 
169   static std::unique_ptr<HttpNetworkSession> SpdyCreateSession(
170       SpdySessionDependencies* session_deps);
171 
172   // Variant that ignores session_deps->socket_factory, and uses the passed in
173   // |factory| instead.
174   static std::unique_ptr<HttpNetworkSession> SpdyCreateSessionWithSocketFactory(
175       SpdySessionDependencies* session_deps,
176       ClientSocketFactory* factory);
177   static HttpNetworkSessionParams CreateSessionParams(
178       SpdySessionDependencies* session_deps);
179   static HttpNetworkSessionContext CreateSessionContext(
180       SpdySessionDependencies* session_deps);
181 
182   // NOTE: host_resolver must be ordered before http_auth_handler_factory.
183   std::unique_ptr<MockHostResolverBase> host_resolver;
184   // For using a HostResolver not derived from MockHostResolverBase.
185   std::unique_ptr<HostResolver> alternate_host_resolver;
186   std::unique_ptr<MockCertVerifier> cert_verifier;
187   std::unique_ptr<TransportSecurityState> transport_security_state;
188   // NOTE: `proxy_delegate` must be ordered before `proxy_resolution_service`.
189   std::unique_ptr<ProxyDelegate> proxy_delegate;
190   std::unique_ptr<ProxyResolutionService> proxy_resolution_service;
191   std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings;
192   std::unique_ptr<SSLConfigService> ssl_config_service;
193   std::unique_ptr<MockClientSocketFactory> socket_factory;
194   std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory;
195   std::unique_ptr<HttpServerProperties> http_server_properties;
196   std::unique_ptr<QuicContext> quic_context;
197   std::unique_ptr<QuicCryptoClientStreamFactory>
198       quic_crypto_client_stream_factory;
199 #if BUILDFLAG(ENABLE_REPORTING)
200   std::unique_ptr<ReportingService> reporting_service;
201   std::unique_ptr<NetworkErrorLoggingService> network_error_logging_service;
202 #endif
203   HostMappingRules host_mapping_rules;
204   bool enable_ip_pooling = true;
205   bool enable_ping = false;
206   bool enable_user_alternate_protocol_ports = false;
207   bool enable_quic = false;
208   bool enable_server_push_cancellation = false;
209   size_t session_max_recv_window_size = kDefaultInitialWindowSize;
210   int session_max_queued_capped_frames = kSpdySessionMaxQueuedCappedFrames;
211   spdy::SettingsMap http2_settings;
212   SpdySession::TimeFunc time_func;
213   bool enable_http2_alternative_service = false;
214   bool enable_http2_settings_grease = false;
215   std::optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame;
216   bool http2_end_stream_with_data_frame = false;
217   raw_ptr<NetLog> net_log = nullptr;
218   bool disable_idle_sockets_close_on_memory_pressure = false;
219   bool enable_early_data = false;
220   bool key_auth_cache_server_entries_by_network_anonymization_key = false;
221   bool enable_priority_update = false;
222 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
223   bool go_away_on_ip_change = true;
224 #else
225   bool go_away_on_ip_change = false;
226 #endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS)
227   bool ignore_ip_address_changes = false;
228 };
229 
230 std::unique_ptr<URLRequestContextBuilder>
231 CreateSpdyTestURLRequestContextBuilder(
232     ClientSocketFactory* client_socket_factory);
233 
234 // Equivalent to pool->GetIfExists(spdy_session_key, NetLogWithSource()) !=
235 // NULL.
236 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key);
237 
238 // Creates a SPDY session for the given key and puts it in the SPDY
239 // session pool in |http_session|. A SPDY session for |key| must not
240 // already exist.
241 base::WeakPtr<SpdySession> CreateSpdySession(HttpNetworkSession* http_session,
242                                              const SpdySessionKey& key,
243                                              const NetLogWithSource& net_log);
244 
245 // Like CreateSpdySession(), but does not fail if there is already an IP
246 // pooled session for |key|.
247 base::WeakPtr<SpdySession> CreateSpdySessionWithIpBasedPoolingDisabled(
248     HttpNetworkSession* http_session,
249     const SpdySessionKey& key,
250     const NetLogWithSource& net_log);
251 
252 // Creates a SPDY session for the given key and puts it in |pool|.
253 // The returned session will neither receive nor send any data.
254 // A SPDY session for |key| must not already exist.
255 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool,
256                                                  const SpdySessionKey& key);
257 
258 class SpdySessionPoolPeer {
259  public:
260   explicit SpdySessionPoolPeer(SpdySessionPool* pool);
261 
262   SpdySessionPoolPeer(const SpdySessionPoolPeer&) = delete;
263   SpdySessionPoolPeer& operator=(const SpdySessionPoolPeer&) = delete;
264 
265   void RemoveAliases(const SpdySessionKey& key);
266   void SetEnableSendingInitialData(bool enabled);
267 
268  private:
269   const raw_ptr<SpdySessionPool> pool_;
270 };
271 
272 class SpdyTestUtil {
273  public:
274   explicit SpdyTestUtil(bool use_priority_header = false);
275   ~SpdyTestUtil();
276 
277   // Add the appropriate headers to put |url| into |block|.
278   void AddUrlToHeaderBlock(std::string_view url,
279                            quiche::HttpHeaderBlock* headers) const;
280 
281   // Add the appropriate priority header if PriorityHeaders is enabled.
282   void AddPriorityToHeaderBlock(RequestPriority request_priority,
283                                 bool priority_incremental,
284                                 quiche::HttpHeaderBlock* headers) const;
285 
286   static quiche::HttpHeaderBlock ConstructGetHeaderBlock(std::string_view url);
287   static quiche::HttpHeaderBlock ConstructGetHeaderBlockForProxy(
288       std::string_view url);
289   static quiche::HttpHeaderBlock ConstructHeadHeaderBlock(
290       std::string_view url,
291       int64_t content_length);
292   static quiche::HttpHeaderBlock ConstructPostHeaderBlock(
293       std::string_view url,
294       int64_t content_length);
295   static quiche::HttpHeaderBlock ConstructPutHeaderBlock(
296       std::string_view url,
297       int64_t content_length);
298 
299   // Construct an expected SPDY reply string from the given headers.
300   std::string ConstructSpdyReplyString(
301       const quiche::HttpHeaderBlock& headers) const;
302 
303   // Construct an expected SPDY SETTINGS frame.
304   // |settings| are the settings to set.
305   // Returns the constructed frame.
306   spdy::SpdySerializedFrame ConstructSpdySettings(
307       const spdy::SettingsMap& settings);
308 
309   // Constructs an expected SPDY SETTINGS acknowledgement frame.
310   spdy::SpdySerializedFrame ConstructSpdySettingsAck();
311 
312   // Construct a SPDY PING frame.  Returns the constructed frame.
313   spdy::SpdySerializedFrame ConstructSpdyPing(uint32_t ping_id, bool is_ack);
314 
315   // Construct a SPDY GOAWAY frame with the specified last_good_stream_id.
316   // Returns the constructed frame.
317   spdy::SpdySerializedFrame ConstructSpdyGoAway(
318       spdy::SpdyStreamId last_good_stream_id);
319 
320   // Construct a SPDY GOAWAY frame with the specified last_good_stream_id,
321   // status, and description. Returns the constructed frame.
322   spdy::SpdySerializedFrame ConstructSpdyGoAway(
323       spdy::SpdyStreamId last_good_stream_id,
324       spdy::SpdyErrorCode error_code,
325       const std::string& desc);
326 
327   // Construct a SPDY WINDOW_UPDATE frame.  Returns the constructed frame.
328   spdy::SpdySerializedFrame ConstructSpdyWindowUpdate(
329       spdy::SpdyStreamId stream_id,
330       uint32_t delta_window_size);
331 
332   // Construct a SPDY RST_STREAM frame.  Returns the constructed frame.
333   spdy::SpdySerializedFrame ConstructSpdyRstStream(
334       spdy::SpdyStreamId stream_id,
335       spdy::SpdyErrorCode error_code);
336 
337   // Construct a PRIORITY frame. The weight is derived from |request_priority|.
338   // Returns the constructed frame.
339   spdy::SpdySerializedFrame ConstructSpdyPriority(
340       spdy::SpdyStreamId stream_id,
341       spdy::SpdyStreamId parent_stream_id,
342       RequestPriority request_priority,
343       bool exclusive);
344 
345   // Constructs a standard SPDY GET HEADERS frame for |url| with header
346   // compression.
347   // |extra_headers| are the extra header-value pairs, which typically
348   // will vary the most between calls.
349   spdy::SpdySerializedFrame ConstructSpdyGet(
350       const char* const url,
351       spdy::SpdyStreamId stream_id,
352       RequestPriority request_priority,
353       bool priority_incremental = kDefaultPriorityIncremental,
354       std::optional<RequestPriority> header_request_priority = std::nullopt);
355 
356   // Constructs a standard SPDY GET HEADERS frame with header compression.
357   // |extra_headers| are the extra header-value pairs, which typically
358   // will vary the most between calls.  If |direct| is false, the
359   // the full url will be used instead of simply the path.
360   spdy::SpdySerializedFrame ConstructSpdyGet(
361       const char* const extra_headers[],
362       int extra_header_count,
363       int stream_id,
364       RequestPriority request_priority,
365       bool priority_incremental = kDefaultPriorityIncremental,
366       std::optional<RequestPriority> header_request_priority = std::nullopt);
367 
368   // Constructs a SPDY HEADERS frame for a CONNECT request. If `extra_headers`
369   // is nullptr, it includes just "user-agent" "test-ua" as that is commonly
370   // required.
371   spdy::SpdySerializedFrame ConstructSpdyConnect(
372       const char* const extra_headers[],
373       int extra_header_count,
374       int stream_id,
375       RequestPriority priority,
376       const HostPortPair& host_port_pair);
377 
378   // Constructs a PUSH_PROMISE frame.
379   spdy::SpdySerializedFrame ConstructSpdyPushPromise(
380       spdy::SpdyStreamId associated_stream_id,
381       spdy::SpdyStreamId stream_id,
382       quiche::HttpHeaderBlock headers);
383 
384   // Constructs a HEADERS frame with the request header compression context with
385   // END_STREAM flag set to |fin|.
386   spdy::SpdySerializedFrame ConstructSpdyResponseHeaders(
387       int stream_id,
388       quiche::HttpHeaderBlock headers,
389       bool fin);
390 
391   // Construct a HEADERS frame carrying exactly the given headers and priority.
392   spdy::SpdySerializedFrame ConstructSpdyHeaders(
393       int stream_id,
394       quiche::HttpHeaderBlock headers,
395       RequestPriority priority,
396       bool fin,
397       bool priority_incremental = kDefaultPriorityIncremental,
398       std::optional<RequestPriority> header_request_priority = std::nullopt);
399 
400   // Construct a reply HEADERS frame carrying exactly the given headers and the
401   // default priority.
402   spdy::SpdySerializedFrame ConstructSpdyReply(int stream_id,
403                                                quiche::HttpHeaderBlock headers);
404 
405   // Constructs a standard SPDY HEADERS frame to match the SPDY GET.
406   // |extra_headers| are the extra header-value pairs, which typically
407   // will vary the most between calls.
408   spdy::SpdySerializedFrame ConstructSpdyGetReply(
409       const char* const extra_headers[],
410       int extra_header_count,
411       int stream_id);
412 
413   // Constructs a standard SPDY HEADERS frame with an Internal Server
414   // Error status code.
415   spdy::SpdySerializedFrame ConstructSpdyReplyError(int stream_id);
416 
417   // Constructs a standard SPDY HEADERS frame with the specified status code.
418   spdy::SpdySerializedFrame ConstructSpdyReplyError(
419       const char* const status,
420       const char* const* const extra_headers,
421       int extra_header_count,
422       int stream_id);
423 
424   // Constructs a standard SPDY POST HEADERS frame.
425   // |extra_headers| are the extra header-value pairs, which typically
426   // will vary the most between calls.
427   spdy::SpdySerializedFrame ConstructSpdyPost(
428       const char* url,
429       spdy::SpdyStreamId stream_id,
430       int64_t content_length,
431       RequestPriority request_priority,
432       const char* const extra_headers[],
433       int extra_header_count,
434       bool priority_incremental = kDefaultPriorityIncremental);
435 
436   // Constructs a chunked transfer SPDY POST HEADERS frame.
437   // |extra_headers| are the extra header-value pairs, which typically
438   // will vary the most between calls.
439   spdy::SpdySerializedFrame ConstructChunkedSpdyPost(
440       const char* const extra_headers[],
441       int extra_header_count,
442       RequestPriority request_priority = RequestPriority::DEFAULT_PRIORITY,
443       bool priority_incremental = kDefaultPriorityIncremental);
444 
445   // Constructs a standard SPDY HEADERS frame to match the SPDY POST.
446   // |extra_headers| are the extra header-value pairs, which typically
447   // will vary the most between calls.
448   spdy::SpdySerializedFrame ConstructSpdyPostReply(
449       const char* const extra_headers[],
450       int extra_header_count);
451 
452   // Constructs a single SPDY data frame with the contents "hello!"
453   spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id, bool fin);
454 
455   // Constructs a single SPDY data frame with the given content.
456   spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id,
457                                                    std::string_view data,
458                                                    bool fin);
459 
460   // Constructs a single SPDY data frame with the given content and padding.
461   spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id,
462                                                    std::string_view data,
463                                                    bool fin,
464                                                    int padding_length);
465 
466   // Wraps |frame| in the payload of a data frame in stream |stream_id|.
467   spdy::SpdySerializedFrame ConstructWrappedSpdyFrame(
468       const spdy::SpdySerializedFrame& frame,
469       int stream_id);
470 
471   // Serialize a spdy::SpdyFrameIR with |headerless_spdy_framer_|.
472   spdy::SpdySerializedFrame SerializeFrame(const spdy::SpdyFrameIR& frame_ir);
473 
474   // Called when necessary (when it will affect stream dependency specification
475   // when setting dependencies based on priorioties) to notify the utility
476   // class of stream destruction.
477   void UpdateWithStreamDestruction(int stream_id);
478 
set_default_url(const GURL & url)479   void set_default_url(const GURL& url) { default_url_ = url; }
480 
481  private:
482   // |content_length| may be NULL, in which case the content-length
483   // header will be omitted.
484   static quiche::HttpHeaderBlock ConstructHeaderBlock(std::string_view method,
485                                                       std::string_view url,
486                                                       int64_t* content_length);
487 
488   // Multiple SpdyFramers are required to keep track of header compression
489   // state.
490   // Use to serialize frames (request or response) without headers.
491   spdy::SpdyFramer headerless_spdy_framer_;
492   // Use to serialize request frames with headers.
493   spdy::SpdyFramer request_spdy_framer_;
494   // Use to serialize response frames with headers.
495   spdy::SpdyFramer response_spdy_framer_;
496 
497   GURL default_url_;
498 
499   // Enable support for addint the "priority" header to requests.
500   bool use_priority_header_;
501 
502   // Track a FIFO list of the stream_id of all created requests by priority.
503   std::map<int, std::vector<int>> priority_to_stream_id_list_;
504 };
505 
506 namespace test {
507 
508 // Returns a SHA1 HashValue in which each byte has the value |label|.
509 HashValue GetTestHashValue(uint8_t label);
510 
511 }  // namespace test
512 }  // namespace net
513 
514 #endif  // NET_SPDY_SPDY_TEST_UTIL_COMMON_H_
515