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