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/spdy/core/spdy_protocol.h" 39 #include "testing/gtest/include/gtest/gtest.h" 40 41 #if BUILDFLAG(ENABLE_REPORTING) 42 #include "net/network_error_logging/network_error_logging_service.h" 43 #include "net/reporting/reporting_service.h" 44 #endif 45 46 class GURL; 47 48 namespace net { 49 50 class ClientSocketFactory; 51 class HashValue; 52 class HostPortPair; 53 class HostResolver; 54 class QuicContext; 55 class HttpUserAgentSettings; 56 class NetLogWithSource; 57 class SpdySessionKey; 58 class SpdyStream; 59 class SpdyStreamRequest; 60 class TransportSecurityState; 61 class URLRequestContextBuilder; 62 class ProxyDelegate; 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 = std::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 bool detect_broken_connection = false, 130 base::TimeDelta heartbeat_interval = base::Seconds(0)); 131 132 // Helper class used by some tests to release a stream as soon as it's 133 // created. 134 class StreamReleaserCallback : public TestCompletionCallbackBase { 135 public: 136 StreamReleaserCallback(); 137 138 ~StreamReleaserCallback() override; 139 140 // Returns a callback that releases |request|'s stream. 141 CompletionOnceCallback MakeCallback(SpdyStreamRequest* request); 142 143 private: 144 void OnComplete(SpdyStreamRequest* request, int result); 145 }; 146 147 // Helper to manage the lifetimes of the dependencies for a 148 // HttpNetworkTransaction. 149 struct SpdySessionDependencies { 150 // Default set of dependencies -- "null" proxy service. 151 SpdySessionDependencies(); 152 153 // Custom proxy service dependency. 154 explicit SpdySessionDependencies( 155 std::unique_ptr<ProxyResolutionService> proxy_resolution_service); 156 157 SpdySessionDependencies(SpdySessionDependencies&&); 158 159 ~SpdySessionDependencies(); 160 161 SpdySessionDependencies& operator=(SpdySessionDependencies&&); 162 GetHostResolverSpdySessionDependencies163 HostResolver* GetHostResolver() { 164 return alternate_host_resolver ? alternate_host_resolver.get() 165 : host_resolver.get(); 166 } 167 168 static std::unique_ptr<HttpNetworkSession> SpdyCreateSession( 169 SpdySessionDependencies* session_deps); 170 171 // Variant that ignores session_deps->socket_factory, and uses the passed in 172 // |factory| instead. 173 static std::unique_ptr<HttpNetworkSession> SpdyCreateSessionWithSocketFactory( 174 SpdySessionDependencies* session_deps, 175 ClientSocketFactory* factory); 176 static HttpNetworkSessionParams CreateSessionParams( 177 SpdySessionDependencies* session_deps); 178 static HttpNetworkSessionContext CreateSessionContext( 179 SpdySessionDependencies* session_deps); 180 181 // NOTE: host_resolver must be ordered before http_auth_handler_factory. 182 std::unique_ptr<MockHostResolverBase> host_resolver; 183 // For using a HostResolver not derived from MockHostResolverBase. 184 std::unique_ptr<HostResolver> alternate_host_resolver; 185 std::unique_ptr<MockCertVerifier> cert_verifier; 186 std::unique_ptr<TransportSecurityState> transport_security_state; 187 // NOTE: `proxy_delegate` must be ordered before `proxy_resolution_service`. 188 std::unique_ptr<ProxyDelegate> proxy_delegate; 189 std::unique_ptr<ProxyResolutionService> proxy_resolution_service; 190 std::unique_ptr<HttpUserAgentSettings> http_user_agent_settings; 191 std::unique_ptr<SSLConfigService> ssl_config_service; 192 std::unique_ptr<MockClientSocketFactory> socket_factory; 193 std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory; 194 std::unique_ptr<HttpServerProperties> http_server_properties; 195 std::unique_ptr<QuicContext> quic_context; 196 std::unique_ptr<QuicCryptoClientStreamFactory> 197 quic_crypto_client_stream_factory; 198 #if BUILDFLAG(ENABLE_REPORTING) 199 std::unique_ptr<ReportingService> reporting_service; 200 std::unique_ptr<NetworkErrorLoggingService> network_error_logging_service; 201 #endif 202 HostMappingRules host_mapping_rules; 203 bool enable_ip_pooling = true; 204 bool enable_ping = false; 205 bool enable_user_alternate_protocol_ports = false; 206 bool enable_quic = false; 207 bool enable_server_push_cancellation = false; 208 size_t session_max_recv_window_size = kDefaultInitialWindowSize; 209 int session_max_queued_capped_frames = kSpdySessionMaxQueuedCappedFrames; 210 spdy::SettingsMap http2_settings; 211 SpdySession::TimeFunc time_func; 212 bool enable_http2_alternative_service = false; 213 bool enable_http2_settings_grease = false; 214 std::optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame; 215 bool http2_end_stream_with_data_frame = false; 216 raw_ptr<NetLog> net_log = nullptr; 217 bool disable_idle_sockets_close_on_memory_pressure = false; 218 bool enable_early_data = false; 219 bool key_auth_cache_server_entries_by_network_anonymization_key = false; 220 bool enable_priority_update = false; 221 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS) 222 bool go_away_on_ip_change = true; 223 #else 224 bool go_away_on_ip_change = false; 225 #endif // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_IOS) 226 bool ignore_ip_address_changes = false; 227 }; 228 229 std::unique_ptr<URLRequestContextBuilder> 230 CreateSpdyTestURLRequestContextBuilder( 231 ClientSocketFactory* client_socket_factory); 232 233 // Equivalent to pool->GetIfExists(spdy_session_key, NetLogWithSource()) != 234 // NULL. 235 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key); 236 237 // Creates a SPDY session for the given key and puts it in the SPDY 238 // session pool in |http_session|. A SPDY session for |key| must not 239 // already exist. 240 base::WeakPtr<SpdySession> CreateSpdySession(HttpNetworkSession* http_session, 241 const SpdySessionKey& key, 242 const NetLogWithSource& net_log); 243 244 // Like CreateSpdySession(), but does not fail if there is already an IP 245 // pooled session for |key|. 246 base::WeakPtr<SpdySession> CreateSpdySessionWithIpBasedPoolingDisabled( 247 HttpNetworkSession* http_session, 248 const SpdySessionKey& key, 249 const NetLogWithSource& net_log); 250 251 // Creates a SPDY session for the given key and puts it in |pool|. 252 // The returned session will neither receive nor send any data. 253 // A SPDY session for |key| must not already exist. 254 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool, 255 const SpdySessionKey& key); 256 257 class SpdySessionPoolPeer { 258 public: 259 explicit SpdySessionPoolPeer(SpdySessionPool* pool); 260 261 SpdySessionPoolPeer(const SpdySessionPoolPeer&) = delete; 262 SpdySessionPoolPeer& operator=(const SpdySessionPoolPeer&) = delete; 263 264 void RemoveAliases(const SpdySessionKey& key); 265 void SetEnableSendingInitialData(bool enabled); 266 267 private: 268 const raw_ptr<SpdySessionPool> pool_; 269 }; 270 271 class SpdyTestUtil { 272 public: 273 explicit SpdyTestUtil(bool use_priority_header = false); 274 ~SpdyTestUtil(); 275 276 // Add the appropriate headers to put |url| into |block|. 277 void AddUrlToHeaderBlock(std::string_view url, 278 spdy::Http2HeaderBlock* headers) const; 279 280 // Add the appropriate priority header if PriorityHeaders is enabled. 281 void AddPriorityToHeaderBlock(RequestPriority request_priority, 282 bool priority_incremental, 283 spdy::Http2HeaderBlock* headers) const; 284 285 static spdy::Http2HeaderBlock ConstructGetHeaderBlock(std::string_view url); 286 static spdy::Http2HeaderBlock ConstructGetHeaderBlockForProxy( 287 std::string_view url); 288 static spdy::Http2HeaderBlock ConstructHeadHeaderBlock( 289 std::string_view url, 290 int64_t content_length); 291 static spdy::Http2HeaderBlock ConstructPostHeaderBlock( 292 std::string_view url, 293 int64_t content_length); 294 static spdy::Http2HeaderBlock ConstructPutHeaderBlock(std::string_view url, 295 int64_t content_length); 296 297 // Construct an expected SPDY reply string from the given headers. 298 std::string ConstructSpdyReplyString( 299 const spdy::Http2HeaderBlock& headers) const; 300 301 // Construct an expected SPDY SETTINGS frame. 302 // |settings| are the settings to set. 303 // Returns the constructed frame. 304 spdy::SpdySerializedFrame ConstructSpdySettings( 305 const spdy::SettingsMap& settings); 306 307 // Constructs an expected SPDY SETTINGS acknowledgement frame. 308 spdy::SpdySerializedFrame ConstructSpdySettingsAck(); 309 310 // Construct a SPDY PING frame. Returns the constructed frame. 311 spdy::SpdySerializedFrame ConstructSpdyPing(uint32_t ping_id, bool is_ack); 312 313 // Construct a SPDY GOAWAY frame with the specified last_good_stream_id. 314 // Returns the constructed frame. 315 spdy::SpdySerializedFrame ConstructSpdyGoAway( 316 spdy::SpdyStreamId last_good_stream_id); 317 318 // Construct a SPDY GOAWAY frame with the specified last_good_stream_id, 319 // status, and description. Returns the constructed frame. 320 spdy::SpdySerializedFrame ConstructSpdyGoAway( 321 spdy::SpdyStreamId last_good_stream_id, 322 spdy::SpdyErrorCode error_code, 323 const std::string& desc); 324 325 // Construct a SPDY WINDOW_UPDATE frame. Returns the constructed frame. 326 spdy::SpdySerializedFrame ConstructSpdyWindowUpdate( 327 spdy::SpdyStreamId stream_id, 328 uint32_t delta_window_size); 329 330 // Construct a SPDY RST_STREAM frame. Returns the constructed frame. 331 spdy::SpdySerializedFrame ConstructSpdyRstStream( 332 spdy::SpdyStreamId stream_id, 333 spdy::SpdyErrorCode error_code); 334 335 // Construct a PRIORITY frame. The weight is derived from |request_priority|. 336 // Returns the constructed frame. 337 spdy::SpdySerializedFrame ConstructSpdyPriority( 338 spdy::SpdyStreamId stream_id, 339 spdy::SpdyStreamId parent_stream_id, 340 RequestPriority request_priority, 341 bool exclusive); 342 343 // Constructs a standard SPDY GET HEADERS frame for |url| with header 344 // compression. 345 // |extra_headers| are the extra header-value pairs, which typically 346 // will vary the most between calls. 347 spdy::SpdySerializedFrame ConstructSpdyGet( 348 const char* const url, 349 spdy::SpdyStreamId stream_id, 350 RequestPriority request_priority, 351 bool priority_incremental = kDefaultPriorityIncremental, 352 std::optional<RequestPriority> header_request_priority = std::nullopt); 353 354 // Constructs a standard SPDY GET HEADERS frame with header compression. 355 // |extra_headers| are the extra header-value pairs, which typically 356 // will vary the most between calls. If |direct| is false, the 357 // the full url will be used instead of simply the path. 358 spdy::SpdySerializedFrame ConstructSpdyGet( 359 const char* const extra_headers[], 360 int extra_header_count, 361 int stream_id, 362 RequestPriority request_priority, 363 bool priority_incremental = kDefaultPriorityIncremental, 364 std::optional<RequestPriority> header_request_priority = std::nullopt); 365 366 // Constructs a SPDY HEADERS frame for a CONNECT request. 367 spdy::SpdySerializedFrame ConstructSpdyConnect( 368 const char* const extra_headers[], 369 int extra_header_count, 370 int stream_id, 371 RequestPriority priority, 372 const HostPortPair& host_port_pair); 373 374 // Constructs a PUSH_PROMISE frame. 375 spdy::SpdySerializedFrame ConstructSpdyPushPromise( 376 spdy::SpdyStreamId associated_stream_id, 377 spdy::SpdyStreamId stream_id, 378 spdy::Http2HeaderBlock headers); 379 380 // Constructs a HEADERS frame with the request header compression context with 381 // END_STREAM flag set to |fin|. 382 spdy::SpdySerializedFrame ConstructSpdyResponseHeaders( 383 int stream_id, 384 spdy::Http2HeaderBlock headers, 385 bool fin); 386 387 // Construct a HEADERS frame carrying exactly the given headers and priority. 388 spdy::SpdySerializedFrame ConstructSpdyHeaders( 389 int stream_id, 390 spdy::Http2HeaderBlock headers, 391 RequestPriority priority, 392 bool fin, 393 bool priority_incremental = kDefaultPriorityIncremental, 394 std::optional<RequestPriority> header_request_priority = std::nullopt); 395 396 // Construct a reply HEADERS frame carrying exactly the given headers and the 397 // default priority. 398 spdy::SpdySerializedFrame ConstructSpdyReply(int stream_id, 399 spdy::Http2HeaderBlock headers); 400 401 // Constructs a standard SPDY HEADERS frame to match the SPDY GET. 402 // |extra_headers| are the extra header-value pairs, which typically 403 // will vary the most between calls. 404 spdy::SpdySerializedFrame ConstructSpdyGetReply( 405 const char* const extra_headers[], 406 int extra_header_count, 407 int stream_id); 408 409 // Constructs a standard SPDY HEADERS frame with an Internal Server 410 // Error status code. 411 spdy::SpdySerializedFrame ConstructSpdyReplyError(int stream_id); 412 413 // Constructs a standard SPDY HEADERS frame with the specified status code. 414 spdy::SpdySerializedFrame ConstructSpdyReplyError( 415 const char* const status, 416 const char* const* const extra_headers, 417 int extra_header_count, 418 int stream_id); 419 420 // Constructs a standard SPDY POST HEADERS frame. 421 // |extra_headers| are the extra header-value pairs, which typically 422 // will vary the most between calls. 423 spdy::SpdySerializedFrame ConstructSpdyPost( 424 const char* url, 425 spdy::SpdyStreamId stream_id, 426 int64_t content_length, 427 RequestPriority request_priority, 428 const char* const extra_headers[], 429 int extra_header_count, 430 bool priority_incremental = kDefaultPriorityIncremental); 431 432 // Constructs a chunked transfer SPDY POST HEADERS frame. 433 // |extra_headers| are the extra header-value pairs, which typically 434 // will vary the most between calls. 435 spdy::SpdySerializedFrame ConstructChunkedSpdyPost( 436 const char* const extra_headers[], 437 int extra_header_count, 438 RequestPriority request_priority = RequestPriority::DEFAULT_PRIORITY, 439 bool priority_incremental = kDefaultPriorityIncremental); 440 441 // Constructs a standard SPDY HEADERS frame to match the SPDY POST. 442 // |extra_headers| are the extra header-value pairs, which typically 443 // will vary the most between calls. 444 spdy::SpdySerializedFrame ConstructSpdyPostReply( 445 const char* const extra_headers[], 446 int extra_header_count); 447 448 // Constructs a single SPDY data frame with the contents "hello!" 449 spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id, bool fin); 450 451 // Constructs a single SPDY data frame with the given content. 452 spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id, 453 std::string_view data, 454 bool fin); 455 456 // Constructs a single SPDY data frame with the given content and padding. 457 spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id, 458 std::string_view data, 459 bool fin, 460 int padding_length); 461 462 // Wraps |frame| in the payload of a data frame in stream |stream_id|. 463 spdy::SpdySerializedFrame ConstructWrappedSpdyFrame( 464 const spdy::SpdySerializedFrame& frame, 465 int stream_id); 466 467 // Serialize a spdy::SpdyFrameIR with |headerless_spdy_framer_|. 468 spdy::SpdySerializedFrame SerializeFrame(const spdy::SpdyFrameIR& frame_ir); 469 470 // Called when necessary (when it will affect stream dependency specification 471 // when setting dependencies based on priorioties) to notify the utility 472 // class of stream destruction. 473 void UpdateWithStreamDestruction(int stream_id); 474 set_default_url(const GURL & url)475 void set_default_url(const GURL& url) { default_url_ = url; } 476 477 private: 478 // |content_length| may be NULL, in which case the content-length 479 // header will be omitted. 480 static spdy::Http2HeaderBlock ConstructHeaderBlock(std::string_view method, 481 std::string_view url, 482 int64_t* content_length); 483 484 // Multiple SpdyFramers are required to keep track of header compression 485 // state. 486 // Use to serialize frames (request or response) without headers. 487 spdy::SpdyFramer headerless_spdy_framer_; 488 // Use to serialize request frames with headers. 489 spdy::SpdyFramer request_spdy_framer_; 490 // Use to serialize response frames with headers. 491 spdy::SpdyFramer response_spdy_framer_; 492 493 GURL default_url_; 494 495 // Enable support for addint the "priority" header to requests. 496 bool use_priority_header_; 497 498 // Track a FIFO list of the stream_id of all created requests by priority. 499 std::map<int, std::vector<int>> priority_to_stream_id_list_; 500 }; 501 502 namespace test { 503 504 // Returns a SHA1 HashValue in which each byte has the value |label|. 505 HashValue GetTestHashValue(uint8_t label); 506 507 } // namespace test 508 } // namespace net 509 510 #endif // NET_SPDY_SPDY_TEST_UTIL_COMMON_H_ 511