0

Introduce net::HttpServerPropertiesManager to manage server-specific properties.

Currently the only property we manage is whether or not a server supports SPDY, as indicated by NPN. Also introduce a chrome/ implementation of HttpServerPropertiesManager that persists the information to Prefererences.

When we get a SpdySession for a SPDY server, record that that server supports SPDY in HttpServerPropertiesManager. When preconnecting, if we know that the server supports SPDY, only preconnect 1 socket.

R=willchan
BUG=66472
TEST=browser ui and unit tests,network unit tests

Review URL: http://codereview.chromium.org/7827033

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@104666 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
rtenneti@chromium.org
2011-10-09 02:01:54 +00:00
parent b7333cbad3
commit db96a88617
39 changed files with 1166 additions and 24 deletions

@ -296,8 +296,9 @@ void BrowsingDataRemover::Remove(int remove_mask) {
}
}
// Also delete cached TransportSecurityState data.
profile_->DeleteTransportSecurityStateSince(delete_begin_);
// Also delete cached network related data (like TransportSecurityState,
// HttpServerProperties data).
profile_->ClearNetworkingHistorySince(delete_begin_);
NotifyAndDeleteIfDone();
}

@ -260,6 +260,9 @@ ConstructProxyScriptFetcherContext(IOThread::Globals* globals,
context->set_origin_bound_cert_service(
globals->system_origin_bound_cert_service.get());
context->set_network_delegate(globals->system_network_delegate.get());
// TODO(rtenneti): We should probably use HttpServerPropertiesManager for the
// system URLRequestContext too. There's no reason this should be tied to a
// profile.
return context;
}
@ -453,6 +456,9 @@ void IOThread::Init() {
session_params.http_auth_handler_factory =
globals_->http_auth_handler_factory.get();
session_params.network_delegate = globals_->system_network_delegate.get();
// TODO(rtenneti): We should probably use HttpServerPropertiesManager for the
// system URLRequestContext too. There's no reason this should be tied to a
// profile.
session_params.net_log = net_log_;
session_params.ssl_config_service = globals_->ssl_config_service;
scoped_refptr<net::HttpNetworkSession> network_session(

@ -0,0 +1,220 @@
// Copyright (c) 2011 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 "chrome/browser/net/http_server_properties_manager.h"
#include "base/bind.h"
#include "base/stl_util.h"
#include "base/values.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_details.h"
#include "content/common/notification_source.h"
namespace chrome_browser_net {
namespace {
// Time to wait before starting an update the spdy_servers_table_ cache from
// preferences. Scheduling another update during this period will reset the
// timer.
const int64 kUpdateCacheDelayMs = 1000;
// Time to wait before starting an update the preferences from the
// spdy_servers cache. Scheduling another update during this period will
// reset the timer.
const int64 kUpdatePrefsDelayMs = 5000;
typedef std::vector<std::string> StringVector;
// String is host/port pair of spdy server.
StringVector* ListValueToStringVector(const base::ListValue* list) {
StringVector* vector = new StringVector;
if (!list)
return vector;
vector->reserve(list->GetSize());
std::string s;
for (base::ListValue::const_iterator it = list->begin();
it != list->end(); ++it) {
if ((*it)->GetAsString(&s))
vector->push_back(s);
}
return vector;
}
} // namespace
////////////////////////////////////////////////////////////////////////////////
// HttpServerPropertiesManager
HttpServerPropertiesManager::HttpServerPropertiesManager(
PrefService* pref_service)
: ALLOW_THIS_IN_INITIALIZER_LIST(ui_method_factory_(this)),
pref_service_(pref_service) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(pref_service);
ui_weak_ptr_factory_.reset(
new base::WeakPtrFactory<HttpServerPropertiesManager>(this));
ui_weak_ptr_ = ui_weak_ptr_factory_->GetWeakPtr();
pref_change_registrar_.Init(pref_service_);
pref_change_registrar_.Add(prefs::kSpdyServers, this);
}
HttpServerPropertiesManager::~HttpServerPropertiesManager() {
}
void HttpServerPropertiesManager::InitializeOnIOThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
http_server_properties_impl_.reset(new net::HttpServerPropertiesImpl());
io_method_factory_.reset(
new ScopedRunnableMethodFactory<HttpServerPropertiesManager>(this));
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefs,
ui_weak_ptr_));
}
void HttpServerPropertiesManager::ShutdownOnUIThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Cancel any pending updates, and stop listening for pref change updates.
ui_method_factory_.RevokeAll();
ui_weak_ptr_factory_.reset();
pref_change_registrar_.RemoveAll();
}
bool HttpServerPropertiesManager::SupportsSpdy(
const net::HostPortPair& server) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
return http_server_properties_impl_->SupportsSpdy(server);
}
void HttpServerPropertiesManager::SetSupportsSpdy(
const net::HostPortPair& server,
bool support_spdy) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
http_server_properties_impl_->SetSupportsSpdy(server, support_spdy);
ScheduleUpdatePrefsOnIO();
}
void HttpServerPropertiesManager::DeleteAll() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
http_server_properties_impl_->DeleteAll();
ScheduleUpdatePrefsOnIO();
}
// static
void HttpServerPropertiesManager::RegisterPrefs(PrefService* prefs) {
prefs->RegisterListPref(prefs::kSpdyServers, PrefService::UNSYNCABLE_PREF);
}
//
// Update spdy_servers (the cached data) with data from preferences.
//
void HttpServerPropertiesManager::ScheduleUpdateCacheOnUI() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Cancel pending updates, if any.
ui_method_factory_.RevokeAll();
PostUpdateTaskOnUI(
ui_method_factory_.NewRunnableMethod(
&HttpServerPropertiesManager::UpdateCacheFromPrefs));
}
void HttpServerPropertiesManager::PostUpdateTaskOnUI(Task* task) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// This is overridden in tests to post the task without the delay.
MessageLoop::current()->PostDelayedTask(FROM_HERE, task, kUpdateCacheDelayMs);
}
void HttpServerPropertiesManager::UpdateCacheFromPrefs() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (!pref_service_->HasPrefPath(prefs::kSpdyServers))
return;
// The preferences can only be read on the UI thread.
StringVector* spdy_servers =
ListValueToStringVector(pref_service_->GetList(prefs::kSpdyServers));
// Go through the IO thread to grab a WeakPtr to |this|. This is safe from
// here, since this task will always execute before a potential deletion of
// ProfileIOData on IO.
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&HttpServerPropertiesManager::UpdateCacheFromPrefsOnIO,
base::Unretained(this), spdy_servers, true));
}
void HttpServerPropertiesManager::UpdateCacheFromPrefsOnIO(
StringVector* spdy_servers,
bool support_spdy) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// Preferences have the master data because admins might have pushed new
// preferences. Clear the cached data and use the new spdy server list from
// preferences.
scoped_ptr<StringVector> scoped_spdy_servers(spdy_servers);
http_server_properties_impl_->Initialize(spdy_servers, support_spdy);
}
//
// Update Preferences with data from spdy_servers (the cached data).
//
void HttpServerPropertiesManager::ScheduleUpdatePrefsOnIO() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// Cancel pending updates, if any.
io_method_factory_->RevokeAll();
PostUpdateTaskOnIO(
io_method_factory_->NewRunnableMethod(
&HttpServerPropertiesManager::UpdatePrefsFromCache));
}
void HttpServerPropertiesManager::PostUpdateTaskOnIO(Task* task) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// This is overridden in tests to post the task without the delay.
MessageLoop::current()->PostDelayedTask(FROM_HERE, task, kUpdatePrefsDelayMs);
}
void HttpServerPropertiesManager::UpdatePrefsFromCache() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
scoped_refptr<RefCountedListValue> spdy_server_list =
new RefCountedListValue();
http_server_properties_impl_->GetSpdyServerList(&spdy_server_list->data);
// Update the preferences on the UI thread.
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(&HttpServerPropertiesManager::SetSpdyServersInPrefsOnUI,
ui_weak_ptr_, spdy_server_list));
}
void HttpServerPropertiesManager::SetSpdyServersInPrefsOnUI(
scoped_refptr<RefCountedListValue> spdy_server_list) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
pref_service_->Set(prefs::kSpdyServers, spdy_server_list->data);
}
void HttpServerPropertiesManager::Observe(int type,
const NotificationSource& source,
const NotificationDetails& details) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(type == chrome::NOTIFICATION_PREF_CHANGED);
PrefService* prefs = Source<PrefService>(source).ptr();
DCHECK(prefs == pref_service_);
std::string* pref_name = Details<std::string>(details).ptr();
DCHECK(*pref_name == prefs::kSpdyServers);
ScheduleUpdateCacheOnUI();
}
} // namespace chrome_browser_net

