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