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