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