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