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