This source file includes following definitions.
- CleanUpDuplicates
- UnregisterAndReplaceOverrideForWebContents
- RunFaviconCallbackAsync
- ValidateOverrideURL
- url_
- bookmark_manager_private_drag_event_router
- RegisterProfilePrefs
- HandleChromeURLOverride
- HandleChromeURLOverrideReverse
- RegisterChromeURLOverrides
- UnregisterAndReplaceOverride
- UnregisterChromeURLOverride
- UnregisterChromeURLOverrides
- GetFaviconForURL
#include "chrome/browser/extensions/extension_web_ui.h"
#include <set>
#include <vector>
#include "base/command_line.h"
#include "base/prefs/pref_service.h"
#include "base/prefs/scoped_user_pref_update.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/extensions/image_loader.h"
#include "chrome/browser/favicon/favicon_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_icon_set.h"
#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
#include "chrome/common/url_constants.h"
#include "components/user_prefs/pref_registry_syncable.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/common/bindings_policy.h"
#include "content/public/common/page_transition_types.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_resource.h"
#include "extensions/common/manifest_handlers/incognito_info.h"
#include "net/base/file_stream.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/image/image_skia.h"
using content::WebContents;
using extensions::Extension;
using extensions::URLOverrides;
namespace {
void CleanUpDuplicates(base::ListValue* list) {
std::set<std::string> seen_values;
for (size_t i = list->GetSize() - 1; (i + 1) > 0; --i) {
std::string value;
if (!list->GetString(i, &value)) {
NOTREACHED();
continue;
}
if (seen_values.find(value) == seen_values.end())
seen_values.insert(value);
else
list->Remove(i, NULL);
}
}
void UnregisterAndReplaceOverrideForWebContents(const std::string& page,
Profile* profile,
WebContents* web_contents) {
if (Profile::FromBrowserContext(web_contents->GetBrowserContext()) != profile)
return;
GURL url = web_contents->GetURL();
if (!url.SchemeIs(content::kChromeUIScheme) || url.host() != page)
return;
web_contents->GetController().LoadURL(
url, content::Referrer(url, blink::WebReferrerPolicyDefault),
content::PAGE_TRANSITION_RELOAD, std::string());
}
void RunFaviconCallbackAsync(
const FaviconService::FaviconResultsCallback& callback,
const gfx::Image& image) {
std::vector<chrome::FaviconBitmapResult>* favicon_bitmap_results =
new std::vector<chrome::FaviconBitmapResult>();
const std::vector<gfx::ImageSkiaRep>& image_reps =
image.AsImageSkia().image_reps();
for (size_t i = 0; i < image_reps.size(); ++i) {
const gfx::ImageSkiaRep& image_rep = image_reps[i];
scoped_refptr<base::RefCountedBytes> bitmap_data(
new base::RefCountedBytes());
if (gfx::PNGCodec::EncodeBGRASkBitmap(image_rep.sk_bitmap(),
false,
&bitmap_data->data())) {
chrome::FaviconBitmapResult bitmap_result;
bitmap_result.bitmap_data = bitmap_data;
bitmap_result.pixel_size = gfx::Size(image_rep.pixel_width(),
image_rep.pixel_height());
bitmap_result.icon_type = chrome::FAVICON;
favicon_bitmap_results->push_back(bitmap_result);
} else {
NOTREACHED() << "Could not encode extension favicon";
}
}
base::MessageLoopProxy::current()->PostTask(
FROM_HERE,
base::Bind(&FaviconService::FaviconResultsCallbackRunner,
callback,
base::Owned(favicon_bitmap_results)));
}
bool ValidateOverrideURL(const base::Value* override_url_value,
const GURL& source_url,
const extensions::ExtensionSet& extensions,
GURL* override_url,
const Extension** extension) {
std::string override;
if (!override_url_value || !override_url_value->GetAsString(&override)) {
return false;
}
if (!source_url.query().empty())
override += "?" + source_url.query();
if (!source_url.ref().empty())
override += "#" + source_url.ref();
*override_url = GURL(override);
if (!override_url->is_valid()) {
return false;
}
*extension = extensions.GetByID(override_url->host());
if (!*extension) {
return false;
}
return true;
}
}
const char ExtensionWebUI::kExtensionURLOverrides[] =
"extensions.chrome_url_overrides";
ExtensionWebUI::ExtensionWebUI(content::WebUI* web_ui, const GURL& url)
: WebUIController(web_ui),
url_(url) {
Profile* profile = Profile::FromWebUI(web_ui);
ExtensionService* service = profile->GetExtensionService();
const Extension* extension =
service->extensions()->GetExtensionOrAppByURL(url);
DCHECK(extension);
int bindings = 0;
web_ui->SetBindings(bindings);
if (extension->id() == extension_misc::kBookmarkManagerId) {
bookmark_manager_private_drag_event_router_.reset(
new extensions::BookmarkManagerPrivateDragEventRouter(
profile, web_ui->GetWebContents()));
web_ui->SetLinkTransitionType(content::PAGE_TRANSITION_AUTO_BOOKMARK);
}
}
ExtensionWebUI::~ExtensionWebUI() {}
extensions::BookmarkManagerPrivateDragEventRouter*
ExtensionWebUI::bookmark_manager_private_drag_event_router() {
return bookmark_manager_private_drag_event_router_.get();
}
void ExtensionWebUI::RegisterProfilePrefs(
user_prefs::PrefRegistrySyncable* registry) {
registry->RegisterDictionaryPref(
kExtensionURLOverrides,
user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
}
bool ExtensionWebUI::HandleChromeURLOverride(
GURL* url,
content::BrowserContext* browser_context) {
if (!url->SchemeIs(content::kChromeUIScheme))
return false;
Profile* profile = Profile::FromBrowserContext(browser_context);
const base::DictionaryValue* overrides =
profile->GetPrefs()->GetDictionary(kExtensionURLOverrides);
std::string url_host = url->host();
const base::ListValue* url_list = NULL;
if (!overrides || !overrides->GetList(url_host, &url_list))
return false;
extensions::ExtensionRegistry* registry =
extensions::ExtensionRegistry::Get(browser_context);
const extensions::ExtensionSet& extensions = registry->enabled_extensions();
GURL component_url;
bool found_component_override = false;
for (size_t i = 0; i < url_list->GetSize(); ++i) {
const base::Value* val = NULL;
url_list->Get(i, &val);
GURL override_url;
const Extension* extension;
if (!ValidateOverrideURL(
val, *url, extensions, &override_url, &extension)) {
LOG(WARNING) << "Invalid chrome URL override";
UnregisterChromeURLOverride(url_host, profile, val);
--i;
continue;
}
bool incognito_override_allowed =
extensions::IncognitoInfo::IsSplitMode(extension) &&
extensions::util::IsIncognitoEnabled(extension->id(), profile);
if (profile->IsOffTheRecord() && !incognito_override_allowed) {
continue;
}
if (!extensions::Manifest::IsComponentLocation(extension->location())) {
*url = override_url;
return true;
}
if (!found_component_override) {
found_component_override = true;
component_url = override_url;
}
}
if (found_component_override) {
*url = component_url;
return true;
}
return false;
}
bool ExtensionWebUI::HandleChromeURLOverrideReverse(
GURL* url, content::BrowserContext* browser_context) {
Profile* profile = Profile::FromBrowserContext(browser_context);
const base::DictionaryValue* overrides =
profile->GetPrefs()->GetDictionary(kExtensionURLOverrides);
if (!overrides)
return false;
for (base::DictionaryValue::Iterator it(*overrides); !it.IsAtEnd();
it.Advance()) {
const base::ListValue* url_list = NULL;
if (!it.value().GetAsList(&url_list))
continue;
for (base::ListValue::const_iterator it2 = url_list->begin();
it2 != url_list->end(); ++it2) {
std::string override;
if (!(*it2)->GetAsString(&override))
continue;
if (StartsWithASCII(url->spec(), override, true)) {
GURL original_url(content::kChromeUIScheme + std::string("://") +
it.key() + url->spec().substr(override.length()));
*url = original_url;
return true;
}
}
}
return false;
}
void ExtensionWebUI::RegisterChromeURLOverrides(
Profile* profile, const URLOverrides::URLOverrideMap& overrides) {
if (overrides.empty())
return;
PrefService* prefs = profile->GetPrefs();
DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
base::DictionaryValue* all_overrides = update.Get();
URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin();
for (; iter != overrides.end(); ++iter) {
const std::string& key = iter->first;
base::ListValue* page_overrides = NULL;
if (!all_overrides->GetList(key, &page_overrides)) {
page_overrides = new base::ListValue();
all_overrides->Set(key, page_overrides);
} else {
CleanUpDuplicates(page_overrides);
base::ListValue::iterator i = page_overrides->begin();
for (; i != page_overrides->end(); ++i) {
std::string override_val;
if (!(*i)->GetAsString(&override_val)) {
NOTREACHED();
continue;
}
if (override_val == iter->second.spec())
break;
}
if (i != page_overrides->end())
continue;
}
page_overrides->Insert(0, new base::StringValue(iter->second.spec()));
}
}
void ExtensionWebUI::UnregisterAndReplaceOverride(const std::string& page,
Profile* profile,
base::ListValue* list,
const base::Value* override) {
size_t index = 0;
bool found = list->Remove(*override, &index);
if (found && index == 0) {
base::Callback<void(WebContents*)> callback =
base::Bind(&UnregisterAndReplaceOverrideForWebContents, page, profile);
extensions::ExtensionTabUtil::ForEachTab(callback);
}
}
void ExtensionWebUI::UnregisterChromeURLOverride(const std::string& page,
Profile* profile,
const base::Value* override) {
if (!override)
return;
PrefService* prefs = profile->GetPrefs();
DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
base::DictionaryValue* all_overrides = update.Get();
base::ListValue* page_overrides = NULL;
if (!all_overrides->GetList(page, &page_overrides)) {
NOTREACHED();
return;
} else {
UnregisterAndReplaceOverride(page, profile, page_overrides, override);
}
}
void ExtensionWebUI::UnregisterChromeURLOverrides(
Profile* profile, const URLOverrides::URLOverrideMap& overrides) {
if (overrides.empty())
return;
PrefService* prefs = profile->GetPrefs();
DictionaryPrefUpdate update(prefs, kExtensionURLOverrides);
base::DictionaryValue* all_overrides = update.Get();
URLOverrides::URLOverrideMap::const_iterator iter = overrides.begin();
for (; iter != overrides.end(); ++iter) {
const std::string& page = iter->first;
base::ListValue* page_overrides = NULL;
if (!all_overrides->GetList(page, &page_overrides)) {
NOTREACHED();
continue;
} else {
base::StringValue override(iter->second.spec());
UnregisterAndReplaceOverride(iter->first, profile,
page_overrides, &override);
}
}
}
void ExtensionWebUI::GetFaviconForURL(
Profile* profile,
const GURL& page_url,
const FaviconService::FaviconResultsCallback& callback) {
ExtensionService* service = profile->GetExtensionService();
if (!service) {
RunFaviconCallbackAsync(callback, gfx::Image());
return;
}
const Extension* extension = service->extensions()->GetByID(page_url.host());
if (!extension) {
RunFaviconCallbackAsync(callback, gfx::Image());
return;
}
const std::vector<ui::ScaleFactor>& scale_factors =
FaviconUtil::GetFaviconScaleFactors();
std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
for (size_t i = 0; i < scale_factors.size(); ++i) {
float scale = ui::GetImageScale(scale_factors[i]);
int pixel_size = static_cast<int>(gfx::kFaviconSize * scale);
extensions::ExtensionResource icon_resource =
extensions::IconsInfo::GetIconResource(extension,
pixel_size,
ExtensionIconSet::MATCH_BIGGER);
info_list.push_back(
extensions::ImageLoader::ImageRepresentation(
icon_resource,
extensions::ImageLoader::ImageRepresentation::ALWAYS_RESIZE,
gfx::Size(pixel_size, pixel_size),
scale_factors[i]));
}
extensions::ImageLoader::Get(profile)->LoadImagesAsync(
extension, info_list, base::Bind(&RunFaviconCallbackAsync, callback));
}