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 #include "net/spdy/spdy_test_util_common.h" 6 7 #include <cstddef> 8 9 #include "base/compiler_specific.h" 10 #include "base/memory/scoped_ptr.h" 11 #include "base/strings/string_number_conversions.h" 12 #include "base/strings/string_split.h" 13 #include "net/cert/mock_cert_verifier.h" 14 #include "net/http/http_cache.h" 15 #include "net/http/http_network_session.h" 16 #include "net/http/http_network_transaction.h" 17 #include "net/http/http_server_properties_impl.h" 18 #include "net/socket/socket_test_util.h" 19 #include "net/socket/ssl_client_socket.h" 20 #include "net/socket/transport_client_socket_pool.h" 21 #include "net/spdy/buffered_spdy_framer.h" 22 #include "net/spdy/spdy_framer.h" 23 #include "net/spdy/spdy_http_utils.h" 24 #include "net/spdy/spdy_session.h" 25 #include "net/spdy/spdy_session_pool.h" 26 #include "net/spdy/spdy_stream.h" 27 28 namespace net { 29 30 namespace { 31 32 bool next_proto_is_spdy(NextProto next_proto) { 33 return next_proto >= kProtoSPDYMinimumVersion && 34 next_proto <= kProtoSPDYMaximumVersion; 35 } 36 37 // Parses a URL into the scheme, host, and path components required for a 38 // SPDY request. 39 void ParseUrl(base::StringPiece url, std::string* scheme, std::string* host, 40 std::string* path) { 41 GURL gurl(url.as_string()); 42 path->assign(gurl.PathForRequest()); 43 scheme->assign(gurl.scheme()); 44 host->assign(gurl.host()); 45 if (gurl.has_port()) { 46 host->append(":"); 47 host->append(gurl.port()); 48 } 49 } 50 51 } // namespace 52 53 std::vector<NextProto> SpdyNextProtos() { 54 std::vector<NextProto> next_protos; 55 for (int i = kProtoMinimumVersion; i <= kProtoMaximumVersion; ++i) { 56 next_protos.push_back(static_cast<NextProto>(i)); 57 } 58 return next_protos; 59 } 60 61 // Chop a frame into an array of MockWrites. 62 // |data| is the frame to chop. 63 // |length| is the length of the frame to chop. 64 // |num_chunks| is the number of chunks to create. 65 MockWrite* ChopWriteFrame(const char* data, int length, int num_chunks) { 66 MockWrite* chunks = new MockWrite[num_chunks]; 67 int chunk_size = length / num_chunks; 68 for (int index = 0; index < num_chunks; index++) { 69 const char* ptr = data + (index * chunk_size); 70 if (index == num_chunks - 1) 71 chunk_size += length % chunk_size; // The last chunk takes the remainder. 72 chunks[index] = MockWrite(ASYNC, ptr, chunk_size); 73 } 74 return chunks; 75 } 76 77 // Chop a SpdyFrame into an array of MockWrites. 78 // |frame| is the frame to chop. 79 // |num_chunks| is the number of chunks to create. 80 MockWrite* ChopWriteFrame(const SpdyFrame& frame, int num_chunks) { 81 return ChopWriteFrame(frame.data(), frame.size(), num_chunks); 82 } 83 84 // Chop a frame into an array of MockReads. 85 // |data| is the frame to chop. 86 // |length| is the length of the frame to chop. 87 // |num_chunks| is the number of chunks to create. 88 MockRead* ChopReadFrame(const char* data, int length, int num_chunks) { 89 MockRead* chunks = new MockRead[num_chunks]; 90 int chunk_size = length / num_chunks; 91 for (int index = 0; index < num_chunks; index++) { 92 const char* ptr = data + (index * chunk_size); 93 if (index == num_chunks - 1) 94 chunk_size += length % chunk_size; // The last chunk takes the remainder. 95 chunks[index] = MockRead(ASYNC, ptr, chunk_size); 96 } 97 return chunks; 98 } 99 100 // Chop a SpdyFrame into an array of MockReads. 101 // |frame| is the frame to chop. 102 // |num_chunks| is the number of chunks to create. 103 MockRead* ChopReadFrame(const SpdyFrame& frame, int num_chunks) { 104 return ChopReadFrame(frame.data(), frame.size(), num_chunks); 105 } 106 107 // Adds headers and values to a map. 108 // |extra_headers| is an array of { name, value } pairs, arranged as strings 109 // where the even entries are the header names, and the odd entries are the 110 // header values. 111 // |headers| gets filled in from |extra_headers|. 112 void AppendToHeaderBlock(const char* const extra_headers[], 113 int extra_header_count, 114 SpdyHeaderBlock* headers) { 115 std::string this_header; 116 std::string this_value; 117 118 if (!extra_header_count) 119 return; 120 121 // Sanity check: Non-NULL header list. 122 DCHECK(NULL != extra_headers) << "NULL header value pair list"; 123 // Sanity check: Non-NULL header map. 124 DCHECK(NULL != headers) << "NULL header map"; 125 // Copy in the headers. 126 for (int i = 0; i < extra_header_count; i++) { 127 // Sanity check: Non-empty header. 128 DCHECK_NE('\0', *extra_headers[i * 2]) << "Empty header value pair"; 129 this_header = extra_headers[i * 2]; 130 std::string::size_type header_len = this_header.length(); 131 if (!header_len) 132 continue; 133 this_value = extra_headers[1 + (i * 2)]; 134 std::string new_value; 135 if (headers->find(this_header) != headers->end()) { 136 // More than one entry in the header. 137 // Don't add the header again, just the append to the value, 138 // separated by a NULL character. 139 140 // Adjust the value. 141 new_value = (*headers)[this_header]; 142 // Put in a NULL separator. 143 new_value.append(1, '\0'); 144 // Append the new value. 145 new_value += this_value; 146 } else { 147 // Not a duplicate, just write the value. 148 new_value = this_value; 149 } 150 (*headers)[this_header] = new_value; 151 } 152 } 153 154 // Create a MockWrite from the given SpdyFrame. 155 MockWrite CreateMockWrite(const SpdyFrame& req) { 156 return MockWrite(ASYNC, req.data(), req.size()); 157 } 158 159 // Create a MockWrite from the given SpdyFrame and sequence number. 160 MockWrite CreateMockWrite(const SpdyFrame& req, int seq) { 161 return CreateMockWrite(req, seq, ASYNC); 162 } 163 164 // Create a MockWrite from the given SpdyFrame and sequence number. 165 MockWrite CreateMockWrite(const SpdyFrame& req, int seq, IoMode mode) { 166 return MockWrite(mode, req.data(), req.size(), seq); 167 } 168 169 // Create a MockRead from the given SpdyFrame. 170 MockRead CreateMockRead(const SpdyFrame& resp) { 171 return MockRead(ASYNC, resp.data(), resp.size()); 172 } 173 174 // Create a MockRead from the given SpdyFrame and sequence number. 175 MockRead CreateMockRead(const SpdyFrame& resp, int seq) { 176 return CreateMockRead(resp, seq, ASYNC); 177 } 178 179 // Create a MockRead from the given SpdyFrame and sequence number. 180 MockRead CreateMockRead(const SpdyFrame& resp, int seq, IoMode mode) { 181 return MockRead(mode, resp.data(), resp.size(), seq); 182 } 183 184 // Combines the given SpdyFrames into the given char array and returns 185 // the total length. 186 int CombineFrames(const SpdyFrame** frames, int num_frames, 187 char* buff, int buff_len) { 188 int total_len = 0; 189 for (int i = 0; i < num_frames; ++i) { 190 total_len += frames[i]->size(); 191 } 192 DCHECK_LE(total_len, buff_len); 193 char* ptr = buff; 194 for (int i = 0; i < num_frames; ++i) { 195 int len = frames[i]->size(); 196 memcpy(ptr, frames[i]->data(), len); 197 ptr += len; 198 } 199 return total_len; 200 } 201 202 namespace { 203 204 class PriorityGetter : public BufferedSpdyFramerVisitorInterface { 205 public: 206 PriorityGetter() : priority_(0) {} 207 virtual ~PriorityGetter() {} 208 209 SpdyPriority priority() const { 210 return priority_; 211 } 212 213 virtual void OnError(SpdyFramer::SpdyError error_code) OVERRIDE {} 214 virtual void OnStreamError(SpdyStreamId stream_id, 215 const std::string& description) OVERRIDE {} 216 virtual void OnSynStream(SpdyStreamId stream_id, 217 SpdyStreamId associated_stream_id, 218 SpdyPriority priority, 219 uint8 credential_slot, 220 bool fin, 221 bool unidirectional, 222 const SpdyHeaderBlock& headers) OVERRIDE { 223 priority_ = priority; 224 } 225 virtual void OnSynReply(SpdyStreamId stream_id, 226 bool fin, 227 const SpdyHeaderBlock& headers) OVERRIDE {} 228 virtual void OnHeaders(SpdyStreamId stream_id, 229 bool fin, 230 const SpdyHeaderBlock& headers) OVERRIDE {} 231 virtual void OnDataFrameHeader(SpdyStreamId stream_id, 232 size_t length, 233 bool fin) OVERRIDE {} 234 virtual void OnStreamFrameData(SpdyStreamId stream_id, 235 const char* data, 236 size_t len, 237 bool fin) OVERRIDE {} 238 virtual void OnSettings(bool clear_persisted) OVERRIDE {} 239 virtual void OnSetting( 240 SpdySettingsIds id, uint8 flags, uint32 value) OVERRIDE {} 241 virtual void OnPing(uint32 unique_id) OVERRIDE {} 242 virtual void OnRstStream(SpdyStreamId stream_id, 243 SpdyRstStreamStatus status) OVERRIDE {} 244 virtual void OnGoAway(SpdyStreamId last_accepted_stream_id, 245 SpdyGoAwayStatus status) OVERRIDE {} 246 virtual void OnWindowUpdate(SpdyStreamId stream_id, 247 uint32 delta_window_size) OVERRIDE {} 248 virtual void OnPushPromise(SpdyStreamId stream_id, 249 SpdyStreamId promised_stream_id) OVERRIDE {} 250 251 private: 252 SpdyPriority priority_; 253 }; 254 255 } // namespace 256 257 bool GetSpdyPriority(SpdyMajorVersion version, 258 const SpdyFrame& frame, 259 SpdyPriority* priority) { 260 BufferedSpdyFramer framer(version, false); 261 PriorityGetter priority_getter; 262 framer.set_visitor(&priority_getter); 263 size_t frame_size = frame.size(); 264 if (framer.ProcessInput(frame.data(), frame_size) != frame_size) { 265 return false; 266 } 267 *priority = priority_getter.priority(); 268 return true; 269 } 270 271 base::WeakPtr<SpdyStream> CreateStreamSynchronously( 272 SpdyStreamType type, 273 const base::WeakPtr<SpdySession>& session, 274 const GURL& url, 275 RequestPriority priority, 276 const BoundNetLog& net_log) { 277 SpdyStreamRequest stream_request; 278 int rv = stream_request.StartRequest(type, session, url, priority, net_log, 279 CompletionCallback()); 280 return 281 (rv == OK) ? stream_request.ReleaseStream() : base::WeakPtr<SpdyStream>(); 282 } 283 284 StreamReleaserCallback::StreamReleaserCallback() {} 285 286 StreamReleaserCallback::~StreamReleaserCallback() {} 287 288 CompletionCallback StreamReleaserCallback::MakeCallback( 289 SpdyStreamRequest* request) { 290 return base::Bind(&StreamReleaserCallback::OnComplete, 291 base::Unretained(this), 292 request); 293 } 294 295 void StreamReleaserCallback::OnComplete( 296 SpdyStreamRequest* request, int result) { 297 if (result == OK) 298 request->ReleaseStream()->Cancel(); 299 SetResult(result); 300 } 301 302 MockECSignatureCreator::MockECSignatureCreator(crypto::ECPrivateKey* key) 303 : key_(key) { 304 } 305 306 bool MockECSignatureCreator::Sign(const uint8* data, 307 int data_len, 308 std::vector<uint8>* signature) { 309 std::vector<uint8> private_key_value; 310 key_->ExportValue(&private_key_value); 311 std::string head = "fakesignature"; 312 std::string tail = "/fakesignature"; 313 314 signature->clear(); 315 signature->insert(signature->end(), head.begin(), head.end()); 316 signature->insert(signature->end(), private_key_value.begin(), 317 private_key_value.end()); 318 signature->insert(signature->end(), '-'); 319 signature->insert(signature->end(), data, data + data_len); 320 signature->insert(signature->end(), tail.begin(), tail.end()); 321 return true; 322 } 323 324 bool MockECSignatureCreator::DecodeSignature( 325 const std::vector<uint8>& signature, 326 std::vector<uint8>* out_raw_sig) { 327 *out_raw_sig = signature; 328 return true; 329 } 330 331 MockECSignatureCreatorFactory::MockECSignatureCreatorFactory() { 332 crypto::ECSignatureCreator::SetFactoryForTesting(this); 333 } 334 335 MockECSignatureCreatorFactory::~MockECSignatureCreatorFactory() { 336 crypto::ECSignatureCreator::SetFactoryForTesting(NULL); 337 } 338 339 crypto::ECSignatureCreator* MockECSignatureCreatorFactory::Create( 340 crypto::ECPrivateKey* key) { 341 return new MockECSignatureCreator(key); 342 } 343 344 SpdySessionDependencies::SpdySessionDependencies(NextProto protocol) 345 : host_resolver(new MockCachingHostResolver), 346 cert_verifier(new MockCertVerifier), 347 transport_security_state(new TransportSecurityState), 348 proxy_service(ProxyService::CreateDirect()), 349 ssl_config_service(new SSLConfigServiceDefaults), 350 socket_factory(new MockClientSocketFactory), 351 deterministic_socket_factory(new DeterministicMockClientSocketFactory), 352 http_auth_handler_factory( 353 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), 354 enable_ip_pooling(true), 355 enable_compression(false), 356 enable_ping(false), 357 enable_user_alternate_protocol_ports(false), 358 protocol(protocol), 359 stream_initial_recv_window_size(kSpdyStreamInitialWindowSize), 360 time_func(&base::TimeTicks::Now), 361 net_log(NULL) { 362 DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol; 363 364 // Note: The CancelledTransaction test does cleanup by running all 365 // tasks in the message loop (RunAllPending). Unfortunately, that 366 // doesn't clean up tasks on the host resolver thread; and 367 // TCPConnectJob is currently not cancellable. Using synchronous 368 // lookups allows the test to shutdown cleanly. Until we have 369 // cancellable TCPConnectJobs, use synchronous lookups. 370 host_resolver->set_synchronous_mode(true); 371 } 372 373 SpdySessionDependencies::SpdySessionDependencies( 374 NextProto protocol, ProxyService* proxy_service) 375 : host_resolver(new MockHostResolver), 376 cert_verifier(new MockCertVerifier), 377 transport_security_state(new TransportSecurityState), 378 proxy_service(proxy_service), 379 ssl_config_service(new SSLConfigServiceDefaults), 380 socket_factory(new MockClientSocketFactory), 381 deterministic_socket_factory(new DeterministicMockClientSocketFactory), 382 http_auth_handler_factory( 383 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), 384 enable_ip_pooling(true), 385 enable_compression(false), 386 enable_ping(false), 387 enable_user_alternate_protocol_ports(false), 388 protocol(protocol), 389 stream_initial_recv_window_size(kSpdyStreamInitialWindowSize), 390 time_func(&base::TimeTicks::Now), 391 net_log(NULL) { 392 DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol; 393 } 394 395 SpdySessionDependencies::~SpdySessionDependencies() {} 396 397 // static 398 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSession( 399 SpdySessionDependencies* session_deps) { 400 net::HttpNetworkSession::Params params = CreateSessionParams(session_deps); 401 params.client_socket_factory = session_deps->socket_factory.get(); 402 HttpNetworkSession* http_session = new HttpNetworkSession(params); 403 SpdySessionPoolPeer pool_peer(http_session->spdy_session_pool()); 404 pool_peer.SetEnableSendingInitialData(false); 405 return http_session; 406 } 407 408 // static 409 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSessionDeterministic( 410 SpdySessionDependencies* session_deps) { 411 net::HttpNetworkSession::Params params = CreateSessionParams(session_deps); 412 params.client_socket_factory = 413 session_deps->deterministic_socket_factory.get(); 414 HttpNetworkSession* http_session = new HttpNetworkSession(params); 415 SpdySessionPoolPeer pool_peer(http_session->spdy_session_pool()); 416 pool_peer.SetEnableSendingInitialData(false); 417 return http_session; 418 } 419 420 // static 421 net::HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams( 422 SpdySessionDependencies* session_deps) { 423 DCHECK(next_proto_is_spdy(session_deps->protocol)) << 424 "Invalid protocol: " << session_deps->protocol; 425 426 net::HttpNetworkSession::Params params; 427 params.host_resolver = session_deps->host_resolver.get(); 428 params.cert_verifier = session_deps->cert_verifier.get(); 429 params.transport_security_state = 430 session_deps->transport_security_state.get(); 431 params.proxy_service = session_deps->proxy_service.get(); 432 params.ssl_config_service = session_deps->ssl_config_service.get(); 433 params.http_auth_handler_factory = 434 session_deps->http_auth_handler_factory.get(); 435 params.http_server_properties = 436 session_deps->http_server_properties.GetWeakPtr(); 437 params.enable_spdy_compression = session_deps->enable_compression; 438 params.enable_spdy_ping_based_connection_checking = session_deps->enable_ping; 439 params.enable_user_alternate_protocol_ports = 440 session_deps->enable_user_alternate_protocol_ports; 441 params.spdy_default_protocol = session_deps->protocol; 442 params.spdy_stream_initial_recv_window_size = 443 session_deps->stream_initial_recv_window_size; 444 params.time_func = session_deps->time_func; 445 params.trusted_spdy_proxy = session_deps->trusted_spdy_proxy; 446 params.net_log = session_deps->net_log; 447 return params; 448 } 449 450 SpdyURLRequestContext::SpdyURLRequestContext(NextProto protocol) 451 : storage_(this) { 452 DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol; 453 454 storage_.set_host_resolver(scoped_ptr<HostResolver>(new MockHostResolver)); 455 storage_.set_cert_verifier(new MockCertVerifier); 456 storage_.set_transport_security_state(new TransportSecurityState); 457 storage_.set_proxy_service(ProxyService::CreateDirect()); 458 storage_.set_ssl_config_service(new SSLConfigServiceDefaults); 459 storage_.set_http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault( 460 host_resolver())); 461 storage_.set_http_server_properties( 462 scoped_ptr<HttpServerProperties>(new HttpServerPropertiesImpl())); 463 net::HttpNetworkSession::Params params; 464 params.client_socket_factory = &socket_factory_; 465 params.host_resolver = host_resolver(); 466 params.cert_verifier = cert_verifier(); 467 params.transport_security_state = transport_security_state(); 468 params.proxy_service = proxy_service(); 469 params.ssl_config_service = ssl_config_service(); 470 params.http_auth_handler_factory = http_auth_handler_factory(); 471 params.network_delegate = network_delegate(); 472 params.enable_spdy_compression = false; 473 params.enable_spdy_ping_based_connection_checking = false; 474 params.spdy_default_protocol = protocol; 475 params.http_server_properties = http_server_properties(); 476 scoped_refptr<HttpNetworkSession> network_session( 477 new HttpNetworkSession(params)); 478 SpdySessionPoolPeer pool_peer(network_session->spdy_session_pool()); 479 pool_peer.SetEnableSendingInitialData(false); 480 storage_.set_http_transaction_factory(new HttpCache( 481 network_session.get(), HttpCache::DefaultBackend::InMemory(0))); 482 } 483 484 SpdyURLRequestContext::~SpdyURLRequestContext() { 485 } 486 487 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key) { 488 return pool->FindAvailableSession(key, BoundNetLog()) != NULL; 489 } 490 491 namespace { 492 493 base::WeakPtr<SpdySession> CreateSpdySessionHelper( 494 const scoped_refptr<HttpNetworkSession>& http_session, 495 const SpdySessionKey& key, 496 const BoundNetLog& net_log, 497 Error expected_status, 498 bool is_secure) { 499 EXPECT_FALSE(HasSpdySession(http_session->spdy_session_pool(), key)); 500 501 scoped_refptr<TransportSocketParams> transport_params( 502 new TransportSocketParams( 503 key.host_port_pair(), false, false, 504 OnHostResolutionCallback())); 505 506 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); 507 TestCompletionCallback callback; 508 509 int rv = ERR_UNEXPECTED; 510 if (is_secure) { 511 SSLConfig ssl_config; 512 scoped_refptr<SSLSocketParams> ssl_params( 513 new SSLSocketParams(transport_params, 514 NULL, 515 NULL, 516 key.host_port_pair(), 517 ssl_config, 518 key.privacy_mode(), 519 0, 520 false, 521 false)); 522 rv = connection->Init(key.host_port_pair().ToString(), 523 ssl_params, 524 MEDIUM, 525 callback.callback(), 526 http_session->GetSSLSocketPool( 527 HttpNetworkSession::NORMAL_SOCKET_POOL), 528 net_log); 529 } else { 530 rv = connection->Init(key.host_port_pair().ToString(), 531 transport_params, 532 MEDIUM, 533 callback.callback(), 534 http_session->GetTransportSocketPool( 535 HttpNetworkSession::NORMAL_SOCKET_POOL), 536 net_log); 537 } 538 539 if (rv == ERR_IO_PENDING) 540 rv = callback.WaitForResult(); 541 542 EXPECT_EQ(OK, rv); 543 544 base::WeakPtr<SpdySession> spdy_session; 545 EXPECT_EQ( 546 expected_status, 547 http_session->spdy_session_pool()->CreateAvailableSessionFromSocket( 548 key, connection.Pass(), net_log, OK, &spdy_session, 549 is_secure)); 550 EXPECT_EQ(expected_status == OK, spdy_session != NULL); 551 EXPECT_EQ(expected_status == OK, 552 HasSpdySession(http_session->spdy_session_pool(), key)); 553 return spdy_session; 554 } 555 556 } // namespace 557 558 base::WeakPtr<SpdySession> CreateInsecureSpdySession( 559 const scoped_refptr<HttpNetworkSession>& http_session, 560 const SpdySessionKey& key, 561 const BoundNetLog& net_log) { 562 return CreateSpdySessionHelper(http_session, key, net_log, 563 OK, false /* is_secure */); 564 } 565 566 void TryCreateInsecureSpdySessionExpectingFailure( 567 const scoped_refptr<HttpNetworkSession>& http_session, 568 const SpdySessionKey& key, 569 Error expected_error, 570 const BoundNetLog& net_log) { 571 DCHECK_LT(expected_error, ERR_IO_PENDING); 572 CreateSpdySessionHelper(http_session, key, net_log, 573 expected_error, false /* is_secure */); 574 } 575 576 base::WeakPtr<SpdySession> CreateSecureSpdySession( 577 const scoped_refptr<HttpNetworkSession>& http_session, 578 const SpdySessionKey& key, 579 const BoundNetLog& net_log) { 580 return CreateSpdySessionHelper(http_session, key, net_log, 581 OK, true /* is_secure */); 582 } 583 584 namespace { 585 586 // A ClientSocket used for CreateFakeSpdySession() below. 587 class FakeSpdySessionClientSocket : public MockClientSocket { 588 public: 589 FakeSpdySessionClientSocket(int read_result) 590 : MockClientSocket(BoundNetLog()), 591 read_result_(read_result) {} 592 593 virtual ~FakeSpdySessionClientSocket() {} 594 595 virtual int Read(IOBuffer* buf, int buf_len, 596 const CompletionCallback& callback) OVERRIDE { 597 return read_result_; 598 } 599 600 virtual int Write(IOBuffer* buf, int buf_len, 601 const CompletionCallback& callback) OVERRIDE { 602 return ERR_IO_PENDING; 603 } 604 605 // Return kProtoUnknown to use the pool's default protocol. 606 virtual NextProto GetNegotiatedProtocol() const OVERRIDE { 607 return kProtoUnknown; 608 } 609 610 // The functions below are not expected to be called. 611 612 virtual int Connect(const CompletionCallback& callback) OVERRIDE { 613 ADD_FAILURE(); 614 return ERR_UNEXPECTED; 615 } 616 617 virtual bool WasEverUsed() const OVERRIDE { 618 ADD_FAILURE(); 619 return false; 620 } 621 622 virtual bool UsingTCPFastOpen() const OVERRIDE { 623 ADD_FAILURE(); 624 return false; 625 } 626 627 virtual bool WasNpnNegotiated() const OVERRIDE { 628 ADD_FAILURE(); 629 return false; 630 } 631 632 virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE { 633 ADD_FAILURE(); 634 return false; 635 } 636 637 private: 638 int read_result_; 639 }; 640 641 base::WeakPtr<SpdySession> CreateFakeSpdySessionHelper( 642 SpdySessionPool* pool, 643 const SpdySessionKey& key, 644 Error expected_status) { 645 EXPECT_NE(expected_status, ERR_IO_PENDING); 646 EXPECT_FALSE(HasSpdySession(pool, key)); 647 base::WeakPtr<SpdySession> spdy_session; 648 scoped_ptr<ClientSocketHandle> handle(new ClientSocketHandle()); 649 handle->SetSocket(scoped_ptr<StreamSocket>(new FakeSpdySessionClientSocket( 650 expected_status == OK ? ERR_IO_PENDING : expected_status))); 651 EXPECT_EQ( 652 expected_status, 653 pool->CreateAvailableSessionFromSocket( 654 key, handle.Pass(), BoundNetLog(), OK, &spdy_session, 655 true /* is_secure */)); 656 EXPECT_EQ(expected_status == OK, spdy_session != NULL); 657 EXPECT_EQ(expected_status == OK, HasSpdySession(pool, key)); 658 return spdy_session; 659 } 660 661 } // namespace 662 663 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool, 664 const SpdySessionKey& key) { 665 return CreateFakeSpdySessionHelper(pool, key, OK); 666 } 667 668 void TryCreateFakeSpdySessionExpectingFailure(SpdySessionPool* pool, 669 const SpdySessionKey& key, 670 Error expected_error) { 671 DCHECK_LT(expected_error, ERR_IO_PENDING); 672 CreateFakeSpdySessionHelper(pool, key, expected_error); 673 } 674 675 SpdySessionPoolPeer::SpdySessionPoolPeer(SpdySessionPool* pool) : pool_(pool) { 676 } 677 678 void SpdySessionPoolPeer::RemoveAliases(const SpdySessionKey& key) { 679 pool_->RemoveAliases(key); 680 } 681 682 void SpdySessionPoolPeer::DisableDomainAuthenticationVerification() { 683 pool_->verify_domain_authentication_ = false; 684 } 685 686 void SpdySessionPoolPeer::SetEnableSendingInitialData(bool enabled) { 687 pool_->enable_sending_initial_data_ = enabled; 688 } 689 690 SpdyTestUtil::SpdyTestUtil(NextProto protocol) 691 : protocol_(protocol), 692 spdy_version_(NextProtoToSpdyMajorVersion(protocol)) { 693 DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol; 694 } 695 696 void SpdyTestUtil::AddUrlToHeaderBlock(base::StringPiece url, 697 SpdyHeaderBlock* headers) const { 698 if (is_spdy2()) { 699 (*headers)["url"] = url.as_string(); 700 } else { 701 std::string scheme, host, path; 702 ParseUrl(url, &scheme, &host, &path); 703 (*headers)[GetSchemeKey()] = scheme; 704 (*headers)[GetHostKey()] = host; 705 (*headers)[GetPathKey()] = path; 706 } 707 } 708 709 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructGetHeaderBlock( 710 base::StringPiece url) const { 711 return ConstructHeaderBlock("GET", url, NULL); 712 } 713 714 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructGetHeaderBlockForProxy( 715 base::StringPiece url) const { 716 scoped_ptr<SpdyHeaderBlock> headers(ConstructGetHeaderBlock(url)); 717 if (is_spdy2()) 718 (*headers)[GetPathKey()] = url.data(); 719 return headers.Pass(); 720 } 721 722 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructHeadHeaderBlock( 723 base::StringPiece url, 724 int64 content_length) const { 725 return ConstructHeaderBlock("HEAD", url, &content_length); 726 } 727 728 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructPostHeaderBlock( 729 base::StringPiece url, 730 int64 content_length) const { 731 return ConstructHeaderBlock("POST", url, &content_length); 732 } 733 734 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructPutHeaderBlock( 735 base::StringPiece url, 736 int64 content_length) const { 737 return ConstructHeaderBlock("PUT", url, &content_length); 738 } 739 740 SpdyFrame* SpdyTestUtil::ConstructSpdyFrame( 741 const SpdyHeaderInfo& header_info, 742 scoped_ptr<SpdyHeaderBlock> headers) const { 743 BufferedSpdyFramer framer(spdy_version_, header_info.compressed); 744 SpdyFrame* frame = NULL; 745 switch (header_info.kind) { 746 case DATA: 747 frame = framer.CreateDataFrame(header_info.id, header_info.data, 748 header_info.data_length, 749 header_info.data_flags); 750 break; 751 case SYN_STREAM: 752 { 753 size_t credential_slot = is_spdy2() ? 0 : header_info.credential_slot; 754 frame = framer.CreateSynStream(header_info.id, header_info.assoc_id, 755 header_info.priority, 756 credential_slot, 757 header_info.control_flags, 758 headers.get()); 759 } 760 break; 761 case SYN_REPLY: 762 frame = framer.CreateSynReply(header_info.id, header_info.control_flags, 763 headers.get()); 764 break; 765 case RST_STREAM: 766 frame = framer.CreateRstStream(header_info.id, header_info.status); 767 break; 768 case HEADERS: 769 frame = framer.CreateHeaders(header_info.id, header_info.control_flags, 770 headers.get()); 771 break; 772 default: 773 ADD_FAILURE(); 774 break; 775 } 776 return frame; 777 } 778 779 SpdyFrame* SpdyTestUtil::ConstructSpdyFrame(const SpdyHeaderInfo& header_info, 780 const char* const extra_headers[], 781 int extra_header_count, 782 const char* const tail_headers[], 783 int tail_header_count) const { 784 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); 785 AppendToHeaderBlock(extra_headers, extra_header_count, headers.get()); 786 if (tail_headers && tail_header_count) 787 AppendToHeaderBlock(tail_headers, tail_header_count, headers.get()); 788 return ConstructSpdyFrame(header_info, headers.Pass()); 789 } 790 791 SpdyFrame* SpdyTestUtil::ConstructSpdyControlFrame( 792 scoped_ptr<SpdyHeaderBlock> headers, 793 bool compressed, 794 SpdyStreamId stream_id, 795 RequestPriority request_priority, 796 SpdyFrameType type, 797 SpdyControlFlags flags, 798 SpdyStreamId associated_stream_id) const { 799 EXPECT_GE(type, FIRST_CONTROL_TYPE); 800 EXPECT_LE(type, LAST_CONTROL_TYPE); 801 const SpdyHeaderInfo header_info = { 802 type, 803 stream_id, 804 associated_stream_id, 805 ConvertRequestPriorityToSpdyPriority(request_priority, spdy_version_), 806 0, // credential slot 807 flags, 808 compressed, 809 RST_STREAM_INVALID, // status 810 NULL, // data 811 0, // length 812 DATA_FLAG_NONE 813 }; 814 return ConstructSpdyFrame(header_info, headers.Pass()); 815 } 816 817 SpdyFrame* SpdyTestUtil::ConstructSpdyControlFrame( 818 const char* const extra_headers[], 819 int extra_header_count, 820 bool compressed, 821 SpdyStreamId stream_id, 822 RequestPriority request_priority, 823 SpdyFrameType type, 824 SpdyControlFlags flags, 825 const char* const* tail_headers, 826 int tail_header_size, 827 SpdyStreamId associated_stream_id) const { 828 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); 829 AppendToHeaderBlock(extra_headers, extra_header_count, headers.get()); 830 if (tail_headers && tail_header_size) 831 AppendToHeaderBlock(tail_headers, tail_header_size / 2, headers.get()); 832 return ConstructSpdyControlFrame( 833 headers.Pass(), compressed, stream_id, 834 request_priority, type, flags, associated_stream_id); 835 } 836 837 std::string SpdyTestUtil::ConstructSpdyReplyString( 838 const SpdyHeaderBlock& headers) const { 839 std::string reply_string; 840 for (SpdyHeaderBlock::const_iterator it = headers.begin(); 841 it != headers.end(); ++it) { 842 std::string key = it->first; 843 // Remove leading colon from "special" headers (for SPDY3 and 844 // above). 845 if (spdy_version() >= SPDY3 && key[0] == ':') 846 key = key.substr(1); 847 std::vector<std::string> values; 848 base::SplitString(it->second, '\0', &values); 849 for (std::vector<std::string>::const_iterator it2 = values.begin(); 850 it2 != values.end(); ++it2) { 851 reply_string += key + ": " + *it2 + "\n"; 852 } 853 } 854 return reply_string; 855 } 856 857 SpdyFrame* SpdyTestUtil::ConstructSpdySettings( 858 const SettingsMap& settings) const { 859 return CreateFramer()->CreateSettings(settings); 860 } 861 862 SpdyFrame* SpdyTestUtil::ConstructSpdyCredential( 863 const SpdyCredential& credential) const { 864 return CreateFramer()->CreateCredentialFrame(credential); 865 } 866 867 SpdyFrame* SpdyTestUtil::ConstructSpdyPing(uint32 ping_id) const { 868 return CreateFramer()->CreatePingFrame(ping_id); 869 } 870 871 SpdyFrame* SpdyTestUtil::ConstructSpdyGoAway() const { 872 return ConstructSpdyGoAway(0); 873 } 874 875 SpdyFrame* SpdyTestUtil::ConstructSpdyGoAway( 876 SpdyStreamId last_good_stream_id) const { 877 return CreateFramer()->CreateGoAway(last_good_stream_id, GOAWAY_OK); 878 } 879 880 SpdyFrame* SpdyTestUtil::ConstructSpdyWindowUpdate( 881 const SpdyStreamId stream_id, uint32 delta_window_size) const { 882 return CreateFramer()->CreateWindowUpdate(stream_id, delta_window_size); 883 } 884 885 SpdyFrame* SpdyTestUtil::ConstructSpdyRstStream( 886 SpdyStreamId stream_id, 887 SpdyRstStreamStatus status) const { 888 return CreateFramer()->CreateRstStream(stream_id, status); 889 } 890 891 SpdyFrame* SpdyTestUtil::ConstructSpdyGet( 892 const char* const url, 893 bool compressed, 894 SpdyStreamId stream_id, 895 RequestPriority request_priority) const { 896 const SpdyHeaderInfo header_info = { 897 SYN_STREAM, 898 stream_id, 899 0, // associated stream ID 900 ConvertRequestPriorityToSpdyPriority(request_priority, spdy_version_), 901 0, // credential slot 902 CONTROL_FLAG_FIN, 903 compressed, 904 RST_STREAM_INVALID, // status 905 NULL, // data 906 0, // length 907 DATA_FLAG_NONE 908 }; 909 return ConstructSpdyFrame(header_info, ConstructGetHeaderBlock(url)); 910 } 911 912 SpdyFrame* SpdyTestUtil::ConstructSpdyGet(const char* const extra_headers[], 913 int extra_header_count, 914 bool compressed, 915 int stream_id, 916 RequestPriority request_priority, 917 bool direct) const { 918 const bool spdy2 = is_spdy2(); 919 const char* url = (spdy2 && !direct) ? "http://www.google.com/" : "/"; 920 const char* const kStandardGetHeaders[] = { 921 GetMethodKey(), "GET", 922 GetHostKey(), "www.google.com", 923 GetSchemeKey(), "http", 924 GetVersionKey(), "HTTP/1.1", 925 GetPathKey(), url 926 }; 927 return ConstructSpdyControlFrame(extra_headers, 928 extra_header_count, 929 compressed, 930 stream_id, 931 request_priority, 932 SYN_STREAM, 933 CONTROL_FLAG_FIN, 934 kStandardGetHeaders, 935 arraysize(kStandardGetHeaders), 936 0); 937 } 938 939 SpdyFrame* SpdyTestUtil::ConstructSpdyConnect( 940 const char* const extra_headers[], 941 int extra_header_count, 942 int stream_id, 943 RequestPriority priority) const { 944 const char* const kConnectHeaders[] = { 945 GetMethodKey(), "CONNECT", 946 GetPathKey(), "www.google.com:443", 947 GetHostKey(), "www.google.com", 948 GetVersionKey(), "HTTP/1.1", 949 }; 950 return ConstructSpdyControlFrame(extra_headers, 951 extra_header_count, 952 /*compressed*/ false, 953 stream_id, 954 priority, 955 SYN_STREAM, 956 CONTROL_FLAG_NONE, 957 kConnectHeaders, 958 arraysize(kConnectHeaders), 959 0); 960 } 961 962 SpdyFrame* SpdyTestUtil::ConstructSpdyPush(const char* const extra_headers[], 963 int extra_header_count, 964 int stream_id, 965 int associated_stream_id, 966 const char* url) { 967 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); 968 (*headers)["hello"] = "bye"; 969 (*headers)[GetStatusKey()] = "200 OK"; 970 (*headers)[GetVersionKey()] = "HTTP/1.1"; 971 AddUrlToHeaderBlock(url, headers.get()); 972 AppendToHeaderBlock(extra_headers, extra_header_count, headers.get()); 973 return ConstructSpdyControlFrame(headers.Pass(), 974 false, 975 stream_id, 976 LOWEST, 977 SYN_STREAM, 978 CONTROL_FLAG_NONE, 979 associated_stream_id); 980 } 981 982 SpdyFrame* SpdyTestUtil::ConstructSpdyPush(const char* const extra_headers[], 983 int extra_header_count, 984 int stream_id, 985 int associated_stream_id, 986 const char* url, 987 const char* status, 988 const char* location) { 989 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); 990 (*headers)["hello"] = "bye"; 991 (*headers)[GetStatusKey()] = status; 992 (*headers)[GetVersionKey()] = "HTTP/1.1"; 993 (*headers)["location"] = location; 994 AddUrlToHeaderBlock(url, headers.get()); 995 AppendToHeaderBlock(extra_headers, extra_header_count, headers.get()); 996 return ConstructSpdyControlFrame(headers.Pass(), 997 false, 998 stream_id, 999 LOWEST, 1000 SYN_STREAM, 1001 CONTROL_FLAG_NONE, 1002 associated_stream_id); 1003 } 1004 1005 SpdyFrame* SpdyTestUtil::ConstructSpdyPushHeaders( 1006 int stream_id, 1007 const char* const extra_headers[], 1008 int extra_header_count) { 1009 const char* const kStandardGetHeaders[] = { 1010 GetStatusKey(), "200 OK", 1011 GetVersionKey(), "HTTP/1.1" 1012 }; 1013 return ConstructSpdyControlFrame(extra_headers, 1014 extra_header_count, 1015 false, 1016 stream_id, 1017 LOWEST, 1018 HEADERS, 1019 CONTROL_FLAG_NONE, 1020 kStandardGetHeaders, 1021 arraysize(kStandardGetHeaders), 1022 0); 1023 } 1024 1025 SpdyFrame* SpdyTestUtil::ConstructSpdySynReplyError( 1026 const char* const status, 1027 const char* const* const extra_headers, 1028 int extra_header_count, 1029 int stream_id) { 1030 const char* const kStandardGetHeaders[] = { 1031 "hello", "bye", 1032 GetStatusKey(), status, 1033 GetVersionKey(), "HTTP/1.1" 1034 }; 1035 return ConstructSpdyControlFrame(extra_headers, 1036 extra_header_count, 1037 false, 1038 stream_id, 1039 LOWEST, 1040 SYN_REPLY, 1041 CONTROL_FLAG_NONE, 1042 kStandardGetHeaders, 1043 arraysize(kStandardGetHeaders), 1044 0); 1045 } 1046 1047 SpdyFrame* SpdyTestUtil::ConstructSpdyGetSynReplyRedirect(int stream_id) { 1048 static const char* const kExtraHeaders[] = { 1049 "location", "http://www.foo.com/index.php", 1050 }; 1051 return ConstructSpdySynReplyError("301 Moved Permanently", kExtraHeaders, 1052 arraysize(kExtraHeaders)/2, stream_id); 1053 } 1054 1055 SpdyFrame* SpdyTestUtil::ConstructSpdySynReplyError(int stream_id) { 1056 return ConstructSpdySynReplyError("500 Internal Server Error", NULL, 0, 1); 1057 } 1058 1059 SpdyFrame* SpdyTestUtil::ConstructSpdyGetSynReply( 1060 const char* const extra_headers[], 1061 int extra_header_count, 1062 int stream_id) { 1063 const char* const kStandardGetHeaders[] = { 1064 "hello", "bye", 1065 GetStatusKey(), "200", 1066 GetVersionKey(), "HTTP/1.1" 1067 }; 1068 return ConstructSpdyControlFrame(extra_headers, 1069 extra_header_count, 1070 false, 1071 stream_id, 1072 LOWEST, 1073 SYN_REPLY, 1074 CONTROL_FLAG_NONE, 1075 kStandardGetHeaders, 1076 arraysize(kStandardGetHeaders), 1077 0); 1078 } 1079 1080 SpdyFrame* SpdyTestUtil::ConstructSpdyPost(const char* url, 1081 SpdyStreamId stream_id, 1082 int64 content_length, 1083 RequestPriority priority, 1084 const char* const extra_headers[], 1085 int extra_header_count) { 1086 const SpdyHeaderInfo kSynStartHeader = { 1087 SYN_STREAM, 1088 stream_id, 1089 0, // Associated stream ID 1090 ConvertRequestPriorityToSpdyPriority(priority, spdy_version_), 1091 kSpdyCredentialSlotUnused, 1092 CONTROL_FLAG_NONE, 1093 false, // Compressed 1094 RST_STREAM_INVALID, 1095 NULL, // Data 1096 0, // Length 1097 DATA_FLAG_NONE 1098 }; 1099 return ConstructSpdyFrame( 1100 kSynStartHeader, ConstructPostHeaderBlock(url, content_length)); 1101 } 1102 1103 SpdyFrame* SpdyTestUtil::ConstructChunkedSpdyPost( 1104 const char* const extra_headers[], 1105 int extra_header_count) { 1106 const char* post_headers[] = { 1107 GetMethodKey(), "POST", 1108 GetPathKey(), "/", 1109 GetHostKey(), "www.google.com", 1110 GetSchemeKey(), "http", 1111 GetVersionKey(), "HTTP/1.1" 1112 }; 1113 return ConstructSpdyControlFrame(extra_headers, 1114 extra_header_count, 1115 false, 1116 1, 1117 LOWEST, 1118 SYN_STREAM, 1119 CONTROL_FLAG_NONE, 1120 post_headers, 1121 arraysize(post_headers), 1122 0); 1123 } 1124 1125 SpdyFrame* SpdyTestUtil::ConstructSpdyPostSynReply( 1126 const char* const extra_headers[], 1127 int extra_header_count) { 1128 const char* const kStandardGetHeaders[] = { 1129 "hello", "bye", 1130 GetStatusKey(), "200", 1131 GetPathKey(), "/index.php", 1132 GetVersionKey(), "HTTP/1.1" 1133 }; 1134 return ConstructSpdyControlFrame(extra_headers, 1135 extra_header_count, 1136 false, 1137 1, 1138 LOWEST, 1139 SYN_REPLY, 1140 CONTROL_FLAG_NONE, 1141 kStandardGetHeaders, 1142 arraysize(kStandardGetHeaders), 1143 0); 1144 } 1145 1146 SpdyFrame* SpdyTestUtil::ConstructSpdyBodyFrame(int stream_id, bool fin) { 1147 SpdyFramer framer(spdy_version_); 1148 return framer.CreateDataFrame( 1149 stream_id, kUploadData, kUploadDataSize, 1150 fin ? DATA_FLAG_FIN : DATA_FLAG_NONE); 1151 } 1152 1153 SpdyFrame* SpdyTestUtil::ConstructSpdyBodyFrame(int stream_id, 1154 const char* data, 1155 uint32 len, 1156 bool fin) { 1157 SpdyFramer framer(spdy_version_); 1158 return framer.CreateDataFrame( 1159 stream_id, data, len, fin ? DATA_FLAG_FIN : DATA_FLAG_NONE); 1160 } 1161 1162 SpdyFrame* SpdyTestUtil::ConstructWrappedSpdyFrame( 1163 const scoped_ptr<SpdyFrame>& frame, 1164 int stream_id) { 1165 return ConstructSpdyBodyFrame(stream_id, frame->data(), 1166 frame->size(), false); 1167 } 1168 1169 const SpdyHeaderInfo SpdyTestUtil::MakeSpdyHeader(SpdyFrameType type) { 1170 const SpdyHeaderInfo kHeader = { 1171 type, 1172 1, // Stream ID 1173 0, // Associated stream ID 1174 ConvertRequestPriorityToSpdyPriority(LOWEST, spdy_version_), 1175 kSpdyCredentialSlotUnused, 1176 CONTROL_FLAG_FIN, // Control Flags 1177 false, // Compressed 1178 RST_STREAM_INVALID, 1179 NULL, // Data 1180 0, // Length 1181 DATA_FLAG_NONE 1182 }; 1183 return kHeader; 1184 } 1185 1186 scoped_ptr<SpdyFramer> SpdyTestUtil::CreateFramer() const { 1187 return scoped_ptr<SpdyFramer>(new SpdyFramer(spdy_version_)); 1188 } 1189 1190 const char* SpdyTestUtil::GetMethodKey() const { 1191 return is_spdy2() ? "method" : ":method"; 1192 } 1193 1194 const char* SpdyTestUtil::GetStatusKey() const { 1195 return is_spdy2() ? "status" : ":status"; 1196 } 1197 1198 const char* SpdyTestUtil::GetHostKey() const { 1199 return is_spdy2() ? "host" : ":host"; 1200 } 1201 1202 const char* SpdyTestUtil::GetSchemeKey() const { 1203 return is_spdy2() ? "scheme" : ":scheme"; 1204 } 1205 1206 const char* SpdyTestUtil::GetVersionKey() const { 1207 return is_spdy2() ? "version" : ":version"; 1208 } 1209 1210 const char* SpdyTestUtil::GetPathKey() const { 1211 return is_spdy2() ? "url" : ":path"; 1212 } 1213 1214 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructHeaderBlock( 1215 base::StringPiece method, 1216 base::StringPiece url, 1217 int64* content_length) const { 1218 std::string scheme, host, path; 1219 ParseUrl(url.data(), &scheme, &host, &path); 1220 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock()); 1221 (*headers)[GetMethodKey()] = method.as_string(); 1222 (*headers)[GetPathKey()] = path.c_str(); 1223 (*headers)[GetHostKey()] = host.c_str(); 1224 (*headers)[GetSchemeKey()] = scheme.c_str(); 1225 (*headers)[GetVersionKey()] = "HTTP/1.1"; 1226 if (content_length) { 1227 std::string length_str = base::Int64ToString(*content_length); 1228 (*headers)["content-length"] = length_str; 1229 } 1230 return headers.Pass(); 1231 } 1232 1233 } // namespace net 1234