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