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