blob: 293a5800f60eff1cb38fc9078ab2f32af329c40a [file] [log] [blame]
// 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 "chrome/browser/net/chrome_url_request_context.h"
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/message_loop.h"
#include "base/message_loop_proxy.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/net/load_time_stats.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_io_data.h"
#include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/common/content_client.h"
#include "net/cookies/cookie_store.h"
#include "net/http/http_util.h"
using content::BrowserThread;
class ChromeURLRequestContextFactory {
public:
ChromeURLRequestContextFactory() {}
virtual ~ChromeURLRequestContextFactory() {}
// Called to create a new instance (will only be called once).
virtual ChromeURLRequestContext* Create() = 0;
protected:
DISALLOW_COPY_AND_ASSIGN(ChromeURLRequestContextFactory);
};
namespace {
// ----------------------------------------------------------------------------
// Helper factories
// ----------------------------------------------------------------------------
// Factory that creates the main ChromeURLRequestContext.
class FactoryForMain : public ChromeURLRequestContextFactory {
public:
explicit FactoryForMain(const ProfileIOData* profile_io_data)
: profile_io_data_(profile_io_data) {}
virtual ChromeURLRequestContext* Create() OVERRIDE {
return profile_io_data_->GetMainRequestContext();
}
private:
const ProfileIOData* const profile_io_data_;
};
// Factory that creates the ChromeURLRequestContext for extensions.
class FactoryForExtensions : public ChromeURLRequestContextFactory {
public:
explicit FactoryForExtensions(const ProfileIOData* profile_io_data)
: profile_io_data_(profile_io_data) {}
virtual ChromeURLRequestContext* Create() OVERRIDE {
return profile_io_data_->GetExtensionsRequestContext();
}
private:
const ProfileIOData* const profile_io_data_;
};
// Factory that creates the ChromeURLRequestContext for a given isolated app.
class FactoryForIsolatedApp : public ChromeURLRequestContextFactory {
public:
FactoryForIsolatedApp(const ProfileIOData* profile_io_data,
const std::string& app_id,
ChromeURLRequestContextGetter* main_context,
scoped_ptr<net::URLRequestJobFactory::Interceptor>
protocol_handler_interceptor)
: profile_io_data_(profile_io_data),
app_id_(app_id),
main_request_context_getter_(main_context),
protocol_handler_interceptor_(protocol_handler_interceptor.Pass()) {}
virtual ChromeURLRequestContext* Create() OVERRIDE {
// We will copy most of the state from the main request context.
//
// Note that this factory is one-shot. After Create() is called once, the
// factory is actually destroyed. Thus it is safe to destructively pass
// state onwards.
return profile_io_data_->GetIsolatedAppRequestContext(
main_request_context_getter_->GetIOContext(), app_id_,
protocol_handler_interceptor_.Pass());
}
private:
const ProfileIOData* const profile_io_data_;
const std::string app_id_;
scoped_refptr<ChromeURLRequestContextGetter>
main_request_context_getter_;
scoped_ptr<net::URLRequestJobFactory::Interceptor>
protocol_handler_interceptor_;
};
// Factory that creates the media ChromeURLRequestContext for a given isolated
// app. The media context is based on the corresponding isolated app's context.
class FactoryForIsolatedMedia : public ChromeURLRequestContextFactory {
public:
FactoryForIsolatedMedia(const ProfileIOData* profile_io_data,
const std::string& app_id,
ChromeURLRequestContextGetter* app_context)
: profile_io_data_(profile_io_data),
app_id_(app_id),
app_context_getter_(app_context) {}
virtual ChromeURLRequestContext* Create() OVERRIDE {
// We will copy most of the state from the corresopnding app's
// request context. We expect to have the same lifetime as
// the associated |app_context_getter_| so we can just reuse
// all its backing objects, including the
// |protocol_handler_interceptor|. This is why the API
// looks different from FactoryForIsolatedApp's.
return profile_io_data_->GetIsolatedMediaRequestContext(
app_context_getter_->GetIOContext(), app_id_);
}
private:
const ProfileIOData* const profile_io_data_;
const std::string app_id_;
scoped_refptr<ChromeURLRequestContextGetter> app_context_getter_;
};
// Factory that creates the ChromeURLRequestContext for media.
class FactoryForMedia : public ChromeURLRequestContextFactory {
public:
explicit FactoryForMedia(const ProfileIOData* profile_io_data)
: profile_io_data_(profile_io_data) {
}
virtual ChromeURLRequestContext* Create() OVERRIDE {
return profile_io_data_->GetMediaRequestContext();
}
private:
const ProfileIOData* const profile_io_data_;
};
} // namespace
// ----------------------------------------------------------------------------
// ChromeURLRequestContextGetter
// ----------------------------------------------------------------------------
ChromeURLRequestContextGetter::ChromeURLRequestContextGetter(
Profile* profile,
ChromeURLRequestContextFactory* factory)
: factory_(factory) {
DCHECK(factory);
DCHECK(profile);
RegisterPrefsObserver(profile);
}
ChromeURLRequestContextGetter::~ChromeURLRequestContextGetter() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
DCHECK(registrar_.IsEmpty()) << "Probably didn't call CleanupOnUIThread";
}
// Lazily create a ChromeURLRequestContext using our factory.
net::URLRequestContext* ChromeURLRequestContextGetter::GetURLRequestContext() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (!url_request_context_) {
DCHECK(factory_.get());
url_request_context_ = factory_->Create()->GetWeakPtr();
factory_.reset();
}
// Should not be NULL, unless we're trying to use the URLRequestContextGetter
// after the Profile has already been deleted.
CHECK(url_request_context_.get());
return url_request_context_;
}
scoped_refptr<base::SingleThreadTaskRunner>
ChromeURLRequestContextGetter::GetNetworkTaskRunner() const {
return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
}
// static
ChromeURLRequestContextGetter* ChromeURLRequestContextGetter::CreateOriginal(
Profile* profile,
const ProfileIOData* profile_io_data) {
DCHECK(!profile->IsOffTheRecord());
return new ChromeURLRequestContextGetter(
profile,
new FactoryForMain(profile_io_data));
}
// static
ChromeURLRequestContextGetter*
ChromeURLRequestContextGetter::CreateOriginalForMedia(
Profile* profile, const ProfileIOData* profile_io_data) {
DCHECK(!profile->IsOffTheRecord());
return new ChromeURLRequestContextGetter(
profile,
new FactoryForMedia(profile_io_data));
}
// static
ChromeURLRequestContextGetter*
ChromeURLRequestContextGetter::CreateOriginalForExtensions(
Profile* profile, const ProfileIOData* profile_io_data) {
DCHECK(!profile->IsOffTheRecord());
return new ChromeURLRequestContextGetter(
profile,
new FactoryForExtensions(profile_io_data));
}
// static
ChromeURLRequestContextGetter*
ChromeURLRequestContextGetter::CreateOriginalForIsolatedApp(
Profile* profile,
const ProfileIOData* profile_io_data,
const std::string& app_id,
scoped_ptr<net::URLRequestJobFactory::Interceptor>
protocol_handler_interceptor) {
DCHECK(!profile->IsOffTheRecord());
ChromeURLRequestContextGetter* main_context =
static_cast<ChromeURLRequestContextGetter*>(profile->GetRequestContext());
return new ChromeURLRequestContextGetter(
profile,
new FactoryForIsolatedApp(profile_io_data, app_id, main_context,
protocol_handler_interceptor.Pass()));
}
// static
ChromeURLRequestContextGetter*
ChromeURLRequestContextGetter::CreateOriginalForIsolatedMedia(
Profile* profile,
ChromeURLRequestContextGetter* app_context,
const ProfileIOData* profile_io_data,
const std::string& app_id) {
DCHECK(!profile->IsOffTheRecord());
return new ChromeURLRequestContextGetter(
profile,
new FactoryForIsolatedMedia(profile_io_data, app_id, app_context));
}
// static
ChromeURLRequestContextGetter*
ChromeURLRequestContextGetter::CreateOffTheRecord(
Profile* profile, const ProfileIOData* profile_io_data) {
DCHECK(profile->IsOffTheRecord());
return new ChromeURLRequestContextGetter(
profile, new FactoryForMain(profile_io_data));
}
// static
ChromeURLRequestContextGetter*
ChromeURLRequestContextGetter::CreateOffTheRecordForExtensions(
Profile* profile, const ProfileIOData* profile_io_data) {
DCHECK(profile->IsOffTheRecord());
return new ChromeURLRequestContextGetter(
profile, new FactoryForExtensions(profile_io_data));
}
// static
ChromeURLRequestContextGetter*
ChromeURLRequestContextGetter::CreateOffTheRecordForIsolatedApp(
Profile* profile,
const ProfileIOData* profile_io_data,
const std::string& app_id,
scoped_ptr<net::URLRequestJobFactory::Interceptor>
protocol_handler_interceptor) {
DCHECK(profile->IsOffTheRecord());
ChromeURLRequestContextGetter* main_context =
static_cast<ChromeURLRequestContextGetter*>(profile->GetRequestContext());
return new ChromeURLRequestContextGetter(
profile,
new FactoryForIsolatedApp(profile_io_data, app_id, main_context,
protocol_handler_interceptor.Pass()));
}
void ChromeURLRequestContextGetter::CleanupOnUIThread() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
// Unregister for pref notifications.
DCHECK(!registrar_.IsEmpty()) << "Called more than once!";
registrar_.RemoveAll();
}
// content::NotificationObserver implementation.
void ChromeURLRequestContextGetter::Observe(
int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (chrome::NOTIFICATION_PREF_CHANGED == type) {
std::string* pref_name_in = content::Details<std::string>(details).ptr();
PrefService* prefs = content::Source<PrefService>(source).ptr();
DCHECK(pref_name_in && prefs);
if (*pref_name_in == prefs::kAcceptLanguages) {
std::string accept_language =
prefs->GetString(prefs::kAcceptLanguages);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(
&ChromeURLRequestContextGetter::OnAcceptLanguageChange,
this,
accept_language));
} else if (*pref_name_in == prefs::kDefaultCharset) {
std::string default_charset = prefs->GetString(prefs::kDefaultCharset);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(
&ChromeURLRequestContextGetter::OnDefaultCharsetChange,
this,
default_charset));
}
} else {
NOTREACHED();
}
}
void ChromeURLRequestContextGetter::RegisterPrefsObserver(Profile* profile) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
registrar_.Init(profile->GetPrefs());
registrar_.Add(prefs::kAcceptLanguages, this);
registrar_.Add(prefs::kDefaultCharset, this);
}
void ChromeURLRequestContextGetter::OnAcceptLanguageChange(
const std::string& accept_language) {
GetIOContext()->OnAcceptLanguageChange(accept_language);
}
void ChromeURLRequestContextGetter::OnDefaultCharsetChange(
const std::string& default_charset) {
GetIOContext()->OnDefaultCharsetChange(default_charset);
}
// ----------------------------------------------------------------------------
// ChromeURLRequestContext
// ----------------------------------------------------------------------------
ChromeURLRequestContext::ChromeURLRequestContext(
ContextType type,
chrome_browser_net::LoadTimeStats* load_time_stats)
: ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)),
is_incognito_(false),
load_time_stats_(load_time_stats) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (load_time_stats_)
load_time_stats_->RegisterURLRequestContext(this, type);
}
ChromeURLRequestContext::~ChromeURLRequestContext() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (load_time_stats_)
load_time_stats_->UnregisterURLRequestContext(this);
}
void ChromeURLRequestContext::CopyFrom(ChromeURLRequestContext* other) {
URLRequestContext::CopyFrom(other);
// Copy ChromeURLRequestContext parameters.
// ChromeURLDataManagerBackend is unique per context.
set_is_incognito(other->is_incognito());
}
ChromeURLDataManagerBackend*
ChromeURLRequestContext::chrome_url_data_manager_backend() const {
return chrome_url_data_manager_backend_;
}
void ChromeURLRequestContext::set_chrome_url_data_manager_backend(
ChromeURLDataManagerBackend* backend) {
DCHECK(backend);
chrome_url_data_manager_backend_ = backend;
}
const std::string& ChromeURLRequestContext::GetUserAgent(
const GURL& url) const {
return content::GetUserAgent(url);
}
void ChromeURLRequestContext::OnAcceptLanguageChange(
const std::string& accept_language) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
set_accept_language(
net::HttpUtil::GenerateAcceptLanguageHeader(accept_language));
}
void ChromeURLRequestContext::OnDefaultCharsetChange(
const std::string& default_charset) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
set_referrer_charset(default_charset);
set_accept_charset(
net::HttpUtil::GenerateAcceptCharsetHeader(default_charset));
}