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

Unified Diff: extensions/renderer/script_injection.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
« no previous file with comments | « extensions/renderer/script_injection.h ('k') | extensions/renderer/user_script_scheduler.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: extensions/renderer/script_injection.cc
diff --git a/extensions/renderer/script_injection.cc b/extensions/renderer/script_injection.cc
new file mode 100644
index 0000000000000000000000000000000000000000..4db534a1f68c1934127ec61a5617c701d28aa40b
--- /dev/null
+++ b/extensions/renderer/script_injection.cc
@@ -0,0 +1,202 @@
+// Copyright 2014 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 "extensions/renderer/script_injection.h"
+
+#include <vector>
+
+#include "base/lazy_instance.h"
+#include "base/metrics/histogram.h"
+#include "content/public/common/url_constants.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_messages.h"
+#include "extensions/common/permissions/permissions_data.h"
+#include "extensions/renderer/dom_activity_logger.h"
+#include "extensions/renderer/extension_groups.h"
+#include "extensions/renderer/script_context.h"
+#include "extensions/renderer/user_script_slave.h"
+#include "grit/renderer_resources.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebScriptSource.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+namespace {
+
+// These two strings are injected before and after the Greasemonkey API and
+// user script to wrap it in an anonymous scope.
+const char kUserScriptHead[] = "(function (unsafeWindow) {\n";
+const char kUserScriptTail[] = "\n})(window);";
+
+// Greasemonkey API source that is injected with the scripts.
+struct GreasemonkeyApiJsString {
+ GreasemonkeyApiJsString();
+ blink::WebScriptSource source;
+};
+
+// The below constructor, monstrous as it is, just makes a WebScriptSource from
+// the GreasemonkeyApiJs resource.
+GreasemonkeyApiJsString::GreasemonkeyApiJsString()
+ : source(blink::WebScriptSource(blink::WebString::fromUTF8(
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_GREASEMONKEY_API_JS).as_string()))) {
+}
+
+base::LazyInstance<GreasemonkeyApiJsString> g_greasemonkey_api =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+ScriptInjection::ScriptsRunInfo::ScriptsRunInfo() : num_css(0u), num_js(0u) {
+}
+
+ScriptInjection::ScriptsRunInfo::~ScriptsRunInfo() {
+}
+
+// static
+GURL ScriptInjection::GetDocumentUrlForFrame(blink::WebFrame* frame) {
+ GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame);
+ if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) {
+ data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
+ data_source_url.spec());
+ }
+
+ return data_source_url;
+}
+
+ScriptInjection::ScriptInjection(
+ scoped_ptr<UserScript> script,
+ UserScriptSlave* user_script_slave)
+ : script_(script.Pass()),
+ extension_id_(script_->extension_id()),
+ user_script_slave_(user_script_slave),
+ is_standalone_or_emulate_greasemonkey_(
+ script_->is_standalone() || script_->emulate_greasemonkey()) {
+}
+
+ScriptInjection::~ScriptInjection() {
+}
+
+bool ScriptInjection::WantsToRun(blink::WebFrame* frame,
+ UserScript::RunLocation run_location,
+ const GURL& document_url) const {
+ if (frame->parent() && !script_->match_all_frames())
+ return false; // Only match subframes if the script declared it wanted to.
+
+ const Extension* extension = user_script_slave_->GetExtension(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)
+ return false;
+
+ // Content scripts are not tab-specific.
+ static const int kNoTabId = -1;
+ // We don't have a process id in this context.
+ static const int kNoProcessId = -1;
+
+ GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
+ frame, document_url, script_->match_about_blank());
+
+ if (!PermissionsData::CanExecuteScriptOnPage(extension,
+ effective_document_url,
+ frame->top()->document().url(),
+ kNoTabId,
+ script_.get(),
+ kNoProcessId,
+ NULL /* ignore error */)) {
+ return false;
+ }
+
+ return ShouldInjectCSS(run_location) || ShouldInjectJS(run_location);
+}
+
+void ScriptInjection::Inject(blink::WebFrame* frame,
+ UserScript::RunLocation run_location,
+ ScriptsRunInfo* scripts_run_info) const {
+ DCHECK(frame);
+ DCHECK(scripts_run_info);
+ DCHECK(WantsToRun(frame, run_location, GetDocumentUrlForFrame(frame)));
+ DCHECK(user_script_slave_->GetExtension(extension_id_));
+
+ if (ShouldInjectCSS(run_location))
+ InjectCSS(frame, scripts_run_info);
+ if (ShouldInjectJS(run_location))
+ InjectJS(frame, scripts_run_info);
+}
+
+bool ScriptInjection::ShouldInjectJS(UserScript::RunLocation run_location)
+ const {
+ return !script_->js_scripts().empty() &&
+ script_->run_location() == run_location;
+}
+
+bool ScriptInjection::ShouldInjectCSS(UserScript::RunLocation run_location)
+ const {
+ return !script_->css_scripts().empty() &&
+ run_location == UserScript::DOCUMENT_START;
+}
+
+void ScriptInjection::InjectJS(blink::WebFrame* frame,
+ ScriptsRunInfo* scripts_run_info) const {
+ const UserScript::FileList& js_scripts = script_->js_scripts();
+ std::vector<blink::WebScriptSource> sources;
+ scripts_run_info->num_js += js_scripts.size();
+ for (UserScript::FileList::const_iterator iter = js_scripts.begin();
+ iter != js_scripts.end();
+ ++iter) {
+ std::string content = iter->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 (is_standalone_or_emulate_greasemonkey_) {
+ content.insert(0, kUserScriptHead);
+ content += kUserScriptTail;
+ }
+ sources.push_back(blink::WebScriptSource(
+ blink::WebString::fromUTF8(content), iter->url()));
+ }
+
+ // Emulate Greasemonkey API for scripts that were converted to extensions
+ // and "standalone" user scripts.
+ if (is_standalone_or_emulate_greasemonkey_)
+ sources.insert(sources.begin(), g_greasemonkey_api.Get().source);
+
+ int isolated_world_id =
+ user_script_slave_->GetIsolatedWorldIdForExtension(
+ user_script_slave_->GetExtension(extension_id_), 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<blink::WebScriptSource>::const_iterator iter =
+ sources.begin();
+ iter != sources.end();
+ ++iter) {
+ scripts_run_info->executing_scripts[extension_id_].insert(
+ GURL(iter->url).path());
+ }
+}
+
+void ScriptInjection::InjectCSS(blink::WebFrame* frame,
+ ScriptsRunInfo* scripts_run_info) const {
+ const UserScript::FileList& css_scripts = script_->css_scripts();
+ scripts_run_info->num_css += css_scripts.size();
+ for (UserScript::FileList::const_iterator iter = css_scripts.begin();
+ iter != css_scripts.end();
+ ++iter) {
+ frame->document().insertStyleSheet(
+ blink::WebString::fromUTF8(iter->GetContent().as_string()));
+ }
+}
+
+} // namespace extensions
« no previous file with comments | « extensions/renderer/script_injection.h ('k') | extensions/renderer/user_script_scheduler.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698