@ -0,0 +1,154 @@
// Copyright (c) 2011 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.
#ifndef CHROME_BROWSER_NET_HTTP_SERVER_PROPERTIES_MANAGER_H_
#define CHROME_BROWSER_NET_HTTP_SERVER_PROPERTIES_MANAGER_H_
#pragma once
#include "base/basictypes.h"
#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/task.h"
#include "base/values.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "content/common/notification_observer.h"
#include "net/base/host_port_pair.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_server_properties_impl.h"
class NotificationDetails;
class NotificationSource;
class PrefService;
namespace chrome_browser_net {
////////////////////////////////////////////////////////////////////////////////
// HttpServerPropertiesManager
// The manager for creating and updating an HttpServerProperties (for example it
// tracks if a server supports SPDY or not).
//
// This class interacts with both the UI thread, where notifications of pref
// changes are received from, and the IO thread, which owns it (in the
// ProfileIOData) and it persists the changes from network stack that if a
// server supports SPDY or not.
//
// It must be constructed on the UI thread, to set up |ui_method_factory_| and
// the prefs listeners.
//
// ShutdownOnUIThread must be called from UI before destruction, to release
// the prefs listeners on the UI thread. This is done from ProfileIOData.
//
// Update tasks from the UI thread can post safely to the IO thread, since the
// destruction order of Profile and ProfileIOData guarantees that if this
// exists in UI, then a potential destruction on IO will come after any task
// posted to IO from that method on UI. This is used to go through IO before
// the actual update starts, and grab a WeakPtr.
class HttpServerPropertiesManager
: public net::HttpServerProperties,
public NotificationObserver {
public:
// Create an instance of the HttpServerPropertiesManager. The lifetime of the
// PrefService objects must be longer than that of the
// HttpServerPropertiesManager object. Must be constructed on the UI thread.
explicit HttpServerPropertiesManager(PrefService* pref_service);
virtual ~HttpServerPropertiesManager();
// Initialize |http_server_properties_impl_| and |io_method_factory_| on IO
// thread. It also posts a task to UI thread to get SPDY Server preferences
// from |pref_service_|.
void InitializeOnIOThread();
// Prepare for shutdown. Must be called on the UI thread, before destruction.
void ShutdownOnUIThread();
// Returns true if |server| supports SPDY. Should only be called from IO
// thread.
virtual bool SupportsSpdy(const net::HostPortPair& server) const OVERRIDE;
// Add |server| as the SPDY server which supports SPDY protocol into the
// persisitent store. Should only be called from IO thread.
virtual void SetSupportsSpdy(const net::HostPortPair& server,
bool support_spdy) OVERRIDE;
// Deletes all data.
virtual void DeleteAll() OVERRIDE;
// Register |prefs| SPDY preferences.
static void RegisterPrefs(PrefService* prefs);
protected:
typedef base::RefCountedData<base::ListValue> RefCountedListValue;
// These are used to delay updating the spdy servers in
// |http_server_properties_impl_| while the preferences are changing, and
// execute only one update per simultaneous prefs changes.
void ScheduleUpdateCacheOnUI();
// Update spdy servers (the cached data in |http_server_properties_impl_|)
// with data from preferences. Virtual for testing.
virtual void UpdateCacheFromPrefs();
// Starts the |spdy_servers| update on the IO thread. Protected for testing.
void UpdateCacheFromPrefsOnIO(StringVector* spdy_servers, bool support_spdy);
// These are used to delay updating the preferences when spdy servers_ are
// changing, and execute only one update per simultaneous spdy server changes.
void ScheduleUpdatePrefsOnIO();
// Update spdy servers in preferences with the cached data from
// |http_server_properties_impl_|. Virtual for testing.
virtual void UpdatePrefsFromCache(); // Virtual for testing.
// Update |prefs::kSpdyServers| preferences with |spdy_server_list| on UI
// thread. Protected for testing.
void SetSpdyServersInPrefsOnUI(
scoped_refptr<RefCountedListValue> spdy_server_list);
private:
// Post the tasks with the delay. These are overridden in tests to post the
// task without the delay.
virtual void PostUpdateTaskOnUI(Task* task); // Virtual for testing.
virtual void PostUpdateTaskOnIO(Task* task); // Virtual for testing.
// Callback for preference changes.
virtual void Observe(int type,
const NotificationSource& source,
const NotificationDetails& details);
// ---------
// UI thread
// ---------
// Used to post update tasks to the UI thread.
ScopedRunnableMethodFactory<HttpServerPropertiesManager> ui_method_factory_;
// Used to get |weak_ptr_| to self on the UI thread.
scoped_ptr<base::WeakPtrFactory<HttpServerPropertiesManager> >
ui_weak_ptr_factory_;
base::WeakPtr<HttpServerPropertiesManager> ui_weak_ptr_;
// Used to track the spdy servers changes.
PrefChangeRegistrar pref_change_registrar_;
PrefService* pref_service_; // Weak.
// ---------
// IO thread
// ---------
// Used to post update tasks to the IO thread.
scoped_ptr<ScopedRunnableMethodFactory<HttpServerPropertiesManager> >
io_method_factory_;
scoped_ptr<net::HttpServerPropertiesImpl> http_server_properties_impl_;
DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesManager);
};
} // namespace chrome_browser_net
#endif // CHROME_BROWSER_NET_HTTP_SERVER_PROPERTIES_MANAGER_H_

