This source file includes following definitions.
- did_defer_
- Resume
- WillStartRequest
- GetNameForLogging
- CreateResourceThrottle
- ShouldDelayRequest
- StartDelayedRequests
- CheckIfAllUserScriptsReady
- UserScriptsReady
- ProfileDestroyed
- AppendNewURLPatterns
- ReplaceURLPatterns
- CollectURLPatterns
- Observe
#include "chrome/browser/extensions/user_script_listener.h"
#include "base/bind.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/resource_controller.h"
#include "content/public/browser/resource_throttle.h"
#include "extensions/common/extension.h"
#include "extensions/common/url_pattern.h"
#include "net/url_request/url_request.h"
using content::BrowserThread;
using content::ResourceThrottle;
namespace extensions {
class UserScriptListener::Throttle
: public ResourceThrottle,
public base::SupportsWeakPtr<UserScriptListener::Throttle> {
public:
Throttle() : should_defer_(true), did_defer_(false) {
}
void Resume() {
DCHECK(should_defer_);
should_defer_ = false;
if (did_defer_)
controller()->Resume();
}
virtual void WillStartRequest(bool* defer) OVERRIDE {
if (should_defer_) {
*defer = true;
did_defer_ = true;
}
}
virtual const char* GetNameForLogging() const OVERRIDE {
return "UserScriptListener::Throttle";
}
private:
bool should_defer_;
bool did_defer_;
};
struct UserScriptListener::ProfileData {
bool user_scripts_ready;
URLPatterns url_patterns;
ProfileData() : user_scripts_ready(false) {}
};
UserScriptListener::UserScriptListener()
: user_scripts_ready_(false) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_USER_SCRIPTS_UPDATED,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
content::NotificationService::AllSources());
}
ResourceThrottle* UserScriptListener::CreateResourceThrottle(
const GURL& url,
ResourceType::Type resource_type) {
if (!ShouldDelayRequest(url, resource_type))
return NULL;
Throttle* throttle = new Throttle();
throttles_.push_back(throttle->AsWeakPtr());
return throttle;
}
UserScriptListener::~UserScriptListener() {
}
bool UserScriptListener::ShouldDelayRequest(const GURL& url,
ResourceType::Type resource_type) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
if (resource_type != ResourceType::MAIN_FRAME &&
resource_type != ResourceType::SUB_FRAME)
return false;
if (user_scripts_ready_)
return false;
for (ProfileDataMap::const_iterator pt = profile_data_.begin();
pt != profile_data_.end(); ++pt) {
for (URLPatterns::const_iterator it = pt->second.url_patterns.begin();
it != pt->second.url_patterns.end(); ++it) {
if ((*it).MatchesURL(url)) {
return true;
}
}
}
return false;
}
void UserScriptListener::StartDelayedRequests() {
WeakThrottleList::const_iterator it;
for (it = throttles_.begin(); it != throttles_.end(); ++it) {
if (it->get())
(*it)->Resume();
}
throttles_.clear();
}
void UserScriptListener::CheckIfAllUserScriptsReady() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
bool was_ready = user_scripts_ready_;
user_scripts_ready_ = true;
for (ProfileDataMap::const_iterator it = profile_data_.begin();
it != profile_data_.end(); ++it) {
if (!it->second.user_scripts_ready)
user_scripts_ready_ = false;
}
if (user_scripts_ready_ && !was_ready)
StartDelayedRequests();
}
void UserScriptListener::UserScriptsReady(void* profile_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
profile_data_[profile_id].user_scripts_ready = true;
CheckIfAllUserScriptsReady();
}
void UserScriptListener::ProfileDestroyed(void* profile_id) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
profile_data_.erase(profile_id);
CheckIfAllUserScriptsReady();
}
void UserScriptListener::AppendNewURLPatterns(void* profile_id,
const URLPatterns& new_patterns) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
user_scripts_ready_ = false;
ProfileData& data = profile_data_[profile_id];
data.user_scripts_ready = false;
data.url_patterns.insert(data.url_patterns.end(),
new_patterns.begin(), new_patterns.end());
}
void UserScriptListener::ReplaceURLPatterns(void* profile_id,
const URLPatterns& patterns) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
ProfileData& data = profile_data_[profile_id];
data.url_patterns = patterns;
}
void UserScriptListener::CollectURLPatterns(const Extension* extension,
URLPatterns* patterns) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
const UserScriptList& scripts =
ContentScriptsInfo::GetContentScripts(extension);
for (UserScriptList::const_iterator iter = scripts.begin();
iter != scripts.end(); ++iter) {
patterns->insert(patterns->end(),
(*iter).url_patterns().begin(),
(*iter).url_patterns().end());
}
}
void UserScriptListener::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
switch (type) {
case chrome::NOTIFICATION_EXTENSION_LOADED: {
Profile* profile = content::Source<Profile>(source).ptr();
const Extension* extension =
content::Details<const Extension>(details).ptr();
if (ContentScriptsInfo::GetContentScripts(extension).empty())
return;
URLPatterns new_patterns;
CollectURLPatterns(extension, &new_patterns);
if (!new_patterns.empty()) {
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
&UserScriptListener::AppendNewURLPatterns, this,
profile, new_patterns));
}
break;
}
case chrome::NOTIFICATION_EXTENSION_UNLOADED_DEPRECATED: {
Profile* profile = content::Source<Profile>(source).ptr();
const Extension* unloaded_extension =
content::Details<UnloadedExtensionInfo>(details)->extension;
if (ContentScriptsInfo::GetContentScripts(unloaded_extension).empty())
return;
URLPatterns new_patterns;
ExtensionService* service = profile->GetExtensionService();
for (ExtensionSet::const_iterator it = service->extensions()->begin();
it != service->extensions()->end(); ++it) {
if (it->get() != unloaded_extension)
CollectURLPatterns(it->get(), &new_patterns);
}
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
&UserScriptListener::ReplaceURLPatterns, this,
profile, new_patterns));
break;
}
case chrome::NOTIFICATION_USER_SCRIPTS_UPDATED: {
Profile* profile = content::Source<Profile>(source).ptr();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
&UserScriptListener::UserScriptsReady, this, profile));
break;
}
case chrome::NOTIFICATION_PROFILE_DESTROYED: {
Profile* profile = content::Source<Profile>(source).ptr();
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
&UserScriptListener::ProfileDestroyed, this, profile));
break;
}
default:
NOTREACHED();
}
}
}