• 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   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.
ChopWriteFrame(const char * data,int length,int num_chunks)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.
ChopWriteFrame(const SpdyFrame & frame,int num_chunks)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.
ChopReadFrame(const char * data,int length,int num_chunks)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.
ChopReadFrame(const SpdyFrame & frame,int num_chunks)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|.
AppendToHeaderBlock(const char * const extra_headers[],int extra_header_count,SpdyHeaderBlock * 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.
CreateMockWrite(const SpdyFrame & req)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.
CreateMockWrite(const SpdyFrame & req,int seq)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.
CreateMockWrite(const SpdyFrame & req,int seq,IoMode mode)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.
CreateMockRead(const SpdyFrame & resp)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.
CreateMockRead(const SpdyFrame & resp,int seq)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.
CreateMockRead(const SpdyFrame & resp,int seq,IoMode mode)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.
CombineFrames(const SpdyFrame ** frames,int num_frames,char * buff,int buff_len)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:
PriorityGetter()210   PriorityGetter() : priority_(0) {}
~PriorityGetter()211   virtual ~PriorityGetter() {}
212 
priority() const213   SpdyPriority priority() const {
214     return priority_;
215   }
216 
OnError(SpdyFramer::SpdyError error_code)217   virtual void OnError(SpdyFramer::SpdyError error_code) OVERRIDE {}
OnStreamError(SpdyStreamId stream_id,const std::string & description)218   virtual void OnStreamError(SpdyStreamId stream_id,
219                              const std::string& description) OVERRIDE {}
OnSynStream(SpdyStreamId stream_id,SpdyStreamId associated_stream_id,SpdyPriority priority,bool fin,bool unidirectional,const SpdyHeaderBlock & headers)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   }
OnSynReply(SpdyStreamId stream_id,bool fin,const SpdyHeaderBlock & headers)228   virtual void OnSynReply(SpdyStreamId stream_id,
229                           bool fin,
230                           const SpdyHeaderBlock& headers) OVERRIDE {}
OnHeaders(SpdyStreamId stream_id,bool fin,const SpdyHeaderBlock & headers)231   virtual void OnHeaders(SpdyStreamId stream_id,
232                          bool fin,
233                          const SpdyHeaderBlock& headers) OVERRIDE {}
OnDataFrameHeader(SpdyStreamId stream_id,size_t length,bool fin)234   virtual void OnDataFrameHeader(SpdyStreamId stream_id,
235                                  size_t length,
236                                  bool fin) OVERRIDE {}
OnStreamFrameData(SpdyStreamId stream_id,const char * data,size_t len,bool fin)237   virtual void OnStreamFrameData(SpdyStreamId stream_id,
238                                  const char* data,
239                                  size_t len,
240                                  bool fin) OVERRIDE {}
OnSettings(bool clear_persisted)241   virtual void OnSettings(bool clear_persisted) OVERRIDE {}
OnSetting(SpdySettingsIds id,uint8 flags,uint32 value)242   virtual void OnSetting(
243       SpdySettingsIds id, uint8 flags, uint32 value) OVERRIDE {}
OnPing(SpdyPingId unique_id,bool is_ack)244   virtual void OnPing(SpdyPingId unique_id, bool is_ack) OVERRIDE {}
OnRstStream(SpdyStreamId stream_id,SpdyRstStreamStatus status)245   virtual void OnRstStream(SpdyStreamId stream_id,
246                            SpdyRstStreamStatus status) OVERRIDE {}
OnGoAway(SpdyStreamId last_accepted_stream_id,SpdyGoAwayStatus status)247   virtual void OnGoAway(SpdyStreamId last_accepted_stream_id,
248                         SpdyGoAwayStatus status) OVERRIDE {}
OnWindowUpdate(SpdyStreamId stream_id,uint32 delta_window_size)249   virtual void OnWindowUpdate(SpdyStreamId stream_id,
250                               uint32 delta_window_size) OVERRIDE {}
OnPushPromise(SpdyStreamId stream_id,SpdyStreamId promised_stream_id,const SpdyHeaderBlock & headers)251   virtual void OnPushPromise(SpdyStreamId stream_id,
252                              SpdyStreamId promised_stream_id,
253                              const SpdyHeaderBlock& headers) OVERRIDE {}
OnUnknownFrame(SpdyStreamId stream_id,int frame_type)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 
GetSpdyPriority(SpdyMajorVersion version,const SpdyFrame & frame,SpdyPriority * priority)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 
CreateStreamSynchronously(SpdyStreamType type,const base::WeakPtr<SpdySession> & session,const GURL & url,RequestPriority priority,const BoundNetLog & net_log)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 
StreamReleaserCallback()291 StreamReleaserCallback::StreamReleaserCallback() {}
292 
~StreamReleaserCallback()293 StreamReleaserCallback::~StreamReleaserCallback() {}
294 
MakeCallback(SpdyStreamRequest * request)295 CompletionCallback StreamReleaserCallback::MakeCallback(
296     SpdyStreamRequest* request) {
297   return base::Bind(&StreamReleaserCallback::OnComplete,
298                     base::Unretained(this),
299                     request);
300 }
301 
OnComplete(SpdyStreamRequest * request,int result)302 void StreamReleaserCallback::OnComplete(
303     SpdyStreamRequest* request, int result) {
304   if (result == OK)
305     request->ReleaseStream()->Cancel();
306   SetResult(result);
307 }
308 
MockECSignatureCreator(crypto::ECPrivateKey * key)309 MockECSignatureCreator::MockECSignatureCreator(crypto::ECPrivateKey* key)
310     : key_(key) {
311 }
312 
Sign(const uint8 * data,int data_len,std::vector<uint8> * signature)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 
DecodeSignature(const std::vector<uint8> & signature,std::vector<uint8> * out_raw_sig)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 
MockECSignatureCreatorFactory()338 MockECSignatureCreatorFactory::MockECSignatureCreatorFactory() {
339   crypto::ECSignatureCreator::SetFactoryForTesting(this);
340 }
341 
~MockECSignatureCreatorFactory()342 MockECSignatureCreatorFactory::~MockECSignatureCreatorFactory() {
343   crypto::ECSignatureCreator::SetFactoryForTesting(NULL);
344 }
345 
Create(crypto::ECPrivateKey * key)346 crypto::ECSignatureCreator* MockECSignatureCreatorFactory::Create(
347     crypto::ECPrivateKey* key) {
348   return new MockECSignatureCreator(key);
349 }
350 
SpdySessionDependencies(NextProto protocol)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 
SpdySessionDependencies(NextProto protocol,ProxyService * proxy_service)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 
~SpdySessionDependencies()410 SpdySessionDependencies::~SpdySessionDependencies() {}
411 
412 // static
SpdyCreateSession(SpdySessionDependencies * session_deps)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
SpdyCreateSessionDeterministic(SpdySessionDependencies * session_deps)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
CreateSessionParams(SpdySessionDependencies * session_deps)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 
SpdyURLRequestContext(NextProto protocol,bool force_spdy_over_ssl,bool force_spdy_always)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 
~SpdyURLRequestContext()509 SpdyURLRequestContext::~SpdyURLRequestContext() {
510   AssertNoURLRequests();
511 }
512 
HasSpdySession(SpdySessionPool * pool,const SpdySessionKey & key)513 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key) {
514   return pool->FindAvailableSession(key, BoundNetLog()) != NULL;
515 }
516 
517 namespace {
518 
CreateSpdySessionHelper(const scoped_refptr<HttpNetworkSession> & http_session,const SpdySessionKey & key,const BoundNetLog & net_log,Error expected_status,bool is_secure)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 
CreateInsecureSpdySession(const scoped_refptr<HttpNetworkSession> & http_session,const SpdySessionKey & key,const BoundNetLog & net_log)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 
TryCreateInsecureSpdySessionExpectingFailure(const scoped_refptr<HttpNetworkSession> & http_session,const SpdySessionKey & key,Error expected_error,const BoundNetLog & net_log)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 
CreateSecureSpdySession(const scoped_refptr<HttpNetworkSession> & http_session,const SpdySessionKey & key,const BoundNetLog & net_log)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:
FakeSpdySessionClientSocket(int read_result)612   FakeSpdySessionClientSocket(int read_result)
613       : MockClientSocket(BoundNetLog()),
614         read_result_(read_result) {}
615 
~FakeSpdySessionClientSocket()616   virtual ~FakeSpdySessionClientSocket() {}
617 
Read(IOBuffer * buf,int buf_len,const CompletionCallback & callback)618   virtual int Read(IOBuffer* buf, int buf_len,
619                    const CompletionCallback& callback) OVERRIDE {
620     return read_result_;
621   }
622 
Write(IOBuffer * buf,int buf_len,const CompletionCallback & callback)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.
GetNegotiatedProtocol() const629   virtual NextProto GetNegotiatedProtocol() const OVERRIDE {
630     return kProtoUnknown;
631   }
632 
633   // The functions below are not expected to be called.
634 
Connect(const CompletionCallback & callback)635   virtual int Connect(const CompletionCallback& callback) OVERRIDE {
636     ADD_FAILURE();
637     return ERR_UNEXPECTED;
638   }
639 
WasEverUsed() const640   virtual bool WasEverUsed() const OVERRIDE {
641     ADD_FAILURE();
642     return false;
643   }
644 
UsingTCPFastOpen() const645   virtual bool UsingTCPFastOpen() const OVERRIDE {
646     ADD_FAILURE();
647     return false;
648   }
649 
WasNpnNegotiated() const650   virtual bool WasNpnNegotiated() const OVERRIDE {
651     ADD_FAILURE();
652     return false;
653   }
654 
GetSSLInfo(SSLInfo * ssl_info)655   virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {
656     ADD_FAILURE();
657     return false;
658   }
659 
660  private:
661   int read_result_;
662 };
663 
CreateFakeSpdySessionHelper(SpdySessionPool * pool,const SpdySessionKey & key,Error expected_status)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 
CreateFakeSpdySession(SpdySessionPool * pool,const SpdySessionKey & key)684 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool,
685                                                  const SpdySessionKey& key) {
686   return CreateFakeSpdySessionHelper(pool, key, OK);
687 }
688 
TryCreateFakeSpdySessionExpectingFailure(SpdySessionPool * pool,const SpdySessionKey & key,Error expected_error)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 
SpdySessionPoolPeer(SpdySessionPool * pool)697 SpdySessionPoolPeer::SpdySessionPoolPeer(SpdySessionPool* pool) : pool_(pool) {
698 }
699 
RemoveAliases(const SpdySessionKey & key)700 void SpdySessionPoolPeer::RemoveAliases(const SpdySessionKey& key) {
701   pool_->RemoveAliases(key);
702 }
703 
DisableDomainAuthenticationVerification()704 void SpdySessionPoolPeer::DisableDomainAuthenticationVerification() {
705   pool_->verify_domain_authentication_ = false;
706 }
707 
SetEnableSendingInitialData(bool enabled)708 void SpdySessionPoolPeer::SetEnableSendingInitialData(bool enabled) {
709   pool_->enable_sending_initial_data_ = enabled;
710 }
711 
SpdyTestUtil(NextProto protocol)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 
AddUrlToHeaderBlock(base::StringPiece url,SpdyHeaderBlock * headers) const718 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 
ConstructGetHeaderBlock(base::StringPiece url) const731 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructGetHeaderBlock(
732     base::StringPiece url) const {
733   return ConstructHeaderBlock("GET", url, NULL);
734 }
735 
ConstructGetHeaderBlockForProxy(base::StringPiece url) const736 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 
ConstructHeadHeaderBlock(base::StringPiece url,int64 content_length) const744 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructHeadHeaderBlock(
745     base::StringPiece url,
746     int64 content_length) const {
747   return ConstructHeaderBlock("HEAD", url, &content_length);
748 }
749 
ConstructPostHeaderBlock(base::StringPiece url,int64 content_length) const750 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructPostHeaderBlock(
751     base::StringPiece url,
752     int64 content_length) const {
753   return ConstructHeaderBlock("POST", url, &content_length);
754 }
755 
ConstructPutHeaderBlock(base::StringPiece url,int64 content_length) const756 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructPutHeaderBlock(
757     base::StringPiece url,
758     int64 content_length) const {
759   return ConstructHeaderBlock("PUT", url, &content_length);
760 }
761 
ConstructSpdyFrame(const SpdyHeaderInfo & header_info,scoped_ptr<SpdyHeaderBlock> headers) const762 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 
ConstructSpdyFrame(const SpdyHeaderInfo & header_info,const char * const extra_headers[],int extra_header_count,const char * const tail_headers[],int tail_header_count) const799 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 
ConstructSpdyControlFrame(scoped_ptr<SpdyHeaderBlock> headers,bool compressed,SpdyStreamId stream_id,RequestPriority request_priority,SpdyFrameType type,SpdyControlFlags flags,SpdyStreamId associated_stream_id) const811 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 
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) const837 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 
ConstructSpdyReplyString(const SpdyHeaderBlock & headers) const857 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).
ConstructSpdySettings(const SettingsMap & settings) const879 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 
ConstructSpdySettingsAck() const894 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 
ConstructSpdyPing(uint32 ping_id,bool is_ack) const906 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 
ConstructSpdyGoAway() const912 SpdyFrame* SpdyTestUtil::ConstructSpdyGoAway() const {
913   return ConstructSpdyGoAway(0);
914 }
915 
ConstructSpdyGoAway(SpdyStreamId last_good_stream_id) const916 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 
ConstructSpdyGoAway(SpdyStreamId last_good_stream_id,SpdyGoAwayStatus status,const std::string & desc) const922 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 
ConstructSpdyWindowUpdate(const SpdyStreamId stream_id,uint32 delta_window_size) const929 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).
ConstructSpdyRstStream(SpdyStreamId stream_id,SpdyRstStreamStatus status) const937 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 
ConstructSpdyGet(const char * const url,bool compressed,SpdyStreamId stream_id,RequestPriority request_priority) const944 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 
ConstructSpdyGet(const char * const extra_headers[],int extra_header_count,bool compressed,int stream_id,RequestPriority request_priority,bool direct) const954 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 
ConstructSpdyConnect(const char * const extra_headers[],int extra_header_count,int stream_id,RequestPriority priority) const971 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 
ConstructSpdyPush(const char * const extra_headers[],int extra_header_count,int stream_id,int associated_stream_id,const char * url)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 
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)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 
ConstructInitialSpdyPushFrame(scoped_ptr<SpdyHeaderBlock> headers,int stream_id,int associated_stream_id)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 
ConstructSpdyPushHeaders(int stream_id,const char * const extra_headers[],int extra_header_count)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 
ConstructSpdySyn(int stream_id,const SpdyHeaderBlock & block,RequestPriority priority,bool compressed,bool fin) const1102 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 
ConstructSpdyReply(int stream_id,const SpdyHeaderBlock & headers)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 
ConstructSpdySynReplyError(const char * const status,const char * const * const extra_headers,int extra_header_count,int stream_id)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 
ConstructSpdyGetSynReplyRedirect(int stream_id)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 
ConstructSpdySynReplyError(int stream_id)1160 SpdyFrame* SpdyTestUtil::ConstructSpdySynReplyError(int stream_id) {
1161   return ConstructSpdySynReplyError("500 Internal Server Error", NULL, 0, 1);
1162 }
1163 
ConstructSpdyGetSynReply(const char * const extra_headers[],int extra_header_count,int stream_id)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 
ConstructSpdyPost(const char * url,SpdyStreamId stream_id,int64 content_length,RequestPriority priority,const char * const extra_headers[],int extra_header_count)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 
ConstructChunkedSpdyPost(const char * const extra_headers[],int extra_header_count)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 
ConstructSpdyPostSynReply(const char * const extra_headers[],int extra_header_count)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 
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 
MaybeAddVersionHeader(SpdyHeaderBlock * block) const1314 void SpdyTestUtil::MaybeAddVersionHeader(SpdyHeaderBlock* block) const {
1315   if (include_version_header()) {
1316     (*block)[GetVersionKey()] = "HTTP/1.1";
1317   }
1318 }
1319 
SetPriority(RequestPriority priority,SpdySynStreamIR * ir) const1320 void SpdyTestUtil::SetPriority(RequestPriority priority,
1321                                SpdySynStreamIR* ir) const {
1322   ir->set_priority(ConvertRequestPriorityToSpdyPriority(
1323       priority, spdy_version()));
1324 }
1325 
1326 }  // namespace net
1327