Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / net / http / http_server_properties_impl.cc
index 13a42af..5177188 100644 (file)
@@ -4,23 +4,37 @@
 
 #include "net/http/http_server_properties_impl.h"
 
+#include "base/bind.h"
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
 #include "base/stl_util.h"
+#include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "net/http/http_pipelined_host_capability.h"
 
 namespace net {
 
+namespace {
+
 // TODO(simonjam): Run experiments with different values of this to see what
 // value is good at avoiding evictions without eating too much memory. Until
 // then, this is just a bad guess.
-static const int kDefaultNumHostsToRemember = 200;
+const int kDefaultNumHostsToRemember = 200;
+
+const uint64 kBrokenAlternateProtocolDelaySecs = 300;
+
+}  // namespace
 
 HttpServerPropertiesImpl::HttpServerPropertiesImpl()
-    : pipeline_capability_map_(
-        new CachedPipelineCapabilityMap(kDefaultNumHostsToRemember)),
+    : spdy_servers_map_(SpdyServerHostPortMap::NO_AUTO_EVICT),
+      alternate_protocol_map_(AlternateProtocolMap::NO_AUTO_EVICT),
+      spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT),
+      pipeline_capability_map_(
+          new CachedPipelineCapabilityMap(kDefaultNumHostsToRemember)),
       weak_ptr_factory_(this) {
+  canoncial_suffixes_.push_back(".c.youtube.com");
+  canoncial_suffixes_.push_back(".googlevideo.com");
 }
 
 HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
