| // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "net/http/http_stream_factory_impl.h" |
| |
| #include <string> |
| |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_util.h" |
| #include "net/http/http_network_session.h" |
| #include "net/http/http_server_properties.h" |
| #include "net/http/http_stream_factory_impl_job.h" |
| #include "net/http/http_stream_factory_impl_job_controller.h" |
| #include "net/http/http_stream_factory_impl_request.h" |
| #include "net/http/transport_security_state.h" |
| #include "net/log/net_log.h" |
| #include "net/quic/core/quic_server_id.h" |
| #include "net/spdy/bidirectional_stream_spdy_impl.h" |
| #include "net/spdy/spdy_http_stream.h" |
| #include "url/gurl.h" |
| |
| namespace net { |
| |
| namespace { |
| // Default JobFactory for creating HttpStreamFactoryImpl::Jobs. |
| class DefaultJobFactory : public HttpStreamFactoryImpl::JobFactory { |
| public: |
| DefaultJobFactory() {} |
| |
| ~DefaultJobFactory() override {} |
| |
| HttpStreamFactoryImpl::Job* CreateJob( |
| HttpStreamFactoryImpl::Job::Delegate* delegate, |
| HttpStreamFactoryImpl::JobType job_type, |
| HttpNetworkSession* session, |
| const HttpRequestInfo& request_info, |
| RequestPriority priority, |
| const SSLConfig& server_ssl_config, |
| const SSLConfig& proxy_ssl_config, |
| HostPortPair destination, |
| GURL origin_url, |
| NetLog* net_log) override { |
| return new HttpStreamFactoryImpl::Job( |
| delegate, job_type, session, request_info, priority, server_ssl_config, |
| proxy_ssl_config, destination, origin_url, net_log); |
| } |
| |
| HttpStreamFactoryImpl::Job* CreateJob( |
| HttpStreamFactoryImpl::Job::Delegate* delegate, |
| HttpStreamFactoryImpl::JobType job_type, |
| HttpNetworkSession* session, |
| const HttpRequestInfo& request_info, |
| RequestPriority priority, |
| const SSLConfig& server_ssl_config, |
| const SSLConfig& proxy_ssl_config, |
| HostPortPair destination, |
| GURL origin_url, |
| AlternativeService alternative_service, |
| NetLog* net_log) override { |
| return new HttpStreamFactoryImpl::Job( |
| delegate, job_type, session, request_info, priority, server_ssl_config, |
| proxy_ssl_config, destination, origin_url, alternative_service, |
| ProxyServer(), net_log); |
| } |
| |
| HttpStreamFactoryImpl::Job* CreateJob( |
| HttpStreamFactoryImpl::Job::Delegate* delegate, |
| HttpStreamFactoryImpl::JobType job_type, |
| HttpNetworkSession* session, |
| const HttpRequestInfo& request_info, |
| RequestPriority priority, |
| const SSLConfig& server_ssl_config, |
| const SSLConfig& proxy_ssl_config, |
| HostPortPair destination, |
| GURL origin_url, |
| const ProxyServer& alternative_proxy_server, |
| NetLog* net_log) override { |
| return new HttpStreamFactoryImpl::Job( |
| delegate, job_type, session, request_info, priority, server_ssl_config, |
| proxy_ssl_config, destination, origin_url, AlternativeService(), |
| alternative_proxy_server, net_log); |
| } |
| }; |
| } // anonymous namespace |
| |
| HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session, |
| bool for_websockets) |
| : session_(session), |
| job_factory_(new DefaultJobFactory()), |
| for_websockets_(for_websockets) {} |
| |
| HttpStreamFactoryImpl::~HttpStreamFactoryImpl() { |
| DCHECK(request_map_.empty()); |
| DCHECK(spdy_session_request_map_.empty()); |
| } |
| |
| HttpStreamRequest* HttpStreamFactoryImpl::RequestStream( |
| const HttpRequestInfo& request_info, |
| RequestPriority priority, |
| const SSLConfig& server_ssl_config, |
| const SSLConfig& proxy_ssl_config, |
| HttpStreamRequest::Delegate* delegate, |
| const BoundNetLog& net_log) { |
| DCHECK(!for_websockets_); |
| return RequestStreamInternal(request_info, priority, server_ssl_config, |
| proxy_ssl_config, delegate, nullptr, |
| HttpStreamRequest::HTTP_STREAM, net_log); |
| } |
| |
| HttpStreamRequest* HttpStreamFactoryImpl::RequestWebSocketHandshakeStream( |
| const HttpRequestInfo& request_info, |
| RequestPriority priority, |
| const SSLConfig& server_ssl_config, |
| const SSLConfig& proxy_ssl_config, |
| HttpStreamRequest::Delegate* delegate, |
| WebSocketHandshakeStreamBase::CreateHelper* create_helper, |
| const BoundNetLog& net_log) { |
| DCHECK(for_websockets_); |
| DCHECK(create_helper); |
| return RequestStreamInternal(request_info, priority, server_ssl_config, |
| proxy_ssl_config, delegate, create_helper, |
| HttpStreamRequest::HTTP_STREAM, net_log); |
| } |
| |
| HttpStreamRequest* HttpStreamFactoryImpl::RequestBidirectionalStreamImpl( |
| const HttpRequestInfo& request_info, |
| RequestPriority priority, |
| const SSLConfig& server_ssl_config, |
| const SSLConfig& proxy_ssl_config, |
| HttpStreamRequest::Delegate* delegate, |
| const BoundNetLog& net_log) { |
| DCHECK(!for_websockets_); |
| DCHECK(request_info.url.SchemeIs(url::kHttpsScheme)); |
| |
| return RequestStreamInternal( |
| request_info, priority, server_ssl_config, proxy_ssl_config, delegate, |
| nullptr, HttpStreamRequest::BIDIRECTIONAL_STREAM, net_log); |
| } |
| |
| HttpStreamRequest* HttpStreamFactoryImpl::RequestStreamInternal( |
| const HttpRequestInfo& request_info, |
| RequestPriority priority, |
| const SSLConfig& server_ssl_config, |
| const SSLConfig& proxy_ssl_config, |
| HttpStreamRequest::Delegate* delegate, |
| WebSocketHandshakeStreamBase::CreateHelper* |
| websocket_handshake_stream_create_helper, |
| HttpStreamRequest::StreamType stream_type, |
| const BoundNetLog& net_log) { |
| JobController* job_controller = |
| new JobController(this, delegate, session_, job_factory_.get()); |
| job_controller_set_.insert(base::WrapUnique(job_controller)); |
| |
| Request* request = job_controller->Start( |
| request_info, delegate, websocket_handshake_stream_create_helper, net_log, |
| stream_type, priority, server_ssl_config, proxy_ssl_config); |
| |
| return request; |
| } |
| |
| void HttpStreamFactoryImpl::PreconnectStreams( |
| int num_streams, |
| const HttpRequestInfo& request_info) { |
| SSLConfig server_ssl_config; |
| SSLConfig proxy_ssl_config; |
| session_->GetSSLConfig(request_info, &server_ssl_config, &proxy_ssl_config); |
| // All preconnects should perform EV certificate verification. |
| server_ssl_config.verify_ev_cert = true; |
| proxy_ssl_config.verify_ev_cert = true; |
| |
| DCHECK(!for_websockets_); |
| |
| JobController* job_controller = |
| new JobController(this, nullptr, session_, job_factory_.get()); |
| job_controller_set_.insert(base::WrapUnique(job_controller)); |
| job_controller->Preconnect(num_streams, request_info, server_ssl_config, |
| proxy_ssl_config); |
| } |
| |
| const HostMappingRules* HttpStreamFactoryImpl::GetHostMappingRules() const { |
| return session_->params().host_mapping_rules; |
| } |
| |
| void HttpStreamFactoryImpl::OnNewSpdySessionReady( |
| const base::WeakPtr<SpdySession>& spdy_session, |
| bool direct, |
| const SSLConfig& used_ssl_config, |
| const ProxyInfo& used_proxy_info, |
| bool was_npn_negotiated, |
| NextProto negotiated_protocol, |
| bool using_spdy, |
| const BoundNetLog& net_log) { |
| while (true) { |
| if (!spdy_session) |
| break; |
| const SpdySessionKey& spdy_session_key = spdy_session->spdy_session_key(); |
| // Each iteration may empty out the RequestSet for |spdy_session_key| in |
| // |spdy_session_request_map_|. So each time, check for RequestSet and use |
| // the first one. |
| // |
| // TODO(willchan): If it's important, switch RequestSet out for a FIFO |
| // queue (Order by priority first, then FIFO within same priority). Unclear |
| // that it matters here. |
| if (!base::ContainsKey(spdy_session_request_map_, spdy_session_key)) |
| break; |
| Request* request = *spdy_session_request_map_[spdy_session_key].begin(); |
| request->Complete(was_npn_negotiated, negotiated_protocol, using_spdy); |
| if (for_websockets_) { |
| // TODO(ricea): Restore this code path when WebSocket over SPDY |
| // implementation is ready. |
| NOTREACHED(); |
| } else if (request->stream_type() == |
| HttpStreamRequest::BIDIRECTIONAL_STREAM) { |
| request->OnBidirectionalStreamImplReady( |
| used_ssl_config, used_proxy_info, |
| new BidirectionalStreamSpdyImpl(spdy_session)); |
| } else { |
| bool use_relative_url = direct || request->url().SchemeIs("https"); |
| request->OnStreamReady( |
| used_ssl_config, used_proxy_info, |
| new SpdyHttpStream(spdy_session, use_relative_url)); |
| } |
| } |
| // TODO(mbelshe): Alert other valid requests. |
| } |
| |
| void HttpStreamFactoryImpl::OnJobControllerComplete(JobController* controller) { |
| for (auto it = job_controller_set_.begin(); it != job_controller_set_.end(); |
| ++it) { |
| if (it->get() == controller) { |
| job_controller_set_.erase(it); |
| return; |
| } |
| } |
| NOTREACHED(); |
| } |
| |
| } // namespace net |