@ -0,0 +1,276 @@
// Copyright (c) 2011 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 "chrome/browser/net/http_server_properties_manager.h"
#include "base/basictypes.h"
#include "base/message_loop.h"
#include "base/values.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_pref_service.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_service.h"
#include "googleurl/src/gurl.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chrome_browser_net {
namespace {
using ::testing::_;
using ::testing::Invoke;
using ::testing::Mock;
class TestingHttpServerPropertiesManager : public HttpServerPropertiesManager {
public:
explicit TestingHttpServerPropertiesManager(PrefService* pref_service)
: HttpServerPropertiesManager(pref_service) {
InitializeOnIOThread();
}
virtual ~TestingHttpServerPropertiesManager() {
}
// Make this method public for testing.
using HttpServerPropertiesManager::ScheduleUpdateCacheOnUI;
using HttpServerPropertiesManager::ScheduleUpdatePrefsOnIO;
// Post tasks without a delay during tests.
virtual void PostUpdateTaskOnUI(Task* task) OVERRIDE {
MessageLoop::current()->PostTask(FROM_HERE, task);
}
// Makes a direct call to UpdateCacheFromPrefsOnIO during tests.
void UpdateCacheFromPrefsOnIO() {
StringVector* spdy_servers = new StringVector;
spdy_servers->push_back("www.google.com:443");
HttpServerPropertiesManager::UpdateCacheFromPrefsOnIO(spdy_servers, true);
}
void UpdateCacheFromPrefsConcrete() {
HttpServerPropertiesManager::UpdateCacheFromPrefs();
}
// Post tasks without a delay during tests.
virtual void PostUpdateTaskOnIO(Task* task) OVERRIDE {
MessageLoop::current()->PostTask(FROM_HERE, task);
}
// Makes a direct call to SetSpdyServersInPrefsOnUI during tests.
void SetSpdyServersInPrefsOnUI() {
net::HostPortPair spdy_server_mail("mail.google.com", 443);
std::string spdy_server_m =
net::HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_mail);
scoped_refptr<RefCountedListValue> spdy_server_list =
new RefCountedListValue();
spdy_server_list->data.Append(new StringValue(spdy_server_m));
HttpServerPropertiesManager::SetSpdyServersInPrefsOnUI(spdy_server_list);
}
void UpdatePrefsFromCacheConcrete() {
HttpServerPropertiesManager::UpdatePrefsFromCache();
}
MOCK_METHOD0(UpdateCacheFromPrefs, void());
MOCK_METHOD0(UpdatePrefsFromCache, void());
MOCK_METHOD2(UpdateCacheFromPrefsOnIO,
void(StringVector* spdy_servers, bool support_spdy));
MOCK_METHOD1(SetSpdyServersInPrefsOnUI,
void(scoped_refptr<RefCountedListValue> spdy_server_list));
private:
DISALLOW_COPY_AND_ASSIGN(TestingHttpServerPropertiesManager);
};
class HttpServerPropertiesManagerTest : public testing::Test {
protected:
HttpServerPropertiesManagerTest()
: ui_thread_(BrowserThread::UI, &loop_),
io_thread_(BrowserThread::IO, &loop_) {
}
virtual void SetUp() OVERRIDE {
pref_service_.RegisterListPref(prefs::kSpdyServers);
http_server_props_manager_.reset(
new TestingHttpServerPropertiesManager(&pref_service_));
loop_.RunAllPending();
}
virtual void TearDown() OVERRIDE {
if (http_server_props_manager_.get())
http_server_props_manager_->ShutdownOnUIThread();
loop_.RunAllPending();
// Delete |http_server_props_manager_| while |io_thread_| is mapping IO to
// |loop_|.
http_server_props_manager_.reset();
}
void ExpectCacheUpdate() {
EXPECT_CALL(*http_server_props_manager_, UpdateCacheFromPrefs())
.WillOnce(
Invoke(http_server_props_manager_.get(),
&TestingHttpServerPropertiesManager::UpdateCacheFromPrefsConcrete));
}
void ExpectPrefsUpdate() {
EXPECT_CALL(*http_server_props_manager_, UpdatePrefsFromCache())
.WillOnce(
Invoke(http_server_props_manager_.get(),
&TestingHttpServerPropertiesManager::UpdatePrefsFromCacheConcrete));
}
MessageLoop loop_;
TestingPrefService pref_service_;
scoped_ptr<TestingHttpServerPropertiesManager> http_server_props_manager_;
private:
BrowserThread ui_thread_;
BrowserThread io_thread_;
DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesManagerTest);
};
TEST_F(HttpServerPropertiesManagerTest, SingleUpdateForTwoPrefChanges) {
ExpectCacheUpdate();
ListValue* http_server_props = new ListValue;
http_server_props->Append(new StringValue("www.google.com:443"));
http_server_props->Append(new StringValue("mail.google.com:443"));
pref_service_.SetManagedPref(prefs::kSpdyServers, http_server_props);
loop_.RunAllPending();
Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
}
TEST_F(HttpServerPropertiesManagerTest, SupportsSpdy) {
ExpectPrefsUpdate();
// Post an update task to the IO thread. SetSupportsSpdy calls
// ScheduleUpdatePrefsOnIO.
// Add mail.google.com:443 as a supporting spdy server.
net::HostPortPair spdy_server_mail("mail.google.com", 443);
EXPECT_FALSE(http_server_props_manager_->SupportsSpdy(spdy_server_mail));
http_server_props_manager_->SetSupportsSpdy(spdy_server_mail, true);
// Run the task.
loop_.RunAllPending();
EXPECT_TRUE(http_server_props_manager_->SupportsSpdy(spdy_server_mail));
Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
}
TEST_F(HttpServerPropertiesManagerTest, DeleteAll) {
ExpectPrefsUpdate();
// Add mail.google.com:443 as a supporting spdy server.
net::HostPortPair spdy_server_mail("mail.google.com", 443);
http_server_props_manager_->SetSupportsSpdy(spdy_server_mail, true);
// Run the task.
loop_.RunAllPending();
EXPECT_TRUE(http_server_props_manager_->SupportsSpdy(spdy_server_mail));
Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
// DeleteAll http server data.
http_server_props_manager_->DeleteAll();
// Run the task.
loop_.RunAllPending();
EXPECT_FALSE(http_server_props_manager_->SupportsSpdy(spdy_server_mail));
Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
}
//
// Tests for shutdown when updating cache.
//
TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache0) {
EXPECT_CALL(*http_server_props_manager_,
UpdateCacheFromPrefsOnIO(_, _)).Times(0);
// Post an update task to the UI thread.
http_server_props_manager_->ScheduleUpdateCacheOnUI();
// Shutdown comes before the task is executed.
http_server_props_manager_->ShutdownOnUIThread();
http_server_props_manager_.reset();
// Run the task after shutdown and deletion.
loop_.RunAllPending();
}
TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache1) {
EXPECT_CALL(*http_server_props_manager_, UpdateCacheFromPrefs()).Times(0);
// Post an update task.
http_server_props_manager_->ScheduleUpdateCacheOnUI();
// Shutdown comes before the task is executed.
http_server_props_manager_->ShutdownOnUIThread();
// Run the task after shutdown, but before deletion.
loop_.RunAllPending();
Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
http_server_props_manager_.reset();
loop_.RunAllPending();
}
TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdateCache2) {
EXPECT_CALL(*http_server_props_manager_,
UpdateCacheFromPrefsOnIO(_, _)).Times(0);
http_server_props_manager_->UpdateCacheFromPrefsConcrete();
// Shutdown comes before the task is executed.
http_server_props_manager_->ShutdownOnUIThread();
// Run the task after shutdown, but before deletion.
loop_.RunAllPending();
Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
http_server_props_manager_.reset();
loop_.RunAllPending();
}
//
// Tests for shutdown when updating prefs.
//
TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs0) {
EXPECT_CALL(*http_server_props_manager_,
SetSpdyServersInPrefsOnUI(_)).Times(0);
// Post an update task to the IO thread.
http_server_props_manager_->ScheduleUpdatePrefsOnIO();
// Shutdown comes before the task is executed.
http_server_props_manager_->ShutdownOnUIThread();
http_server_props_manager_.reset();
// Run the task after shutdown and deletion.
loop_.RunAllPending();
}
TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs1) {
EXPECT_CALL(*http_server_props_manager_,
SetSpdyServersInPrefsOnUI(_)).Times(0);
// Post an update task.
http_server_props_manager_->ScheduleUpdatePrefsOnIO();
// Shutdown comes before the task is executed.
http_server_props_manager_->ShutdownOnUIThread();
// Run the task after shutdown, but before deletion.
loop_.RunAllPending();
Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
http_server_props_manager_.reset();
loop_.RunAllPending();
}
TEST_F(HttpServerPropertiesManagerTest, ShutdownWithPendingUpdatePrefs2) {
EXPECT_CALL(*http_server_props_manager_,
SetSpdyServersInPrefsOnUI(_)).Times(0);
// This posts a task to the UI thread.
http_server_props_manager_->UpdatePrefsFromCacheConcrete();
// Shutdown comes before the task is executed.
http_server_props_manager_->ShutdownOnUIThread();
// Run the task after shutdown, but before deletion.
loop_.RunAllPending();
Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
http_server_props_manager_.reset();
loop_.RunAllPending();
}
} // namespace
} // namespace chrome_browser_net

