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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "extensions/renderer/programmatic_script_injection.h"
6
7 #include <vector>
8
9 #include "base/values.h"
10 #include "content/public/renderer/render_view.h"
11 #include "content/public/renderer/v8_value_converter.h"
12 #include "extensions/common/error_utils.h"
13 #include "extensions/common/extension.h"
14 #include "extensions/common/extension_messages.h"
15 #include "extensions/common/manifest_constants.h"
16 #include "extensions/common/permissions/permissions_data.h"
17 #include "extensions/renderer/dom_activity_logger.h"
18 #include "extensions/renderer/extension_groups.h"
19 #include "extensions/renderer/script_context.h"
20 #include "third_party/WebKit/public/platform/WebString.h"
21 #include "third_party/WebKit/public/web/WebDocument.h"
22 #include "third_party/WebKit/public/web/WebFrame.h"
23 #include "third_party/WebKit/public/web/WebScopedUserGesture.h"
24 #include "third_party/WebKit/public/web/WebScriptSource.h"
25 #include "url/gurl.h"
26
27 namespace extensions {
28
29 namespace {
30
31 // Append all the child frames of |parent_frame| to |frames_vector|.
32 void AppendAllChildFrames(blink::WebFrame* parent_frame,
33 std::vector<blink::WebFrame*>* frames_vector) {
34 DCHECK(parent_frame);
35 for (blink::WebFrame* child_frame = parent_frame->firstChild();
36 child_frame;
37 child_frame = child_frame->nextSibling()) {
38 frames_vector->push_back(child_frame);
39 AppendAllChildFrames(child_frame, frames_vector);
40 }
41 }
42
43 } // namespace
44
45 ProgrammaticScriptInjection::ProgrammaticScriptInjection(
46 blink::WebFrame* web_frame,
47 const ExtensionMsg_ExecuteCode_Params& params,
48 int tab_id)
49 : ScriptInjection(web_frame,
50 params.extension_id,
51 static_cast<UserScript::RunLocation>(params.run_at),
52 tab_id),
53 params_(new ExtensionMsg_ExecuteCode_Params(params)) {
54 }
55
56 ProgrammaticScriptInjection::~ProgrammaticScriptInjection() {
57 }
58
59 content::RenderView* ProgrammaticScriptInjection::GetRenderView() {
60 return content::RenderView::FromWebView(web_frame()->view());
61 }
62
63 bool ProgrammaticScriptInjection::CanExecuteOnFrame(
64 const Extension* extension,
65 const blink::WebFrame* frame,
66 const GURL& top_url) const {
67 GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
68 frame, frame->document().url(), params_->match_about_blank);
69 if (params_->is_web_view)
70 return effective_document_url == params_->webview_src;
71
72 return extension->permissions_data()->CanAccessPage(extension,
73 effective_document_url,
74 top_url,
75 tab_id(),
76 -1, // no process ID.
77 NULL); // ignore error.
78 }
79
80 void ProgrammaticScriptInjection::ExtensionNotFound() {
81 content::RenderView* render_view = GetRenderView();
82 // Inform the browser process that we are not executing the script.
83 render_view->Send(
84 new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(),
85 params_->request_id,
86 std::string(), // no error
87 -1, // no page id
88 GURL(std::string()),
89 base::ListValue()));
90 }
91
92 bool ProgrammaticScriptInjection::Allowed(const Extension* extension) {
93 GURL url = web_frame()->document().url();
94 bool can_execute = CanExecuteOnFrame(extension, web_frame(), url);
95 if (!can_execute) {
96 // Send an error message indicating we could not execute script.
97 content::RenderView* render_view = GetRenderView();
98 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished(
99 render_view->GetRoutingID(),
100 params_->request_id,
101 ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage,
102 url.spec()),
103 render_view->GetPageId(),
104 ScriptContext::GetDataSourceURLForFrame(web_frame()),
105 base::ListValue()));
106 }
107
108 return can_execute;
109 }
110
111 void ProgrammaticScriptInjection::Inject(ScriptsRunInfo* scripts_run_info,
112 const Extension* extension) {
113 std::vector<blink::WebFrame*> frame_vector;
114 frame_vector.push_back(web_frame());
115 if (params_->all_frames)
116 AppendAllChildFrames(web_frame(), &frame_vector);
117
118 scoped_ptr<blink::WebScopedUserGesture> gesture;
119 if (params_->user_gesture)
120 gesture.reset(new blink::WebScopedUserGesture);
121
122 GURL top_url = web_frame()->document().url();
123 base::ListValue execution_results;
124 for (std::vector<blink::WebFrame*>::iterator frame_it = frame_vector.begin();
125 frame_it != frame_vector.end();
126 ++frame_it) {
127 blink::WebFrame* child_frame = *frame_it;
128 CHECK(child_frame) << top_url;
129
130 // We recheck access here in the renderer for extra safety against races
131 // with navigation, but different frames can have different URLs, and the
132 // extension might only have access to a subset of them.
133 // For child frames, we just skip ones the extension doesn't have access
134 // to and carry on.
135 if (!CanExecuteOnFrame(extension, child_frame, top_url)) {
136 // If we couldn't access the top frame, we shouldn't be injecting at all.
137 DCHECK(child_frame->parent());
138 continue;
139 }
140
141 if (params_->is_javascript) {
142 blink::WebScriptSource source(blink::WebString::fromUTF8(params_->code),
143 params_->file_url);
144 v8::HandleScope scope(v8::Isolate::GetCurrent());
145
146 scoped_ptr<content::V8ValueConverter> v8_converter(
147 content::V8ValueConverter::create());
148 v8::Local<v8::Value> script_value;
149
150 if (params_->in_main_world) {
151 DOMActivityLogger::AttachToWorld(DOMActivityLogger::kMainWorldId,
152 extension->id());
153 script_value = child_frame->executeScriptAndReturnValue(source);
154 } else { // in isolated world
155 blink::WebVector<v8::Local<v8::Value> > results;
156 std::vector<blink::WebScriptSource> sources;
157 sources.push_back(source);
158 int isolated_world_id =
159 GetIsolatedWorldIdForExtension(extension, child_frame);
160 DOMActivityLogger::AttachToWorld(isolated_world_id, extension->id());
161 child_frame->executeScriptInIsolatedWorld(
162 isolated_world_id,
163 &sources.front(),
164 sources.size(),
165 EXTENSION_GROUP_CONTENT_SCRIPTS, // A blatant lie!
166 &results);
167 // We only expect one value back since we only pushed one source
168 if (results.size() == 1 && !results[0].IsEmpty())
169 script_value = results[0];
170 }
171
172 if (params_->wants_result && !script_value.IsEmpty()) {
173 // It's safe to always use the main world context when converting here.
174 // V8ValueConverterImpl shouldn't actually care about the context scope,
175 // and it switches to v8::Object's creation context when encountered.
176 v8::Local<v8::Context> context = child_frame->mainWorldScriptContext();
177 base::Value* result = v8_converter->FromV8Value(script_value, context);
178 // Always append an execution result (i.e. no result == null result) so
179 // that |execution_results| lines up with the frames.
180 execution_results.Append(result ? result
181 : base::Value::CreateNullValue());
182 }
183 } else { // css
184 child_frame->document().insertStyleSheet(
185 blink::WebString::fromUTF8(params_->code));
186 }
187 }
188
189 content::RenderView* render_view = GetRenderView();
190 render_view->Send(new ExtensionHostMsg_ExecuteCodeFinished(
191 render_view->GetRoutingID(),
192 params_->request_id,
193 std::string(), // no error.
194 render_view->GetPageId(),
195 ScriptContext::GetDataSourceURLForFrame(web_frame()),
196 execution_results));
197 }
198
199 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698