| Index: net/http/http_stream_factory_impl.cc
|
| diff --git a/net/http/http_stream_factory_impl.cc b/net/http/http_stream_factory_impl.cc
|
| index c7b0c9308d637c4e66c9f094a9289c37ae36417c..8a1ee60ee492b1bda01fa5110d4e1f77628a9153 100644
|
| --- a/net/http/http_stream_factory_impl.cc
|
| +++ b/net/http/http_stream_factory_impl.cc
|
| @@ -4,6 +4,7 @@
|
|
|
| #include "net/http/http_stream_factory_impl.h"
|
|
|
| +#include "base/string_number_conversions.h"
|
| #include "base/stl_util-inl.h"
|
| #include "googleurl/src/gurl.h"
|
| #include "net/base/net_log.h"
|
| @@ -15,6 +16,34 @@
|
|
|
| namespace net {
|
|
|
| +namespace {
|
| +
|
| +bool HasSpdyExclusion(const HostPortPair& endpoint) {
|
| + std::list<HostPortPair>* exclusions =
|
| + HttpStreamFactory::forced_spdy_exclusions();
|
| + if (!exclusions)
|
| + return false;
|
| +
|
| + std::list<HostPortPair>::const_iterator it;
|
| + for (it = exclusions->begin(); it != exclusions->end(); it++)
|
| + if (it->Equals(endpoint))
|
| + return true;
|
| + return false;
|
| +}
|
| +
|
| +GURL UpgradeUrlToHttps(const GURL& original_url) {
|
| + GURL::Replacements replacements;
|
| + // new_sheme and new_port need to be in scope here because GURL::Replacements
|
| + // references the memory contained by them directly.
|
| + const std::string new_scheme = "https";
|
| + const std::string new_port = base::IntToString(443);
|
| + replacements.SetSchemeStr(new_scheme);
|
| + replacements.SetPortStr(new_port);
|
| + return original_url.ReplaceComponents(replacements);
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| HttpStreamFactoryImpl::HttpStreamFactoryImpl(HttpNetworkSession* session)
|
| : session_(session) {}
|
|
|
| @@ -23,6 +52,11 @@ HttpStreamFactoryImpl::~HttpStreamFactoryImpl() {
|
| DCHECK(spdy_session_request_map_.empty());
|
|
|
| std::set<const Job*> tmp_job_set;
|
| + tmp_job_set.swap(orphaned_job_set_);
|
| + STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end());
|
| + DCHECK(orphaned_job_set_.empty());
|
| +
|
| + tmp_job_set.clear();
|
| tmp_job_set.swap(preconnect_job_set_);
|
| STLDeleteContainerPointers(tmp_job_set.begin(), tmp_job_set.end());
|
| DCHECK(preconnect_job_set_.empty());
|
| @@ -33,10 +67,34 @@ HttpStreamRequest* HttpStreamFactoryImpl::RequestStream(
|
| const SSLConfig& ssl_config,
|
| HttpStreamRequest::Delegate* delegate,
|
| const BoundNetLog& net_log) {
|
| - Job* job = new Job(this, session_);
|
| Request* request = new Request(request_info.url, this, delegate, net_log);
|
| +
|
| + GURL alternate_url;
|
| + bool has_alternate_protocol =
|
| + GetAlternateProtocolRequestFor(request_info.url, &alternate_url);
|
| + Job* alternate_job = NULL;
|
| + if (has_alternate_protocol) {
|
| + HttpRequestInfo alternate_request_info = request_info;
|
| + alternate_request_info.url = alternate_url;
|
| + alternate_job =
|
| + new Job(this, session_, alternate_request_info, ssl_config, net_log);
|
| + request->AttachJob(alternate_job);
|
| + alternate_job->MarkAsAlternate(request_info.url);
|
| + }
|
| +
|
| + Job* job = new Job(this, session_, request_info, ssl_config, net_log);
|
| request->AttachJob(job);
|
| - job->Start(request, request_info, ssl_config, net_log);
|
| + if (alternate_job) {
|
| + job->WaitFor(alternate_job);
|
| + // Make sure to wait until we call WaitFor(), before starting
|
| + // |alternate_job|, otherwise |alternate_job| will not notify |job|
|
| + // appropriately.
|
| + alternate_job->Start(request);
|
| + }
|
| + // Even if |alternate_job| has already finished, it won't have notified the
|
| + // request yet, since we defer that to the next iteration of the MessageLoop,
|
| + // so starting |job| is always safe.
|
| + job->Start(request);
|
| return request;
|
| }
|
|
|
| @@ -45,17 +103,66 @@ void HttpStreamFactoryImpl::PreconnectStreams(
|
| const HttpRequestInfo& request_info,
|
| const SSLConfig& ssl_config,
|
| const BoundNetLog& net_log) {
|
| - Job* job = new Job(this, session_);
|
| + GURL alternate_url;
|
| + bool has_alternate_protocol =
|
| + GetAlternateProtocolRequestFor(request_info.url, &alternate_url);
|
| + Job* job = NULL;
|
| + if (has_alternate_protocol) {
|
| + HttpRequestInfo alternate_request_info = request_info;
|
| + alternate_request_info.url = alternate_url;
|
| + job = new Job(this, session_, alternate_request_info, ssl_config, net_log);
|
| + job->MarkAsAlternate(request_info.url);
|
| + } else {
|
| + job = new Job(this, session_, request_info, ssl_config, net_log);
|
| + }
|
| preconnect_job_set_.insert(job);
|
| - job->Preconnect(num_streams, request_info, ssl_config, net_log);
|
| + job->Preconnect(num_streams);
|
| +}
|
| +
|
| +void HttpStreamFactoryImpl::AddTLSIntolerantServer(const HostPortPair& server) {
|
| + tls_intolerant_servers_.insert(server);
|
| }
|
|
|
| -void HttpStreamFactoryImpl::AddTLSIntolerantServer(const GURL& url) {
|
| - tls_intolerant_servers_.insert(GetHostAndPort(url));
|
| +bool HttpStreamFactoryImpl::IsTLSIntolerantServer(
|
| + const HostPortPair& server) const {
|
| + return ContainsKey(tls_intolerant_servers_, server);
|
| }
|
|
|
| -bool HttpStreamFactoryImpl::IsTLSIntolerantServer(const GURL& url) const {
|
| - return ContainsKey(tls_intolerant_servers_, GetHostAndPort(url));
|
| +bool HttpStreamFactoryImpl::GetAlternateProtocolRequestFor(
|
| + const GURL& original_url,
|
| + GURL* alternate_url) const {
|
| + if (!spdy_enabled())
|
| + return false;
|
| +
|
| + if (!use_alternate_protocols())
|
| + return false;
|
| +
|
| + HostPortPair origin = HostPortPair(original_url.HostNoBrackets(),
|
| + original_url.EffectiveIntPort());
|
| +
|
| + const HttpAlternateProtocols& alternate_protocols =
|
| + session_->alternate_protocols();
|
| + if (!alternate_protocols.HasAlternateProtocolFor(origin))
|
| + return false;
|
| +
|
| + HttpAlternateProtocols::PortProtocolPair alternate =
|
| + alternate_protocols.GetAlternateProtocolFor(origin);
|
| + if (alternate.protocol == HttpAlternateProtocols::BROKEN)
|
| + return false;
|
| +
|
| + DCHECK_LE(HttpAlternateProtocols::NPN_SPDY_1, alternate.protocol);
|
| + DCHECK_GT(HttpAlternateProtocols::NUM_ALTERNATE_PROTOCOLS,
|
| + alternate.protocol);
|
| +
|
| + if (alternate.protocol != HttpAlternateProtocols::NPN_SPDY_2)
|
| + return false;
|
| +
|
| + origin.set_port(alternate.port);
|
| + if (HasSpdyExclusion(origin))
|
| + return false;
|
| +
|
| + *alternate_url = UpgradeUrlToHttps(original_url);
|
| + return true;
|
| }
|
|
|
| void HttpStreamFactoryImpl::OrphanJob(Job* job, const Request* request) {
|
| @@ -74,7 +181,6 @@ void HttpStreamFactoryImpl::OnSpdySessionReady(
|
| bool direct,
|
| const SSLConfig& used_ssl_config,
|
| const ProxyInfo& used_proxy_info,
|
| - bool was_alternate_protocol_available,
|
| bool was_npn_negotiated,
|
| bool using_spdy,
|
| const NetLog::Source& source) {
|
| @@ -91,8 +197,7 @@ void HttpStreamFactoryImpl::OnSpdySessionReady(
|
| if (!ContainsKey(spdy_session_request_map_, spdy_session_key))
|
| break;
|
| Request* request = *spdy_session_request_map_[spdy_session_key].begin();
|
| - request->Complete(was_alternate_protocol_available,
|
| - was_npn_negotiated,
|
| + request->Complete(was_npn_negotiated,
|
| using_spdy,
|
| source);
|
| bool use_relative_url = direct || request->url().SchemeIs("https");
|
|
|