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