@@ -30,31 +44,67 @@ void HttpServerPropertiesImpl::InitializeSpdyServers(
     std::vector<std::string>* spdy_servers,
     bool support_spdy) {
   DCHECK(CalledOnValidThread());
-  spdy_servers_table_.clear();
   if (!spdy_servers)
     return;
-  for (std::vector<std::string>::iterator it = spdy_servers->begin();
-       it != spdy_servers->end(); ++it) {
-    spdy_servers_table_[*it] = support_spdy;
+  // Add the entries from persisted data.
+  for (std::vector<std::string>::reverse_iterator it = spdy_servers->rbegin();
+       it != spdy_servers->rend(); ++it) {
+    spdy_servers_map_.Put(*it, support_spdy);
   }
 }
 
 void HttpServerPropertiesImpl::InitializeAlternateProtocolServers(
     AlternateProtocolMap* alternate_protocol_map) {
-  // First swap, and then add back all the ALTERNATE_PROTOCOL_BROKEN ones since
-  // those don't get persisted.
-  alternate_protocol_map_.swap(*alternate_protocol_map);
-  for (AlternateProtocolMap::const_iterator it =
-       alternate_protocol_map->begin();
-       it != alternate_protocol_map->end(); ++it) {
-    if (it->second.protocol == ALTERNATE_PROTOCOL_BROKEN)
-      alternate_protocol_map_[it->first] = it->second;
+  // Keep all the ALTERNATE_PROTOCOL_BROKEN ones since those don't
+  // get persisted.
+  for (AlternateProtocolMap::iterator it = alternate_protocol_map_.begin();
+       it != alternate_protocol_map_.end();) {
+    AlternateProtocolMap::iterator old_it = it;
+    ++it;
+    if (old_it->second.protocol != ALTERNATE_PROTOCOL_BROKEN) {
+      alternate_protocol_map_.Erase(old_it);
+    }
+  }
+
+  // Add the entries from persisted data.
+  for (AlternateProtocolMap::reverse_iterator it =
+           alternate_protocol_map->rbegin();
+       it != alternate_protocol_map->rend(); ++it) {
+    alternate_protocol_map_.Put(it->first, it->second);
+  }
+
+  // Attempt to find canonical servers.
+  int canonical_ports[] = { 80, 443 };
+  for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
+    std::string canonical_suffix = canoncial_suffixes_[i];
+    for (size_t j = 0; j < arraysize(canonical_ports); ++j) {
+      HostPortPair canonical_host(canonical_suffix, canonical_ports[j]);
+      // If we already have a valid canonical server, we're done.
+      if (ContainsKey(canonical_host_to_origin_map_, canonical_host) &&
+          (alternate_protocol_map_.Peek(canonical_host_to_origin_map_[
+               canonical_host]) != alternate_protocol_map_.end())) {
+        continue;
+      }
+      // Now attempt to find a server which matches this origin and set it as
+      // canonical .
+      for (AlternateProtocolMap::const_iterator it =
+               alternate_protocol_map_.begin();
+           it != alternate_protocol_map_.end(); ++it) {
+        if (EndsWith(it->first.host(), canoncial_suffixes_[i], false)) {
+          canonical_host_to_origin_map_[canonical_host] = it->first;
+          break;
+        }
+      }
+    }
   }
 }
 
 void HttpServerPropertiesImpl::InitializeSpdySettingsServers(
     SpdySettingsMap* spdy_settings_map) {
-  spdy_settings_map_.swap(*spdy_settings_map);
+  for (SpdySettingsMap::reverse_iterator it = spdy_settings_map->rbegin();
+       it != spdy_settings_map->rend(); ++it) {
+    spdy_settings_map_.Put(it->first, it->second);
+  }
 }
 
 void HttpServerPropertiesImpl::InitializePipelineCapabilities(
@@ -73,16 +123,20 @@ void HttpServerPropertiesImpl::SetNumPipelinedHostsToRemember(int max_size) {
 }
 
 void HttpServerPropertiesImpl::GetSpdyServerList(
-    base::ListValue* spdy_server_list) const {
+    base::ListValue* spdy_server_list,
+    size_t max_size) const {
   DCHECK(CalledOnValidThread());
   DCHECK(spdy_server_list);
   spdy_server_list->Clear();
+  size_t count = 0;
   // Get the list of servers (host/port) that support SPDY.
-  for (SpdyServerHostPortTable::const_iterator it = spdy_servers_table_.begin();
-       it != spdy_servers_table_.end(); ++it) {
+  for (SpdyServerHostPortMap::const_iterator it = spdy_servers_map_.begin();
+       it != spdy_servers_map_.end() && count < max_size; ++it) {
     const std::string spdy_server_host_port = it->first;
-    if (it->second)
+    if (it->second) {
       spdy_server_list->Append(new base::StringValue(spdy_server_host_port));
+      ++count;
+    }
   }
 }
 
@@ -119,22 +173,22 @@ base::WeakPtr<HttpServerProperties> HttpServerPropertiesImpl::GetWeakPtr() {
 
 void HttpServerPropertiesImpl::Clear() {
   DCHECK(CalledOnValidThread());
-  spdy_servers_table_.clear();
-  alternate_protocol_map_.clear();
-  spdy_settings_map_.clear();
+  spdy_servers_map_.Clear();
+  alternate_protocol_map_.Clear();
+  spdy_settings_map_.Clear();
   pipeline_capability_map_->Clear();
 }
 
 bool HttpServerPropertiesImpl::SupportsSpdy(
-    const net::HostPortPair& host_port_pair) const {
+    const net::HostPortPair& host_port_pair) {
   DCHECK(CalledOnValidThread());
   if (host_port_pair.host().empty())
     return false;
   std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
 
-  SpdyServerHostPortTable::const_iterator spdy_host_port =
-      spdy_servers_table_.find(spdy_server);
-  if (spdy_host_port != spdy_servers_table_.end())
+  SpdyServerHostPortMap::iterator spdy_host_port =
+      spdy_servers_map_.Get(spdy_server);
+  if (spdy_host_port != spdy_servers_map_.end())
     return spdy_host_port->second;
   return false;
 }
@@ -147,33 +201,40 @@ void HttpServerPropertiesImpl::SetSupportsSpdy(
     return;
   std::string spdy_server = GetFlattenedSpdyServer(host_port_pair);
 
-  SpdyServerHostPortTable::iterator spdy_host_port =
-      spdy_servers_table_.find(spdy_server);
-  if ((spdy_host_port != spdy_servers_table_.end()) &&
+  SpdyServerHostPortMap::iterator spdy_host_port =
+      spdy_servers_map_.Get(spdy_server);
+  if ((spdy_host_port != spdy_servers_map_.end()) &&
       (spdy_host_port->second == support_spdy)) {
     return;
   }
   // Cache the data.
-  spdy_servers_table_[spdy_server] = support_spdy;
+  spdy_servers_map_.Put(spdy_server, support_spdy);
 }
 
 bool HttpServerPropertiesImpl::HasAlternateProtocol(
-    const HostPortPair& server) const {
-  return ContainsKey(alternate_protocol_map_, server) ||
-      g_forced_alternate_protocol;
+    const HostPortPair& server) {
+  if (alternate_protocol_map_.Get(server) != alternate_protocol_map_.end() ||
+      g_forced_alternate_protocol)
+    return true;
+
+  return GetCanonicalHost(server) != canonical_host_to_origin_map_.end();
 }
 
 PortAlternateProtocolPair
 HttpServerPropertiesImpl::GetAlternateProtocol(
-    const HostPortPair& server) const {
+    const HostPortPair& server) {
   DCHECK(HasAlternateProtocol(server));
 
   // First check the map.
-  AlternateProtocolMap::const_iterator it =
-      alternate_protocol_map_.find(server);
+  AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
   if (it != alternate_protocol_map_.end())
     return it->second;
 
+  // Next check the canonical host.
+  CanonicalHostMap::const_iterator canonical_host = GetCanonicalHost(server);
+  if (canonical_host != canonical_host_to_origin_map_.end())
+    return alternate_protocol_map_.Get(canonical_host->second)->second;
+
   // We must be forcing an alternate.
   DCHECK(g_forced_alternate_protocol);
   return *g_forced_alternate_protocol;
@@ -210,14 +271,68 @@ void HttpServerPropertiesImpl::SetAlternateProtocol(
                    << ", Protocol: " << alternate_protocol
                    << "].";
     }
+  } else {
+    // TODO(rch): Consider the case where multiple requests are started
+    // before the first completes. In this case, only one of the jobs
+    // would reach this code, whereas all of them should should have.
+    HistogramAlternateProtocolUsage(ALTERNATE_PROTOCOL_USAGE_MAPPING_MISSING);
   }
 
-  alternate_protocol_map_[server] = alternate;
+  alternate_protocol_map_.Put(server, alternate);
+
+  // If this host ends with a canonical suffix, then set it as the
+  // canonical host.
+  for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
+    std::string canonical_suffix = canoncial_suffixes_[i];
+    if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
+      HostPortPair canonical_host(canonical_suffix, server.port());
+      canonical_host_to_origin_map_[canonical_host] = server;
+      break;
+    }
+  }
 }
 
 void HttpServerPropertiesImpl::SetBrokenAlternateProtocol(
     const HostPortPair& server) {
-  alternate_protocol_map_[server].protocol = ALTERNATE_PROTOCOL_BROKEN;
+  AlternateProtocolMap::iterator it = alternate_protocol_map_.Get(server);
+  if (it != alternate_protocol_map_.end()) {
+    it->second.protocol = ALTERNATE_PROTOCOL_BROKEN;
+    return;
+  }
+  PortAlternateProtocolPair alternate;
+  alternate.protocol = ALTERNATE_PROTOCOL_BROKEN;
+  alternate_protocol_map_.Put(server, alternate);
+
+  int count = ++broken_alternate_protocol_map_[server];
+  base::TimeDelta delay =
+      base::TimeDelta::FromSeconds(kBrokenAlternateProtocolDelaySecs);
+  BrokenAlternateProtocolEntry entry;
+  entry.server = server;
+  entry.when = base::TimeTicks::Now() + delay * (1 << (count - 1));
+  broken_alternate_protocol_list_.push_back(entry);
+  // If this is the only entry in the list, schedule an expiration task.
+  // Otherwse it will be rescheduled automatically when the pending
+  // task runs.
+  if (broken_alternate_protocol_list_.size() == 1) {
+    ScheduleBrokenAlternateProtocolMappingsExpiration();
+  }
+}
+
+bool HttpServerPropertiesImpl::WasAlternateProtocolRecentlyBroken(
+    const HostPortPair& server) {
+  return ContainsKey(broken_alternate_protocol_map_, server);
+}
+
+void HttpServerPropertiesImpl::ConfirmAlternateProtocol(
+    const HostPortPair& server) {
+  broken_alternate_protocol_map_.erase(server);
+}
+
+void HttpServerPropertiesImpl::ClearAlternateProtocol(
+    const HostPortPair& server) {
+  AlternateProtocolMap::iterator it = alternate_protocol_map_.Peek(server);
+  if (it != alternate_protocol_map_.end())
+    alternate_protocol_map_.Erase(it);
 }
 
 const AlternateProtocolMap&
@@ -226,8 +341,8 @@ HttpServerPropertiesImpl::alternate_protocol_map() const {
 }
 
 const SettingsMap& HttpServerPropertiesImpl::GetSpdySettings(
-    const HostPortPair& host_port_pair) const {
-  SpdySettingsMap::const_iterator it = spdy_settings_map_.find(host_port_pair);
+    const HostPortPair& host_port_pair) {
+  SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
   if (it == spdy_settings_map_.end()) {
     CR_DEFINE_STATIC_LOCAL(SettingsMap, kEmptySettingsMap, ());
     return kEmptySettingsMap;
@@ -243,19 +358,28 @@ bool HttpServerPropertiesImpl::SetSpdySetting(
   if (!(flags & SETTINGS_FLAG_PLEASE_PERSIST))
       return false;
 
-  SettingsMap& settings_map = spdy_settings_map_[host_port_pair];
   SettingsFlagsAndValue flags_and_value(SETTINGS_FLAG_PERSISTED, value);
-  settings_map[id] = flags_and_value;
+  SpdySettingsMap::iterator it = spdy_settings_map_.Get(host_port_pair);
+  if (it == spdy_settings_map_.end()) {
+    SettingsMap settings_map;
+    settings_map[id] = flags_and_value;
+    spdy_settings_map_.Put(host_port_pair, settings_map);
+  } else {
+    SettingsMap& settings_map = it->second;
+    settings_map[id] = flags_and_value;
+  }
   return true;
 }
 
 void HttpServerPropertiesImpl::ClearSpdySettings(
     const HostPortPair& host_port_pair) {
-  spdy_settings_map_.erase(host_port_pair);
+  SpdySettingsMap::iterator it = spdy_settings_map_.Peek(host_port_pair);
+  if (it != spdy_settings_map_.end())
+    spdy_settings_map_.Erase(it);
 }
 
 void HttpServerPropertiesImpl::ClearAllSpdySettings() {
-  spdy_settings_map_.clear();
+  spdy_settings_map_.Clear();
 }
 
 const SpdySettingsMap&
@@ -317,4 +441,48 @@ HttpServerPropertiesImpl::GetPipelineCapabilityMap() const {
   return result;
 }
 
+HttpServerPropertiesImpl::CanonicalHostMap::const_iterator
+HttpServerPropertiesImpl::GetCanonicalHost(HostPortPair server) const {
+  for (size_t i = 0; i < canoncial_suffixes_.size(); ++i) {
+    std::string canonical_suffix = canoncial_suffixes_[i];
+    if (EndsWith(server.host(), canoncial_suffixes_[i], false)) {
+      HostPortPair canonical_host(canonical_suffix, server.port());
+      return canonical_host_to_origin_map_.find(canonical_host);
+    }
+  }
+
+  return canonical_host_to_origin_map_.end();
+}
+
+void HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings() {
+  base::TimeTicks now = base::TimeTicks::Now();
+  while (!broken_alternate_protocol_list_.empty()) {
+    BrokenAlternateProtocolEntry entry =
+        broken_alternate_protocol_list_.front();
+    if (now < entry.when) {
+      break;
+    }
+
+    ClearAlternateProtocol(entry.server);
+    broken_alternate_protocol_list_.pop_front();
+  }
+  ScheduleBrokenAlternateProtocolMappingsExpiration();
+}
+
+void
+HttpServerPropertiesImpl::ScheduleBrokenAlternateProtocolMappingsExpiration() {
+  if (broken_alternate_protocol_list_.empty()) {
+    return;
+  }
+  base::TimeTicks now = base::TimeTicks::Now();
+  base::TimeTicks when = broken_alternate_protocol_list_.front().when;
+  base::TimeDelta delay = when > now ? when - now : base::TimeDelta();
+  base::MessageLoop::current()->PostDelayedTask(
+      FROM_HERE,
+      base::Bind(
+          &HttpServerPropertiesImpl::ExpireBrokenAlternateProtocolMappings,
+          weak_ptr_factory_.GetWeakPtr()),
+      delay);
+}
+
 }  // namespace net