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 <string> 9 #include <vector> 10 11 #include "base/memory/ref_counted.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "crypto/ec_private_key.h" 14 #include "crypto/ec_signature_creator.h" 15 #include "net/base/completion_callback.h" 16 #include "net/base/request_priority.h" 17 #include "net/base/test_completion_callback.h" 18 #include "net/cert/cert_verifier.h" 19 #include "net/dns/mock_host_resolver.h" 20 #include "net/http/http_auth_handler_factory.h" 21 #include "net/http/http_network_session.h" 22 #include "net/http/http_response_info.h" 23 #include "net/http/http_server_properties_impl.h" 24 #include "net/http/transport_security_state.h" 25 #include "net/proxy/proxy_service.h" 26 #include "net/socket/next_proto.h" 27 #include "net/socket/socket_test_util.h" 28 #include "net/spdy/spdy_protocol.h" 29 #include "net/ssl/ssl_config_service_defaults.h" 30 #include "net/url_request/url_request_context.h" 31 #include "net/url_request/url_request_context_storage.h" 32 #include "testing/gtest/include/gtest/gtest.h" 33 34 class GURL; 35 36 namespace net { 37 38 class BoundNetLog; 39 class SpdySession; 40 class SpdySessionKey; 41 class SpdySessionPool; 42 class SpdyStream; 43 class SpdyStreamRequest; 44 45 // Default upload data used by both, mock objects and framer when creating 46 // data frames. 47 const char kDefaultURL[] = "http://www.google.com"; 48 const char kUploadData[] = "hello!"; 49 const int kUploadDataSize = arraysize(kUploadData)-1; 50 51 // SpdyNextProtos returns a vector of next protocols for negotiating 52 // SPDY. 53 std::vector<NextProto> SpdyNextProtos(); 54 55 // Chop a frame into an array of MockWrites. 56 // |data| is the frame to chop. 57 // |length| is the length of the frame to chop. 58 // |num_chunks| is the number of chunks to create. 59 MockWrite* ChopWriteFrame(const char* data, int length, int num_chunks); 60 61 // Chop a SpdyFrame into an array of MockWrites. 62 // |frame| is the frame to chop. 63 // |num_chunks| is the number of chunks to create. 64 MockWrite* ChopWriteFrame(const SpdyFrame& frame, int num_chunks); 65 66 // Chop a frame into an array of MockReads. 67 // |data| is the frame to chop. 68 // |length| is the length of the frame to chop. 69 // |num_chunks| is the number of chunks to create. 70 MockRead* ChopReadFrame(const char* data, int length, int num_chunks); 71 72 // Chop a SpdyFrame into an array of MockReads. 73 // |frame| is the frame to chop. 74 // |num_chunks| is the number of chunks to create. 75 MockRead* ChopReadFrame(const SpdyFrame& frame, int num_chunks); 76 77 // Adds headers and values to a map. 78 // |extra_headers| is an array of { name, value } pairs, arranged as strings 79 // where the even entries are the header names, and the odd entries are the 80 // header values. 81 // |headers| gets filled in from |extra_headers|. 82 void AppendToHeaderBlock(const char* const extra_headers[], 83 int extra_header_count, 84 SpdyHeaderBlock* headers); 85 86 // Create an async MockWrite from the given SpdyFrame. 87 MockWrite CreateMockWrite(const SpdyFrame& req); 88 89 // Create an async MockWrite from the given SpdyFrame and sequence number. 90 MockWrite CreateMockWrite(const SpdyFrame& req, int seq); 91 92 MockWrite CreateMockWrite(const SpdyFrame& req, int seq, IoMode mode); 93 94 // Create a MockRead from the given SpdyFrame. 95 MockRead CreateMockRead(const SpdyFrame& resp); 96 97 // Create a MockRead from the given SpdyFrame and sequence number. 98 MockRead CreateMockRead(const SpdyFrame& resp, int seq); 99 100 MockRead CreateMockRead(const SpdyFrame& resp, int seq, IoMode mode); 101 102 // Combines the given SpdyFrames into the given char array and returns 103 // the total length. 104 int CombineFrames(const SpdyFrame** frames, int num_frames, 105 char* buff, int buff_len); 106 107 // Returns the SpdyPriority embedded in the given frame. Returns true 108 // and fills in |priority| on success. 109 bool GetSpdyPriority(SpdyMajorVersion version, 110 const SpdyFrame& frame, 111 SpdyPriority* priority); 112 113 // Tries to create a stream in |session| synchronously. Returns NULL 114 // on failure. 115 base::WeakPtr<SpdyStream> CreateStreamSynchronously( 116 SpdyStreamType type, 117 const base::WeakPtr<SpdySession>& session, 118 const GURL& url, 119 RequestPriority priority, 120 const BoundNetLog& net_log); 121 122 // Helper class used by some tests to release a stream as soon as it's 123 // created. 124 class StreamReleaserCallback : public TestCompletionCallbackBase { 125 public: 126 StreamReleaserCallback(); 127 128 virtual ~StreamReleaserCallback(); 129 130 // Returns a callback that releases |request|'s stream. 131 CompletionCallback MakeCallback(SpdyStreamRequest* request); 132 133 private: 134 void OnComplete(SpdyStreamRequest* request, int result); 135 }; 136 137 const size_t kSpdyCredentialSlotUnused = 0; 138 139 // This struct holds information used to construct spdy control and data frames. 140 struct SpdyHeaderInfo { 141 SpdyFrameType kind; 142 SpdyStreamId id; 143 SpdyStreamId assoc_id; 144 SpdyPriority priority; 145 size_t credential_slot; // SPDY3 only 146 SpdyControlFlags control_flags; 147 bool compressed; 148 SpdyRstStreamStatus status; 149 const char* data; 150 uint32 data_length; 151 SpdyDataFlags data_flags; 152 }; 153 154 // An ECSignatureCreator that returns deterministic signatures. 155 class MockECSignatureCreator : public crypto::ECSignatureCreator { 156 public: 157 explicit MockECSignatureCreator(crypto::ECPrivateKey* key); 158 159 // crypto::ECSignatureCreator 160 virtual bool Sign(const uint8* data, 161 int data_len, 162 std::vector<uint8>* signature) OVERRIDE; 163 virtual bool DecodeSignature(const std::vector<uint8>& signature, 164 std::vector<uint8>* out_raw_sig) OVERRIDE; 165 166 private: 167 crypto::ECPrivateKey* key_; 168 169 DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreator); 170 }; 171 172 // An ECSignatureCreatorFactory creates MockECSignatureCreator. 173 class MockECSignatureCreatorFactory : public crypto::ECSignatureCreatorFactory { 174 public: 175 MockECSignatureCreatorFactory(); 176 virtual ~MockECSignatureCreatorFactory(); 177 178 // crypto::ECSignatureCreatorFactory 179 virtual crypto::ECSignatureCreator* Create( 180 crypto::ECPrivateKey* key) OVERRIDE; 181 182 private: 183 DISALLOW_COPY_AND_ASSIGN(MockECSignatureCreatorFactory); 184 }; 185 186 // Helper to manage the lifetimes of the dependencies for a 187 // HttpNetworkTransaction. 188 struct SpdySessionDependencies { 189 // Default set of dependencies -- "null" proxy service. 190 explicit SpdySessionDependencies(NextProto protocol); 191 192 // Custom proxy service dependency. 193 SpdySessionDependencies(NextProto protocol, ProxyService* proxy_service); 194 195 ~SpdySessionDependencies(); 196 197 static HttpNetworkSession* SpdyCreateSession( 198 SpdySessionDependencies* session_deps); 199 static HttpNetworkSession* SpdyCreateSessionDeterministic( 200 SpdySessionDependencies* session_deps); 201 static HttpNetworkSession::Params CreateSessionParams( 202 SpdySessionDependencies* session_deps); 203 204 // NOTE: host_resolver must be ordered before http_auth_handler_factory. 205 scoped_ptr<MockHostResolverBase> host_resolver; 206 scoped_ptr<CertVerifier> cert_verifier; 207 scoped_ptr<TransportSecurityState> transport_security_state; 208 scoped_ptr<ProxyService> proxy_service; 209 scoped_refptr<SSLConfigService> ssl_config_service; 210 scoped_ptr<MockClientSocketFactory> socket_factory; 211 scoped_ptr<DeterministicMockClientSocketFactory> deterministic_socket_factory; 212 scoped_ptr<HttpAuthHandlerFactory> http_auth_handler_factory; 213 HttpServerPropertiesImpl http_server_properties; 214 bool enable_ip_pooling; 215 bool enable_compression; 216 bool enable_ping; 217 bool enable_user_alternate_protocol_ports; 218 NextProto protocol; 219 size_t stream_initial_recv_window_size; 220 SpdySession::TimeFunc time_func; 221 std::string trusted_spdy_proxy; 222 NetLog* net_log; 223 }; 224 225 class SpdyURLRequestContext : public URLRequestContext { 226 public: 227 explicit SpdyURLRequestContext(NextProto protocol); 228 virtual ~SpdyURLRequestContext(); 229 230 MockClientSocketFactory& socket_factory() { return socket_factory_; } 231 232 private: 233 MockClientSocketFactory socket_factory_; 234 net::URLRequestContextStorage storage_; 235 }; 236 237 // Equivalent to pool->GetIfExists(spdy_session_key, BoundNetLog()) != NULL. 238 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key); 239 240 // Creates a SPDY session for the given key and puts it in the SPDY 241 // session pool in |http_session|. A SPDY session for |key| must not 242 // already exist. 243 base::WeakPtr<SpdySession> CreateInsecureSpdySession( 244 const scoped_refptr<HttpNetworkSession>& http_session, 245 const SpdySessionKey& key, 246 const BoundNetLog& net_log); 247 248 // Tries to create a SPDY session for the given key but expects the 249 // attempt to fail with the given error. A SPDY session for |key| must 250 // not already exist. 251 void TryCreateInsecureSpdySessionExpectingFailure( 252 const scoped_refptr<HttpNetworkSession>& http_session, 253 const SpdySessionKey& key, 254 Error expected_error, 255 const BoundNetLog& net_log); 256 257 // Like CreateInsecureSpdySession(), but uses TLS. 258 base::WeakPtr<SpdySession> CreateSecureSpdySession( 259 const scoped_refptr<HttpNetworkSession>& http_session, 260 const SpdySessionKey& key, 261 const BoundNetLog& net_log); 262 263 // Creates an insecure SPDY session for the given key and puts it in 264 // |pool|. The returned session will neither receive nor send any 265 // data. A SPDY session for |key| must not already exist. 266 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool, 267 const SpdySessionKey& key); 268 269 // Tries to create an insecure SPDY session for the given key but 270 // expects the attempt to fail with the given error. The session will 271 // neither receive nor send any data. A SPDY session for |key| must 272 // not already exist. 273 void TryCreateFakeSpdySessionExpectingFailure(SpdySessionPool* pool, 274 const SpdySessionKey& key, 275 Error expected_error); 276 277 class SpdySessionPoolPeer { 278 public: 279 explicit SpdySessionPoolPeer(SpdySessionPool* pool); 280 281 void RemoveAliases(const SpdySessionKey& key); 282 void DisableDomainAuthenticationVerification(); 283 void SetEnableSendingInitialData(bool enabled); 284 285 private: 286 SpdySessionPool* const pool_; 287 288 DISALLOW_COPY_AND_ASSIGN(SpdySessionPoolPeer); 289 }; 290 291 class SpdyTestUtil { 292 public: 293 explicit SpdyTestUtil(NextProto protocol); 294 295 // Add the appropriate headers to put |url| into |block|. 296 void AddUrlToHeaderBlock(base::StringPiece url, 297 SpdyHeaderBlock* headers) const; 298 299 scoped_ptr<SpdyHeaderBlock> ConstructGetHeaderBlock( 300 base::StringPiece url) const; 301 scoped_ptr<SpdyHeaderBlock> ConstructGetHeaderBlockForProxy( 302 base::StringPiece url) const; 303 scoped_ptr<SpdyHeaderBlock> ConstructHeadHeaderBlock( 304 base::StringPiece url, 305 int64 content_length) const; 306 scoped_ptr<SpdyHeaderBlock> ConstructPostHeaderBlock( 307 base::StringPiece url, 308 int64 content_length) const; 309 scoped_ptr<SpdyHeaderBlock> ConstructPutHeaderBlock( 310 base::StringPiece url, 311 int64 content_length) const; 312 313 // Construct a SPDY frame. If it is a SYN_STREAM or SYN_REPLY frame (as 314 // specified in header_info.kind), the provided headers are included in the 315 // frame. 316 SpdyFrame* ConstructSpdyFrame( 317 const SpdyHeaderInfo& header_info, 318 scoped_ptr<SpdyHeaderBlock> headers) const; 319 320 // Construct a SPDY frame. If it is a SYN_STREAM or SYN_REPLY frame (as 321 // specified in header_info.kind), the headers provided in extra_headers and 322 // (if non-NULL) tail_headers are concatenated and included in the frame. 323 // (extra_headers must always be non-NULL.) 324 SpdyFrame* ConstructSpdyFrame(const SpdyHeaderInfo& header_info, 325 const char* const extra_headers[], 326 int extra_header_count, 327 const char* const tail_headers[], 328 int tail_header_count) const; 329 330 // Construct a generic SpdyControlFrame. 331 SpdyFrame* ConstructSpdyControlFrame( 332 scoped_ptr<SpdyHeaderBlock> headers, 333 bool compressed, 334 SpdyStreamId stream_id, 335 RequestPriority request_priority, 336 SpdyFrameType type, 337 SpdyControlFlags flags, 338 SpdyStreamId associated_stream_id) const; 339 340 // Construct a generic SpdyControlFrame. 341 // 342 // Warning: extra_header_count is the number of header-value pairs in 343 // extra_headers (so half the number of elements), but tail_headers_size is 344 // the actual number of elements (both keys and values) in tail_headers. 345 // TODO(ttuttle): Fix this inconsistency. 346 SpdyFrame* ConstructSpdyControlFrame( 347 const char* const extra_headers[], 348 int extra_header_count, 349 bool compressed, 350 SpdyStreamId stream_id, 351 RequestPriority request_priority, 352 SpdyFrameType type, 353 SpdyControlFlags flags, 354 const char* const* tail_headers, 355 int tail_headers_size, 356 SpdyStreamId associated_stream_id) const; 357 358 // Construct an expected SPDY reply string from the given headers. 359 std::string ConstructSpdyReplyString(const SpdyHeaderBlock& headers) const; 360 361 // Construct an expected SPDY SETTINGS frame. 362 // |settings| are the settings to set. 363 // Returns the constructed frame. The caller takes ownership of the frame. 364 SpdyFrame* ConstructSpdySettings(const SettingsMap& settings) const; 365 366 // Construct an expected SPDY CREDENTIAL frame. 367 // |credential| is the credential to send. 368 // Returns the constructed frame. The caller takes ownership of the frame. 369 SpdyFrame* ConstructSpdyCredential(const SpdyCredential& credential) const; 370 371 // Construct a SPDY PING frame. 372 // Returns the constructed frame. The caller takes ownership of the frame. 373 SpdyFrame* ConstructSpdyPing(uint32 ping_id) const; 374 375 // Construct a SPDY GOAWAY frame with last_good_stream_id = 0. 376 // Returns the constructed frame. The caller takes ownership of the frame. 377 SpdyFrame* ConstructSpdyGoAway() const; 378 379 // Construct a SPDY GOAWAY frame with the specified last_good_stream_id. 380 // Returns the constructed frame. The caller takes ownership of the frame. 381 SpdyFrame* ConstructSpdyGoAway(SpdyStreamId last_good_stream_id) const; 382 383 // Construct a SPDY WINDOW_UPDATE frame. 384 // Returns the constructed frame. The caller takes ownership of the frame. 385 SpdyFrame* ConstructSpdyWindowUpdate( 386 SpdyStreamId stream_id, 387 uint32 delta_window_size) const; 388 389 // Construct a SPDY RST_STREAM frame. 390 // Returns the constructed frame. The caller takes ownership of the frame. 391 SpdyFrame* ConstructSpdyRstStream(SpdyStreamId stream_id, 392 SpdyRstStreamStatus status) const; 393 394 // Constructs a standard SPDY GET SYN frame, optionally compressed 395 // for the url |url|. 396 // |extra_headers| are the extra header-value pairs, which typically 397 // will vary the most between calls. 398 // Returns a SpdyFrame. 399 SpdyFrame* ConstructSpdyGet(const char* const url, 400 bool compressed, 401 SpdyStreamId stream_id, 402 RequestPriority request_priority) const; 403 404 SpdyFrame* ConstructSpdyGetForProxy(const char* const url, 405 bool compressed, 406 SpdyStreamId stream_id, 407 RequestPriority request_priority) const; 408 409 // Constructs a standard SPDY GET SYN frame, optionally compressed. 410 // |extra_headers| are the extra header-value pairs, which typically 411 // will vary the most between calls. If |direct| is false, the 412 // the full url will be used instead of simply the path. 413 // Returns a SpdyFrame. 414 SpdyFrame* ConstructSpdyGet(const char* const extra_headers[], 415 int extra_header_count, 416 bool compressed, 417 int stream_id, 418 RequestPriority request_priority, 419 bool direct) const; 420 421 // Constructs a standard SPDY SYN_STREAM frame for a CONNECT request. 422 SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[], 423 int extra_header_count, 424 int stream_id, 425 RequestPriority priority) const; 426 427 // Constructs a standard SPDY push SYN frame. 428 // |extra_headers| are the extra header-value pairs, which typically 429 // will vary the most between calls. 430 // Returns a SpdyFrame. 431 SpdyFrame* ConstructSpdyPush(const char* const extra_headers[], 432 int extra_header_count, 433 int stream_id, 434 int associated_stream_id, 435 const char* url); 436 SpdyFrame* ConstructSpdyPush(const char* const extra_headers[], 437 int extra_header_count, 438 int stream_id, 439 int associated_stream_id, 440 const char* url, 441 const char* status, 442 const char* location); 443 444 SpdyFrame* ConstructSpdyPushHeaders(int stream_id, 445 const char* const extra_headers[], 446 int extra_header_count); 447 448 // Constructs a standard SPDY SYN_REPLY frame to match the SPDY GET. 449 // |extra_headers| are the extra header-value pairs, which typically 450 // will vary the most between calls. 451 // Returns a SpdyFrame. 452 SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[], 453 int extra_header_count, 454 int stream_id); 455 456 // Constructs a standard SPDY SYN_REPLY frame to match the SPDY GET. 457 // |extra_headers| are the extra header-value pairs, which typically 458 // will vary the most between calls. 459 // Returns a SpdyFrame. 460 SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id); 461 462 // Constructs a standard SPDY SYN_REPLY frame with an Internal Server 463 // Error status code. 464 // Returns a SpdyFrame. 465 SpdyFrame* ConstructSpdySynReplyError(int stream_id); 466 467 // Constructs a standard SPDY SYN_REPLY frame with the specified status code. 468 // Returns a SpdyFrame. 469 SpdyFrame* ConstructSpdySynReplyError(const char* const status, 470 const char* const* const extra_headers, 471 int extra_header_count, 472 int stream_id); 473 474 // Constructs a standard SPDY POST SYN frame. 475 // |extra_headers| are the extra header-value pairs, which typically 476 // will vary the most between calls. 477 // Returns a SpdyFrame. 478 SpdyFrame* ConstructSpdyPost(const char* url, 479 SpdyStreamId stream_id, 480 int64 content_length, 481 RequestPriority priority, 482 const char* const extra_headers[], 483 int extra_header_count); 484 485 // Constructs a chunked transfer SPDY POST SYN frame. 486 // |extra_headers| are the extra header-value pairs, which typically 487 // will vary the most between calls. 488 // Returns a SpdyFrame. 489 SpdyFrame* ConstructChunkedSpdyPost(const char* const extra_headers[], 490 int extra_header_count); 491 492 // Constructs a standard SPDY SYN_REPLY frame to match the SPDY POST. 493 // |extra_headers| are the extra header-value pairs, which typically 494 // will vary the most between calls. 495 // Returns a SpdyFrame. 496 SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[], 497 int extra_header_count); 498 499 // Constructs a single SPDY data frame with the contents "hello!" 500 SpdyFrame* ConstructSpdyBodyFrame(int stream_id, 501 bool fin); 502 503 // Constructs a single SPDY data frame with the given content. 504 SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data, 505 uint32 len, bool fin); 506 507 // Wraps |frame| in the payload of a data frame in stream |stream_id|. 508 SpdyFrame* ConstructWrappedSpdyFrame(const scoped_ptr<SpdyFrame>& frame, 509 int stream_id); 510 511 const SpdyHeaderInfo MakeSpdyHeader(SpdyFrameType type); 512 513 NextProto protocol() const { return protocol_; } 514 SpdyMajorVersion spdy_version() const { return spdy_version_; } 515 bool is_spdy2() const { return protocol_ < kProtoSPDY3; } 516 scoped_ptr<SpdyFramer> CreateFramer() const; 517 518 const char* GetMethodKey() const; 519 const char* GetStatusKey() const; 520 const char* GetHostKey() const; 521 const char* GetSchemeKey() const; 522 const char* GetVersionKey() const; 523 const char* GetPathKey() const; 524 525 private: 526 // |content_length| may be NULL, in which case the content-length 527 // header will be omitted. 528 scoped_ptr<SpdyHeaderBlock> ConstructHeaderBlock( 529 base::StringPiece method, 530 base::StringPiece url, 531 int64* content_length) const; 532 533 const NextProto protocol_; 534 const SpdyMajorVersion spdy_version_; 535 }; 536 537 } // namespace net 538 539 #endif // NET_SPDY_SPDY_TEST_UTIL_COMMON_H_ 540