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 NextProtoVector 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 NextProtoVector next_protos; 222 std::string trusted_spdy_proxy; 223 bool force_spdy_over_ssl; 224 bool force_spdy_always; 225 bool use_alternate_protocols; 226 bool enable_websocket_over_spdy; 227 NetLog* net_log; 228 }; 229 230 class SpdyURLRequestContext : public URLRequestContext { 231 public: 232 SpdyURLRequestContext(NextProto protocol, 233 bool force_spdy_over_ssl, 234 bool force_spdy_always); 235 virtual ~SpdyURLRequestContext(); 236 socket_factory()237 MockClientSocketFactory& socket_factory() { return socket_factory_; } 238 239 private: 240 MockClientSocketFactory socket_factory_; 241 net::URLRequestContextStorage storage_; 242 }; 243 244 // Equivalent to pool->GetIfExists(spdy_session_key, BoundNetLog()) != NULL. 245 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key); 246 247 // Creates a SPDY session for the given key and puts it in the SPDY 248 // session pool in |http_session|. A SPDY session for |key| must not 249 // already exist. 250 base::WeakPtr<SpdySession> CreateInsecureSpdySession( 251 const scoped_refptr<HttpNetworkSession>& http_session, 252 const SpdySessionKey& key, 253 const BoundNetLog& net_log); 254 255 // Tries to create a SPDY session for the given key but expects the 256 // attempt to fail with the given error. A SPDY session for |key| must 257 // not already exist. The session will be created but close in the 258 // next event loop iteration. 259 base::WeakPtr<SpdySession> TryCreateInsecureSpdySessionExpectingFailure( 260 const scoped_refptr<HttpNetworkSession>& http_session, 261 const SpdySessionKey& key, 262 Error expected_error, 263 const BoundNetLog& net_log); 264 265 // Like CreateInsecureSpdySession(), but uses TLS. 266 base::WeakPtr<SpdySession> CreateSecureSpdySession( 267 const scoped_refptr<HttpNetworkSession>& http_session, 268 const SpdySessionKey& key, 269 const BoundNetLog& net_log); 270 271 // Creates an insecure SPDY session for the given key and puts it in 272 // |pool|. The returned session will neither receive nor send any 273 // data. A SPDY session for |key| must not already exist. 274 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool, 275 const SpdySessionKey& key); 276 277 // Tries to create an insecure SPDY session for the given key but 278 // expects the attempt to fail with the given error. The session will 279 // neither receive nor send any data. A SPDY session for |key| must 280 // not already exist. The session will be created but close in the 281 // next event loop iteration. 282 base::WeakPtr<SpdySession> TryCreateFakeSpdySessionExpectingFailure( 283 SpdySessionPool* pool, 284 const SpdySessionKey& key, 285 Error expected_error); 286 287 class SpdySessionPoolPeer { 288 public: 289 explicit SpdySessionPoolPeer(SpdySessionPool* pool); 290 291 void RemoveAliases(const SpdySessionKey& key); 292 void DisableDomainAuthenticationVerification(); 293 void SetEnableSendingInitialData(bool enabled); 294 295 private: 296 SpdySessionPool* const pool_; 297 298 DISALLOW_COPY_AND_ASSIGN(SpdySessionPoolPeer); 299 }; 300 301 class SpdyTestUtil { 302 public: 303 explicit SpdyTestUtil(NextProto protocol); 304 305 // Add the appropriate headers to put |url| into |block|. 306 void AddUrlToHeaderBlock(base::StringPiece url, 307 SpdyHeaderBlock* headers) const; 308 309 scoped_ptr<SpdyHeaderBlock> ConstructGetHeaderBlock( 310 base::StringPiece url) const; 311 scoped_ptr<SpdyHeaderBlock> ConstructGetHeaderBlockForProxy( 312 base::StringPiece url) const; 313 scoped_ptr<SpdyHeaderBlock> ConstructHeadHeaderBlock( 314 base::StringPiece url, 315 int64 content_length) const; 316 scoped_ptr<SpdyHeaderBlock> ConstructPostHeaderBlock( 317 base::StringPiece url, 318 int64 content_length) const; 319 scoped_ptr<SpdyHeaderBlock> ConstructPutHeaderBlock( 320 base::StringPiece url, 321 int64 content_length) const; 322 323 // Construct a SPDY frame. If it is a SYN_STREAM or SYN_REPLY frame (as 324 // specified in header_info.kind), the provided headers are included in the 325 // frame. 326 SpdyFrame* ConstructSpdyFrame( 327 const SpdyHeaderInfo& header_info, 328 scoped_ptr<SpdyHeaderBlock> headers) const; 329 330 // Construct a SPDY frame. If it is a SYN_STREAM or SYN_REPLY frame (as 331 // specified in header_info.kind), the headers provided in extra_headers and 332 // (if non-NULL) tail_headers are concatenated and included in the frame. 333 // (extra_headers must always be non-NULL.) 334 SpdyFrame* ConstructSpdyFrame(const SpdyHeaderInfo& header_info, 335 const char* const extra_headers[], 336 int extra_header_count, 337 const char* const tail_headers[], 338 int tail_header_count) const; 339 340 // Construct a generic SpdyControlFrame. 341 SpdyFrame* ConstructSpdyControlFrame( 342 scoped_ptr<SpdyHeaderBlock> headers, 343 bool compressed, 344 SpdyStreamId stream_id, 345 RequestPriority request_priority, 346 SpdyFrameType type, 347 SpdyControlFlags flags, 348 SpdyStreamId associated_stream_id) const; 349 350 // Construct a generic SpdyControlFrame. 351 // 352 // Warning: extra_header_count is the number of header-value pairs in 353 // extra_headers (so half the number of elements), but tail_headers_size is 354 // the actual number of elements (both keys and values) in tail_headers. 355 // TODO(ttuttle): Fix this inconsistency. 356 SpdyFrame* ConstructSpdyControlFrame( 357 const char* const extra_headers[], 358 int extra_header_count, 359 bool compressed, 360 SpdyStreamId stream_id, 361 RequestPriority request_priority, 362 SpdyFrameType type, 363 SpdyControlFlags flags, 364 const char* const* tail_headers, 365 int tail_headers_size, 366 SpdyStreamId associated_stream_id) const; 367 368 // Construct an expected SPDY reply string from the given headers. 369 std::string ConstructSpdyReplyString(const SpdyHeaderBlock& headers) const; 370 371 // Construct an expected SPDY SETTINGS frame. 372 // |settings| are the settings to set. 373 // Returns the constructed frame. The caller takes ownership of the frame. 374 SpdyFrame* ConstructSpdySettings(const SettingsMap& settings) const; 375 376 // Constructs an expected SPDY SETTINGS acknowledgement frame, if the protocol 377 // version is SPDY4 or higher, or an empty placeholder frame otherwise. 378 SpdyFrame* ConstructSpdySettingsAck() const; 379 380 // Construct a SPDY PING frame. 381 // Returns the constructed frame. The caller takes ownership of the frame. 382 SpdyFrame* ConstructSpdyPing(uint32 ping_id, bool is_ack) const; 383 384 // Construct a SPDY GOAWAY frame with last_good_stream_id = 0. 385 // Returns the constructed frame. The caller takes ownership of the frame. 386 SpdyFrame* ConstructSpdyGoAway() const; 387 388 // Construct a SPDY GOAWAY frame with the specified last_good_stream_id. 389 // Returns the constructed frame. The caller takes ownership of the frame. 390 SpdyFrame* ConstructSpdyGoAway(SpdyStreamId last_good_stream_id) const; 391 392 // Construct a SPDY GOAWAY frame with the specified last_good_stream_id, 393 // status, and description. Returns the constructed frame. The caller takes 394 // ownership of the frame. 395 SpdyFrame* ConstructSpdyGoAway(SpdyStreamId last_good_stream_id, 396 SpdyGoAwayStatus status, 397 const std::string& desc) const; 398 399 // Construct a SPDY WINDOW_UPDATE frame. 400 // Returns the constructed frame. The caller takes ownership of the frame. 401 SpdyFrame* ConstructSpdyWindowUpdate( 402 SpdyStreamId stream_id, 403 uint32 delta_window_size) const; 404 405 // Construct a SPDY RST_STREAM frame. 406 // Returns the constructed frame. The caller takes ownership of the frame. 407 SpdyFrame* ConstructSpdyRstStream(SpdyStreamId stream_id, 408 SpdyRstStreamStatus status) const; 409 410 // Constructs a standard SPDY GET SYN frame, optionally compressed 411 // for |url|. 412 // |extra_headers| are the extra header-value pairs, which typically 413 // will vary the most between calls. 414 // Returns a SpdyFrame. 415 SpdyFrame* ConstructSpdyGet(const char* const url, 416 bool compressed, 417 SpdyStreamId stream_id, 418 RequestPriority request_priority) const; 419 420 SpdyFrame* ConstructSpdyGetForProxy(const char* const url, 421 bool compressed, 422 SpdyStreamId stream_id, 423 RequestPriority request_priority) const; 424 425 // Constructs a standard SPDY GET SYN frame, optionally compressed. 426 // |extra_headers| are the extra header-value pairs, which typically 427 // will vary the most between calls. If |direct| is false, the 428 // the full url will be used instead of simply the path. 429 // Returns a SpdyFrame. 430 SpdyFrame* ConstructSpdyGet(const char* const extra_headers[], 431 int extra_header_count, 432 bool compressed, 433 int stream_id, 434 RequestPriority request_priority, 435 bool direct) const; 436 437 // Constructs a standard SPDY SYN_STREAM frame for a CONNECT request. 438 SpdyFrame* ConstructSpdyConnect(const char* const extra_headers[], 439 int extra_header_count, 440 int stream_id, 441 RequestPriority priority) const; 442 443 // Constructs a standard SPDY push SYN frame. 444 // |extra_headers| are the extra header-value pairs, which typically 445 // will vary the most between calls. 446 // Returns a SpdyFrame. 447 SpdyFrame* ConstructSpdyPush(const char* const extra_headers[], 448 int extra_header_count, 449 int stream_id, 450 int associated_stream_id, 451 const char* url); 452 SpdyFrame* ConstructSpdyPush(const char* const extra_headers[], 453 int extra_header_count, 454 int stream_id, 455 int associated_stream_id, 456 const char* url, 457 const char* status, 458 const char* location); 459 460 SpdyFrame* ConstructInitialSpdyPushFrame(scoped_ptr<SpdyHeaderBlock> headers, 461 int stream_id, 462 int associated_stream_id); 463 464 SpdyFrame* ConstructSpdyPushHeaders(int stream_id, 465 const char* const extra_headers[], 466 int extra_header_count); 467 468 // Construct a SPDY syn (HEADERS or SYN_STREAM, depending on protocol 469 // version) carrying exactly the given headers and priority. 470 SpdyFrame* ConstructSpdySyn(int stream_id, 471 const SpdyHeaderBlock& headers, 472 RequestPriority priority, 473 bool compressed, 474 bool fin) const; 475 476 // Construct a SPDY reply (HEADERS or SYN_REPLY, depending on protocol 477 // version) carrying exactly the given headers, and the default priority 478 // (or no priority, depending on protocl version). 479 // The |headers| parameter variant is preferred. 480 SpdyFrame* ConstructSpdyReply(int stream_id, const SpdyHeaderBlock& headers); 481 482 // Constructs a standard SPDY SYN_REPLY frame to match the SPDY GET. 483 // |extra_headers| are the extra header-value pairs, which typically 484 // will vary the most between calls. 485 // Returns a SpdyFrame. 486 SpdyFrame* ConstructSpdyGetSynReply(const char* const extra_headers[], 487 int extra_header_count, 488 int stream_id); 489 490 // Constructs a standard SPDY SYN_REPLY frame to match the SPDY GET. 491 // |extra_headers| are the extra header-value pairs, which typically 492 // will vary the most between calls. 493 // Returns a SpdyFrame. 494 SpdyFrame* ConstructSpdyGetSynReplyRedirect(int stream_id); 495 496 // Constructs a standard SPDY SYN_REPLY frame with an Internal Server 497 // Error status code. 498 // Returns a SpdyFrame. 499 SpdyFrame* ConstructSpdySynReplyError(int stream_id); 500 501 // Constructs a standard SPDY SYN_REPLY frame with the specified status code. 502 // Returns a SpdyFrame. 503 SpdyFrame* ConstructSpdySynReplyError(const char* const status, 504 const char* const* const extra_headers, 505 int extra_header_count, 506 int stream_id); 507 508 // Constructs a standard SPDY POST SYN frame. 509 // |extra_headers| are the extra header-value pairs, which typically 510 // will vary the most between calls. 511 // Returns a SpdyFrame. 512 SpdyFrame* ConstructSpdyPost(const char* url, 513 SpdyStreamId stream_id, 514 int64 content_length, 515 RequestPriority priority, 516 const char* const extra_headers[], 517 int extra_header_count); 518 519 // Constructs a chunked transfer SPDY POST SYN frame. 520 // |extra_headers| are the extra header-value pairs, which typically 521 // will vary the most between calls. 522 // Returns a SpdyFrame. 523 SpdyFrame* ConstructChunkedSpdyPost(const char* const extra_headers[], 524 int extra_header_count); 525 526 // Constructs a standard SPDY SYN_REPLY frame to match the SPDY POST. 527 // |extra_headers| are the extra header-value pairs, which typically 528 // will vary the most between calls. 529 // Returns a SpdyFrame. 530 SpdyFrame* ConstructSpdyPostSynReply(const char* const extra_headers[], 531 int extra_header_count); 532 533 // Constructs a single SPDY data frame with the contents "hello!" 534 SpdyFrame* ConstructSpdyBodyFrame(int stream_id, 535 bool fin); 536 537 // Constructs a single SPDY data frame with the given content. 538 SpdyFrame* ConstructSpdyBodyFrame(int stream_id, const char* data, 539 uint32 len, bool fin); 540 541 // Wraps |frame| in the payload of a data frame in stream |stream_id|. 542 SpdyFrame* ConstructWrappedSpdyFrame(const scoped_ptr<SpdyFrame>& frame, 543 int stream_id); 544 545 const SpdyHeaderInfo MakeSpdyHeader(SpdyFrameType type); 546 547 // For versions below SPDY4, adds the version HTTP/1.1 header. 548 void MaybeAddVersionHeader(SpdyFrameWithNameValueBlockIR* frame_ir) const; 549 void MaybeAddVersionHeader(SpdyHeaderBlock* block) const; 550 551 // Maps |priority| to SPDY version priority, and sets it on |frame_ir|. 552 void SetPriority(RequestPriority priority, SpdySynStreamIR* frame_ir) const; 553 protocol()554 NextProto protocol() const { return protocol_; } spdy_version()555 SpdyMajorVersion spdy_version() const { return spdy_version_; } is_spdy2()556 bool is_spdy2() const { return protocol_ < kProtoSPDY3; } include_version_header()557 bool include_version_header() const { return protocol_ < kProtoSPDY4; } 558 scoped_ptr<SpdyFramer> CreateFramer(bool compressed) const; 559 560 const char* GetMethodKey() const; 561 const char* GetStatusKey() const; 562 const char* GetHostKey() const; 563 const char* GetSchemeKey() const; 564 const char* GetVersionKey() const; 565 const char* GetPathKey() const; 566 567 private: 568 // |content_length| may be NULL, in which case the content-length 569 // header will be omitted. 570 scoped_ptr<SpdyHeaderBlock> ConstructHeaderBlock( 571 base::StringPiece method, 572 base::StringPiece url, 573 int64* content_length) const; 574 575 const NextProto protocol_; 576 const SpdyMajorVersion spdy_version_; 577 }; 578 579 } // namespace net 580 581 #endif // NET_SPDY_SPDY_TEST_UTIL_COMMON_H_ 582