Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(95)

Unified Diff: extensions/renderer/user_script_slave.cc

Issue 284153006: Introduce ScriptInjection in extensions/renderer to inject UserScripts (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: extensions/renderer/user_script_slave.cc
diff --git a/extensions/renderer/user_script_slave.cc b/extensions/renderer/user_script_slave.cc
index f05d214799a264c3cefc665c90571b9351abf7ee..06390a20a2929fe9cdabd4830b4cc953ee663596 100644
--- a/extensions/renderer/user_script_slave.cc
+++ b/extensions/renderer/user_script_slave.cc
@@ -6,14 +6,11 @@
#include <map>
-#include "base/command_line.h"
#include "base/logging.h"
#include "base/memory/shared_memory.h"
#include "base/metrics/histogram.h"
#include "base/pickle.h"
-#include "base/strings/stringprintf.h"
#include "base/timer/elapsed_timer.h"
-#include "content/public/common/url_constants.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "extensions/common/extension.h"
@@ -21,66 +18,48 @@
#include "extensions/common/extension_set.h"
#include "extensions/common/manifest_handlers/csp_info.h"
#include "extensions/common/permissions/permissions_data.h"
-#include "extensions/renderer/dom_activity_logger.h"
-#include "extensions/renderer/extension_groups.h"
#include "extensions/renderer/extensions_renderer_client.h"
#include "extensions/renderer/script_context.h"
-#include "grit/renderer_resources.h"
-#include "third_party/WebKit/public/platform/WebURLRequest.h"
-#include "third_party/WebKit/public/platform/WebVector.h"
-#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFrame.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h"
#include "third_party/WebKit/public/web/WebSecurityPolicy.h"
#include "third_party/WebKit/public/web/WebView.h"
-#include "ui/base/resource/resource_bundle.h"
#include "url/gurl.h"
using blink::WebFrame;
using blink::WebSecurityOrigin;
using blink::WebSecurityPolicy;
using blink::WebString;
-using blink::WebVector;
using blink::WebView;
using content::RenderThread;
namespace extensions {
-// These two strings are injected before and after the Greasemonkey API and
-// user script to wrap it in an anonymous scope.
-static const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
-static const char kUserScriptTail[] = "\n})(window);";
-
int UserScriptSlave::GetIsolatedWorldIdForExtension(const Extension* extension,
WebFrame* frame) {
static int g_next_isolated_world_id =
ExtensionsRendererClient::Get()->GetLowestIsolatedWorldId();
+ int id = 0;
IsolatedWorldMap::iterator iter = isolated_world_ids_.find(extension->id());
if (iter != isolated_world_ids_.end()) {
- // We need to set the isolated world origin and CSP even if it's not a new
- // world since these are stored per frame, and we might not have used this
- // isolated world in this frame before.
- frame->setIsolatedWorldSecurityOrigin(
- iter->second, WebSecurityOrigin::create(extension->url()));
- frame->setIsolatedWorldContentSecurityPolicy(
- iter->second,
- WebString::fromUTF8(CSPInfo::GetContentSecurityPolicy(extension)));
- return iter->second;
+ id = iter->second;
+ } else {
+ id = g_next_isolated_world_id++;
+ // This map will tend to pile up over time, but realistically, you're never
+ // going to have enough extensions for it to matter.
+ isolated_world_ids_[extension->id()] = id;
}
- int new_id = g_next_isolated_world_id;
- ++g_next_isolated_world_id;
-
- // This map will tend to pile up over time, but realistically, you're never
- // going to have enough extensions for it to matter.
- isolated_world_ids_[extension->id()] = new_id;
+ // We need to set the isolated world origin and CSP even if it's not a new
+ // world since these are stored per frame, and we might not have used this
+ // isolated world in this frame before.
frame->setIsolatedWorldSecurityOrigin(
- new_id, WebSecurityOrigin::create(extension->url()));
+ id, WebSecurityOrigin::create(extension->url()));
frame->setIsolatedWorldContentSecurityPolicy(
- new_id,
- WebString::fromUTF8(CSPInfo::GetContentSecurityPolicy(extension)));
- return new_id;
+ id, WebString::fromUTF8(CSPInfo::GetContentSecurityPolicy(extension)));
+
+ return id;
}
std::string UserScriptSlave::GetExtensionIdForIsolatedWorld(
@@ -99,9 +78,7 @@ void UserScriptSlave::RemoveIsolatedWorld(const std::string& extension_id) {
}
UserScriptSlave::UserScriptSlave(const ExtensionSet* extensions)
- : script_deleter_(&scripts_), extensions_(extensions) {
- api_js_ = ResourceBundle::GetSharedInstance().GetRawDataResource(
- IDR_GREASEMONKEY_API_JS);
+ : script_deleter_(&script_injections_), extensions_(extensions) {
}
UserScriptSlave::~UserScriptSlave() {
@@ -109,14 +86,23 @@ UserScriptSlave::~UserScriptSlave() {
void UserScriptSlave::GetActiveExtensions(
std::set<std::string>* extension_ids) {
- for (size_t i = 0; i < scripts_.size(); ++i) {
- DCHECK(!scripts_[i]->extension_id().empty());
- extension_ids->insert(scripts_[i]->extension_id());
+ DCHECK(extension_ids);
+ for (std::vector<ScriptInjection*>::const_iterator iter =
+ script_injections_.begin();
+ iter != script_injections_.end();
+ ++iter) {
+ DCHECK(!(*iter)->extension_id().empty());
+ extension_ids->insert((*iter)->extension_id());
}
}
+const Extension* UserScriptSlave::GetExtension(
+ const std::string& extension_id) {
+ return extensions_->GetByID(extension_id);
+}
+
bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) {
- scripts_.clear();
+ STLDeleteElements(&script_injections_);
bool only_inject_incognito =
ExtensionsRendererClient::Get()->IsIncognitoProcess();
@@ -144,10 +130,9 @@ bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) {
PickleIterator iter(pickle);
CHECK(pickle.ReadUInt64(&iter, &num_scripts));
- scripts_.reserve(num_scripts);
+ script_injections_.reserve(num_scripts);
for (uint64 i = 0; i < num_scripts; ++i) {
- scripts_.push_back(new UserScript());
- UserScript* script = scripts_.back();
+ scoped_ptr<UserScript> script(new UserScript());
script->Unpickle(pickle, &iter);
// Note that this is a pointer into shared memory. We don't own it. It gets
@@ -168,11 +153,10 @@ bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) {
base::StringPiece(body, body_length));
}
- if (only_inject_incognito && !script->is_incognito_enabled()) {
- // This script shouldn't run in an incognito tab.
- delete script;
- scripts_.pop_back();
- }
+ if (only_inject_incognito && !script->is_incognito_enabled())
+ continue; // This script shouldn't run in an incognito tab.
+
+ script_injections_.push_back(new ScriptInjection(script.Pass(), this));
}
return true;
@@ -180,142 +164,68 @@ bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) {
void UserScriptSlave::InjectScripts(WebFrame* frame,
UserScript::RunLocation location) {
- GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame);
- if (data_source_url.is_empty())
+ GURL document_url = ScriptInjection::GetDocumentUrlForFrame(frame);
+ if (document_url.is_empty())
return;
- if (frame->isViewSourceModeEnabled())
- data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
- data_source_url.spec());
-
- base::ElapsedTimer timer;
- int num_css = 0;
- int num_scripts = 0;
-
- ExecutingScriptsMap extensions_executing_scripts;
-
- blink::WebFrame* top_frame = frame->top();
content::RenderView* top_render_view =
- content::RenderView::FromWebView(top_frame->view());
+ content::RenderView::FromWebView(frame->top()->view());
- for (size_t i = 0; i < scripts_.size(); ++i) {
- std::vector<WebScriptSource> sources;
- UserScript* script = scripts_[i];
-
- if (frame->parent() && !script->match_all_frames())
- continue; // Only match subframes if the script declared it wanted to.
-
- const Extension* extension = extensions_->GetByID(script->extension_id());
-
- // Since extension info is sent separately from user script info, they can
- // be out of sync. We just ignore this situation.
- if (!extension)
+ ScriptInjection::ScriptsRunInfo scripts_run_info;
+ for (std::vector<ScriptInjection*>::const_iterator iter =
+ script_injections_.begin();
+ iter != script_injections_.end();
+ ++iter) {
+ ScriptInjection* injection = *iter;
+ if (!injection->WantsToRun(frame, location, document_url))
continue;
- // Content scripts are not tab-specific.
- const int kNoTabId = -1;
- // We don't have a process id in this context.
- const int kNoProcessId = -1;
- if (!PermissionsData::CanExecuteScriptOnPage(extension,
- data_source_url,
- top_frame->document().url(),
- kNoTabId,
- script,
- kNoProcessId,
- NULL)) {
- continue;
- }
+ const Extension* extension = GetExtension(injection->extension_id());
+ DCHECK(extension);
not at google - send to devlin 2014/05/15 23:23:21 I note you removed your TODO here :)
Devlin 2014/05/16 22:32:20 Whoops! That was actually just because this was b
- if (location == UserScript::DOCUMENT_START) {
- num_css += script->css_scripts().size();
- for (UserScript::FileList::const_iterator iter =
- script->css_scripts().begin();
- iter != script->css_scripts().end();
- ++iter) {
- frame->document().insertStyleSheet(
- WebString::fromUTF8(iter->GetContent().as_string()));
- }
+ if (PermissionsData::RequiresActionForScriptExecution(extension)) {
+ top_render_view->Send(
+ new ExtensionHostMsg_NotifyExtensionScriptExecution(
+ top_render_view->GetRoutingID(),
+ extension->id(),
+ top_render_view->GetPageId()));
}
- if (script->run_location() == location) {
- // TODO(rdevlin.cronin): Right now, this is just a notification, but soon
- // we should block without user consent.
- if (PermissionsData::RequiresActionForScriptExecution(extension)) {
- top_render_view->Send(
- new ExtensionHostMsg_NotifyExtensionScriptExecution(
- top_render_view->GetRoutingID(),
- extension->id(),
- top_render_view->GetPageId()));
- }
- num_scripts += script->js_scripts().size();
- for (size_t j = 0; j < script->js_scripts().size(); ++j) {
- UserScript::File& file = script->js_scripts()[j];
- std::string content = file.GetContent().as_string();
-
- // We add this dumb function wrapper for standalone user script to
- // emulate what Greasemonkey does.
- // TODO(aa): I think that maybe "is_standalone" scripts don't exist
- // anymore. Investigate.
- if (script->is_standalone() || script->emulate_greasemonkey()) {
- content.insert(0, kUserScriptHead);
- content += kUserScriptTail;
- }
- sources.push_back(
- WebScriptSource(WebString::fromUTF8(content), file.url()));
- }
- }
-
- if (!sources.empty()) {
- // Emulate Greasemonkey API for scripts that were converted to extensions
- // and "standalone" user scripts.
- if (script->is_standalone() || script->emulate_greasemonkey()) {
- sources.insert(
- sources.begin(),
- WebScriptSource(WebString::fromUTF8(api_js_.as_string())));
- }
-
- int isolated_world_id = GetIsolatedWorldIdForExtension(extension, frame);
-
- base::ElapsedTimer exec_timer;
- DOMActivityLogger::AttachToWorld(isolated_world_id, extension->id());
- frame->executeScriptInIsolatedWorld(isolated_world_id,
- &sources.front(),
- sources.size(),
- EXTENSION_GROUP_CONTENT_SCRIPTS);
- UMA_HISTOGRAM_TIMES("Extensions.InjectScriptTime", exec_timer.Elapsed());
-
- for (std::vector<WebScriptSource>::const_iterator iter = sources.begin();
- iter != sources.end();
- ++iter) {
- extensions_executing_scripts[extension->id()].insert(
- GURL(iter->url).path());
- }
- }
+ injection->Inject(frame, location, &scripts_run_info);
}
+ LogScriptsRun(frame, location, scripts_run_info);
+}
+
+void UserScriptSlave::LogScriptsRun(
+ blink::WebFrame* frame,
+ UserScript::RunLocation location,
+ const ScriptInjection::ScriptsRunInfo& info) {
// Notify the browser if any extensions are now executing scripts.
- if (!extensions_executing_scripts.empty()) {
- top_render_view->Send(new ExtensionHostMsg_ContentScriptsExecuting(
- top_render_view->GetRoutingID(),
- extensions_executing_scripts,
- top_render_view->GetPageId(),
- ScriptContext::GetDataSourceURLForFrame(top_frame)));
+ if (!info.executing_scripts.empty()) {
+ content::RenderView* render_view =
+ content::RenderView::FromWebView(frame->view());
+ render_view->Send(new ExtensionHostMsg_ContentScriptsExecuting(
+ render_view->GetRoutingID(),
+ info.executing_scripts,
+ render_view->GetPageId(),
+ ScriptContext::GetDataSourceURLForFrame(frame)));
}
- // Log debug info.
if (location == UserScript::DOCUMENT_START) {
- UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount", num_css);
- UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", num_scripts);
- if (num_css || num_scripts)
- UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", timer.Elapsed());
+ UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount",
+ info.num_css);
+ UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", info.num_js);
+ if (info.num_css || info.num_js)
+ UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", info.timer.Elapsed());
} else if (location == UserScript::DOCUMENT_END) {
- UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", num_scripts);
- if (num_scripts)
- UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", timer.Elapsed());
+ UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", info.num_js);
+ if (info.num_js)
+ UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", info.timer.Elapsed());
} else if (location == UserScript::DOCUMENT_IDLE) {
- UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount", num_scripts);
- if (num_scripts)
- UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", timer.Elapsed());
+ UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount", info.num_js);
+ if (info.num_js)
+ UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", info.timer.Elapsed());
} else {
NOTREACHED();
}
« extensions/renderer/user_script_slave.h ('K') | « extensions/renderer/user_script_slave.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698