@ -25,6 +25,7 @@
#include "chrome/browser/intranet_redirect_detector.h"
#include "chrome/browser/metrics/metrics_log.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "chrome/browser/net/http_server_properties_manager.h"
#include "chrome/browser/net/net_pref_observer.h"
#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/pref_proxy_config_service.h"
@ -186,6 +187,7 @@ void RegisterUserPrefs(PrefService* user_prefs) {
#if defined(ENABLE_CONFIGURATION_POLICY)
policy::URLBlacklistManager::RegisterPrefs(user_prefs);
#endif
chrome_browser_net::HttpServerPropertiesManager::RegisterPrefs(user_prefs);
}
void MigrateBrowserPrefs(PrefService* user_prefs, PrefService* local_state) {

@ -53,6 +53,7 @@
#include "content/browser/tab_contents/tab_contents.h"
#include "content/common/notification_service.h"
#include "net/base/transport_security_state.h"
#include "net/http/http_server_properties.h"
#include "webkit/database/database_tracker.h"
#include "webkit/quota/quota_manager.h"
@ -584,8 +585,7 @@ chrome_browser_net::Predictor* OffTheRecordProfileImpl::GetNetworkPredictor() {
return NULL;
}
void OffTheRecordProfileImpl::DeleteTransportSecurityStateSince(
base::Time time) {
void OffTheRecordProfileImpl::ClearNetworkingHistorySince(base::Time time) {
// No need to do anything here, our transport security state is read-only.
}

@ -128,7 +128,7 @@ class OffTheRecordProfileImpl : public Profile,
virtual PrefProxyConfigTracker* GetProxyConfigTracker() OVERRIDE;
virtual chrome_browser_net::Predictor* GetNetworkPredictor() OVERRIDE;
virtual void DeleteTransportSecurityStateSince(base::Time time) OVERRIDE;
virtual void ClearNetworkingHistorySince(base::Time time) OVERRIDE;
// NotificationObserver implementation.
virtual void Observe(int type,

@ -197,6 +197,7 @@ void OffTheRecordProfileIOData::LazyInitializeInternal(
main_context->ssl_config_service(),
main_context->http_auth_handler_factory(),
main_context->network_delegate(),
main_context->http_server_properties(),
main_context->net_log(),
main_backend);

@ -482,10 +482,11 @@ class Profile : public content::BrowserContext {
// Returns the Predictor object used for dns prefetch.
virtual chrome_browser_net::Predictor* GetNetworkPredictor() = 0;
// Deletes transport security state since |time|. The implementation
// is free to run this on a background thread, so when this method
// returns data is not guaranteed to be deleted.
virtual void DeleteTransportSecurityStateSince(base::Time time) = 0;
// Deletes all network related data since |time|. It deletes transport
// security state since |time| and it also delete HttpServerProperties data.
// The implementation is free to run this on a background thread, so when this
// method returns data is not guaranteed to be deleted.
virtual void ClearNetworkingHistorySince(base::Time time) = 0;
std::string GetDebugName();

@ -106,6 +106,7 @@
#include "grit/browser_resources.h"
#include "grit/locale_settings.h"
#include "net/base/transport_security_state.h"
#include "net/http/http_server_properties.h"
#include "ui/base/resource/resource_bundle.h"
#include "webkit/database/database_tracker.h"
#include "webkit/quota/quota_manager.h"
@ -1752,8 +1753,8 @@ chrome_browser_net::Predictor* ProfileImpl::GetNetworkPredictor() {
return predictor_;
}
void ProfileImpl::DeleteTransportSecurityStateSince(base::Time time) {
io_data_.DeleteTransportSecurityStateSince(time);
void ProfileImpl::ClearNetworkingHistorySince(base::Time time) {
io_data_.ClearNetworkingHistorySince(time);
}
SpellCheckProfile* ProfileImpl::GetSpellCheckProfile() {

@ -130,7 +130,7 @@ class ProfileImpl : public Profile,
virtual PromoCounter* GetInstantPromoCounter() OVERRIDE;
virtual ChromeURLDataManager* GetChromeURLDataManager() OVERRIDE;
virtual chrome_browser_net::Predictor* GetNetworkPredictor() OVERRIDE;
virtual void DeleteTransportSecurityStateSince(base::Time time) OVERRIDE;
virtual void ClearNetworkingHistorySince(base::Time time) OVERRIDE;
#if defined(OS_CHROMEOS)
virtual void ChangeAppLocale(const std::string& locale,

@ -13,6 +13,7 @@
#include "chrome/browser/net/chrome_net_log.h"
#include "chrome/browser/net/chrome_network_delegate.h"
#include "chrome/browser/net/connect_interceptor.h"
#include "chrome/browser/net/http_server_properties_manager.h"
#include "chrome/browser/net/predictor.h"
#include "chrome/browser/net/sqlite_origin_bound_cert_store.h"
#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
@ -31,10 +32,11 @@
namespace {
void DeleteTransportSecurityStateSinceOnIOThread(
void ClearNetworkingHistorySinceOnIOThread(
ProfileImplIOData* io_data, base::Time time) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
io_data->transport_security_state()->DeleteSince(time);
io_data->http_server_properties()->DeleteAll();
}
} // namespace
@ -71,6 +73,8 @@ ProfileImplIOData::Handle::~Handle() {
iter->second->CleanupOnUIThread();
}
if (io_data_->http_server_properties_manager_.get())
io_data_->http_server_properties_manager_->ShutdownOnUIThread();
io_data_->ShutdownOnUIThread();
}
@ -186,7 +190,7 @@ ProfileImplIOData::Handle::GetIsolatedAppRequestContextGetter(
return context;
}
void ProfileImplIOData::Handle::DeleteTransportSecurityStateSince(
void ProfileImplIOData::Handle::ClearNetworkingHistorySince(
base::Time time) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
LazyInitialize();
@ -194,7 +198,7 @@ void ProfileImplIOData::Handle::DeleteTransportSecurityStateSince(
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(
&DeleteTransportSecurityStateSinceOnIOThread,
&ClearNetworkingHistorySinceOnIOThread,
io_data_,
time));
}
@ -202,14 +206,17 @@ void ProfileImplIOData::Handle::DeleteTransportSecurityStateSince(
void ProfileImplIOData::Handle::LazyInitialize() const {
if (!initialized_) {
io_data_->InitializeOnUIThread(profile_);
PrefService* pref_service = profile_->GetPrefs();
io_data_->http_server_properties_manager_.reset(
new chrome_browser_net::HttpServerPropertiesManager(pref_service));
ChromeNetworkDelegate::InitializeReferrersEnabled(
io_data_->enable_referrers(), profile_->GetPrefs());
io_data_->enable_referrers(), pref_service);
io_data_->clear_local_state_on_exit()->Init(
prefs::kClearSiteDataOnExit, profile_->GetPrefs(), NULL);
prefs::kClearSiteDataOnExit, pref_service, NULL);
io_data_->clear_local_state_on_exit()->MoveToThread(BrowserThread::IO);
#if defined(ENABLE_SAFE_BROWSING)
io_data_->safe_browsing_enabled()->Init(prefs::kSafeBrowsingEnabled,
profile_->GetPrefs(), NULL);
pref_service, NULL);
io_data_->safe_browsing_enabled()->MoveToThread(BrowserThread::IO);
#endif
initialized_ = true;
@ -248,6 +255,9 @@ void ProfileImplIOData::LazyInitializeInternal(
ApplyProfileParamsToContext(media_request_context_);
ApplyProfileParamsToContext(extensions_context);
if (http_server_properties_manager_.get())
http_server_properties_manager_->InitializeOnIOThread();
main_context->set_transport_security_state(transport_security_state());
media_request_context_->set_transport_security_state(
transport_security_state());
@ -260,6 +270,9 @@ void ProfileImplIOData::LazyInitializeInternal(
main_context->set_network_delegate(network_delegate());
media_request_context_->set_network_delegate(network_delegate());
main_context->set_http_server_properties(http_server_properties());
media_request_context_->set_http_server_properties(http_server_properties());
main_context->set_host_resolver(
io_thread_globals->host_resolver.get());
media_request_context_->set_host_resolver(
@ -353,6 +366,7 @@ void ProfileImplIOData::LazyInitializeInternal(
main_context->ssl_config_service(),
main_context->http_auth_handler_factory(),
main_context->network_delegate(),
main_context->http_server_properties(),
main_context->net_log(),
main_backend);
@ -391,6 +405,10 @@ void ProfileImplIOData::LazyInitializeInternal(
lazy_params_.reset();
}
net::HttpServerProperties* ProfileImplIOData::http_server_properties() const {
return http_server_properties_manager_.get();
}
scoped_refptr<ChromeURLRequestContext>
ProfileImplIOData::InitializeAppRequestContext(
scoped_refptr<ChromeURLRequestContext> main_context,

@ -13,10 +13,12 @@
#include "chrome/browser/profiles/profile_io_data.h"
namespace chrome_browser_net {
class HttpServerPropertiesManager;
class Predictor;
}
namespace net {
class HttpServerProperties;
class HttpTransactionFactory;
} // namespace net
@ -58,7 +60,7 @@ class ProfileImplIOData : public ProfileIOData {
GetIsolatedAppRequestContextGetter(
const std::string& app_id) const;
void DeleteTransportSecurityStateSince(base::Time time);
void ClearNetworkingHistorySince(base::Time time);
private:
typedef base::hash_map<std::string,
@ -94,6 +96,8 @@ class ProfileImplIOData : public ProfileIOData {
DISALLOW_COPY_AND_ASSIGN(Handle);
};
net::HttpServerProperties* http_server_properties() const;
private:
friend class base::RefCountedThreadSafe<ProfileImplIOData>;
@ -137,6 +141,8 @@ class ProfileImplIOData : public ProfileIOData {
mutable scoped_ptr<net::HttpTransactionFactory> media_http_factory_;
mutable scoped_ptr<chrome_browser_net::Predictor> predictor_;
mutable scoped_ptr<chrome_browser_net::HttpServerPropertiesManager>
http_server_properties_manager_;
// Parameters needed for isolated apps.
FilePath app_path_;

@ -1582,6 +1582,8 @@
'browser/net/sqlite_origin_bound_cert_store.h',
'browser/net/sqlite_persistent_cookie_store.cc',
'browser/net/sqlite_persistent_cookie_store.h',
'browser/net/http_server_properties_manager.h',
'browser/net/http_server_properties_manager.cc',
'browser/net/ssl_config_service_manager.h',
'browser/net/ssl_config_service_manager_pref.cc',
'browser/net/url_fixer_upper.cc',

@ -1371,6 +1371,7 @@
'browser/net/gaia/gaia_oauth_fetcher_unittest.cc',
'browser/net/gaia/token_service_unittest.cc',
'browser/net/gaia/token_service_unittest.h',
'browser/net/http_server_properties_manager_unittest.cc',
'browser/net/load_timing_observer_unittest.cc',
'browser/net/network_stats_unittest.cc',
'browser/net/passive_log_collector_unittest.cc',

@ -327,6 +327,9 @@ const char kDnsPrefetchingHostReferralList[] =
// Disables the SPDY protocol.
const char kDisableSpdy[] = "spdy.disabled";
// Prefs for server names that support SPDY protocol.
const char kSpdyServers[] = "spdy.servers";
// Disables the listed protocol schemes.
const char kDisabledSchemes[] = "protocol.disabled_schemes";

@ -128,6 +128,7 @@ extern const char kDnsPrefetchingStartupList[];
extern const char kDnsHostReferralList[]; // OBSOLETE
extern const char kDnsPrefetchingHostReferralList[];
extern const char kDisableSpdy[];
extern const char kSpdyServers[];
extern const char kDisabledSchemes[];
extern const char kUrlBlacklist[];
extern const char kUrlWhitelist[];

@ -788,7 +788,7 @@ chrome_browser_net::Predictor* TestingProfile::GetNetworkPredictor() {
return NULL;
}
void TestingProfile::DeleteTransportSecurityStateSince(base::Time time) {
void TestingProfile::ClearNetworkingHistorySince(base::Time time) {
NOTIMPLEMENTED();
}

@ -279,7 +279,7 @@ class TestingProfile : public Profile {
virtual PromoCounter* GetInstantPromoCounter();
virtual ChromeURLDataManager* GetChromeURLDataManager();
virtual chrome_browser_net::Predictor* GetNetworkPredictor();
virtual void DeleteTransportSecurityStateSince(base::Time time);
virtual void ClearNetworkingHistorySince(base::Time time) OVERRIDE;
virtual PrefService* GetOffTheRecordPrefs();
// TODO(jam): remove me once webkit_context_unittest.cc doesn't use Profile

@ -94,7 +94,8 @@ net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() {
proxy_service_.get(),
new net::SSLConfigServiceDefaults(),
http_auth_handler_factory_.get(),
NULL, // network_delegate
NULL, // network_delegate
NULL, // http_server_properties
net_log,
main_backend);
main_http_factory_.reset(main_cache);

@ -56,6 +56,8 @@ ProxyResolvingClientSocket::ProxyResolvingClientSocket(
session_params.http_auth_handler_factory =
request_context->http_auth_handler_factory();
session_params.network_delegate = request_context->network_delegate();
session_params.http_server_properties =
request_context->http_server_properties();
session_params.net_log = request_context->net_log();
network_session_ = new net::HttpNetworkSession(session_params);
}

@ -51,6 +51,7 @@ HttpNetworkSession* CreateNetworkSession(
SSLConfigService* ssl_config_service,
HttpAuthHandlerFactory* http_auth_handler_factory,
NetworkDelegate* network_delegate,
HttpServerProperties* http_server_properties,
NetLog* net_log) {
HttpNetworkSession::Params params;
params.host_resolver = host_resolver;
@ -63,6 +64,7 @@ HttpNetworkSession* CreateNetworkSession(
params.ssl_config_service = ssl_config_service;
params.http_auth_handler_factory = http_auth_handler_factory;
params.network_delegate = network_delegate;
params.http_server_properties = http_server_properties;
params.net_log = net_log;
return new HttpNetworkSession(params);
}
@ -321,6 +323,7 @@ HttpCache::HttpCache(HostResolver* host_resolver,
SSLConfigService* ssl_config_service,
HttpAuthHandlerFactory* http_auth_handler_factory,
NetworkDelegate* network_delegate,
HttpServerProperties* http_server_properties,
NetLog* net_log,
BackendFactory* backend_factory)
: net_log_(net_log),
@ -343,6 +346,7 @@ HttpCache::HttpCache(HostResolver* host_resolver,
ssl_config_service,
http_auth_handler_factory,
network_delegate,
http_server_properties,
net_log))),
ALLOW_THIS_IN_INITIALIZER_LIST(task_factory_(this)) {
}

@ -51,6 +51,7 @@ class HttpAuthHandlerFactory;
class HttpNetworkSession;
struct HttpRequestInfo;
class HttpResponseInfo;
class HttpServerProperties;
class IOBuffer;
class NetLog;
class NetworkDelegate;
@ -129,6 +130,7 @@ class NET_EXPORT HttpCache : public HttpTransactionFactory,
SSLConfigService* ssl_config_service,
HttpAuthHandlerFactory* http_auth_handler_factory,
NetworkDelegate* network_delegate,
HttpServerProperties* http_server_properties,
NetLog* net_log,
BackendFactory* backend_factory);

@ -25,6 +25,7 @@ namespace net {
HttpNetworkSession::HttpNetworkSession(const Params& params)
: net_log_(params.net_log),
network_delegate_(params.network_delegate),
http_server_properties_(params.http_server_properties),
cert_verifier_(params.cert_verifier),
http_auth_handler_factory_(params.http_auth_handler_factory),
proxy_service_(params.proxy_service),

@ -35,6 +35,7 @@ class HttpAuthHandlerFactory;
class HttpNetworkSessionPeer;
class HttpProxyClientSocketPool;
class HttpResponseBodyDrainer;
class HttpServerProperties;
class NetLog;
class NetworkDelegate;
class ProxyService;
@ -59,6 +60,7 @@ class NET_EXPORT HttpNetworkSession
ssl_config_service(NULL),
http_auth_handler_factory(NULL),
network_delegate(NULL),
http_server_properties(NULL),
net_log(NULL) {}
ClientSocketFactory* client_socket_factory;
@ -72,6 +74,7 @@ class NET_EXPORT HttpNetworkSession
SSLConfigService* ssl_config_service;
HttpAuthHandlerFactory* http_auth_handler_factory;
NetworkDelegate* network_delegate;
HttpServerProperties* http_server_properties;
NetLog* net_log;
};
@ -120,6 +123,9 @@ class NET_EXPORT HttpNetworkSession
NetworkDelegate* network_delegate() {
return network_delegate_;
}
HttpServerProperties* http_server_properties() {
return http_server_properties_;
}
HttpStreamFactory* http_stream_factory() {
return http_stream_factory_.get();
@ -148,6 +154,7 @@ class NET_EXPORT HttpNetworkSession
NetLog* const net_log_;
NetworkDelegate* const network_delegate_;
HttpServerProperties* const http_server_properties_;
CertVerifier* const cert_verifier_;
HttpAuthHandlerFactory* const http_auth_handler_factory_;

@ -0,0 +1,42 @@
// Copyright (c) 2011 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.
#ifndef NET_HTTP_HTTP_SERVER_PROPERTIES_H_
#define NET_HTTP_HTTP_SERVER_PROPERTIES_H_
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_export.h"
namespace net {
// The interface for setting/retrieving the HTTP server properties.
class NET_EXPORT HttpServerProperties {
public:
typedef std::vector<std::string> StringVector;
HttpServerProperties() {}
virtual ~HttpServerProperties() {}
// Returns true if |server| supports SPDY.
virtual bool SupportsSpdy(const HostPortPair& server) const = 0;
// Add |server| into the persistent store. Should only be called from IO
// thread.
virtual void SetSupportsSpdy(const HostPortPair& server,
bool support_spdy) = 0;
// Deletes all data.
virtual void DeleteAll() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(HttpServerProperties);
};
} // namespace net
#endif // NET_HTTP_HTTP_SERVER_PROPERTIES_H_

@ -0,0 +1,93 @@
// Copyright (c) 2011 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_server_properties_impl.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/stringprintf.h"
namespace net {
HttpServerPropertiesImpl::HttpServerPropertiesImpl() {
}
HttpServerPropertiesImpl::~HttpServerPropertiesImpl() {
}
void HttpServerPropertiesImpl::Initialize(StringVector* spdy_servers,
bool support_spdy) {
DCHECK(CalledOnValidThread());
spdy_servers_table_.clear();
if (!spdy_servers)
return;
for (StringVector::iterator it = spdy_servers->begin();
it != spdy_servers->end(); ++it) {
spdy_servers_table_[*it] = support_spdy;
}
}
bool HttpServerPropertiesImpl::SupportsSpdy(
const net::HostPortPair& host_port_pair) const {
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())
return spdy_host_port->second;
return false;
}
void HttpServerPropertiesImpl::SetSupportsSpdy(
const net::HostPortPair& host_port_pair,
bool support_spdy) {
DCHECK(CalledOnValidThread());
if (host_port_pair.host().empty())
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()) &&
(spdy_host_port->second == support_spdy)) {
return;
}
// Cache the data.
spdy_servers_table_[spdy_server] = support_spdy;
}
void HttpServerPropertiesImpl::DeleteAll() {
DCHECK(CalledOnValidThread());
spdy_servers_table_.clear();
}
void HttpServerPropertiesImpl::GetSpdyServerList(
base::ListValue* spdy_server_list) const {
DCHECK(CalledOnValidThread());
DCHECK(spdy_server_list);
spdy_server_list->Clear();
// 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) {
const std::string spdy_server_host_port = it->first;
if (it->second)
spdy_server_list->Append(new StringValue(spdy_server_host_port));
}
}
// static
std::string HttpServerPropertiesImpl::GetFlattenedSpdyServer(
const net::HostPortPair& host_port_pair) {
std::string spdy_server;
spdy_server.append(host_port_pair.host());
spdy_server.append(":");
base::StringAppendF(&spdy_server, "%d", host_port_pair.port());
return spdy_server;
}
} // namespace net

@ -0,0 +1,66 @@
// Copyright (c) 2011 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.
#ifndef NET_HTTP_HTTP_SERVER_PROPERTIES_IMPL_H_
#define NET_HTTP_HTTP_SERVER_PROPERTIES_IMPL_H_
#include <string>
#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/hash_tables.h"
#include "base/threading/non_thread_safe.h"
#include "base/values.h"
#include "net/base/host_port_pair.h"
#include "net/base/net_export.h"
#include "net/http/http_server_properties.h"
namespace base {
class ListValue;
}
namespace net {
// The implementation for setting/retrieving the HTTP server properties.
class NET_EXPORT HttpServerPropertiesImpl
: public HttpServerProperties,
NON_EXPORTED_BASE(public base::NonThreadSafe) {
public:
HttpServerPropertiesImpl();
virtual ~HttpServerPropertiesImpl();
// Initializes |spdy_servers_table_| with the servers (host/port) from
// |spdy_servers| that either support SPDY or not.
void Initialize(StringVector* spdy_servers, bool support_spdy);
// Returns true if |server| supports SPDY.
virtual bool SupportsSpdy(const HostPortPair& server) const OVERRIDE;
// Add |server| into the persistent store.
virtual void SetSupportsSpdy(const HostPortPair& server,
bool support_spdy) OVERRIDE;
// Deletes all data.
virtual void DeleteAll() OVERRIDE;
// Get the list of servers (host/port) that support SPDY.
void GetSpdyServerList(base::ListValue* spdy_server_list) const;
// Returns flattened string representation of the |host_port_pair|. Used by
// unittests.
static std::string GetFlattenedSpdyServer(
const net::HostPortPair& host_port_pair);
private:
// |spdy_servers_table_| has flattened representation of servers (host/port
// pair) that either support or not support SPDY protocol.
typedef base::hash_map<std::string, bool> SpdyServerHostPortTable;
SpdyServerHostPortTable spdy_servers_table_;
DISALLOW_COPY_AND_ASSIGN(HttpServerPropertiesImpl);
};
} // namespace net
#endif // NET_HTTP_HTTP_SERVER_PROPERTIES_IMPL_H_

@ -0,0 +1,186 @@
// Copyright (c) 2011 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_server_properties_impl.h"
#include <string>
#include "base/basictypes.h"
#include "base/hash_tables.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/values.h"
#include "net/base/host_port_pair.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace base {
class ListValue;
}
namespace net {
namespace {
class HttpServerPropertiesImplTest : public testing::Test {
protected:
HttpServerPropertiesImpl impl_;
};
TEST_F(HttpServerPropertiesImplTest, InitializeTest) {
HostPortPair spdy_server_google("www.google.com", 443);
std::string spdy_server_g =
HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_google);
HostPortPair spdy_server_docs("docs.google.com", 443);
std::string spdy_server_d =
HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_docs);
// Check by initializing NULL spdy servers.
impl_.Initialize(NULL, true);
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_google));
// Check by initializing empty spdy servers.
HttpServerProperties::StringVector spdy_servers;
impl_.Initialize(&spdy_servers, true);
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_google));
// Check by initializing with www.google.com:443 spdy server.
HttpServerProperties::StringVector spdy_servers1;
spdy_servers1.push_back(spdy_server_g);
impl_.Initialize(&spdy_servers1, true);
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_google));
// Check by initializing with www.google.com:443 and docs.google.com:443 spdy
// servers.
HttpServerProperties::StringVector spdy_servers2;
spdy_servers2.push_back(spdy_server_g);
spdy_servers2.push_back(spdy_server_d);
impl_.Initialize(&spdy_servers2, true);
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_google));
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_docs));
}
TEST_F(HttpServerPropertiesImplTest, SupportsSpdyTest) {
HostPortPair spdy_server_empty("", 443);
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_empty));
// Add www.google.com:443 as supporting SPDY.
HostPortPair spdy_server_google("www.google.com", 443);
impl_.SetSupportsSpdy(spdy_server_google, true);
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_google));
// Add mail.google.com:443 as not supporting SPDY.
HostPortPair spdy_server_mail("mail.google.com", 443);
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_mail));
// Add docs.google.com:443 as supporting SPDY.
HostPortPair spdy_server_docs("docs.google.com", 443);
impl_.SetSupportsSpdy(spdy_server_docs, true);
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_docs));
// Verify all the entries are the same after additions.
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_google));
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_mail));
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_docs));
}
TEST_F(HttpServerPropertiesImplTest, SetSupportsSpdyTest) {
HostPortPair spdy_server_empty("", 443);
impl_.SetSupportsSpdy(spdy_server_empty, true);
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_empty));
// Add www.google.com:443 as supporting SPDY.
HostPortPair spdy_server_google("www.google.com", 443);
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_google));
impl_.SetSupportsSpdy(spdy_server_google, true);
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_google));
// Make www.google.com:443 as not supporting SPDY.
impl_.SetSupportsSpdy(spdy_server_google, false);
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_google));
// Add mail.google.com:443 as supporting SPDY.
HostPortPair spdy_server_mail("mail.google.com", 443);
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_mail));
impl_.SetSupportsSpdy(spdy_server_mail, true);
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_mail));
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_google));
}
TEST_F(HttpServerPropertiesImplTest, DeleteAllTest) {
// Add www.google.com:443 and mail.google.com:443 as supporting SPDY.
HostPortPair spdy_server_google("www.google.com", 443);
impl_.SetSupportsSpdy(spdy_server_google, true);
HostPortPair spdy_server_mail("mail.google.com", 443);
impl_.SetSupportsSpdy(spdy_server_mail, true);
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_google));
EXPECT_TRUE(impl_.SupportsSpdy(spdy_server_mail));
impl_.DeleteAll();
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_google));
EXPECT_FALSE(impl_.SupportsSpdy(spdy_server_mail));
}
TEST_F(HttpServerPropertiesImplTest, GetSpdyServerListTest) {
base::ListValue spdy_server_list;
// Check there are no spdy_servers.
impl_.GetSpdyServerList(&spdy_server_list);
EXPECT_EQ(0u, spdy_server_list.GetSize());
// Check empty server is not added.
HostPortPair spdy_server_empty("", 443);
impl_.SetSupportsSpdy(spdy_server_empty, true);
impl_.GetSpdyServerList(&spdy_server_list);
EXPECT_EQ(0u, spdy_server_list.GetSize());
std::string string_value_g;
std::string string_value_m;
HostPortPair spdy_server_google("www.google.com", 443);
std::string spdy_server_g =
HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_google);
HostPortPair spdy_server_mail("mail.google.com", 443);
std::string spdy_server_m =
HttpServerPropertiesImpl::GetFlattenedSpdyServer(spdy_server_mail);
// Add www.google.com:443 as not supporting SPDY.
impl_.SetSupportsSpdy(spdy_server_google, false);
impl_.GetSpdyServerList(&spdy_server_list);
EXPECT_EQ(0u, spdy_server_list.GetSize());
// Add www.google.com:443 as supporting SPDY.
impl_.SetSupportsSpdy(spdy_server_google, true);
impl_.GetSpdyServerList(&spdy_server_list);
EXPECT_EQ(1u, spdy_server_list.GetSize());
ASSERT_TRUE(spdy_server_list.GetString(0, &string_value_g));
ASSERT_EQ(spdy_server_g, string_value_g);
// Add mail.google.com:443 as not supporting SPDY.
impl_.SetSupportsSpdy(spdy_server_mail, false);
impl_.GetSpdyServerList(&spdy_server_list);
EXPECT_EQ(1u, spdy_server_list.GetSize());
ASSERT_TRUE(spdy_server_list.GetString(0, &string_value_g));
ASSERT_EQ(spdy_server_g, string_value_g);
// Add mail.google.com:443 as supporting SPDY.
impl_.SetSupportsSpdy(spdy_server_mail, true);
impl_.GetSpdyServerList(&spdy_server_list);
EXPECT_EQ(2u, spdy_server_list.GetSize());
// Verify www.google.com:443 and mail.google.com:443 are in the list.
ASSERT_TRUE(spdy_server_list.GetString(0, &string_value_g));
ASSERT_TRUE(spdy_server_list.GetString(1, &string_value_m));
if (string_value_g.compare(spdy_server_g) == 0) {
ASSERT_EQ(spdy_server_g, string_value_g);
ASSERT_EQ(spdy_server_m, string_value_m);
} else {
ASSERT_EQ(spdy_server_g, string_value_m);
ASSERT_EQ(spdy_server_m, string_value_g);
}
}
} // namespace
} // namespace net

