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