1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
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/memory/ref_counted.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_piece.h"
19 #include "crypto/ec_private_key.h"
20 #include "crypto/ec_signature_creator.h"
21 #include "net/base/completion_once_callback.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/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/socket/socket_test_util.h"
34 #include "net/spdy/spdy_session.h"
35 #include "net/spdy/spdy_session_pool.h"
36 #include "net/ssl/ssl_config_service_defaults.h"
37 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
38 #include "net/url_request/url_request_context.h"
39 #include "net/url_request/url_request_context_storage.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 CTVerifier;
52 class CTPolicyEnforcer;
53 class HashValue;
54 class HostPortPair;
55 class HostResolver;
56 class QuicContext;
57 class HttpUserAgentSettings;
58 class NetLogWithSource;
59 class SpdySessionKey;
60 class SpdyStream;
61 class SpdyStreamRequest;
62 class TransportSecurityState;
63 
64 // Default upload data used by both, mock objects and framer when creating
65 // data frames.
66 const char kDefaultUrl[] = "https://www.example.org/";
67 const char kUploadData[] = "hello!";
68 const int kUploadDataSize = base::size(kUploadData) - 1;
69 
70 // While HTTP/2 protocol defines default SETTINGS_MAX_HEADER_LIST_SIZE_FOR_TEST
71 // to be unlimited, BufferedSpdyFramer constructor requires a value.
72 const uint32_t kMaxHeaderListSizeForTest = 1024;
73 
74 // Chop a spdy::SpdySerializedFrame into an array of MockWrites.
75 // |frame| is the frame to chop.
76 // |num_chunks| is the number of chunks to create.
77 std::unique_ptr<MockWrite[]> ChopWriteFrame(
78     const spdy::SpdySerializedFrame& frame,
79     int num_chunks);
80 
81 // Adds headers and values to a map.
82 // |extra_headers| is an array of { name, value } pairs, arranged as strings
83 // where the even entries are the header names, and the odd entries are the
84 // header values.
85 // |headers| gets filled in from |extra_headers|.
86 void AppendToHeaderBlock(const char* const extra_headers[],
87                          int extra_header_count,
88                          spdy::Http2HeaderBlock* headers);
89 
90 // Create an async MockWrite from the given spdy::SpdySerializedFrame.
91 MockWrite CreateMockWrite(const spdy::SpdySerializedFrame& req);
92 
93 // Create an async MockWrite from the given spdy::SpdySerializedFrame and
94 // sequence number.
95 MockWrite CreateMockWrite(const spdy::SpdySerializedFrame& req, int seq);
96 
97 MockWrite CreateMockWrite(const spdy::SpdySerializedFrame& req,
98                           int seq,
99                           IoMode mode);
100 
101 // Create a MockRead from the given spdy::SpdySerializedFrame.
102 MockRead CreateMockRead(const spdy::SpdySerializedFrame& resp);
103 
104 // Create a MockRead from the given spdy::SpdySerializedFrame and sequence
105 // number.
106 MockRead CreateMockRead(const spdy::SpdySerializedFrame& resp, int seq);
107 
108 MockRead CreateMockRead(const spdy::SpdySerializedFrame& resp,
109                         int seq,
110                         IoMode mode);
111 
112 // Combines the given vector of spdy::SpdySerializedFrame into a single frame.
113 spdy::SpdySerializedFrame CombineFrames(
114     std::vector<const spdy::SpdySerializedFrame*> frames);
115 
116 // Returns the spdy::SpdyPriority embedded in the given frame.  Returns true
117 // and fills in |priority| on success.
118 bool GetSpdyPriority(const spdy::SpdySerializedFrame& frame,
119                      spdy::SpdyPriority* priority);
120 
121 // Tries to create a stream in |session| synchronously. Returns NULL
122 // on failure.
123 base::WeakPtr<SpdyStream> CreateStreamSynchronously(
124     SpdyStreamType type,
125     const base::WeakPtr<SpdySession>& session,
126     const GURL& url,
127     RequestPriority priority,
128     const NetLogWithSource& net_log);
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 // An ECSignatureCreator that returns deterministic signatures.
146 class MockECSignatureCreator : public crypto::ECSignatureCreator {
147  public:
148   explicit MockECSignatureCreator(crypto::ECPrivateKey* key);
149 
150   // crypto::ECSignatureCreator
151   bool Sign(const uint8_t* data,
152             int data_len,
153             std::vector<uint8_t>* signature) override;
154   bool DecodeSignature(const std::vector<uint8_t>& signature,
155                        std::vector<uint8_t>* out_raw_sig) override;
156 
157  private:
158   crypto::ECPrivateKey* key_;
159 
160   DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreator);
161 };
162 
163 // An ECSignatureCreatorFactory creates MockECSignatureCreator.
164 class MockECSignatureCreatorFactory : public crypto::ECSignatureCreatorFactory {
165  public:
166   MockECSignatureCreatorFactory();
167   ~MockECSignatureCreatorFactory() override;
168 
169   // crypto::ECSignatureCreatorFactory
170   std::unique_ptr<crypto::ECSignatureCreator> Create(
171       crypto::ECPrivateKey* key) override;
172 
173  private:
174   DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreatorFactory);
175 };
176 
177 // Helper to manage the lifetimes of the dependencies for a
178 // HttpNetworkTransaction.
179 struct SpdySessionDependencies {
180   // Default set of dependencies -- "null" proxy service.
181   SpdySessionDependencies();
182 
183   // Custom proxy service dependency.
184   explicit SpdySessionDependencies(
185       std::unique_ptr<ProxyResolutionService> proxy_resolution_service);
186 
187   ~SpdySessionDependencies();
188 
GetHostResolverSpdySessionDependencies189   HostResolver* GetHostResolver() {
190     return alternate_host_resolver ? alternate_host_resolver.get()
191                                    : host_resolver.get();
192   }
193 
194   static std::unique_ptr<HttpNetworkSession> SpdyCreateSession(
195       SpdySessionDependencies* session_deps);
196 
197   // Variant that ignores session_deps->socket_factory, and uses the passed in
198   // |factory| instead.
199   static std::unique_ptr<HttpNetworkSession> SpdyCreateSessionWithSocketFactory(
200       SpdySessionDependencies* session_deps,
201       ClientSocketFactory* factory);
202   static HttpNetworkSession::Params CreateSessionParams(
203       SpdySessionDependencies* session_deps);
204   static HttpNetworkSession::Context CreateSessionContext(
205       SpdySessionDependencies* session_deps);
206 
207   // NOTE: host_resolver must be ordered before http_auth_handler_factory.
208   std::unique_ptr<MockHostResolverBase> host_resolver;
209   // For using a HostResolver not derived from MockHostResolverBase.
210   std::unique_ptr<HostResolver> alternate_host_resolver;
211   std::unique_ptr<CertVerifier> cert_verifier;
212   std::unique_ptr<TransportSecurityState> transport_security_state;
213   std::unique_ptr<CTVerifier> cert_transparency_verifier;
214   std::unique_ptr<CTPolicyEnforcer> ct_policy_enforcer;
215   std::unique_ptr<ProxyResolutionService> proxy_resolution_service;
216   std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings;
217   std::unique_ptr<SSLConfigService> ssl_config_service;
218   std::unique_ptr<MockClientSocketFactory> socket_factory;
219   std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory;
220   std::unique_ptr<HttpServerProperties> http_server_properties;
221   std::unique_ptr<QuicContext> quic_context;
222 #if BUILDFLAG(ENABLE_REPORTING)
223   std::unique_ptr<ReportingService> reporting_service;
224   std::unique_ptr<NetworkErrorLoggingService> network_error_logging_service;
225 #endif
226   bool enable_ip_pooling;
227   bool enable_ping;
228   bool enable_user_alternate_protocol_ports;
229   bool enable_quic;
230   bool enable_server_push_cancellation;
231   size_t session_max_recv_window_size;
232   int session_max_queued_capped_frames;
233   spdy::SettingsMap http2_settings;
234   SpdySession::TimeFunc time_func;
235   bool enable_http2_alternative_service;
236   bool enable_websocket_over_http2;
237   base::Optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame;
238   bool http2_end_stream_with_data_frame;
239   NetLog* net_log;
240   bool disable_idle_sockets_close_on_memory_pressure;
241   bool enable_early_data;
242   bool key_auth_cache_server_entries_by_network_isolation_key;
243 };
244 
245 class SpdyURLRequestContext : public URLRequestContext {
246  public:
247   SpdyURLRequestContext();
248   ~SpdyURLRequestContext() override;
249 
socket_factory()250   MockClientSocketFactory& socket_factory() { return socket_factory_; }
251 
252  private:
253   MockClientSocketFactory socket_factory_;
254   URLRequestContextStorage storage_;
255 };
256 
257 // Equivalent to pool->GetIfExists(spdy_session_key, NetLogWithSource()) !=
258 // NULL.
259 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key);
260 
261 // Creates a SPDY session for the given key and puts it in the SPDY
262 // session pool in |http_session|. A SPDY session for |key| must not
263 // already exist.
264 base::WeakPtr<SpdySession> CreateSpdySession(HttpNetworkSession* http_session,
265                                              const SpdySessionKey& key,
266                                              const NetLogWithSource& net_log);
267 
268 // Like CreateSpdySession(), but the host is considered a trusted proxy and
269 // allowed to push cross-origin resources.
270 base::WeakPtr<SpdySession> CreateTrustedSpdySession(
271     HttpNetworkSession* http_session,
272     const SpdySessionKey& key,
273     const NetLogWithSource& net_log);
274 
275 // Like CreateSpdySession(), but does not fail if there is already an IP
276 // pooled session for |key|.
277 base::WeakPtr<SpdySession> CreateSpdySessionWithIpBasedPoolingDisabled(
278     HttpNetworkSession* http_session,
279     const SpdySessionKey& key,
280     const NetLogWithSource& net_log);
281 
282 // Creates an insecure SPDY session for the given key and puts it in
283 // |pool|. The returned session will neither receive nor send any
284 // data. A SPDY session for |key| must not already exist.
285 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool,
286                                                  const SpdySessionKey& key);
287 
288 // Tries to create an insecure SPDY session for the given key but
289 // expects the attempt to fail with the given error. The session will
290 // neither receive nor send any data. A SPDY session for |key| must
291 // not already exist. The session will be created but close in the
292 // next event loop iteration.
293 base::WeakPtr<SpdySession> TryCreateFakeSpdySessionExpectingFailure(
294     SpdySessionPool* pool,
295     const SpdySessionKey& key,
296     Error expected_status);
297 
298 class SpdySessionPoolPeer {
299  public:
300   explicit SpdySessionPoolPeer(SpdySessionPool* pool);
301 
302   void RemoveAliases(const SpdySessionKey& key);
303   void SetEnableSendingInitialData(bool enabled);
304 
305  private:
306   SpdySessionPool* const pool_;
307 
308   DISALLOW_COPY_AND_ASSIGN(SpdySessionPoolPeer);
309 };
310 
311 class SpdyTestUtil {
312  public:
313   SpdyTestUtil();
314   ~SpdyTestUtil();
315 
316   // Add the appropriate headers to put |url| into |block|.
317   void AddUrlToHeaderBlock(base::StringPiece url,
318                            spdy::Http2HeaderBlock* headers) const;
319 
320   static spdy::Http2HeaderBlock ConstructGetHeaderBlock(base::StringPiece url);
321   static spdy::Http2HeaderBlock ConstructGetHeaderBlockForProxy(
322       base::StringPiece url);
323   static spdy::Http2HeaderBlock ConstructHeadHeaderBlock(
324       base::StringPiece url,
325       int64_t content_length);
326   static spdy::Http2HeaderBlock ConstructPostHeaderBlock(
327       base::StringPiece url,
328       int64_t content_length);
329   static spdy::Http2HeaderBlock ConstructPutHeaderBlock(base::StringPiece url,
330                                                         int64_t content_length);
331 
332   // Construct an expected SPDY reply string from the given headers.
333   std::string ConstructSpdyReplyString(
334       const spdy::Http2HeaderBlock& headers) const;
335 
336   // Construct an expected SPDY SETTINGS frame.
337   // |settings| are the settings to set.
338   // Returns the constructed frame.
339   spdy::SpdySerializedFrame ConstructSpdySettings(
340       const spdy::SettingsMap& settings);
341 
342   // Constructs an expected SPDY SETTINGS acknowledgement frame.
343   spdy::SpdySerializedFrame ConstructSpdySettingsAck();
344 
345   // Construct a SPDY PING frame.  Returns the constructed frame.
346   spdy::SpdySerializedFrame ConstructSpdyPing(uint32_t ping_id, bool is_ack);
347 
348   // Construct a SPDY GOAWAY frame with the specified last_good_stream_id.
349   // Returns the constructed frame.
350   spdy::SpdySerializedFrame ConstructSpdyGoAway(
351       spdy::SpdyStreamId last_good_stream_id);
352 
353   // Construct a SPDY GOAWAY frame with the specified last_good_stream_id,
354   // status, and description. Returns the constructed frame.
355   spdy::SpdySerializedFrame ConstructSpdyGoAway(
356       spdy::SpdyStreamId last_good_stream_id,
357       spdy::SpdyErrorCode error_code,
358       const std::string& desc);
359 
360   // Construct a SPDY WINDOW_UPDATE frame.  Returns the constructed frame.
361   spdy::SpdySerializedFrame ConstructSpdyWindowUpdate(
362       spdy::SpdyStreamId stream_id,
363       uint32_t delta_window_size);
364 
365   // Construct a SPDY RST_STREAM frame.  Returns the constructed frame.
366   spdy::SpdySerializedFrame ConstructSpdyRstStream(
367       spdy::SpdyStreamId stream_id,
368       spdy::SpdyErrorCode error_code);
369 
370   // Construct a PRIORITY frame. The weight is derived from |request_priority|.
371   // Returns the constructed frame.
372   spdy::SpdySerializedFrame ConstructSpdyPriority(
373       spdy::SpdyStreamId stream_id,
374       spdy::SpdyStreamId parent_stream_id,
375       RequestPriority request_priority,
376       bool exclusive);
377 
378   // Constructs a standard SPDY GET HEADERS frame for |url| with header
379   // compression.
380   // |extra_headers| are the extra header-value pairs, which typically
381   // will vary the most between calls.
382   spdy::SpdySerializedFrame ConstructSpdyGet(const char* const url,
383                                              spdy::SpdyStreamId stream_id,
384                                              RequestPriority request_priority);
385 
386   // Constructs a standard SPDY GET HEADERS frame with header compression.
387   // |extra_headers| are the extra header-value pairs, which typically
388   // will vary the most between calls.  If |direct| is false, the
389   // the full url will be used instead of simply the path.
390   spdy::SpdySerializedFrame ConstructSpdyGet(const char* const extra_headers[],
391                                              int extra_header_count,
392                                              int stream_id,
393                                              RequestPriority request_priority);
394 
395   // Constructs a SPDY HEADERS frame for a CONNECT request.
396   spdy::SpdySerializedFrame ConstructSpdyConnect(
397       const char* const extra_headers[],
398       int extra_header_count,
399       int stream_id,
400       RequestPriority priority,
401       const HostPortPair& host_port_pair);
402 
403   // Constructs a PUSH_PROMISE frame and a HEADERS frame on the pushed stream.
404   // |extra_headers| are the extra header-value pairs, which typically
405   // will vary the most between calls.
406   // Returns a spdy::SpdySerializedFrame object with the two frames
407   // concatenated.
408   spdy::SpdySerializedFrame ConstructSpdyPush(const char* const extra_headers[],
409                                               int extra_header_count,
410                                               int stream_id,
411                                               int associated_stream_id,
412                                               const char* url);
413   spdy::SpdySerializedFrame ConstructSpdyPush(const char* const extra_headers[],
414                                               int extra_header_count,
415                                               int stream_id,
416                                               int associated_stream_id,
417                                               const char* url,
418                                               const char* status,
419                                               const char* location);
420 
421   // Constructs a PUSH_PROMISE frame.
422   spdy::SpdySerializedFrame ConstructSpdyPushPromise(
423       spdy::SpdyStreamId associated_stream_id,
424       spdy::SpdyStreamId stream_id,
425       spdy::Http2HeaderBlock headers);
426 
427   spdy::SpdySerializedFrame ConstructSpdyPushHeaders(
428       int stream_id,
429       const char* const extra_headers[],
430       int extra_header_count);
431 
432   // Constructs a HEADERS frame with the request header compression context with
433   // END_STREAM flag set to |fin|.
434   spdy::SpdySerializedFrame ConstructSpdyResponseHeaders(
435       int stream_id,
436       spdy::Http2HeaderBlock headers,
437       bool fin);
438 
439   // Construct a HEADERS frame carrying exactly the given headers and priority.
440   spdy::SpdySerializedFrame ConstructSpdyHeaders(int stream_id,
441                                                  spdy::Http2HeaderBlock headers,
442                                                  RequestPriority priority,
443                                                  bool fin);
444 
445   // Construct a reply HEADERS frame carrying exactly the given headers and the
446   // default priority.
447   spdy::SpdySerializedFrame ConstructSpdyReply(int stream_id,
448                                                spdy::Http2HeaderBlock headers);
449 
450   // Constructs a standard SPDY HEADERS frame to match the SPDY GET.
451   // |extra_headers| are the extra header-value pairs, which typically
452   // will vary the most between calls.
453   spdy::SpdySerializedFrame ConstructSpdyGetReply(
454       const char* const extra_headers[],
455       int extra_header_count,
456       int stream_id);
457 
458   // Constructs a standard SPDY HEADERS frame with an Internal Server
459   // Error status code.
460   spdy::SpdySerializedFrame ConstructSpdyReplyError(int stream_id);
461 
462   // Constructs a standard SPDY HEADERS frame with the specified status code.
463   spdy::SpdySerializedFrame ConstructSpdyReplyError(
464       const char* const status,
465       const char* const* const extra_headers,
466       int extra_header_count,
467       int stream_id);
468 
469   // Constructs a standard SPDY POST HEADERS frame.
470   // |extra_headers| are the extra header-value pairs, which typically
471   // will vary the most between calls.
472   spdy::SpdySerializedFrame ConstructSpdyPost(const char* url,
473                                               spdy::SpdyStreamId stream_id,
474                                               int64_t content_length,
475                                               RequestPriority priority,
476                                               const char* const extra_headers[],
477                                               int extra_header_count);
478 
479   // Constructs a chunked transfer SPDY POST HEADERS frame.
480   // |extra_headers| are the extra header-value pairs, which typically
481   // will vary the most between calls.
482   spdy::SpdySerializedFrame ConstructChunkedSpdyPost(
483       const char* const extra_headers[],
484       int extra_header_count);
485 
486   // Constructs a standard SPDY HEADERS frame to match the SPDY POST.
487   // |extra_headers| are the extra header-value pairs, which typically
488   // will vary the most between calls.
489   spdy::SpdySerializedFrame ConstructSpdyPostReply(
490       const char* const extra_headers[],
491       int extra_header_count);
492 
493   // Constructs a single SPDY data frame with the contents "hello!"
494   spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id, bool fin);
495 
496   // Constructs a single SPDY data frame with the given content.
497   spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id,
498                                                    base::StringPiece data,
499                                                    bool fin);
500 
501   // Constructs a single SPDY data frame with the given content and padding.
502   spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id,
503                                                    base::StringPiece data,
504                                                    bool fin,
505                                                    int padding_length);
506 
507   // Wraps |frame| in the payload of a data frame in stream |stream_id|.
508   spdy::SpdySerializedFrame ConstructWrappedSpdyFrame(
509       const spdy::SpdySerializedFrame& frame,
510       int stream_id);
511 
512   // Serialize a spdy::SpdyFrameIR with |headerless_spdy_framer_|.
513   spdy::SpdySerializedFrame SerializeFrame(const spdy::SpdyFrameIR& frame_ir);
514 
515   // Called when necessary (when it will affect stream dependency specification
516   // when setting dependencies based on priorioties) to notify the utility
517   // class of stream destruction.
518   void UpdateWithStreamDestruction(int stream_id);
519 
set_default_url(const GURL & url)520   void set_default_url(const GURL& url) { default_url_ = url; }
521 
522  private:
523   // |content_length| may be NULL, in which case the content-length
524   // header will be omitted.
525   static spdy::Http2HeaderBlock ConstructHeaderBlock(base::StringPiece method,
526                                                      base::StringPiece url,
527                                                      int64_t* content_length);
528 
529   // Multiple SpdyFramers are required to keep track of header compression
530   // state.
531   // Use to serialize frames (request or response) without headers.
532   spdy::SpdyFramer headerless_spdy_framer_;
533   // Use to serialize request frames with headers.
534   spdy::SpdyFramer request_spdy_framer_;
535   // Use to serialize response frames with headers.
536   spdy::SpdyFramer response_spdy_framer_;
537 
538   GURL default_url_;
539 
540   // Track a FIFO list of the stream_id of all created requests by priority.
541   std::map<int, std::vector<int>> priority_to_stream_id_list_;
542 };
543 
544 namespace test {
545 
546 // Returns a SHA1 HashValue in which each byte has the value |label|.
547 HashValue GetTestHashValue(uint8_t label);
548 
549 // A test implementation of ServerPushDelegate that caches all the pushed
550 // request and provides a interface to cancel the push given url.
551 class TestServerPushDelegate : public ServerPushDelegate {
552  public:
553   TestServerPushDelegate();
554   ~TestServerPushDelegate() override;
555 
556   void OnPush(std::unique_ptr<ServerPushHelper> push_helper,
557               const NetLogWithSource& session_net_log) override;
558 
559   bool CancelPush(GURL url);
560 
561  private:
562   std::map<GURL, std::unique_ptr<ServerPushHelper>> push_helpers;
563 };
564 
565 }  // namespace test
566 }  // namespace net
567 
568 #endif  // NET_SPDY_SPDY_TEST_UTIL_COMMON_H_
569