@ -19,6 +19,7 @@
#include "net/http/http_proxy_client_socket.h"
#include "net/http/http_proxy_client_socket_pool.h"
#include "net/http/http_request_info.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_stream_factory_impl_request.h"
#include "net/socket/client_socket_handle.h"
#include "net/socket/client_socket_pool.h"
@ -119,7 +120,17 @@ void HttpStreamFactoryImpl::Job::Start(Request* request) {
int HttpStreamFactoryImpl::Job::Preconnect(int num_streams) {
DCHECK_GT(num_streams, 0);
num_streams_ = num_streams;
HostPortPair origin_server =
HostPortPair(request_info_.url.HostNoBrackets(),
request_info_.url.EffectiveIntPort());
HttpServerProperties* http_server_properties =
session_->http_server_properties();
if (http_server_properties &&
http_server_properties->SupportsSpdy(origin_server)) {
num_streams_ = 1;
} else {
num_streams_ = num_streams;
}
return StartInternal();
}
@ -821,6 +832,11 @@ int HttpStreamFactoryImpl::Job::DoCreateStream() {
&new_spdy_session_, using_ssl_);
if (error != OK)
return error;
const HostPortPair& host_port_pair = pair.first;
HttpServerProperties* http_server_properties =
session_->http_server_properties();
if (http_server_properties)
http_server_properties->SetSupportsSpdy(host_port_pair, true);
spdy_session_direct_ = direct;
return OK;
}

