Disable view source for Developer Tools.
[chromium-blink-merge.git] / net / spdy / spdy_test_util_common.cc
blob89d18821b285e81c4f685237a1e68b4267542cfd
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"
28 namespace net {
30 namespace {
32 bool next_proto_is_spdy(NextProto next_proto) {
33 return next_proto >= kProtoSPDYMinimumVersion &&
34 next_proto <= kProtoSPDYMaximumVersion;
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());
51 } // namespace
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));
58 return next_protos;
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);
74 return chunks;
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);
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);
97 return chunks;
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);
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;
118 if (!extra_header_count)
119 return;
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.
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;
150 (*headers)[this_header] = new_value;
154 // Create a MockWrite from the given SpdyFrame.
155 MockWrite CreateMockWrite(const SpdyFrame& req) {
156 return MockWrite(ASYNC, req.data(), req.size());
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);
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);
169 // Create a MockRead from the given SpdyFrame.
170 MockRead CreateMockRead(const SpdyFrame& resp) {
171 return MockRead(ASYNC, resp.data(), resp.size());
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);
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);
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();
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;
199 return total_len;
202 namespace {
204 class PriorityGetter : public BufferedSpdyFramerVisitorInterface {
205 public:
206 PriorityGetter() : priority_(0) {}
207 virtual ~PriorityGetter() {}
209 SpdyPriority priority() const {
210 return priority_;
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 uint8 credential_slot,
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(uint32 unique_id) 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) OVERRIDE {}
251 private:
252 SpdyPriority priority_;
255 } // namespace
257 bool GetSpdyPriority(SpdyMajorVersion version,
258 const SpdyFrame& frame,
259 SpdyPriority* priority) {
260 BufferedSpdyFramer framer(version, false);
261 PriorityGetter priority_getter;
262 framer.set_visitor(&priority_getter);
263 size_t frame_size = frame.size();
264 if (framer.ProcessInput(frame.data(), frame_size) != frame_size) {
265 return false;
267 *priority = priority_getter.priority();
268 return true;
271 base::WeakPtr<SpdyStream> CreateStreamSynchronously(
272 SpdyStreamType type,
273 const base::WeakPtr<SpdySession>& session,
274 const GURL& url,
275 RequestPriority priority,
276 const BoundNetLog& net_log) {
277 SpdyStreamRequest stream_request;
278 int rv = stream_request.StartRequest(type, session, url, priority, net_log,
279 CompletionCallback());
280 return
281 (rv == OK) ? stream_request.ReleaseStream() : base::WeakPtr<SpdyStream>();
284 StreamReleaserCallback::StreamReleaserCallback() {}
286 StreamReleaserCallback::~StreamReleaserCallback() {}
288 CompletionCallback StreamReleaserCallback::MakeCallback(
289 SpdyStreamRequest* request) {
290 return base::Bind(&StreamReleaserCallback::OnComplete,
291 base::Unretained(this),
292 request);
295 void StreamReleaserCallback::OnComplete(
296 SpdyStreamRequest* request, int result) {
297 if (result == OK)
298 request->ReleaseStream()->Cancel();
299 SetResult(result);
302 MockECSignatureCreator::MockECSignatureCreator(crypto::ECPrivateKey* key)
303 : key_(key) {
306 bool MockECSignatureCreator::Sign(const uint8* data,
307 int data_len,
308 std::vector<uint8>* signature) {
309 std::vector<uint8> private_key_value;
310 key_->ExportValue(&private_key_value);
311 std::string head = "fakesignature";
312 std::string tail = "/fakesignature";
314 signature->clear();
315 signature->insert(signature->end(), head.begin(), head.end());
316 signature->insert(signature->end(), private_key_value.begin(),
317 private_key_value.end());
318 signature->insert(signature->end(), '-');
319 signature->insert(signature->end(), data, data + data_len);
320 signature->insert(signature->end(), tail.begin(), tail.end());
321 return true;
324 bool MockECSignatureCreator::DecodeSignature(
325 const std::vector<uint8>& signature,
326 std::vector<uint8>* out_raw_sig) {
327 *out_raw_sig = signature;
328 return true;
331 MockECSignatureCreatorFactory::MockECSignatureCreatorFactory() {
332 crypto::ECSignatureCreator::SetFactoryForTesting(this);
335 MockECSignatureCreatorFactory::~MockECSignatureCreatorFactory() {
336 crypto::ECSignatureCreator::SetFactoryForTesting(NULL);
339 crypto::ECSignatureCreator* MockECSignatureCreatorFactory::Create(
340 crypto::ECPrivateKey* key) {
341 return new MockECSignatureCreator(key);
344 SpdySessionDependencies::SpdySessionDependencies(NextProto protocol)
345 : host_resolver(new MockCachingHostResolver),
346 cert_verifier(new MockCertVerifier),
347 transport_security_state(new TransportSecurityState),
348 proxy_service(ProxyService::CreateDirect()),
349 ssl_config_service(new SSLConfigServiceDefaults),
350 socket_factory(new MockClientSocketFactory),
351 deterministic_socket_factory(new DeterministicMockClientSocketFactory),
352 http_auth_handler_factory(
353 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())),
354 enable_ip_pooling(true),
355 enable_compression(false),
356 enable_ping(false),
357 enable_user_alternate_protocol_ports(false),
358 protocol(protocol),
359 stream_initial_recv_window_size(kSpdyStreamInitialWindowSize),
360 time_func(&base::TimeTicks::Now),
361 net_log(NULL) {
362 DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
364 // Note: The CancelledTransaction test does cleanup by running all
365 // tasks in the message loop (RunAllPending). Unfortunately, that
366 // doesn't clean up tasks on the host resolver thread; and
367 // TCPConnectJob is currently not cancellable. Using synchronous
368 // lookups allows the test to shutdown cleanly. Until we have
369 // cancellable TCPConnectJobs, use synchronous lookups.
370 host_resolver->set_synchronous_mode(true);
373 SpdySessionDependencies::SpdySessionDependencies(
374 NextProto protocol, ProxyService* proxy_service)
375 : host_resolver(new MockHostResolver),
376 cert_verifier(new MockCertVerifier),
377 transport_security_state(new TransportSecurityState),
378 proxy_service(proxy_service),
379 ssl_config_service(new SSLConfigServiceDefaults),
380 socket_factory(new MockClientSocketFactory),
381 deterministic_socket_factory(new DeterministicMockClientSocketFactory),
382 http_auth_handler_factory(
383 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())),
384 enable_ip_pooling(true),
385 enable_compression(false),
386 enable_ping(false),
387 enable_user_alternate_protocol_ports(false),
388 protocol(protocol),
389 stream_initial_recv_window_size(kSpdyStreamInitialWindowSize),
390 time_func(&base::TimeTicks::Now),
391 net_log(NULL) {
392 DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
395 SpdySessionDependencies::~SpdySessionDependencies() {}
397 // static
398 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSession(
399 SpdySessionDependencies* session_deps) {
400 net::HttpNetworkSession::Params params = CreateSessionParams(session_deps);
401 params.client_socket_factory = session_deps->socket_factory.get();
402 HttpNetworkSession* http_session = new HttpNetworkSession(params);
403 SpdySessionPoolPeer pool_peer(http_session->spdy_session_pool());
404 pool_peer.SetEnableSendingInitialData(false);
405 return http_session;
408 // static
409 HttpNetworkSession* SpdySessionDependencies::SpdyCreateSessionDeterministic(
410 SpdySessionDependencies* session_deps) {
411 net::HttpNetworkSession::Params params = CreateSessionParams(session_deps);
412 params.client_socket_factory =
413 session_deps->deterministic_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 net::HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams(
422 SpdySessionDependencies* session_deps) {
423 DCHECK(next_proto_is_spdy(session_deps->protocol)) <<
424 "Invalid protocol: " << session_deps->protocol;
426 net::HttpNetworkSession::Params params;
427 params.host_resolver = session_deps->host_resolver.get();
428 params.cert_verifier = session_deps->cert_verifier.get();
429 params.transport_security_state =
430 session_deps->transport_security_state.get();
431 params.proxy_service = session_deps->proxy_service.get();
432 params.ssl_config_service = session_deps->ssl_config_service.get();
433 params.http_auth_handler_factory =
434 session_deps->http_auth_handler_factory.get();
435 params.http_server_properties =
436 session_deps->http_server_properties.GetWeakPtr();
437 params.enable_spdy_compression = session_deps->enable_compression;
438 params.enable_spdy_ping_based_connection_checking = session_deps->enable_ping;
439 params.enable_user_alternate_protocol_ports =
440 session_deps->enable_user_alternate_protocol_ports;
441 params.spdy_default_protocol = session_deps->protocol;
442 params.spdy_stream_initial_recv_window_size =
443 session_deps->stream_initial_recv_window_size;
444 params.time_func = session_deps->time_func;
445 params.trusted_spdy_proxy = session_deps->trusted_spdy_proxy;
446 params.net_log = session_deps->net_log;
447 return params;
450 SpdyURLRequestContext::SpdyURLRequestContext(NextProto protocol)
451 : storage_(this) {
452 DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
454 storage_.set_host_resolver(scoped_ptr<HostResolver>(new MockHostResolver));
455 storage_.set_cert_verifier(new MockCertVerifier);
456 storage_.set_transport_security_state(new TransportSecurityState);
457 storage_.set_proxy_service(ProxyService::CreateDirect());
458 storage_.set_ssl_config_service(new SSLConfigServiceDefaults);
459 storage_.set_http_auth_handler_factory(HttpAuthHandlerFactory::CreateDefault(
460 host_resolver()));
461 storage_.set_http_server_properties(
462 scoped_ptr<HttpServerProperties>(new HttpServerPropertiesImpl()));
463 net::HttpNetworkSession::Params params;
464 params.client_socket_factory = &socket_factory_;
465 params.host_resolver = host_resolver();
466 params.cert_verifier = cert_verifier();
467 params.transport_security_state = transport_security_state();
468 params.proxy_service = proxy_service();
469 params.ssl_config_service = ssl_config_service();
470 params.http_auth_handler_factory = http_auth_handler_factory();
471 params.network_delegate = network_delegate();
472 params.enable_spdy_compression = false;
473 params.enable_spdy_ping_based_connection_checking = false;
474 params.spdy_default_protocol = protocol;
475 params.http_server_properties = http_server_properties();
476 scoped_refptr<HttpNetworkSession> network_session(
477 new HttpNetworkSession(params));
478 SpdySessionPoolPeer pool_peer(network_session->spdy_session_pool());
479 pool_peer.SetEnableSendingInitialData(false);
480 storage_.set_http_transaction_factory(new HttpCache(
481 network_session.get(), HttpCache::DefaultBackend::InMemory(0)));
484 SpdyURLRequestContext::~SpdyURLRequestContext() {
487 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key) {
488 return pool->FindAvailableSession(key, BoundNetLog()) != NULL;
491 namespace {
493 base::WeakPtr<SpdySession> CreateSpdySessionHelper(
494 const scoped_refptr<HttpNetworkSession>& http_session,
495 const SpdySessionKey& key,
496 const BoundNetLog& net_log,
497 Error expected_status,
498 bool is_secure) {
499 EXPECT_FALSE(HasSpdySession(http_session->spdy_session_pool(), key));
501 scoped_refptr<TransportSocketParams> transport_params(
502 new TransportSocketParams(
503 key.host_port_pair(), false, false,
504 OnHostResolutionCallback()));
506 scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle);
507 TestCompletionCallback callback;
509 int rv = ERR_UNEXPECTED;
510 if (is_secure) {
511 SSLConfig ssl_config;
512 scoped_refptr<SSLSocketParams> ssl_params(
513 new SSLSocketParams(transport_params,
514 NULL,
515 NULL,
516 key.host_port_pair(),
517 ssl_config,
518 key.privacy_mode(),
520 false,
521 false));
522 rv = connection->Init(key.host_port_pair().ToString(),
523 ssl_params,
524 MEDIUM,
525 callback.callback(),
526 http_session->GetSSLSocketPool(
527 HttpNetworkSession::NORMAL_SOCKET_POOL),
528 net_log);
529 } else {
530 rv = connection->Init(key.host_port_pair().ToString(),
531 transport_params,
532 MEDIUM,
533 callback.callback(),
534 http_session->GetTransportSocketPool(
535 HttpNetworkSession::NORMAL_SOCKET_POOL),
536 net_log);
539 if (rv == ERR_IO_PENDING)
540 rv = callback.WaitForResult();
542 EXPECT_EQ(OK, rv);
544 base::WeakPtr<SpdySession> spdy_session;
545 EXPECT_EQ(
546 expected_status,
547 http_session->spdy_session_pool()->CreateAvailableSessionFromSocket(
548 key, connection.Pass(), net_log, OK, &spdy_session,
549 is_secure));
550 EXPECT_EQ(expected_status == OK, spdy_session != NULL);
551 EXPECT_EQ(expected_status == OK,
552 HasSpdySession(http_session->spdy_session_pool(), key));
553 return spdy_session;
556 } // namespace
558 base::WeakPtr<SpdySession> CreateInsecureSpdySession(
559 const scoped_refptr<HttpNetworkSession>& http_session,
560 const SpdySessionKey& key,
561 const BoundNetLog& net_log) {
562 return CreateSpdySessionHelper(http_session, key, net_log,
563 OK, false /* is_secure */);
566 void TryCreateInsecureSpdySessionExpectingFailure(
567 const scoped_refptr<HttpNetworkSession>& http_session,
568 const SpdySessionKey& key,
569 Error expected_error,
570 const BoundNetLog& net_log) {
571 DCHECK_LT(expected_error, ERR_IO_PENDING);
572 CreateSpdySessionHelper(http_session, key, net_log,
573 expected_error, false /* is_secure */);
576 base::WeakPtr<SpdySession> CreateSecureSpdySession(
577 const scoped_refptr<HttpNetworkSession>& http_session,
578 const SpdySessionKey& key,
579 const BoundNetLog& net_log) {
580 return CreateSpdySessionHelper(http_session, key, net_log,
581 OK, true /* is_secure */);
584 namespace {
586 // A ClientSocket used for CreateFakeSpdySession() below.
587 class FakeSpdySessionClientSocket : public MockClientSocket {
588 public:
589 FakeSpdySessionClientSocket(int read_result)
590 : MockClientSocket(BoundNetLog()),
591 read_result_(read_result) {}
593 virtual ~FakeSpdySessionClientSocket() {}
595 virtual int Read(IOBuffer* buf, int buf_len,
596 const CompletionCallback& callback) OVERRIDE {
597 return read_result_;
600 virtual int Write(IOBuffer* buf, int buf_len,
601 const CompletionCallback& callback) OVERRIDE {
602 return ERR_IO_PENDING;
605 // Return kProtoUnknown to use the pool's default protocol.
606 virtual NextProto GetNegotiatedProtocol() const OVERRIDE {
607 return kProtoUnknown;
610 // The functions below are not expected to be called.
612 virtual int Connect(const CompletionCallback& callback) OVERRIDE {
613 ADD_FAILURE();
614 return ERR_UNEXPECTED;
617 virtual bool WasEverUsed() const OVERRIDE {
618 ADD_FAILURE();
619 return false;
622 virtual bool UsingTCPFastOpen() const OVERRIDE {
623 ADD_FAILURE();
624 return false;
627 virtual bool WasNpnNegotiated() const OVERRIDE {
628 ADD_FAILURE();
629 return false;
632 virtual bool GetSSLInfo(SSLInfo* ssl_info) OVERRIDE {
633 ADD_FAILURE();
634 return false;
637 private:
638 int read_result_;
641 base::WeakPtr<SpdySession> CreateFakeSpdySessionHelper(
642 SpdySessionPool* pool,
643 const SpdySessionKey& key,
644 Error expected_status) {
645 EXPECT_NE(expected_status, ERR_IO_PENDING);
646 EXPECT_FALSE(HasSpdySession(pool, key));
647 base::WeakPtr<SpdySession> spdy_session;
648 scoped_ptr<ClientSocketHandle> handle(new ClientSocketHandle());
649 handle->SetSocket(scoped_ptr<StreamSocket>(new FakeSpdySessionClientSocket(
650 expected_status == OK ? ERR_IO_PENDING : expected_status)));
651 EXPECT_EQ(
652 expected_status,
653 pool->CreateAvailableSessionFromSocket(
654 key, handle.Pass(), BoundNetLog(), OK, &spdy_session,
655 true /* is_secure */));
656 EXPECT_EQ(expected_status == OK, spdy_session != NULL);
657 EXPECT_EQ(expected_status == OK, HasSpdySession(pool, key));
658 return spdy_session;
661 } // namespace
663 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool,
664 const SpdySessionKey& key) {
665 return CreateFakeSpdySessionHelper(pool, key, OK);
668 void TryCreateFakeSpdySessionExpectingFailure(SpdySessionPool* pool,
669 const SpdySessionKey& key,
670 Error expected_error) {
671 DCHECK_LT(expected_error, ERR_IO_PENDING);
672 CreateFakeSpdySessionHelper(pool, key, expected_error);
675 SpdySessionPoolPeer::SpdySessionPoolPeer(SpdySessionPool* pool) : pool_(pool) {
678 void SpdySessionPoolPeer::RemoveAliases(const SpdySessionKey& key) {
679 pool_->RemoveAliases(key);
682 void SpdySessionPoolPeer::DisableDomainAuthenticationVerification() {
683 pool_->verify_domain_authentication_ = false;
686 void SpdySessionPoolPeer::SetEnableSendingInitialData(bool enabled) {
687 pool_->enable_sending_initial_data_ = enabled;
690 SpdyTestUtil::SpdyTestUtil(NextProto protocol)
691 : protocol_(protocol),
692 spdy_version_(NextProtoToSpdyMajorVersion(protocol)) {
693 DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
696 void SpdyTestUtil::AddUrlToHeaderBlock(base::StringPiece url,
697 SpdyHeaderBlock* headers) const {
698 if (is_spdy2()) {
699 (*headers)["url"] = url.as_string();
700 } else {
701 std::string scheme, host, path;
702 ParseUrl(url, &scheme, &host, &path);
703 (*headers)[GetSchemeKey()] = scheme;
704 (*headers)[GetHostKey()] = host;
705 (*headers)[GetPathKey()] = path;
709 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructGetHeaderBlock(
710 base::StringPiece url) const {
711 return ConstructHeaderBlock("GET", url, NULL);
714 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructGetHeaderBlockForProxy(
715 base::StringPiece url) const {
716 scoped_ptr<SpdyHeaderBlock> headers(ConstructGetHeaderBlock(url));
717 if (is_spdy2())
718 (*headers)[GetPathKey()] = url.data();
719 return headers.Pass();
722 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructHeadHeaderBlock(
723 base::StringPiece url,
724 int64 content_length) const {
725 return ConstructHeaderBlock("HEAD", url, &content_length);
728 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructPostHeaderBlock(
729 base::StringPiece url,
730 int64 content_length) const {
731 return ConstructHeaderBlock("POST", url, &content_length);
734 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructPutHeaderBlock(
735 base::StringPiece url,
736 int64 content_length) const {
737 return ConstructHeaderBlock("PUT", url, &content_length);
740 SpdyFrame* SpdyTestUtil::ConstructSpdyFrame(
741 const SpdyHeaderInfo& header_info,
742 scoped_ptr<SpdyHeaderBlock> headers) const {
743 BufferedSpdyFramer framer(spdy_version_, header_info.compressed);
744 SpdyFrame* frame = NULL;
745 switch (header_info.kind) {
746 case DATA:
747 frame = framer.CreateDataFrame(header_info.id, header_info.data,
748 header_info.data_length,
749 header_info.data_flags);
750 break;
751 case SYN_STREAM:
753 size_t credential_slot = is_spdy2() ? 0 : header_info.credential_slot;
754 frame = framer.CreateSynStream(header_info.id, header_info.assoc_id,
755 header_info.priority,
756 credential_slot,
757 header_info.control_flags,
758 headers.get());
760 break;
761 case SYN_REPLY:
762 frame = framer.CreateSynReply(header_info.id, header_info.control_flags,
763 headers.get());
764 break;
765 case RST_STREAM:
766 frame = framer.CreateRstStream(header_info.id, header_info.status);
767 break;
768 case HEADERS:
769 frame = framer.CreateHeaders(header_info.id, header_info.control_flags,
770 headers.get());
771 break;
772 default:
773 ADD_FAILURE();
774 break;
776 return frame;
779 SpdyFrame* SpdyTestUtil::ConstructSpdyFrame(const SpdyHeaderInfo& header_info,
780 const char* const extra_headers[],
781 int extra_header_count,
782 const char* const tail_headers[],
783 int tail_header_count) const {
784 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
785 AppendToHeaderBlock(extra_headers, extra_header_count, headers.get());
786 if (tail_headers && tail_header_count)
787 AppendToHeaderBlock(tail_headers, tail_header_count, headers.get());
788 return ConstructSpdyFrame(header_info, headers.Pass());
791 SpdyFrame* SpdyTestUtil::ConstructSpdyControlFrame(
792 scoped_ptr<SpdyHeaderBlock> headers,
793 bool compressed,
794 SpdyStreamId stream_id,
795 RequestPriority request_priority,
796 SpdyFrameType type,
797 SpdyControlFlags flags,
798 SpdyStreamId associated_stream_id) const {
799 EXPECT_GE(type, FIRST_CONTROL_TYPE);
800 EXPECT_LE(type, LAST_CONTROL_TYPE);
801 const SpdyHeaderInfo header_info = {
802 type,
803 stream_id,
804 associated_stream_id,
805 ConvertRequestPriorityToSpdyPriority(request_priority, spdy_version_),
806 0, // credential slot
807 flags,
808 compressed,
809 RST_STREAM_INVALID, // status
810 NULL, // data
811 0, // length
812 DATA_FLAG_NONE
814 return ConstructSpdyFrame(header_info, headers.Pass());
817 SpdyFrame* SpdyTestUtil::ConstructSpdyControlFrame(
818 const char* const extra_headers[],
819 int extra_header_count,
820 bool compressed,
821 SpdyStreamId stream_id,
822 RequestPriority request_priority,
823 SpdyFrameType type,
824 SpdyControlFlags flags,
825 const char* const* tail_headers,
826 int tail_header_size,
827 SpdyStreamId associated_stream_id) const {
828 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
829 AppendToHeaderBlock(extra_headers, extra_header_count, headers.get());
830 if (tail_headers && tail_header_size)
831 AppendToHeaderBlock(tail_headers, tail_header_size / 2, headers.get());
832 return ConstructSpdyControlFrame(
833 headers.Pass(), compressed, stream_id,
834 request_priority, type, flags, associated_stream_id);
837 std::string SpdyTestUtil::ConstructSpdyReplyString(
838 const SpdyHeaderBlock& headers) const {
839 std::string reply_string;
840 for (SpdyHeaderBlock::const_iterator it = headers.begin();
841 it != headers.end(); ++it) {
842 std::string key = it->first;
843 // Remove leading colon from "special" headers (for SPDY3 and
844 // above).
845 if (spdy_version() >= SPDY3 && key[0] == ':')
846 key = key.substr(1);
847 std::vector<std::string> values;
848 base::SplitString(it->second, '\0', &values);
849 for (std::vector<std::string>::const_iterator it2 = values.begin();
850 it2 != values.end(); ++it2) {
851 reply_string += key + ": " + *it2 + "\n";
854 return reply_string;
857 SpdyFrame* SpdyTestUtil::ConstructSpdySettings(
858 const SettingsMap& settings) const {
859 return CreateFramer()->CreateSettings(settings);
862 SpdyFrame* SpdyTestUtil::ConstructSpdyCredential(
863 const SpdyCredential& credential) const {
864 return CreateFramer()->CreateCredentialFrame(credential);
867 SpdyFrame* SpdyTestUtil::ConstructSpdyPing(uint32 ping_id) const {
868 return CreateFramer()->CreatePingFrame(ping_id);
871 SpdyFrame* SpdyTestUtil::ConstructSpdyGoAway() const {
872 return ConstructSpdyGoAway(0);
875 SpdyFrame* SpdyTestUtil::ConstructSpdyGoAway(
876 SpdyStreamId last_good_stream_id) const {
877 return CreateFramer()->CreateGoAway(last_good_stream_id, GOAWAY_OK);
880 SpdyFrame* SpdyTestUtil::ConstructSpdyWindowUpdate(
881 const SpdyStreamId stream_id, uint32 delta_window_size) const {
882 return CreateFramer()->CreateWindowUpdate(stream_id, delta_window_size);
885 SpdyFrame* SpdyTestUtil::ConstructSpdyRstStream(
886 SpdyStreamId stream_id,
887 SpdyRstStreamStatus status) const {
888 return CreateFramer()->CreateRstStream(stream_id, status);
891 SpdyFrame* SpdyTestUtil::ConstructSpdyGet(
892 const char* const url,
893 bool compressed,
894 SpdyStreamId stream_id,
895 RequestPriority request_priority) const {
896 const SpdyHeaderInfo header_info = {
897 SYN_STREAM,
898 stream_id,
899 0, // associated stream ID
900 ConvertRequestPriorityToSpdyPriority(request_priority, spdy_version_),
901 0, // credential slot
902 CONTROL_FLAG_FIN,
903 compressed,
904 RST_STREAM_INVALID, // status
905 NULL, // data
906 0, // length
907 DATA_FLAG_NONE
909 return ConstructSpdyFrame(header_info, ConstructGetHeaderBlock(url));
912 SpdyFrame* SpdyTestUtil::ConstructSpdyGet(const char* const extra_headers[],
913 int extra_header_count,
914 bool compressed,
915 int stream_id,
916 RequestPriority request_priority,
917 bool direct) const {
918 const bool spdy2 = is_spdy2();
919 const char* url = (spdy2 && !direct) ? "http://www.google.com/" : "/";
920 const char* const kStandardGetHeaders[] = {
921 GetMethodKey(), "GET",
922 GetHostKey(), "www.google.com",
923 GetSchemeKey(), "http",
924 GetVersionKey(), "HTTP/1.1",
925 GetPathKey(), url
927 return ConstructSpdyControlFrame(extra_headers,
928 extra_header_count,
929 compressed,
930 stream_id,
931 request_priority,
932 SYN_STREAM,
933 CONTROL_FLAG_FIN,
934 kStandardGetHeaders,
935 arraysize(kStandardGetHeaders),
939 SpdyFrame* SpdyTestUtil::ConstructSpdyConnect(
940 const char* const extra_headers[],
941 int extra_header_count,
942 int stream_id,
943 RequestPriority priority) const {
944 const char* const kConnectHeaders[] = {
945 GetMethodKey(), "CONNECT",
946 GetPathKey(), "www.google.com:443",
947 GetHostKey(), "www.google.com",
948 GetVersionKey(), "HTTP/1.1",
950 return ConstructSpdyControlFrame(extra_headers,
951 extra_header_count,
952 /*compressed*/ false,
953 stream_id,
954 priority,
955 SYN_STREAM,
956 CONTROL_FLAG_NONE,
957 kConnectHeaders,
958 arraysize(kConnectHeaders),
962 SpdyFrame* SpdyTestUtil::ConstructSpdyPush(const char* const extra_headers[],
963 int extra_header_count,
964 int stream_id,
965 int associated_stream_id,
966 const char* url) {
967 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
968 (*headers)["hello"] = "bye";
969 (*headers)[GetStatusKey()] = "200 OK";
970 (*headers)[GetVersionKey()] = "HTTP/1.1";
971 AddUrlToHeaderBlock(url, headers.get());
972 AppendToHeaderBlock(extra_headers, extra_header_count, headers.get());
973 return ConstructSpdyControlFrame(headers.Pass(),
974 false,
975 stream_id,
976 LOWEST,
977 SYN_STREAM,
978 CONTROL_FLAG_NONE,
979 associated_stream_id);
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 const char* status,
988 const char* location) {
989 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
990 (*headers)["hello"] = "bye";
991 (*headers)[GetStatusKey()] = status;
992 (*headers)[GetVersionKey()] = "HTTP/1.1";
993 (*headers)["location"] = location;
994 AddUrlToHeaderBlock(url, headers.get());
995 AppendToHeaderBlock(extra_headers, extra_header_count, headers.get());
996 return ConstructSpdyControlFrame(headers.Pass(),
997 false,
998 stream_id,
999 LOWEST,
1000 SYN_STREAM,
1001 CONTROL_FLAG_NONE,
1002 associated_stream_id);
1005 SpdyFrame* SpdyTestUtil::ConstructSpdyPushHeaders(
1006 int stream_id,
1007 const char* const extra_headers[],
1008 int extra_header_count) {
1009 const char* const kStandardGetHeaders[] = {
1010 GetStatusKey(), "200 OK",
1011 GetVersionKey(), "HTTP/1.1"
1013 return ConstructSpdyControlFrame(extra_headers,
1014 extra_header_count,
1015 false,
1016 stream_id,
1017 LOWEST,
1018 HEADERS,
1019 CONTROL_FLAG_NONE,
1020 kStandardGetHeaders,
1021 arraysize(kStandardGetHeaders),
1025 SpdyFrame* SpdyTestUtil::ConstructSpdySynReplyError(
1026 const char* const status,
1027 const char* const* const extra_headers,
1028 int extra_header_count,
1029 int stream_id) {
1030 const char* const kStandardGetHeaders[] = {
1031 "hello", "bye",
1032 GetStatusKey(), status,
1033 GetVersionKey(), "HTTP/1.1"
1035 return ConstructSpdyControlFrame(extra_headers,
1036 extra_header_count,
1037 false,
1038 stream_id,
1039 LOWEST,
1040 SYN_REPLY,
1041 CONTROL_FLAG_NONE,
1042 kStandardGetHeaders,
1043 arraysize(kStandardGetHeaders),
1047 SpdyFrame* SpdyTestUtil::ConstructSpdyGetSynReplyRedirect(int stream_id) {
1048 static const char* const kExtraHeaders[] = {
1049 "location", "http://www.foo.com/index.php",
1051 return ConstructSpdySynReplyError("301 Moved Permanently", kExtraHeaders,
1052 arraysize(kExtraHeaders)/2, stream_id);
1055 SpdyFrame* SpdyTestUtil::ConstructSpdySynReplyError(int stream_id) {
1056 return ConstructSpdySynReplyError("500 Internal Server Error", NULL, 0, 1);
1059 SpdyFrame* SpdyTestUtil::ConstructSpdyGetSynReply(
1060 const char* const extra_headers[],
1061 int extra_header_count,
1062 int stream_id) {
1063 const char* const kStandardGetHeaders[] = {
1064 "hello", "bye",
1065 GetStatusKey(), "200",
1066 GetVersionKey(), "HTTP/1.1"
1068 return ConstructSpdyControlFrame(extra_headers,
1069 extra_header_count,
1070 false,
1071 stream_id,
1072 LOWEST,
1073 SYN_REPLY,
1074 CONTROL_FLAG_NONE,
1075 kStandardGetHeaders,
1076 arraysize(kStandardGetHeaders),
1080 SpdyFrame* SpdyTestUtil::ConstructSpdyPost(const char* url,
1081 SpdyStreamId stream_id,
1082 int64 content_length,
1083 RequestPriority priority,
1084 const char* const extra_headers[],
1085 int extra_header_count) {
1086 const SpdyHeaderInfo kSynStartHeader = {
1087 SYN_STREAM,
1088 stream_id,
1089 0, // Associated stream ID
1090 ConvertRequestPriorityToSpdyPriority(priority, spdy_version_),
1091 kSpdyCredentialSlotUnused,
1092 CONTROL_FLAG_NONE,
1093 false, // Compressed
1094 RST_STREAM_INVALID,
1095 NULL, // Data
1096 0, // Length
1097 DATA_FLAG_NONE
1099 return ConstructSpdyFrame(
1100 kSynStartHeader, ConstructPostHeaderBlock(url, content_length));
1103 SpdyFrame* SpdyTestUtil::ConstructChunkedSpdyPost(
1104 const char* const extra_headers[],
1105 int extra_header_count) {
1106 const char* post_headers[] = {
1107 GetMethodKey(), "POST",
1108 GetPathKey(), "/",
1109 GetHostKey(), "www.google.com",
1110 GetSchemeKey(), "http",
1111 GetVersionKey(), "HTTP/1.1"
1113 return ConstructSpdyControlFrame(extra_headers,
1114 extra_header_count,
1115 false,
1117 LOWEST,
1118 SYN_STREAM,
1119 CONTROL_FLAG_NONE,
1120 post_headers,
1121 arraysize(post_headers),
1125 SpdyFrame* SpdyTestUtil::ConstructSpdyPostSynReply(
1126 const char* const extra_headers[],
1127 int extra_header_count) {
1128 const char* const kStandardGetHeaders[] = {
1129 "hello", "bye",
1130 GetStatusKey(), "200",
1131 GetPathKey(), "/index.php",
1132 GetVersionKey(), "HTTP/1.1"
1134 return ConstructSpdyControlFrame(extra_headers,
1135 extra_header_count,
1136 false,
1138 LOWEST,
1139 SYN_REPLY,
1140 CONTROL_FLAG_NONE,
1141 kStandardGetHeaders,
1142 arraysize(kStandardGetHeaders),
1146 SpdyFrame* SpdyTestUtil::ConstructSpdyBodyFrame(int stream_id, bool fin) {
1147 SpdyFramer framer(spdy_version_);
1148 return framer.CreateDataFrame(
1149 stream_id, kUploadData, kUploadDataSize,
1150 fin ? DATA_FLAG_FIN : DATA_FLAG_NONE);
1153 SpdyFrame* SpdyTestUtil::ConstructSpdyBodyFrame(int stream_id,
1154 const char* data,
1155 uint32 len,
1156 bool fin) {
1157 SpdyFramer framer(spdy_version_);
1158 return framer.CreateDataFrame(
1159 stream_id, data, len, fin ? DATA_FLAG_FIN : DATA_FLAG_NONE);
1162 SpdyFrame* SpdyTestUtil::ConstructWrappedSpdyFrame(
1163 const scoped_ptr<SpdyFrame>& frame,
1164 int stream_id) {
1165 return ConstructSpdyBodyFrame(stream_id, frame->data(),
1166 frame->size(), false);
1169 const SpdyHeaderInfo SpdyTestUtil::MakeSpdyHeader(SpdyFrameType type) {
1170 const SpdyHeaderInfo kHeader = {
1171 type,
1172 1, // Stream ID
1173 0, // Associated stream ID
1174 ConvertRequestPriorityToSpdyPriority(LOWEST, spdy_version_),
1175 kSpdyCredentialSlotUnused,
1176 CONTROL_FLAG_FIN, // Control Flags
1177 false, // Compressed
1178 RST_STREAM_INVALID,
1179 NULL, // Data
1180 0, // Length
1181 DATA_FLAG_NONE
1183 return kHeader;
1186 scoped_ptr<SpdyFramer> SpdyTestUtil::CreateFramer() const {
1187 return scoped_ptr<SpdyFramer>(new SpdyFramer(spdy_version_));
1190 const char* SpdyTestUtil::GetMethodKey() const {
1191 return is_spdy2() ? "method" : ":method";
1194 const char* SpdyTestUtil::GetStatusKey() const {
1195 return is_spdy2() ? "status" : ":status";
1198 const char* SpdyTestUtil::GetHostKey() const {
1199 return is_spdy2() ? "host" : ":host";
1202 const char* SpdyTestUtil::GetSchemeKey() const {
1203 return is_spdy2() ? "scheme" : ":scheme";
1206 const char* SpdyTestUtil::GetVersionKey() const {
1207 return is_spdy2() ? "version" : ":version";
1210 const char* SpdyTestUtil::GetPathKey() const {
1211 return is_spdy2() ? "url" : ":path";
1214 scoped_ptr<SpdyHeaderBlock> SpdyTestUtil::ConstructHeaderBlock(
1215 base::StringPiece method,
1216 base::StringPiece url,
1217 int64* content_length) const {
1218 std::string scheme, host, path;
1219 ParseUrl(url.data(), &scheme, &host, &path);
1220 scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
1221 (*headers)[GetMethodKey()] = method.as_string();
1222 (*headers)[GetPathKey()] = path.c_str();
1223 (*headers)[GetHostKey()] = host.c_str();
1224 (*headers)[GetSchemeKey()] = scheme.c_str();
1225 (*headers)[GetVersionKey()] = "HTTP/1.1";
1226 if (content_length) {
1227 std::string length_str = base::Int64ToString(*content_length);
1228 (*headers)["content-length"] = length_str;
1230 return headers.Pass();
1233 } // namespace net