OLD | NEW |
| (Empty) |
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 <stdint.h> | |
8 | |
9 #include <cstddef> | |
10 #include <utility> | |
11 | |
12 #include "base/compiler_specific.h" | |
13 #include "base/logging.h" | |
14 #include "base/memory/ptr_util.h" | |
15 #include "base/strings/string_number_conversions.h" | |
16 #include "base/strings/string_split.h" | |
17 #include "net/base/host_port_pair.h" | |
18 #include "net/cert/ct_policy_enforcer.h" | |
19 #include "net/cert/ct_policy_status.h" | |
20 #include "net/cert/do_nothing_ct_verifier.h" | |
21 #include "net/cert/mock_cert_verifier.h" | |
22 #include "net/cert/signed_certificate_timestamp_and_status.h" | |
23 #include "net/http/http_cache.h" | |
24 #include "net/http/http_network_session.h" | |
25 #include "net/http/http_network_transaction.h" | |
26 #include "net/http/http_server_properties_impl.h" | |
27 #include "net/log/net_log_with_source.h" | |
28 #include "net/socket/client_socket_handle.h" | |
29 #include "net/socket/next_proto.h" | |
30 #include "net/socket/socket_test_util.h" | |
31 #include "net/socket/ssl_client_socket.h" | |
32 #include "net/socket/transport_client_socket_pool.h" | |
33 #include "net/spdy/buffered_spdy_framer.h" | |
34 #include "net/spdy/spdy_alt_svc_wire_format.h" | |
35 #include "net/spdy/spdy_framer.h" | |
36 #include "net/spdy/spdy_http_utils.h" | |
37 #include "net/spdy/spdy_session.h" | |
38 #include "net/spdy/spdy_session_pool.h" | |
39 #include "net/spdy/spdy_stream.h" | |
40 #include "net/test/gtest_util.h" | |
41 #include "net/url_request/url_request_job_factory_impl.h" | |
42 #include "testing/gmock/include/gmock/gmock.h" | |
43 | |
44 using net::test::IsOk; | |
45 | |
46 namespace net { | |
47 | |
48 namespace { | |
49 | |
50 // Parses a URL into the scheme, host, and path components required for a | |
51 // SPDY request. | |
52 void ParseUrl(SpdyStringPiece url, | |
53 SpdyString* scheme, | |
54 SpdyString* host, | |
55 SpdyString* path) { | |
56 GURL gurl(url); | |
57 path->assign(gurl.PathForRequest()); | |
58 scheme->assign(gurl.scheme()); | |
59 host->assign(gurl.host()); | |
60 if (gurl.has_port()) { | |
61 host->append(":"); | |
62 host->append(gurl.port()); | |
63 } | |
64 } | |
65 | |
66 } // namespace | |
67 | |
68 // Chop a frame into an array of MockWrites. | |
69 // |frame| is the frame to chop. | |
70 // |num_chunks| is the number of chunks to create. | |
71 MockWrite* ChopWriteFrame(const SpdySerializedFrame& frame, int num_chunks) { | |
72 MockWrite* chunks = new MockWrite[num_chunks]; | |
73 int chunk_size = frame.size() / num_chunks; | |
74 for (int index = 0; index < num_chunks; index++) { | |
75 const char* ptr = frame.data() + (index * chunk_size); | |
76 if (index == num_chunks - 1) | |
77 chunk_size += | |
78 frame.size() % chunk_size; // The last chunk takes the remainder. | |
79 chunks[index] = MockWrite(ASYNC, ptr, chunk_size); | |
80 } | |
81 return chunks; | |
82 } | |
83 | |
84 // Adds headers and values to a map. | |
85 // |extra_headers| is an array of { name, value } pairs, arranged as strings | |
86 // where the even entries are the header names, and the odd entries are the | |
87 // header values. | |
88 // |headers| gets filled in from |extra_headers|. | |
89 void AppendToHeaderBlock(const char* const extra_headers[], | |
90 int extra_header_count, | |
91 SpdyHeaderBlock* headers) { | |
92 SpdyString this_header; | |
93 SpdyString this_value; | |
94 | |
95 if (!extra_header_count) | |
96 return; | |
97 | |
98 // Sanity check: Non-NULL header list. | |
99 DCHECK(NULL != extra_headers) << "NULL header value pair list"; | |
100 // Sanity check: Non-NULL header map. | |
101 DCHECK(NULL != headers) << "NULL header map"; | |
102 // Copy in the headers. | |
103 for (int i = 0; i < extra_header_count; i++) { | |
104 // Sanity check: Non-empty header. | |
105 DCHECK_NE('\0', *extra_headers[i * 2]) << "Empty header value pair"; | |
106 this_header = extra_headers[i * 2]; | |
107 SpdyString::size_type header_len = this_header.length(); | |
108 if (!header_len) | |
109 continue; | |
110 this_value = extra_headers[1 + (i * 2)]; | |
111 SpdyString new_value; | |
112 if (headers->find(this_header) != headers->end()) { | |
113 // More than one entry in the header. | |
114 // Don't add the header again, just the append to the value, | |
115 // separated by a NULL character. | |
116 | |
117 // Adjust the value. | |
118 new_value = (*headers)[this_header].as_string(); | |
119 // Put in a NULL separator. | |
120 new_value.append(1, '\0'); | |
121 // Append the new value. | |
122 new_value += this_value; | |
123 } else { | |
124 // Not a duplicate, just write the value. | |
125 new_value = this_value; | |
126 } | |
127 (*headers)[this_header] = new_value; | |
128 } | |
129 } | |
130 | |
131 // Create a MockWrite from the given SpdySerializedFrame. | |
132 MockWrite CreateMockWrite(const SpdySerializedFrame& req) { | |
133 return MockWrite(ASYNC, req.data(), req.size()); | |
134 } | |
135 | |
136 // Create a MockWrite from the given SpdySerializedFrame and sequence number. | |
137 MockWrite CreateMockWrite(const SpdySerializedFrame& req, int seq) { | |
138 return CreateMockWrite(req, seq, ASYNC); | |
139 } | |
140 | |
141 // Create a MockWrite from the given SpdySerializedFrame and sequence number. | |
142 MockWrite CreateMockWrite(const SpdySerializedFrame& req, | |
143 int seq, | |
144 IoMode mode) { | |
145 return MockWrite(mode, req.data(), req.size(), seq); | |
146 } | |
147 | |
148 // Create a MockRead from the given SpdySerializedFrame. | |
149 MockRead CreateMockRead(const SpdySerializedFrame& resp) { | |
150 return MockRead(ASYNC, resp.data(), resp.size()); | |
151 } | |
152 | |
153 // Create a MockRead from the given SpdySerializedFrame and sequence number. | |
154 MockRead CreateMockRead(const SpdySerializedFrame& resp, int seq) { | |
155 return CreateMockRead(resp, seq, ASYNC); | |
156 } | |
157 | |
158 // Create a MockRead from the given SpdySerializedFrame and sequence number. | |
159 MockRead CreateMockRead(const SpdySerializedFrame& resp, int seq, IoMode mode) { | |
160 return MockRead(mode, resp.data(), resp.size(), seq); | |
161 } | |
162 | |
163 // Combines the given SpdyFrames into the given char array and returns | |
164 // the total length. | |
165 int CombineFrames(const SpdySerializedFrame** frames, | |
166 int num_frames, | |
167 char* buf, | |
168 int buf_len) { | |
169 int total_len = 0; | |
170 for (int i = 0; i < num_frames; ++i) { | |
171 total_len += frames[i]->size(); | |
172 } | |
173 DCHECK_LE(total_len, buf_len); | |
174 char* ptr = buf; | |
175 for (int i = 0; i < num_frames; ++i) { | |
176 int len = frames[i]->size(); | |
177 memcpy(ptr, frames[i]->data(), len); | |
178 ptr += len; | |
179 } | |
180 return total_len; | |
181 } | |
182 | |
183 namespace { | |
184 | |
185 class PriorityGetter : public BufferedSpdyFramerVisitorInterface { | |
186 public: | |
187 PriorityGetter() : priority_(0) {} | |
188 ~PriorityGetter() override {} | |
189 | |
190 SpdyPriority priority() const { | |
191 return priority_; | |
192 } | |
193 | |
194 void OnError(SpdyFramer::SpdyFramerError spdy_framer_error) override {} | |
195 void OnStreamError(SpdyStreamId stream_id, | |
196 const SpdyString& description) override {} | |
197 void OnHeaders(SpdyStreamId stream_id, | |
198 bool has_priority, | |
199 int weight, | |
200 SpdyStreamId parent_stream_id, | |
201 bool exclusive, | |
202 bool fin, | |
203 SpdyHeaderBlock headers) override { | |
204 if (has_priority) { | |
205 priority_ = Http2WeightToSpdy3Priority(weight); | |
206 } | |
207 } | |
208 void OnDataFrameHeader(SpdyStreamId stream_id, | |
209 size_t length, | |
210 bool fin) override {} | |
211 void OnStreamFrameData(SpdyStreamId stream_id, | |
212 const char* data, | |
213 size_t len) override {} | |
214 void OnStreamEnd(SpdyStreamId stream_id) override {} | |
215 void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {} | |
216 void OnSettings() override {} | |
217 void OnSetting(SpdySettingsIds id, uint32_t value) override {} | |
218 void OnPing(SpdyPingId unique_id, bool is_ack) override {} | |
219 void OnRstStream(SpdyStreamId stream_id, SpdyErrorCode error_code) override {} | |
220 void OnGoAway(SpdyStreamId last_accepted_stream_id, | |
221 SpdyErrorCode error_code, | |
222 SpdyStringPiece debug_data) override {} | |
223 void OnWindowUpdate(SpdyStreamId stream_id, int delta_window_size) override {} | |
224 void OnPushPromise(SpdyStreamId stream_id, | |
225 SpdyStreamId promised_stream_id, | |
226 SpdyHeaderBlock headers) override {} | |
227 void OnAltSvc(SpdyStreamId stream_id, | |
228 SpdyStringPiece origin, | |
229 const SpdyAltSvcWireFormat::AlternativeServiceVector& | |
230 altsvc_vector) override {} | |
231 bool OnUnknownFrame(SpdyStreamId stream_id, uint8_t frame_type) override { | |
232 return false; | |
233 } | |
234 | |
235 private: | |
236 SpdyPriority priority_; | |
237 }; | |
238 | |
239 } // namespace | |
240 | |
241 bool GetSpdyPriority(const SpdySerializedFrame& frame, SpdyPriority* priority) { | |
242 BufferedSpdyFramer framer; | |
243 PriorityGetter priority_getter; | |
244 framer.set_visitor(&priority_getter); | |
245 size_t frame_size = frame.size(); | |
246 if (framer.ProcessInput(frame.data(), frame_size) != frame_size) { | |
247 return false; | |
248 } | |
249 *priority = priority_getter.priority(); | |
250 return true; | |
251 } | |
252 | |
253 base::WeakPtr<SpdyStream> CreateStreamSynchronously( | |
254 SpdyStreamType type, | |
255 const base::WeakPtr<SpdySession>& session, | |
256 const GURL& url, | |
257 RequestPriority priority, | |
258 const NetLogWithSource& net_log) { | |
259 SpdyStreamRequest stream_request; | |
260 int rv = stream_request.StartRequest(type, session, url, priority, net_log, | |
261 CompletionCallback()); | |
262 return | |
263 (rv == OK) ? stream_request.ReleaseStream() : base::WeakPtr<SpdyStream>(); | |
264 } | |
265 | |
266 StreamReleaserCallback::StreamReleaserCallback() {} | |
267 | |
268 StreamReleaserCallback::~StreamReleaserCallback() {} | |
269 | |
270 CompletionCallback StreamReleaserCallback::MakeCallback( | |
271 SpdyStreamRequest* request) { | |
272 return base::Bind(&StreamReleaserCallback::OnComplete, | |
273 base::Unretained(this), | |
274 request); | |
275 } | |
276 | |
277 void StreamReleaserCallback::OnComplete( | |
278 SpdyStreamRequest* request, int result) { | |
279 if (result == OK) | |
280 request->ReleaseStream()->Cancel(); | |
281 SetResult(result); | |
282 } | |
283 | |
284 MockECSignatureCreator::MockECSignatureCreator(crypto::ECPrivateKey* key) | |
285 : key_(key) { | |
286 } | |
287 | |
288 bool MockECSignatureCreator::Sign(const uint8_t* data, | |
289 int data_len, | |
290 std::vector<uint8_t>* signature) { | |
291 std::vector<uint8_t> private_key; | |
292 if (!key_->ExportPrivateKey(&private_key)) | |
293 return false; | |
294 SpdyString head = "fakesignature"; | |
295 SpdyString tail = "/fakesignature"; | |
296 | |
297 signature->clear(); | |
298 signature->insert(signature->end(), head.begin(), head.end()); | |
299 signature->insert(signature->end(), private_key.begin(), private_key.end()); | |
300 signature->insert(signature->end(), '-'); | |
301 signature->insert(signature->end(), data, data + data_len); | |
302 signature->insert(signature->end(), tail.begin(), tail.end()); | |
303 return true; | |
304 } | |
305 | |
306 bool MockECSignatureCreator::DecodeSignature( | |
307 const std::vector<uint8_t>& signature, | |
308 std::vector<uint8_t>* out_raw_sig) { | |
309 *out_raw_sig = signature; | |
310 return true; | |
311 } | |
312 | |
313 MockECSignatureCreatorFactory::MockECSignatureCreatorFactory() { | |
314 crypto::ECSignatureCreator::SetFactoryForTesting(this); | |
315 } | |
316 | |
317 MockECSignatureCreatorFactory::~MockECSignatureCreatorFactory() { | |
318 crypto::ECSignatureCreator::SetFactoryForTesting(nullptr); | |
319 } | |
320 | |
321 std::unique_ptr<crypto::ECSignatureCreator> | |
322 MockECSignatureCreatorFactory::Create(crypto::ECPrivateKey* key) { | |
323 return base::MakeUnique<MockECSignatureCreator>(key); | |
324 } | |
325 | |
326 SpdySessionDependencies::SpdySessionDependencies() | |
327 : SpdySessionDependencies(ProxyService::CreateDirect()) {} | |
328 | |
329 SpdySessionDependencies::SpdySessionDependencies( | |
330 std::unique_ptr<ProxyService> proxy_service) | |
331 : host_resolver(new MockCachingHostResolver), | |
332 cert_verifier(new MockCertVerifier), | |
333 channel_id_service(nullptr), | |
334 transport_security_state(new TransportSecurityState), | |
335 cert_transparency_verifier(new DoNothingCTVerifier), | |
336 ct_policy_enforcer(new CTPolicyEnforcer), | |
337 proxy_service(std::move(proxy_service)), | |
338 ssl_config_service(new SSLConfigServiceDefaults), | |
339 socket_factory(new MockClientSocketFactory), | |
340 http_auth_handler_factory( | |
341 HttpAuthHandlerFactory::CreateDefault(host_resolver.get())), | |
342 http_server_properties(new HttpServerPropertiesImpl), | |
343 enable_ip_pooling(true), | |
344 enable_ping(false), | |
345 enable_user_alternate_protocol_ports(false), | |
346 enable_quic(false), | |
347 enable_server_push_cancellation(false), | |
348 session_max_recv_window_size(kDefaultInitialWindowSize), | |
349 time_func(&base::TimeTicks::Now), | |
350 enable_http2_alternative_service(false), | |
351 net_log(nullptr), | |
352 http_09_on_non_default_ports_enabled(false), | |
353 restrict_to_one_preconnect_for_proxies(false), | |
354 quic_do_not_mark_as_broken_on_network_change(false) { | |
355 // Note: The CancelledTransaction test does cleanup by running all | |
356 // tasks in the message loop (RunAllPending). Unfortunately, that | |
357 // doesn't clean up tasks on the host resolver thread; and | |
358 // TCPConnectJob is currently not cancellable. Using synchronous | |
359 // lookups allows the test to shutdown cleanly. Until we have | |
360 // cancellable TCPConnectJobs, use synchronous lookups. | |
361 host_resolver->set_synchronous_mode(true); | |
362 http2_settings[SETTINGS_INITIAL_WINDOW_SIZE] = kDefaultInitialWindowSize; | |
363 } | |
364 | |
365 SpdySessionDependencies::~SpdySessionDependencies() {} | |
366 | |
367 // static | |
368 std::unique_ptr<HttpNetworkSession> SpdySessionDependencies::SpdyCreateSession( | |
369 SpdySessionDependencies* session_deps) { | |
370 return SpdyCreateSessionWithSocketFactory(session_deps, | |
371 session_deps->socket_factory.get()); | |
372 } | |
373 | |
374 // static | |
375 std::unique_ptr<HttpNetworkSession> | |
376 SpdySessionDependencies::SpdyCreateSessionWithSocketFactory( | |
377 SpdySessionDependencies* session_deps, | |
378 ClientSocketFactory* factory) { | |
379 HttpNetworkSession::Params params = CreateSessionParams(session_deps); | |
380 params.client_socket_factory = factory; | |
381 std::unique_ptr<HttpNetworkSession> http_session( | |
382 new HttpNetworkSession(params)); | |
383 SpdySessionPoolPeer pool_peer(http_session->spdy_session_pool()); | |
384 pool_peer.SetEnableSendingInitialData(false); | |
385 return http_session; | |
386 } | |
387 | |
388 // static | |
389 HttpNetworkSession::Params SpdySessionDependencies::CreateSessionParams( | |
390 SpdySessionDependencies* session_deps) { | |
391 HttpNetworkSession::Params params; | |
392 params.host_resolver = session_deps->host_resolver.get(); | |
393 params.cert_verifier = session_deps->cert_verifier.get(); | |
394 params.channel_id_service = session_deps->channel_id_service.get(); | |
395 params.transport_security_state = | |
396 session_deps->transport_security_state.get(); | |
397 params.cert_transparency_verifier = | |
398 session_deps->cert_transparency_verifier.get(); | |
399 params.ct_policy_enforcer = session_deps->ct_policy_enforcer.get(); | |
400 params.proxy_service = session_deps->proxy_service.get(); | |
401 params.ssl_config_service = session_deps->ssl_config_service.get(); | |
402 params.http_auth_handler_factory = | |
403 session_deps->http_auth_handler_factory.get(); | |
404 params.http_server_properties = session_deps->http_server_properties.get(); | |
405 params.enable_spdy_ping_based_connection_checking = session_deps->enable_ping; | |
406 params.enable_user_alternate_protocol_ports = | |
407 session_deps->enable_user_alternate_protocol_ports; | |
408 params.enable_quic = session_deps->enable_quic; | |
409 params.enable_server_push_cancellation = | |
410 session_deps->enable_server_push_cancellation; | |
411 params.spdy_session_max_recv_window_size = | |
412 session_deps->session_max_recv_window_size; | |
413 params.http2_settings = session_deps->http2_settings; | |
414 params.time_func = session_deps->time_func; | |
415 params.proxy_delegate = session_deps->proxy_delegate.get(); | |
416 params.enable_http2_alternative_service = | |
417 session_deps->enable_http2_alternative_service; | |
418 params.net_log = session_deps->net_log; | |
419 params.http_09_on_non_default_ports_enabled = | |
420 session_deps->http_09_on_non_default_ports_enabled; | |
421 params.restrict_to_one_preconnect_for_proxies = | |
422 session_deps->restrict_to_one_preconnect_for_proxies; | |
423 params.quic_do_not_mark_as_broken_on_network_change = | |
424 session_deps->quic_do_not_mark_as_broken_on_network_change; | |
425 return params; | |
426 } | |
427 | |
428 class AllowAnyCertCTPolicyEnforcer : public CTPolicyEnforcer { | |
429 public: | |
430 AllowAnyCertCTPolicyEnforcer() {} | |
431 ~AllowAnyCertCTPolicyEnforcer() override = default; | |
432 | |
433 ct::CertPolicyCompliance DoesConformToCertPolicy( | |
434 X509Certificate* cert, | |
435 const SCTList& verified_scts, | |
436 const NetLogWithSource& net_log) override { | |
437 return ct::CertPolicyCompliance::CERT_POLICY_COMPLIES_VIA_SCTS; | |
438 } | |
439 | |
440 ct::EVPolicyCompliance DoesConformToCTEVPolicy( | |
441 X509Certificate* cert, | |
442 const ct::EVCertsWhitelist* ev_whitelist, | |
443 const SCTList& verified_scts, | |
444 const NetLogWithSource& net_log) override { | |
445 return ct::EVPolicyCompliance::EV_POLICY_COMPLIES_VIA_SCTS; | |
446 } | |
447 }; | |
448 | |
449 SpdyURLRequestContext::SpdyURLRequestContext() : storage_(this) { | |
450 storage_.set_host_resolver( | |
451 std::unique_ptr<HostResolver>(new MockHostResolver)); | |
452 storage_.set_cert_verifier(base::WrapUnique(new MockCertVerifier)); | |
453 storage_.set_transport_security_state( | |
454 base::WrapUnique(new TransportSecurityState)); | |
455 storage_.set_proxy_service(ProxyService::CreateDirect()); | |
456 storage_.set_ct_policy_enforcer( | |
457 base::WrapUnique(new AllowAnyCertCTPolicyEnforcer())); | |
458 storage_.set_cert_transparency_verifier( | |
459 base::WrapUnique(new DoNothingCTVerifier())); | |
460 storage_.set_ssl_config_service(new SSLConfigServiceDefaults); | |
461 storage_.set_http_auth_handler_factory( | |
462 HttpAuthHandlerFactory::CreateDefault(host_resolver())); | |
463 storage_.set_http_server_properties( | |
464 std::unique_ptr<HttpServerProperties>(new HttpServerPropertiesImpl())); | |
465 storage_.set_job_factory(base::MakeUnique<URLRequestJobFactoryImpl>()); | |
466 HttpNetworkSession::Params params; | |
467 params.client_socket_factory = &socket_factory_; | |
468 params.host_resolver = host_resolver(); | |
469 params.cert_verifier = cert_verifier(); | |
470 params.transport_security_state = transport_security_state(); | |
471 params.proxy_service = proxy_service(); | |
472 params.ct_policy_enforcer = ct_policy_enforcer(); | |
473 params.cert_transparency_verifier = cert_transparency_verifier(); | |
474 params.ssl_config_service = ssl_config_service(); | |
475 params.http_auth_handler_factory = http_auth_handler_factory(); | |
476 params.enable_spdy_ping_based_connection_checking = false; | |
477 params.http_server_properties = http_server_properties(); | |
478 storage_.set_http_network_session( | |
479 base::MakeUnique<HttpNetworkSession>(params)); | |
480 SpdySessionPoolPeer pool_peer( | |
481 storage_.http_network_session()->spdy_session_pool()); | |
482 pool_peer.SetEnableSendingInitialData(false); | |
483 storage_.set_http_transaction_factory(base::MakeUnique<HttpCache>( | |
484 storage_.http_network_session(), HttpCache::DefaultBackend::InMemory(0), | |
485 false)); | |
486 } | |
487 | |
488 SpdyURLRequestContext::~SpdyURLRequestContext() { | |
489 AssertNoURLRequests(); | |
490 } | |
491 | |
492 bool HasSpdySession(SpdySessionPool* pool, const SpdySessionKey& key) { | |
493 return static_cast<bool>(pool->FindAvailableSession( | |
494 key, GURL(), | |
495 /* enable_ip_based_pooling = */ true, NetLogWithSource())); | |
496 } | |
497 | |
498 namespace { | |
499 | |
500 base::WeakPtr<SpdySession> CreateSpdySessionHelper( | |
501 HttpNetworkSession* http_session, | |
502 const SpdySessionKey& key, | |
503 const NetLogWithSource& net_log, | |
504 Error expected_status, | |
505 bool is_secure, | |
506 bool enable_ip_based_pooling) { | |
507 EXPECT_FALSE(http_session->spdy_session_pool()->FindAvailableSession( | |
508 key, GURL(), enable_ip_based_pooling, NetLogWithSource())); | |
509 | |
510 scoped_refptr<TransportSocketParams> transport_params( | |
511 new TransportSocketParams( | |
512 key.host_port_pair(), false, OnHostResolutionCallback(), | |
513 TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)); | |
514 | |
515 std::unique_ptr<ClientSocketHandle> connection(new ClientSocketHandle); | |
516 TestCompletionCallback callback; | |
517 | |
518 int rv = ERR_UNEXPECTED; | |
519 if (is_secure) { | |
520 SSLConfig ssl_config; | |
521 scoped_refptr<SSLSocketParams> ssl_params( | |
522 new SSLSocketParams(transport_params, | |
523 NULL, | |
524 NULL, | |
525 key.host_port_pair(), | |
526 ssl_config, | |
527 key.privacy_mode(), | |
528 0, | |
529 false)); | |
530 rv = connection->Init( | |
531 key.host_port_pair().ToString(), ssl_params, MEDIUM, | |
532 ClientSocketPool::RespectLimits::ENABLED, callback.callback(), | |
533 http_session->GetSSLSocketPool(HttpNetworkSession::NORMAL_SOCKET_POOL), | |
534 net_log); | |
535 } else { | |
536 rv = connection->Init(key.host_port_pair().ToString(), transport_params, | |
537 MEDIUM, ClientSocketPool::RespectLimits::ENABLED, | |
538 callback.callback(), | |
539 http_session->GetTransportSocketPool( | |
540 HttpNetworkSession::NORMAL_SOCKET_POOL), | |
541 net_log); | |
542 } | |
543 | |
544 if (rv == ERR_IO_PENDING) | |
545 rv = callback.WaitForResult(); | |
546 | |
547 EXPECT_THAT(rv, IsOk()); | |
548 | |
549 base::WeakPtr<SpdySession> spdy_session = | |
550 http_session->spdy_session_pool()->CreateAvailableSessionFromSocket( | |
551 key, std::move(connection), net_log, is_secure); | |
552 // Failure is reported asynchronously. | |
553 EXPECT_TRUE(spdy_session); | |
554 EXPECT_TRUE(HasSpdySession(http_session->spdy_session_pool(), key)); | |
555 return spdy_session; | |
556 } | |
557 | |
558 } // namespace | |
559 | |
560 base::WeakPtr<SpdySession> CreateInsecureSpdySession( | |
561 HttpNetworkSession* http_session, | |
562 const SpdySessionKey& key, | |
563 const NetLogWithSource& net_log) { | |
564 return CreateSpdySessionHelper(http_session, key, net_log, OK, | |
565 /* is_secure = */ false, | |
566 /* enable_ip_based_pooling = */ true); | |
567 } | |
568 | |
569 base::WeakPtr<SpdySession> TryCreateSpdySessionExpectingFailure( | |
570 HttpNetworkSession* http_session, | |
571 const SpdySessionKey& key, | |
572 Error expected_error, | |
573 const NetLogWithSource& net_log) { | |
574 DCHECK_LT(expected_error, ERR_IO_PENDING); | |
575 return CreateSpdySessionHelper(http_session, key, net_log, expected_error, | |
576 /* is_secure = */ true, | |
577 /* enable_ip_based_pooling = */ true); | |
578 } | |
579 | |
580 base::WeakPtr<SpdySession> CreateSecureSpdySession( | |
581 HttpNetworkSession* http_session, | |
582 const SpdySessionKey& key, | |
583 const NetLogWithSource& net_log) { | |
584 return CreateSpdySessionHelper(http_session, key, net_log, OK, | |
585 /* is_secure = */ true, | |
586 /* enable_ip_based_pooling = */ true); | |
587 } | |
588 | |
589 base::WeakPtr<SpdySession> CreateSecureSpdySessionWithIpBasedPoolingDisabled( | |
590 HttpNetworkSession* http_session, | |
591 const SpdySessionKey& key, | |
592 const NetLogWithSource& net_log) { | |
593 return CreateSpdySessionHelper(http_session, key, net_log, OK, | |
594 /* is_secure = */ true, | |
595 /* enable_ip_based_pooling = */ false); | |
596 } | |
597 | |
598 namespace { | |
599 | |
600 // A ClientSocket used for CreateFakeSpdySession() below. | |
601 class FakeSpdySessionClientSocket : public MockClientSocket { | |
602 public: | |
603 explicit FakeSpdySessionClientSocket(int read_result) | |
604 : MockClientSocket(NetLogWithSource()), read_result_(read_result) {} | |
605 | |
606 ~FakeSpdySessionClientSocket() override {} | |
607 | |
608 int Read(IOBuffer* buf, | |
609 int buf_len, | |
610 const CompletionCallback& callback) override { | |
611 return read_result_; | |
612 } | |
613 | |
614 int Write(IOBuffer* buf, | |
615 int buf_len, | |
616 const CompletionCallback& callback) override { | |
617 return ERR_IO_PENDING; | |
618 } | |
619 | |
620 // Return kProtoUnknown to use the pool's default protocol. | |
621 NextProto GetNegotiatedProtocol() const override { return kProtoUnknown; } | |
622 | |
623 // The functions below are not expected to be called. | |
624 | |
625 int Connect(const CompletionCallback& callback) override { | |
626 ADD_FAILURE(); | |
627 return ERR_UNEXPECTED; | |
628 } | |
629 | |
630 bool WasEverUsed() const override { | |
631 ADD_FAILURE(); | |
632 return false; | |
633 } | |
634 | |
635 bool WasAlpnNegotiated() const override { | |
636 ADD_FAILURE(); | |
637 return false; | |
638 } | |
639 | |
640 bool GetSSLInfo(SSLInfo* ssl_info) override { | |
641 ADD_FAILURE(); | |
642 return false; | |
643 } | |
644 | |
645 int64_t GetTotalReceivedBytes() const override { | |
646 NOTIMPLEMENTED(); | |
647 return 0; | |
648 } | |
649 | |
650 private: | |
651 int read_result_; | |
652 }; | |
653 | |
654 base::WeakPtr<SpdySession> CreateFakeSpdySessionHelper( | |
655 SpdySessionPool* pool, | |
656 const SpdySessionKey& key, | |
657 Error expected_status) { | |
658 EXPECT_NE(expected_status, ERR_IO_PENDING); | |
659 EXPECT_FALSE(HasSpdySession(pool, key)); | |
660 std::unique_ptr<ClientSocketHandle> handle(new ClientSocketHandle()); | |
661 handle->SetSocket( | |
662 std::unique_ptr<StreamSocket>(new FakeSpdySessionClientSocket( | |
663 expected_status == OK ? ERR_IO_PENDING : expected_status))); | |
664 base::WeakPtr<SpdySession> spdy_session = | |
665 pool->CreateAvailableSessionFromSocket( | |
666 key, std::move(handle), NetLogWithSource(), true /* is_secure */); | |
667 // Failure is reported asynchronously. | |
668 EXPECT_TRUE(spdy_session); | |
669 EXPECT_TRUE(HasSpdySession(pool, key)); | |
670 return spdy_session; | |
671 } | |
672 | |
673 } // namespace | |
674 | |
675 base::WeakPtr<SpdySession> CreateFakeSpdySession(SpdySessionPool* pool, | |
676 const SpdySessionKey& key) { | |
677 return CreateFakeSpdySessionHelper(pool, key, OK); | |
678 } | |
679 | |
680 base::WeakPtr<SpdySession> TryCreateFakeSpdySessionExpectingFailure( | |
681 SpdySessionPool* pool, | |
682 const SpdySessionKey& key, | |
683 Error expected_error) { | |
684 DCHECK_LT(expected_error, ERR_IO_PENDING); | |
685 return CreateFakeSpdySessionHelper(pool, key, expected_error); | |
686 } | |
687 | |
688 SpdySessionPoolPeer::SpdySessionPoolPeer(SpdySessionPool* pool) : pool_(pool) { | |
689 } | |
690 | |
691 void SpdySessionPoolPeer::RemoveAliases(const SpdySessionKey& key) { | |
692 pool_->RemoveAliases(key); | |
693 } | |
694 | |
695 void SpdySessionPoolPeer::SetEnableSendingInitialData(bool enabled) { | |
696 pool_->enable_sending_initial_data_ = enabled; | |
697 } | |
698 | |
699 SpdyTestUtil::SpdyTestUtil() | |
700 : headerless_spdy_framer_(SpdyFramer::ENABLE_COMPRESSION), | |
701 request_spdy_framer_(SpdyFramer::ENABLE_COMPRESSION), | |
702 response_spdy_framer_(SpdyFramer::ENABLE_COMPRESSION), | |
703 default_url_(GURL(kDefaultUrl)) {} | |
704 | |
705 SpdyTestUtil::~SpdyTestUtil() {} | |
706 | |
707 void SpdyTestUtil::AddUrlToHeaderBlock(SpdyStringPiece url, | |
708 SpdyHeaderBlock* headers) const { | |
709 SpdyString scheme, host, path; | |
710 ParseUrl(url, &scheme, &host, &path); | |
711 (*headers)[GetHostKey()] = host; | |
712 (*headers)[GetSchemeKey()] = scheme; | |
713 (*headers)[GetPathKey()] = path; | |
714 } | |
715 | |
716 // static | |
717 SpdyHeaderBlock SpdyTestUtil::ConstructGetHeaderBlock(SpdyStringPiece url) { | |
718 return ConstructHeaderBlock("GET", url, NULL); | |
719 } | |
720 | |
721 // static | |
722 SpdyHeaderBlock SpdyTestUtil::ConstructGetHeaderBlockForProxy( | |
723 SpdyStringPiece url) { | |
724 return ConstructGetHeaderBlock(url); | |
725 } | |
726 | |
727 // static | |
728 SpdyHeaderBlock SpdyTestUtil::ConstructHeadHeaderBlock(SpdyStringPiece url, | |
729 int64_t content_length) { | |
730 return ConstructHeaderBlock("HEAD", url, nullptr); | |
731 } | |
732 | |
733 // static | |
734 SpdyHeaderBlock SpdyTestUtil::ConstructPostHeaderBlock(SpdyStringPiece url, | |
735 int64_t content_length) { | |
736 return ConstructHeaderBlock("POST", url, &content_length); | |
737 } | |
738 | |
739 // static | |
740 SpdyHeaderBlock SpdyTestUtil::ConstructPutHeaderBlock(SpdyStringPiece url, | |
741 int64_t content_length) { | |
742 return ConstructHeaderBlock("PUT", url, &content_length); | |
743 } | |
744 | |
745 SpdyString SpdyTestUtil::ConstructSpdyReplyString( | |
746 const SpdyHeaderBlock& headers) const { | |
747 SpdyString reply_string; | |
748 for (SpdyHeaderBlock::const_iterator it = headers.begin(); | |
749 it != headers.end(); ++it) { | |
750 SpdyString key = it->first.as_string(); | |
751 // Remove leading colon from pseudo headers. | |
752 if (key[0] == ':') | |
753 key = key.substr(1); | |
754 for (const SpdyString& value : | |
755 base::SplitString(it->second, SpdyStringPiece("\0", 1), | |
756 base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)) { | |
757 reply_string += key + ": " + value + "\n"; | |
758 } | |
759 } | |
760 return reply_string; | |
761 } | |
762 | |
763 // TODO(jgraettinger): Eliminate uses of this method in tests (prefer | |
764 // SpdySettingsIR). | |
765 SpdySerializedFrame SpdyTestUtil::ConstructSpdySettings( | |
766 const SettingsMap& settings) { | |
767 SpdySettingsIR settings_ir; | |
768 for (SettingsMap::const_iterator it = settings.begin(); it != settings.end(); | |
769 ++it) { | |
770 settings_ir.AddSetting(it->first, it->second); | |
771 } | |
772 return SpdySerializedFrame( | |
773 headerless_spdy_framer_.SerializeFrame(settings_ir)); | |
774 } | |
775 | |
776 SpdySerializedFrame SpdyTestUtil::ConstructSpdySettingsAck() { | |
777 SpdySettingsIR settings_ir; | |
778 settings_ir.set_is_ack(true); | |
779 return SpdySerializedFrame( | |
780 headerless_spdy_framer_.SerializeFrame(settings_ir)); | |
781 } | |
782 | |
783 SpdySerializedFrame SpdyTestUtil::ConstructSpdyPing(uint32_t ping_id, | |
784 bool is_ack) { | |
785 SpdyPingIR ping_ir(ping_id); | |
786 ping_ir.set_is_ack(is_ack); | |
787 return SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(ping_ir)); | |
788 } | |
789 | |
790 SpdySerializedFrame SpdyTestUtil::ConstructSpdyGoAway() { | |
791 return ConstructSpdyGoAway(0); | |
792 } | |
793 | |
794 SpdySerializedFrame SpdyTestUtil::ConstructSpdyGoAway( | |
795 SpdyStreamId last_good_stream_id) { | |
796 SpdyGoAwayIR go_ir(last_good_stream_id, ERROR_CODE_NO_ERROR, "go away"); | |
797 return SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(go_ir)); | |
798 } | |
799 | |
800 SpdySerializedFrame SpdyTestUtil::ConstructSpdyGoAway( | |
801 SpdyStreamId last_good_stream_id, | |
802 SpdyErrorCode error_code, | |
803 const SpdyString& desc) { | |
804 SpdyGoAwayIR go_ir(last_good_stream_id, error_code, desc); | |
805 return SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(go_ir)); | |
806 } | |
807 | |
808 SpdySerializedFrame SpdyTestUtil::ConstructSpdyWindowUpdate( | |
809 const SpdyStreamId stream_id, | |
810 uint32_t delta_window_size) { | |
811 SpdyWindowUpdateIR update_ir(stream_id, delta_window_size); | |
812 return SpdySerializedFrame(headerless_spdy_framer_.SerializeFrame(update_ir)); | |
813 } | |
814 | |
815 // TODO(jgraettinger): Eliminate uses of this method in tests (prefer | |
816 // SpdyRstStreamIR). | |
817 SpdySerializedFrame SpdyTestUtil::ConstructSpdyRstStream( | |
818 SpdyStreamId stream_id, | |
819 SpdyErrorCode error_code) { | |
820 SpdyRstStreamIR rst_ir(stream_id, error_code); | |
821 return SpdySerializedFrame( | |
822 headerless_spdy_framer_.SerializeRstStream(rst_ir)); | |
823 } | |
824 | |
825 // TODO(jgraettinger): Eliminate uses of this method in tests (prefer | |
826 // SpdyPriorityIR). | |
827 SpdySerializedFrame SpdyTestUtil::ConstructSpdyPriority( | |
828 SpdyStreamId stream_id, | |
829 SpdyStreamId parent_stream_id, | |
830 RequestPriority request_priority, | |
831 bool exclusive) { | |
832 int weight = Spdy3PriorityToHttp2Weight( | |
833 ConvertRequestPriorityToSpdyPriority(request_priority)); | |
834 SpdyPriorityIR ir(stream_id, parent_stream_id, weight, exclusive); | |
835 return SpdySerializedFrame(headerless_spdy_framer_.SerializePriority(ir)); | |
836 } | |
837 | |
838 SpdySerializedFrame SpdyTestUtil::ConstructSpdyGet( | |
839 const char* const url, | |
840 SpdyStreamId stream_id, | |
841 RequestPriority request_priority) { | |
842 SpdyHeaderBlock block(ConstructGetHeaderBlock(url)); | |
843 return ConstructSpdyHeaders(stream_id, std::move(block), request_priority, | |
844 true); | |
845 } | |
846 | |
847 SpdySerializedFrame SpdyTestUtil::ConstructSpdyGet( | |
848 const char* const extra_headers[], | |
849 int extra_header_count, | |
850 int stream_id, | |
851 RequestPriority request_priority, | |
852 bool direct) { | |
853 SpdyHeaderBlock block; | |
854 block[GetMethodKey()] = "GET"; | |
855 AddUrlToHeaderBlock(default_url_.spec(), &block); | |
856 AppendToHeaderBlock(extra_headers, extra_header_count, &block); | |
857 return ConstructSpdyHeaders(stream_id, std::move(block), request_priority, | |
858 true); | |
859 } | |
860 | |
861 SpdySerializedFrame SpdyTestUtil::ConstructSpdyConnect( | |
862 const char* const extra_headers[], | |
863 int extra_header_count, | |
864 int stream_id, | |
865 RequestPriority priority, | |
866 const HostPortPair& host_port_pair) { | |
867 SpdyHeaderBlock block; | |
868 block[GetMethodKey()] = "CONNECT"; | |
869 block[GetHostKey()] = host_port_pair.ToString(); | |
870 AppendToHeaderBlock(extra_headers, extra_header_count, &block); | |
871 return ConstructSpdyHeaders(stream_id, std::move(block), priority, false); | |
872 } | |
873 | |
874 SpdySerializedFrame SpdyTestUtil::ConstructSpdyPush( | |
875 const char* const extra_headers[], | |
876 int extra_header_count, | |
877 int stream_id, | |
878 int associated_stream_id, | |
879 const char* url) { | |
880 SpdyHeaderBlock push_promise_header_block; | |
881 AddUrlToHeaderBlock(url, &push_promise_header_block); | |
882 SpdyPushPromiseIR push_promise(associated_stream_id, stream_id, | |
883 std::move(push_promise_header_block)); | |
884 SpdySerializedFrame push_promise_frame( | |
885 response_spdy_framer_.SerializeFrame(push_promise)); | |
886 | |
887 SpdyHeaderBlock headers_header_block; | |
888 headers_header_block[GetStatusKey()] = "200"; | |
889 headers_header_block["hello"] = "bye"; | |
890 AppendToHeaderBlock(extra_headers, extra_header_count, &headers_header_block); | |
891 SpdyHeadersIR headers(stream_id, std::move(headers_header_block)); | |
892 SpdySerializedFrame headers_frame( | |
893 response_spdy_framer_.SerializeFrame(headers)); | |
894 | |
895 int joint_data_size = push_promise_frame.size() + headers_frame.size(); | |
896 std::unique_ptr<char[]> data(new char[joint_data_size]); | |
897 const SpdySerializedFrame* frames[2] = { | |
898 &push_promise_frame, &headers_frame, | |
899 }; | |
900 int combined_size = | |
901 CombineFrames(frames, arraysize(frames), data.get(), joint_data_size); | |
902 DCHECK_EQ(combined_size, joint_data_size); | |
903 return SpdySerializedFrame(data.release(), joint_data_size, true); | |
904 } | |
905 | |
906 SpdySerializedFrame SpdyTestUtil::ConstructSpdyPush( | |
907 const char* const extra_headers[], | |
908 int extra_header_count, | |
909 int stream_id, | |
910 int associated_stream_id, | |
911 const char* url, | |
912 const char* status, | |
913 const char* location) { | |
914 SpdyHeaderBlock push_promise_header_block; | |
915 AddUrlToHeaderBlock(url, &push_promise_header_block); | |
916 SpdyPushPromiseIR push_promise(associated_stream_id, stream_id, | |
917 std::move(push_promise_header_block)); | |
918 SpdySerializedFrame push_promise_frame( | |
919 response_spdy_framer_.SerializeFrame(push_promise)); | |
920 | |
921 SpdyHeaderBlock headers_header_block; | |
922 headers_header_block["hello"] = "bye"; | |
923 headers_header_block[GetStatusKey()] = status; | |
924 headers_header_block["location"] = location; | |
925 AppendToHeaderBlock(extra_headers, extra_header_count, &headers_header_block); | |
926 SpdyHeadersIR headers(stream_id, std::move(headers_header_block)); | |
927 SpdySerializedFrame headers_frame( | |
928 response_spdy_framer_.SerializeFrame(headers)); | |
929 | |
930 int joint_data_size = push_promise_frame.size() + headers_frame.size(); | |
931 std::unique_ptr<char[]> data(new char[joint_data_size]); | |
932 const SpdySerializedFrame* frames[2] = { | |
933 &push_promise_frame, &headers_frame, | |
934 }; | |
935 int combined_size = | |
936 CombineFrames(frames, arraysize(frames), data.get(), joint_data_size); | |
937 DCHECK_EQ(combined_size, joint_data_size); | |
938 return SpdySerializedFrame(data.release(), joint_data_size, true); | |
939 } | |
940 | |
941 SpdySerializedFrame SpdyTestUtil::ConstructInitialSpdyPushFrame( | |
942 SpdyHeaderBlock headers, | |
943 int stream_id, | |
944 int associated_stream_id) { | |
945 SpdyPushPromiseIR push_promise(associated_stream_id, stream_id, | |
946 std::move(headers)); | |
947 return SpdySerializedFrame( | |
948 response_spdy_framer_.SerializeFrame(push_promise)); | |
949 } | |
950 | |
951 SpdySerializedFrame SpdyTestUtil::ConstructSpdyPushHeaders( | |
952 int stream_id, | |
953 const char* const extra_headers[], | |
954 int extra_header_count) { | |
955 SpdyHeaderBlock header_block; | |
956 header_block[GetStatusKey()] = "200"; | |
957 AppendToHeaderBlock(extra_headers, extra_header_count, &header_block); | |
958 SpdyHeadersIR headers(stream_id, std::move(header_block)); | |
959 return SpdySerializedFrame(response_spdy_framer_.SerializeFrame(headers)); | |
960 } | |
961 | |
962 SpdySerializedFrame SpdyTestUtil::ConstructSpdyResponseHeaders( | |
963 int stream_id, | |
964 SpdyHeaderBlock headers, | |
965 bool fin) { | |
966 SpdyHeadersIR spdy_headers(stream_id, std::move(headers)); | |
967 spdy_headers.set_fin(fin); | |
968 return SpdySerializedFrame( | |
969 response_spdy_framer_.SerializeFrame(spdy_headers)); | |
970 } | |
971 | |
972 SpdySerializedFrame SpdyTestUtil::ConstructSpdyHeaders(int stream_id, | |
973 SpdyHeaderBlock block, | |
974 RequestPriority priority, | |
975 bool fin) { | |
976 // Get the stream id of the next highest priority request | |
977 // (most recent request of the same priority, or last request of | |
978 // an earlier priority). | |
979 // Note that this is a duplicate of the logic in Http2PriorityDependencies | |
980 // (slightly transformed as this is based on RequestPriority and that logic | |
981 // on SpdyPriority, but only slightly transformed) and hence tests using | |
982 // this function do not effectively test that logic. | |
983 // That logic is tested by the Http2PriorityDependencies unit tests. | |
984 int parent_stream_id = 0; | |
985 for (int q = priority; q <= HIGHEST; ++q) { | |
986 if (!priority_to_stream_id_list_[q].empty()) { | |
987 parent_stream_id = priority_to_stream_id_list_[q].back(); | |
988 break; | |
989 } | |
990 } | |
991 | |
992 priority_to_stream_id_list_[priority].push_back(stream_id); | |
993 | |
994 SpdyHeadersIR headers(stream_id, std::move(block)); | |
995 headers.set_has_priority(true); | |
996 headers.set_weight(Spdy3PriorityToHttp2Weight( | |
997 ConvertRequestPriorityToSpdyPriority(priority))); | |
998 headers.set_parent_stream_id(parent_stream_id); | |
999 headers.set_exclusive(true); | |
1000 headers.set_fin(fin); | |
1001 return SpdySerializedFrame(request_spdy_framer_.SerializeFrame(headers)); | |
1002 } | |
1003 | |
1004 SpdySerializedFrame SpdyTestUtil::ConstructSpdyReply(int stream_id, | |
1005 SpdyHeaderBlock headers) { | |
1006 SpdyHeadersIR reply(stream_id, std::move(headers)); | |
1007 return SpdySerializedFrame(response_spdy_framer_.SerializeFrame(reply)); | |
1008 } | |
1009 | |
1010 SpdySerializedFrame SpdyTestUtil::ConstructSpdyReplyError( | |
1011 const char* const status, | |
1012 const char* const* const extra_headers, | |
1013 int extra_header_count, | |
1014 int stream_id) { | |
1015 SpdyHeaderBlock block; | |
1016 block[GetStatusKey()] = status; | |
1017 block["hello"] = "bye"; | |
1018 AppendToHeaderBlock(extra_headers, extra_header_count, &block); | |
1019 | |
1020 return ConstructSpdyReply(stream_id, std::move(block)); | |
1021 } | |
1022 | |
1023 SpdySerializedFrame SpdyTestUtil::ConstructSpdyGetReplyRedirect(int stream_id) { | |
1024 static const char* const kExtraHeaders[] = { | |
1025 "location", "http://www.foo.com/index.php", | |
1026 }; | |
1027 return ConstructSpdyReplyError("301", kExtraHeaders, | |
1028 arraysize(kExtraHeaders) / 2, stream_id); | |
1029 } | |
1030 | |
1031 SpdySerializedFrame SpdyTestUtil::ConstructSpdyReplyError(int stream_id) { | |
1032 return ConstructSpdyReplyError("500", NULL, 0, 1); | |
1033 } | |
1034 | |
1035 SpdySerializedFrame SpdyTestUtil::ConstructSpdyGetReply( | |
1036 const char* const extra_headers[], | |
1037 int extra_header_count, | |
1038 int stream_id) { | |
1039 SpdyHeaderBlock block; | |
1040 block[GetStatusKey()] = "200"; | |
1041 block["hello"] = "bye"; | |
1042 AppendToHeaderBlock(extra_headers, extra_header_count, &block); | |
1043 | |
1044 return ConstructSpdyReply(stream_id, std::move(block)); | |
1045 } | |
1046 | |
1047 SpdySerializedFrame SpdyTestUtil::ConstructSpdyPost( | |
1048 const char* url, | |
1049 SpdyStreamId stream_id, | |
1050 int64_t content_length, | |
1051 RequestPriority priority, | |
1052 const char* const extra_headers[], | |
1053 int extra_header_count) { | |
1054 SpdyHeaderBlock block(ConstructPostHeaderBlock(url, content_length)); | |
1055 AppendToHeaderBlock(extra_headers, extra_header_count, &block); | |
1056 return ConstructSpdyHeaders(stream_id, std::move(block), priority, false); | |
1057 } | |
1058 | |
1059 SpdySerializedFrame SpdyTestUtil::ConstructChunkedSpdyPost( | |
1060 const char* const extra_headers[], | |
1061 int extra_header_count) { | |
1062 SpdyHeaderBlock block; | |
1063 block[GetMethodKey()] = "POST"; | |
1064 AddUrlToHeaderBlock(default_url_.spec(), &block); | |
1065 AppendToHeaderBlock(extra_headers, extra_header_count, &block); | |
1066 return ConstructSpdyHeaders(1, std::move(block), LOWEST, false); | |
1067 } | |
1068 | |
1069 SpdySerializedFrame SpdyTestUtil::ConstructSpdyPostReply( | |
1070 const char* const extra_headers[], | |
1071 int extra_header_count) { | |
1072 // TODO(jgraettinger): Remove this method. | |
1073 return ConstructSpdyGetReply(extra_headers, extra_header_count, 1); | |
1074 } | |
1075 | |
1076 SpdySerializedFrame SpdyTestUtil::ConstructSpdyDataFrame(int stream_id, | |
1077 bool fin) { | |
1078 SpdyDataIR data_ir(stream_id, SpdyStringPiece(kUploadData, kUploadDataSize)); | |
1079 data_ir.set_fin(fin); | |
1080 return SpdySerializedFrame(headerless_spdy_framer_.SerializeData(data_ir)); | |
1081 } | |
1082 | |
1083 SpdySerializedFrame SpdyTestUtil::ConstructSpdyDataFrame(int stream_id, | |
1084 const char* data, | |
1085 uint32_t len, | |
1086 bool fin) { | |
1087 SpdyDataIR data_ir(stream_id, SpdyStringPiece(data, len)); | |
1088 data_ir.set_fin(fin); | |
1089 return SpdySerializedFrame(headerless_spdy_framer_.SerializeData(data_ir)); | |
1090 } | |
1091 | |
1092 SpdySerializedFrame SpdyTestUtil::ConstructSpdyDataFrame(int stream_id, | |
1093 const char* data, | |
1094 uint32_t len, | |
1095 bool fin, | |
1096 int padding_length) { | |
1097 SpdyDataIR data_ir(stream_id, SpdyStringPiece(data, len)); | |
1098 data_ir.set_fin(fin); | |
1099 data_ir.set_padding_len(padding_length); | |
1100 return SpdySerializedFrame(headerless_spdy_framer_.SerializeData(data_ir)); | |
1101 } | |
1102 | |
1103 SpdySerializedFrame SpdyTestUtil::ConstructWrappedSpdyFrame( | |
1104 const SpdySerializedFrame& frame, | |
1105 int stream_id) { | |
1106 return ConstructSpdyDataFrame(stream_id, frame.data(), frame.size(), false); | |
1107 } | |
1108 | |
1109 SpdySerializedFrame SpdyTestUtil::SerializeFrame(const SpdyFrameIR& frame_ir) { | |
1110 return headerless_spdy_framer_.SerializeFrame(frame_ir); | |
1111 } | |
1112 | |
1113 void SpdyTestUtil::UpdateWithStreamDestruction(int stream_id) { | |
1114 for (auto priority_it = priority_to_stream_id_list_.begin(); | |
1115 priority_it != priority_to_stream_id_list_.end(); ++priority_it) { | |
1116 for (auto stream_it = priority_it->second.begin(); | |
1117 stream_it != priority_it->second.end(); ++stream_it) { | |
1118 if (*stream_it == stream_id) { | |
1119 priority_it->second.erase(stream_it); | |
1120 return; | |
1121 } | |
1122 } | |
1123 } | |
1124 NOTREACHED(); | |
1125 } | |
1126 | |
1127 // static | |
1128 const char* SpdyTestUtil::GetMethodKey() { | |
1129 return ":method"; | |
1130 } | |
1131 | |
1132 // static | |
1133 const char* SpdyTestUtil::GetStatusKey() { | |
1134 return ":status"; | |
1135 } | |
1136 | |
1137 // static | |
1138 const char* SpdyTestUtil::GetHostKey() { | |
1139 return ":authority"; | |
1140 } | |
1141 | |
1142 // static | |
1143 const char* SpdyTestUtil::GetSchemeKey() { | |
1144 return ":scheme"; | |
1145 } | |
1146 | |
1147 // static | |
1148 const char* SpdyTestUtil::GetPathKey() { | |
1149 return ":path"; | |
1150 } | |
1151 | |
1152 // static | |
1153 SpdyHeaderBlock SpdyTestUtil::ConstructHeaderBlock(SpdyStringPiece method, | |
1154 SpdyStringPiece url, | |
1155 int64_t* content_length) { | |
1156 SpdyString scheme, host, path; | |
1157 ParseUrl(url, &scheme, &host, &path); | |
1158 SpdyHeaderBlock headers; | |
1159 headers[GetMethodKey()] = method.as_string(); | |
1160 headers[GetHostKey()] = host.c_str(); | |
1161 headers[GetSchemeKey()] = scheme.c_str(); | |
1162 headers[GetPathKey()] = path.c_str(); | |
1163 if (content_length) { | |
1164 SpdyString length_str = base::Int64ToString(*content_length); | |
1165 headers["content-length"] = length_str; | |
1166 } | |
1167 return headers; | |
1168 } | |
1169 | |
1170 } // namespace net | |
OLD | NEW |