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 SpdyTestUtil(); 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 static spdy::Http2HeaderBlock ConstructGetHeaderBlock(base::StringPiece url); 275 static spdy::Http2HeaderBlock ConstructGetHeaderBlockForProxy( 276 base::StringPiece url); 277 static spdy::Http2HeaderBlock ConstructHeadHeaderBlock( 278 base::StringPiece url, 279 int64_t content_length); 280 static spdy::Http2HeaderBlock ConstructPostHeaderBlock( 281 base::StringPiece url, 282 int64_t content_length); 283 static spdy::Http2HeaderBlock ConstructPutHeaderBlock(base::StringPiece url, 284 int64_t content_length); 285 286 // Construct an expected SPDY reply string from the given headers. 287 std::string ConstructSpdyReplyString( 288 const spdy::Http2HeaderBlock& headers) const; 289 290 // Construct an expected SPDY SETTINGS frame. 291 // |settings| are the settings to set. 292 // Returns the constructed frame. 293 spdy::SpdySerializedFrame ConstructSpdySettings( 294 const spdy::SettingsMap& settings); 295 296 // Constructs an expected SPDY SETTINGS acknowledgement frame. 297 spdy::SpdySerializedFrame ConstructSpdySettingsAck(); 298 299 // Construct a SPDY PING frame. Returns the constructed frame. 300 spdy::SpdySerializedFrame ConstructSpdyPing(uint32_t ping_id, bool is_ack); 301 302 // Construct a SPDY GOAWAY frame with the specified last_good_stream_id. 303 // Returns the constructed frame. 304 spdy::SpdySerializedFrame ConstructSpdyGoAway( 305 spdy::SpdyStreamId last_good_stream_id); 306 307 // Construct a SPDY GOAWAY frame with the specified last_good_stream_id, 308 // status, and description. Returns the constructed frame. 309 spdy::SpdySerializedFrame ConstructSpdyGoAway( 310 spdy::SpdyStreamId last_good_stream_id, 311 spdy::SpdyErrorCode error_code, 312 const std::string& desc); 313 314 // Construct a SPDY WINDOW_UPDATE frame. Returns the constructed frame. 315 spdy::SpdySerializedFrame ConstructSpdyWindowUpdate( 316 spdy::SpdyStreamId stream_id, 317 uint32_t delta_window_size); 318 319 // Construct a SPDY RST_STREAM frame. Returns the constructed frame. 320 spdy::SpdySerializedFrame ConstructSpdyRstStream( 321 spdy::SpdyStreamId stream_id, 322 spdy::SpdyErrorCode error_code); 323 324 // Construct a PRIORITY frame. The weight is derived from |request_priority|. 325 // Returns the constructed frame. 326 spdy::SpdySerializedFrame ConstructSpdyPriority( 327 spdy::SpdyStreamId stream_id, 328 spdy::SpdyStreamId parent_stream_id, 329 RequestPriority request_priority, 330 bool exclusive); 331 332 // Constructs a standard SPDY GET HEADERS frame for |url| with header 333 // compression. 334 // |extra_headers| are the extra header-value pairs, which typically 335 // will vary the most between calls. 336 spdy::SpdySerializedFrame ConstructSpdyGet(const char* const url, 337 spdy::SpdyStreamId stream_id, 338 RequestPriority request_priority); 339 340 // Constructs a standard SPDY GET HEADERS frame with header compression. 341 // |extra_headers| are the extra header-value pairs, which typically 342 // will vary the most between calls. If |direct| is false, the 343 // the full url will be used instead of simply the path. 344 spdy::SpdySerializedFrame ConstructSpdyGet(const char* const extra_headers[], 345 int extra_header_count, 346 int stream_id, 347 RequestPriority request_priority); 348 349 // Constructs a SPDY HEADERS frame for a CONNECT request. 350 spdy::SpdySerializedFrame ConstructSpdyConnect( 351 const char* const extra_headers[], 352 int extra_header_count, 353 int stream_id, 354 RequestPriority priority, 355 const HostPortPair& host_port_pair); 356 357 // Constructs a PUSH_PROMISE frame and a HEADERS frame on the pushed stream. 358 // |extra_headers| are the extra header-value pairs, which typically 359 // will vary the most between calls. 360 // Returns a spdy::SpdySerializedFrame object with the two frames 361 // concatenated. 362 spdy::SpdySerializedFrame ConstructSpdyPush(const char* const extra_headers[], 363 int extra_header_count, 364 int stream_id, 365 int associated_stream_id, 366 const char* url); 367 spdy::SpdySerializedFrame ConstructSpdyPush(const char* const extra_headers[], 368 int extra_header_count, 369 int stream_id, 370 int associated_stream_id, 371 const char* url, 372 const char* status, 373 const char* location); 374 375 // Constructs a PUSH_PROMISE frame. 376 spdy::SpdySerializedFrame ConstructSpdyPushPromise( 377 spdy::SpdyStreamId associated_stream_id, 378 spdy::SpdyStreamId stream_id, 379 spdy::Http2HeaderBlock headers); 380 381 spdy::SpdySerializedFrame ConstructSpdyPushHeaders( 382 int stream_id, 383 const char* const extra_headers[], 384 int extra_header_count); 385 386 // Constructs a HEADERS frame with the request header compression context with 387 // END_STREAM flag set to |fin|. 388 spdy::SpdySerializedFrame ConstructSpdyResponseHeaders( 389 int stream_id, 390 spdy::Http2HeaderBlock headers, 391 bool fin); 392 393 // Construct a HEADERS frame carrying exactly the given headers and priority. 394 spdy::SpdySerializedFrame ConstructSpdyHeaders(int stream_id, 395 spdy::Http2HeaderBlock headers, 396 RequestPriority priority, 397 bool fin); 398 399 // Construct a reply HEADERS frame carrying exactly the given headers and the 400 // default priority. 401 spdy::SpdySerializedFrame ConstructSpdyReply(int stream_id, 402 spdy::Http2HeaderBlock headers); 403 404 // Constructs a standard SPDY HEADERS frame to match the SPDY GET. 405 // |extra_headers| are the extra header-value pairs, which typically 406 // will vary the most between calls. 407 spdy::SpdySerializedFrame ConstructSpdyGetReply( 408 const char* const extra_headers[], 409 int extra_header_count, 410 int stream_id); 411 412 // Constructs a standard SPDY HEADERS frame with an Internal Server 413 // Error status code. 414 spdy::SpdySerializedFrame ConstructSpdyReplyError(int stream_id); 415 416 // Constructs a standard SPDY HEADERS frame with the specified status code. 417 spdy::SpdySerializedFrame ConstructSpdyReplyError( 418 const char* const status, 419 const char* const* const extra_headers, 420 int extra_header_count, 421 int stream_id); 422 423 // Constructs a standard SPDY POST HEADERS frame. 424 // |extra_headers| are the extra header-value pairs, which typically 425 // will vary the most between calls. 426 spdy::SpdySerializedFrame ConstructSpdyPost(const char* url, 427 spdy::SpdyStreamId stream_id, 428 int64_t content_length, 429 RequestPriority priority, 430 const char* const extra_headers[], 431 int extra_header_count); 432 433 // Constructs a chunked transfer SPDY POST HEADERS frame. 434 // |extra_headers| are the extra header-value pairs, which typically 435 // will vary the most between calls. 436 spdy::SpdySerializedFrame ConstructChunkedSpdyPost( 437 const char* const extra_headers[], 438 int extra_header_count); 439 440 // Constructs a standard SPDY HEADERS frame to match the SPDY POST. 441 // |extra_headers| are the extra header-value pairs, which typically 442 // will vary the most between calls. 443 spdy::SpdySerializedFrame ConstructSpdyPostReply( 444 const char* const extra_headers[], 445 int extra_header_count); 446 447 // Constructs a single SPDY data frame with the contents "hello!" 448 spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id, bool fin); 449 450 // Constructs a single SPDY data frame with the given content. 451 spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id, 452 base::StringPiece data, 453 bool fin); 454 455 // Constructs a single SPDY data frame with the given content and padding. 456 spdy::SpdySerializedFrame ConstructSpdyDataFrame(int stream_id, 457 base::StringPiece data, 458 bool fin, 459 int padding_length); 460 461 // Wraps |frame| in the payload of a data frame in stream |stream_id|. 462 spdy::SpdySerializedFrame ConstructWrappedSpdyFrame( 463 const spdy::SpdySerializedFrame& frame, 464 int stream_id); 465 466 // Serialize a spdy::SpdyFrameIR with |headerless_spdy_framer_|. 467 spdy::SpdySerializedFrame SerializeFrame(const spdy::SpdyFrameIR& frame_ir); 468 469 // Called when necessary (when it will affect stream dependency specification 470 // when setting dependencies based on priorioties) to notify the utility 471 // class of stream destruction. 472 void UpdateWithStreamDestruction(int stream_id); 473 set_default_url(const GURL & url)474 void set_default_url(const GURL& url) { default_url_ = url; } 475 476 private: 477 // |content_length| may be NULL, in which case the content-length 478 // header will be omitted. 479 static spdy::Http2HeaderBlock ConstructHeaderBlock(base::StringPiece method, 480 base::StringPiece url, 481 int64_t* content_length); 482 483 // Multiple SpdyFramers are required to keep track of header compression 484 // state. 485 // Use to serialize frames (request or response) without headers. 486 spdy::SpdyFramer headerless_spdy_framer_; 487 // Use to serialize request frames with headers. 488 spdy::SpdyFramer request_spdy_framer_; 489 // Use to serialize response frames with headers. 490 spdy::SpdyFramer response_spdy_framer_; 491 492 GURL default_url_; 493 494 // Track a FIFO list of the stream_id of all created requests by priority. 495 std::map<int, std::vector<int>> priority_to_stream_id_list_; 496 }; 497 498 namespace test { 499 500 // Returns a SHA1 HashValue in which each byte has the value |label|. 501 HashValue GetTestHashValue(uint8_t label); 502 503 // A test implementation of ServerPushDelegate that caches all the pushed 504 // request and provides a interface to cancel the push given url. 505 class TestServerPushDelegate : public ServerPushDelegate { 506 public: 507 TestServerPushDelegate(); 508 ~TestServerPushDelegate() override; 509 510 void OnPush(std::unique_ptr<ServerPushHelper> push_helper, 511 const NetLogWithSource& session_net_log) override; 512 513 bool CancelPush(GURL url); 514 515 private: 516 std::map<GURL, std::unique_ptr<ServerPushHelper>> push_helpers; 517 }; 518 519 } // namespace test 520 } // namespace net 521 522 #endif // NET_SPDY_SPDY_TEST_UTIL_COMMON_H_ 523