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