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