@ -425,6 +425,9 @@
'http/http_response_headers.h',
'http/http_response_info.cc',
'http/http_response_info.h',
'http/http_server_properties.h',
'http/http_server_properties_impl.cc',
'http/http_server_properties_impl.h',
'http/http_stream.h',
'http/http_stream_factory.cc',
'http/http_stream_factory.h',
@ -1020,6 +1023,7 @@
'http/http_request_headers_unittest.cc',
'http/http_response_body_drainer_unittest.cc',
'http/http_response_headers_unittest.cc',
'http/http_server_properties_impl_unittest.cc',
'http/http_stream_factory_impl_unittest.cc',
'http/http_transaction_unittest.cc',
'http/http_transaction_unittest.h',

@ -957,6 +957,7 @@ SpdyURLRequestContext::SpdyURLRequestContext()
params.ssl_config_service = ssl_config_service();
params.http_auth_handler_factory = http_auth_handler_factory();
params.network_delegate = network_delegate();
params.http_server_properties = http_server_properties();
scoped_refptr<HttpNetworkSession> network_session(
new HttpNetworkSession(params));
storage_.set_http_transaction_factory(new HttpCache(

@ -24,6 +24,7 @@ URLRequestContext::URLRequestContext()
http_auth_handler_factory_(NULL),
proxy_service_(NULL),
network_delegate_(NULL),
http_server_properties_(NULL),
transport_security_state_(NULL),
ftp_auth_cache_(new FtpAuthCache),
http_transaction_factory_(NULL),
@ -43,6 +44,7 @@ void URLRequestContext::CopyFrom(URLRequestContext* other) {
set_proxy_service(other->proxy_service());
set_ssl_config_service(other->ssl_config_service());
set_network_delegate(other->network_delegate());
set_http_server_properties(other->http_server_properties());
set_cookie_store(other->cookie_store());
set_transport_security_state(other->transport_security_state());
// FTPAuthCache is unique per context.

@ -19,6 +19,7 @@
#include "net/base/net_log.h"
#include "net/base/ssl_config_service.h"
#include "net/base/transport_security_state.h"
#include "net/http/http_server_properties.h"
#include "net/ftp/ftp_auth_cache.h"
namespace net {
@ -143,6 +144,14 @@ class NET_EXPORT URLRequestContext
}
NetworkDelegate* network_delegate() const { return network_delegate_; }
void set_http_server_properties(
HttpServerProperties* http_server_properties) {
http_server_properties_ = http_server_properties;
}
HttpServerProperties* http_server_properties() const {
return http_server_properties_;
}
// Gets the cookie store for this context (may be null, in which case
// cookies are not stored).
CookieStore* cookie_store() const { return cookie_store_.get(); }
@ -213,6 +222,7 @@ class NET_EXPORT URLRequestContext
ProxyService* proxy_service_;
scoped_refptr<SSLConfigService> ssl_config_service_;
NetworkDelegate* network_delegate_;
HttpServerProperties* http_server_properties_;
scoped_refptr<CookieStore> cookie_store_;
TransportSecurityState* transport_security_state_;
scoped_ptr<FtpAuthCache> ftp_auth_cache_;

@ -14,6 +14,7 @@
#include "net/base/origin_bound_cert_service.h"
#include "net/ftp/ftp_transaction_factory.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_server_properties.h"
#include "net/http/http_transaction_factory.h"
#include "net/proxy/proxy_service.h"
#include "net/socket/dns_cert_provenance_checker.h"
@ -85,6 +86,12 @@ void URLRequestContextStorage::set_network_delegate(
network_delegate_.reset(network_delegate);
}
void URLRequestContextStorage::set_http_server_properties(
HttpServerProperties* http_server_properties) {
context_->set_http_server_properties(http_server_properties);
http_server_properties_ = http_server_properties;
}
void URLRequestContextStorage::set_cookie_store(CookieStore* cookie_store) {
context_->set_cookie_store(cookie_store);
cookie_store_ = cookie_store;

@ -20,6 +20,7 @@ class DnsRRResolver;
class FtpTransactionFactory;
class HostResolver;
class HttpAuthHandlerFactory;
class HttpServerProperties;
class HttpTransactionFactory;
class NetLog;
class NetworkDelegate;
@ -55,6 +56,7 @@ class NET_EXPORT URLRequestContextStorage {
void set_proxy_service(ProxyService* proxy_service);
void set_ssl_config_service(SSLConfigService* ssl_config_service);
void set_network_delegate(NetworkDelegate* network_delegate);
void set_http_server_properties(HttpServerProperties* http_server_properties);
void set_cookie_store(CookieStore* cookie_store);
void set_transport_security_state(
TransportSecurityState* transport_security_state);
@ -82,6 +84,7 @@ class NET_EXPORT URLRequestContextStorage {
// TODO(willchan): Remove refcounting on these members.
scoped_refptr<SSLConfigService> ssl_config_service_;
scoped_ptr<NetworkDelegate> network_delegate_;
HttpServerProperties* http_server_properties_;
scoped_refptr<CookieStore> cookie_store_;
scoped_ptr<TransportSecurityState> transport_security_state_;

@ -125,6 +125,7 @@ void TestURLRequestContext::Init() {
params.ssl_config_service = ssl_config_service();
params.http_auth_handler_factory = http_auth_handler_factory();
params.network_delegate = network_delegate();
params.http_server_properties = http_server_properties();
if (!http_transaction_factory()) {
context_storage_.set_http_transaction_factory(new net::HttpCache(

@ -93,7 +93,8 @@ void TestShellRequestContext::Init(
new net::HttpCache(host_resolver(), cert_verifier(),
origin_bound_cert_service(), NULL, NULL,
proxy_service(), ssl_config_service(),
http_auth_handler_factory(), NULL, NULL, backend);
http_auth_handler_factory(), NULL, NULL, NULL,
backend);
cache->set_mode(cache_mode);
storage_.set_http_transaction_factory(cache);