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

Unified Diff: extensions/renderer/programmatic_script_injection.cc

Issue 321993003: Refactor renderer-side script injection (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Missing files Created 6 years, 6 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/programmatic_script_injection.cc
diff --git a/extensions/renderer/programmatic_script_injection.cc b/extensions/renderer/programmatic_script_injection.cc
new file mode 100644
index 0000000000000000000000000000000000000000..d885459905324a89b58be4fdd0bd52d1151797c7
--- /dev/null
+++ b/extensions/renderer/programmatic_script_injection.cc
@@ -0,0 +1,199 @@
+// 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/programmatic_script_injection.h"
+
+#include <vector>
+
+#include "base/values.h"
+#include "content/public/renderer/render_view.h"
+#include "content/public/renderer/v8_value_converter.h"
+#include "extensions/common/error_utils.h"
+#include "extensions/common/extension.h"
+#include "extensions/common/extension_messages.h"
+#include "extensions/common/manifest_constants.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 "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
+#include "third_party/WebKit/public/web/WebFrame.h"
+#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
+#include "third_party/WebKit/public/web/WebScriptSource.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+namespace {
+
+// Append all the child frames of |parent_frame| to |frames_vector|.
+void AppendAllChildFrames(blink::WebFrame* parent_frame,
+ std::vector<blink::WebFrame*>* frames_vector) {
+ DCHECK(parent_frame);
+ for (blink::WebFrame* child_frame = parent_frame->firstChild();
+ child_frame;
+ child_frame = child_frame->nextSibling()) {
+ frames_vector->push_back(child_frame);
+ AppendAllChildFrames(child_frame, frames_vector);
+ }
+}
+
+} // namespace
+
+ProgrammaticScriptInjection::ProgrammaticScriptInjection(
+ blink::WebFrame* web_frame,
+ const ExtensionMsg_ExecuteCode_Params& params,
+ int tab_id)
+ : ScriptInjection(web_frame,
+ params.extension_id,
+ static_cast<UserScript::RunLocation>(params.run_at),
+ tab_id),
+ params_(new ExtensionMsg_ExecuteCode_Params(params)) {
+}
+
+ProgrammaticScriptInjection::~ProgrammaticScriptInjection() {
+}
+
+content::RenderView* ProgrammaticScriptInjection::GetRenderView() {
+ return content::RenderView::FromWebView(web_frame()->view());
+}
+
+bool ProgrammaticScriptInjection::CanExecuteOnFrame(
+ const Extension* extension,
+ const blink::WebFrame* frame,
+ const GURL& top_url) const {
+ GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
+ frame, frame->document().url(), params_->match_about_blank);
+ if (params_->is_web_view)
+ return effective_document_url == params_->webview_src;
+
+ return extension->permissions_data()->CanAccessPage(extension,
+ effective_document_url,
+ top_url,
+ tab_id(),
+ -1, // no process ID.
+ NULL); // ignore error.
+}
+
+void ProgrammaticScriptInjection::ExtensionNotFound() {
+ content::RenderView* render_view = GetRenderView();
+ // Inform the browser process that we are not executing the script.
+ render_view->Send(
+ new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(),
+ params_->request_id,
+ std::string(), // no error
+ -1, // no page id
+ GURL(std::string()),
+ base::ListValue()));
+}
+
+bool ProgrammaticScriptInjection::Allowed(const Extension* extension) {
+ GURL url = web_frame()->document().url();
+ bool can_execute = CanExecuteOnFrame(extension, web_frame(), url);
+ if (!can_execute) {
+ // Send an error message indicating we could not execute script.
+ content::RenderView* render_view = GetRenderView();
+ render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished(
+ render_view->GetRoutingID(),
+ params_->request_id,
+ ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage,
+ url.spec()),
+ render_view->GetPageId(),
+ ScriptContext::GetDataSourceURLForFrame(web_frame()),
+ base::ListValue()));
+ }
+
+ return can_execute;
+}
+
+void ProgrammaticScriptInjection::Inject(ScriptsRunInfo* scripts_run_info,
+ const Extension* extension) {
+ std::vector<blink::WebFrame*> frame_vector;
+ frame_vector.push_back(web_frame());
+ if (params_->all_frames)
+ AppendAllChildFrames(web_frame(), &frame_vector);
+
+ scoped_ptr<blink::WebScopedUserGesture> gesture;
+ if (params_->user_gesture)
+ gesture.reset(new blink::WebScopedUserGesture);
+
+ GURL top_url = web_frame()->document().url();
+ base::ListValue execution_results;
+ for (std::vector<blink::WebFrame*>::iterator frame_it = frame_vector.begin();
+ frame_it != frame_vector.end();
+ ++frame_it) {
+ blink::WebFrame* child_frame = *frame_it;
+ CHECK(child_frame) << top_url;
+
+ // We recheck access here in the renderer for extra safety against races
+ // with navigation, but different frames can have different URLs, and the
+ // extension might only have access to a subset of them.
+ // For child frames, we just skip ones the extension doesn't have access
+ // to and carry on.
+ if (!CanExecuteOnFrame(extension, child_frame, top_url)) {
+ // If we couldn't access the top frame, we shouldn't be injecting at all.
+ DCHECK(child_frame->parent());
+ continue;
+ }
+
+ if (params_->is_javascript) {
+ blink::WebScriptSource source(blink::WebString::fromUTF8(params_->code),
+ params_->file_url);
+ v8::HandleScope scope(v8::Isolate::GetCurrent());
+
+ scoped_ptr<content::V8ValueConverter> v8_converter(
+ content::V8ValueConverter::create());
+ v8::Local<v8::Value> script_value;
+
+ if (params_->in_main_world) {
+ DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId,
+ extension->id());
+ script_value = child_frame->executeScriptAndReturnValue(source);
+ } else { // in isolated world
+ blink::WebVector<v8::Local<v8::Value> > results;
+ std::vector<blink::WebScriptSource> sources;
+ sources.push_back(source);
+ int isolated_world_id =
+ GetIsolatedWorldIdForExtension(extension, child_frame);
+ DOMActivityLogger::AttachToWorld(isolated_world_id, extension->id());
+ child_frame->executeScriptInIsolatedWorld(
+ isolated_world_id,
+ &sources.front(),
+ sources.size(),
+ EXTENSION_GROUP_CONTENT_SCRIPTS, // A blatant lie!
+ &results);
+ // We only expect one value back since we only pushed one source
+ if (results.size() == 1 && !results[0].IsEmpty())
+ script_value = results[0];
+ }
+
+ if (params_->wants_result && !script_value.IsEmpty()) {
+ // It's safe to always use the main world context when converting here.
+ // V8ValueConverterImpl shouldn't actually care about the context scope,
+ // and it switches to v8::Object's creation context when encountered.
+ v8::Local<v8::Context> context = child_frame->mainWorldScriptContext();
+ base::Value* result = v8_converter->FromV8Value(script_value, context);
+ // Always append an execution result (i.e. no result == null result) so
+ // that |execution_results| lines up with the frames.
+ execution_results.Append(result ? result
+ : base::Value::CreateNullValue());
+ }
+ } else { // css
+ child_frame->document().insertStyleSheet(
+ blink::WebString::fromUTF8(params_->code));
+ }
+ }
+
+ content::RenderView* render_view = GetRenderView();
+ render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished(
+ render_view->GetRoutingID(),
+ params_->request_id,
+ std::string(), // no error.
+ render_view->GetPageId(),
+ ScriptContext::GetDataSourceURLForFrame(web_frame()),
+ execution_results));
+}
+
+} // namespace extensions

Powered by Google App Engine
This is Rietveld 408576698