| 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 |