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

Side by Side Diff: extensions/renderer/script_injection.cc

Issue 934763003: Refactoring: de-couple Extensions from "script injection System" [render side]:3 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@decouple_brower_isolated_world_routingid_user_script_1
Patch Set: Rebase. Created 5 years, 9 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "extensions/renderer/script_injection.h" 5 #include "extensions/renderer/script_injection.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 } 101 }
102 102
103 // static 103 // static
104 void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) { 104 void ScriptInjection::RemoveIsolatedWorld(const std::string& host_id) {
105 g_isolated_worlds.Get().erase(host_id); 105 g_isolated_worlds.Get().erase(host_id);
106 } 106 }
107 107
108 ScriptInjection::ScriptInjection( 108 ScriptInjection::ScriptInjection(
109 scoped_ptr<ScriptInjector> injector, 109 scoped_ptr<ScriptInjector> injector,
110 blink::WebLocalFrame* web_frame, 110 blink::WebLocalFrame* web_frame,
111 const HostID& host_id, 111 scoped_ptr<const InjectionHost> injection_host,
112 UserScript::RunLocation run_location, 112 UserScript::RunLocation run_location,
113 int tab_id) 113 int tab_id)
114 : injector_(injector.Pass()), 114 : injector_(injector.Pass()),
115 web_frame_(web_frame), 115 web_frame_(web_frame),
116 host_id_(host_id), 116 injection_host_(injection_host.Pass()),
117 run_location_(run_location), 117 run_location_(run_location),
118 tab_id_(tab_id), 118 tab_id_(tab_id),
119 request_id_(kInvalidRequestId), 119 request_id_(kInvalidRequestId),
120 complete_(false) { 120 complete_(false) {
121 CHECK(injection_host_.get());
121 } 122 }
122 123
123 ScriptInjection::~ScriptInjection() { 124 ScriptInjection::~ScriptInjection() {
124 if (!complete_) 125 if (!complete_)
125 injector_->OnWillNotInject(ScriptInjector::WONT_INJECT); 126 injector_->OnWillNotInject(ScriptInjector::WONT_INJECT);
126 } 127 }
127 128
128 bool ScriptInjection::TryToInject(UserScript::RunLocation current_location, 129 bool ScriptInjection::TryToInject(UserScript::RunLocation current_location,
129 const InjectionHost* injection_host,
130 ScriptsRunInfo* scripts_run_info) { 130 ScriptsRunInfo* scripts_run_info) {
131 if (current_location < run_location_) 131 if (current_location < run_location_)
132 return false; // Wait for the right location. 132 return false; // Wait for the right location.
133 133
134 if (request_id_ != kInvalidRequestId) 134 if (request_id_ != kInvalidRequestId)
135 return false; // We're waiting for permission right now, try again later. 135 return false; // We're waiting for permission right now, try again later.
136 136
137 if (!injection_host) { 137 if (!injection_host_) {
138 NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED); 138 NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
139 return true; // We're done. 139 return true; // We're done.
140 } 140 }
141 141
142 switch (injector_->CanExecuteOnFrame(injection_host, web_frame_, tab_id_, 142 switch (injector_->CanExecuteOnFrame(
143 web_frame_->top()->document().url())) { 143 injection_host_.get(), web_frame_, tab_id_,
144 web_frame_->top()->document().url())) {
144 case PermissionsData::ACCESS_DENIED: 145 case PermissionsData::ACCESS_DENIED:
145 NotifyWillNotInject(ScriptInjector::NOT_ALLOWED); 146 NotifyWillNotInject(ScriptInjector::NOT_ALLOWED);
146 return true; // We're done. 147 return true; // We're done.
147 case PermissionsData::ACCESS_WITHHELD: 148 case PermissionsData::ACCESS_WITHHELD:
148 SendInjectionMessage(true /* request permission */); 149 SendInjectionMessage(true /* request permission */);
149 return false; // Wait around for permission. 150 return false; // Wait around for permission.
150 case PermissionsData::ACCESS_ALLOWED: 151 case PermissionsData::ACCESS_ALLOWED:
151 Inject(injection_host, scripts_run_info); 152 Inject(scripts_run_info);
152 return true; // We're done! 153 return true; // We're done!
153 } 154 }
154 155
155 NOTREACHED(); 156 NOTREACHED();
156 return false; 157 return false;
157 } 158 }
158 159
159 bool ScriptInjection::OnPermissionGranted(const InjectionHost* injection_host, 160 bool ScriptInjection::OnPermissionGranted(ScriptsRunInfo* scripts_run_info) {
160 ScriptsRunInfo* scripts_run_info) { 161 if (!injection_host_) {
161 if (!injection_host) {
162 NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED); 162 NotifyWillNotInject(ScriptInjector::EXTENSION_REMOVED);
163 return false; 163 return false;
164 } 164 }
165 165
166 Inject(injection_host, scripts_run_info); 166 Inject(scripts_run_info);
167 return true; 167 return true;
168 } 168 }
169 169
170 void ScriptInjection::OnHostRemoved() {
171 injection_host_.reset(nullptr);
172 }
173
170 void ScriptInjection::SendInjectionMessage(bool request_permission) { 174 void ScriptInjection::SendInjectionMessage(bool request_permission) {
171 content::RenderView* render_view = 175 content::RenderView* render_view =
172 content::RenderView::FromWebView(web_frame()->top()->view()); 176 content::RenderView::FromWebView(web_frame()->top()->view());
173 177
174 // If we are just notifying the browser of the injection, then send an 178 // If we are just notifying the browser of the injection, then send an
175 // invalid request (which is treated like a notification). 179 // invalid request (which is treated like a notification).
176 request_id_ = request_permission ? g_next_pending_id++ : kInvalidRequestId; 180 request_id_ = request_permission ? g_next_pending_id++ : kInvalidRequestId;
177 render_view->Send(new ExtensionHostMsg_RequestScriptInjectionPermission( 181 render_view->Send(new ExtensionHostMsg_RequestScriptInjectionPermission(
178 render_view->GetRoutingID(), 182 render_view->GetRoutingID(),
179 host_id_.id(), 183 host_id().id(),
180 injector_->script_type(), 184 injector_->script_type(),
181 request_id_)); 185 request_id_));
182 } 186 }
183 187
184 void ScriptInjection::NotifyWillNotInject( 188 void ScriptInjection::NotifyWillNotInject(
185 ScriptInjector::InjectFailureReason reason) { 189 ScriptInjector::InjectFailureReason reason) {
186 complete_ = true; 190 complete_ = true;
187 injector_->OnWillNotInject(reason); 191 injector_->OnWillNotInject(reason);
188 } 192 }
189 193
190 void ScriptInjection::Inject(const InjectionHost* injection_host, 194 void ScriptInjection::Inject(ScriptsRunInfo* scripts_run_info) {
191 ScriptsRunInfo* scripts_run_info) { 195 DCHECK(injection_host_);
192 DCHECK(injection_host);
193 DCHECK(scripts_run_info); 196 DCHECK(scripts_run_info);
194 DCHECK(!complete_); 197 DCHECK(!complete_);
195 198
196 if (injection_host->ShouldNotifyBrowserOfInjection()) 199 if (injection_host_->ShouldNotifyBrowserOfInjection())
197 SendInjectionMessage(false /* don't request permission */); 200 SendInjectionMessage(false /* don't request permission */);
198 201
199 std::vector<blink::WebFrame*> frame_vector; 202 std::vector<blink::WebFrame*> frame_vector;
200 frame_vector.push_back(web_frame_); 203 frame_vector.push_back(web_frame_);
201 if (injector_->ShouldExecuteInChildFrames()) 204 if (injector_->ShouldExecuteInChildFrames())
202 AppendAllChildFrames(web_frame_, &frame_vector); 205 AppendAllChildFrames(web_frame_, &frame_vector);
203 206
204 scoped_ptr<blink::WebScopedUserGesture> gesture; 207 scoped_ptr<blink::WebScopedUserGesture> gesture;
205 if (injector_->IsUserGesture()) 208 if (injector_->IsUserGesture())
206 gesture.reset(new blink::WebScopedUserGesture()); 209 gesture.reset(new blink::WebScopedUserGesture());
(...skipping 12 matching lines...) Expand all
219 blink::WebLocalFrame* frame = (*iter)->toWebLocalFrame(); 222 blink::WebLocalFrame* frame = (*iter)->toWebLocalFrame();
220 223
221 // We recheck access here in the renderer for extra safety against races 224 // We recheck access here in the renderer for extra safety against races
222 // with navigation, but different frames can have different URLs, and the 225 // with navigation, but different frames can have different URLs, and the
223 // injection host might only have access to a subset of them. 226 // injection host might only have access to a subset of them.
224 // For child frames, we just skip ones the injection host doesn't have 227 // For child frames, we just skip ones the injection host doesn't have
225 // access to and carry on. 228 // access to and carry on.
226 // Note: we don't consider ACCESS_WITHHELD because there is nowhere to 229 // Note: we don't consider ACCESS_WITHHELD because there is nowhere to
227 // surface a request for a child frame. 230 // surface a request for a child frame.
228 // TODO(rdevlin.cronin): We should ask for permission somehow. 231 // TODO(rdevlin.cronin): We should ask for permission somehow.
229 if (injector_->CanExecuteOnFrame(injection_host, frame, tab_id_, top_url) == 232 if (injector_->CanExecuteOnFrame(
230 PermissionsData::ACCESS_DENIED) { 233 injection_host_.get(), frame, tab_id_, top_url) ==
234 PermissionsData::ACCESS_DENIED) {
231 DCHECK(frame->parent()); 235 DCHECK(frame->parent());
232 continue; 236 continue;
233 } 237 }
234 if (inject_js) 238 if (inject_js)
235 InjectJs(injection_host, frame, execution_results.get()); 239 InjectJs(frame, execution_results.get());
236 if (inject_css) 240 if (inject_css)
237 InjectCss(frame); 241 InjectCss(frame);
238 } 242 }
239 243
240 complete_ = true; 244 complete_ = true;
241 245
242 // TODO(hanxi): don't log these metrics for webUIs' injections. 246 // TODO(hanxi): don't log these metrics for webUIs' injections.
243 injector_->OnInjectionComplete(execution_results.Pass(), 247 injector_->OnInjectionComplete(execution_results.Pass(),
244 scripts_run_info, 248 scripts_run_info,
245 run_location_); 249 run_location_);
246 } 250 }
247 251
248 void ScriptInjection::InjectJs(const InjectionHost* injection_host, 252 void ScriptInjection::InjectJs(blink::WebLocalFrame* frame,
249 blink::WebLocalFrame* frame,
250 base::ListValue* execution_results) { 253 base::ListValue* execution_results) {
251 std::vector<blink::WebScriptSource> sources = 254 std::vector<blink::WebScriptSource> sources =
252 injector_->GetJsSources(run_location_); 255 injector_->GetJsSources(run_location_);
253 bool in_main_world = injector_->ShouldExecuteInMainWorld(); 256 bool in_main_world = injector_->ShouldExecuteInMainWorld();
254 int world_id = in_main_world 257 int world_id = in_main_world
255 ? DOMActivityLogger::kMainWorldId 258 ? DOMActivityLogger::kMainWorldId
256 : GetIsolatedWorldIdForInstance(injection_host, frame); 259 : GetIsolatedWorldIdForInstance(injection_host_.get(),
260 frame);
257 bool expects_results = injector_->ExpectsResults(); 261 bool expects_results = injector_->ExpectsResults();
258 262
259 base::ElapsedTimer exec_timer; 263 base::ElapsedTimer exec_timer;
260 if (injection_host->id().type() == HostID::EXTENSIONS) 264 if (injection_host_->id().type() == HostID::EXTENSIONS)
261 DOMActivityLogger::AttachToWorld(world_id, injection_host->id().id()); 265 DOMActivityLogger::AttachToWorld(world_id, injection_host_->id().id());
262 v8::HandleScope scope(v8::Isolate::GetCurrent()); 266 v8::HandleScope scope(v8::Isolate::GetCurrent());
263 v8::Local<v8::Value> script_value; 267 v8::Local<v8::Value> script_value;
264 if (in_main_world) { 268 if (in_main_world) {
265 // We only inject in the main world for javascript: urls. 269 // We only inject in the main world for javascript: urls.
266 DCHECK_EQ(1u, sources.size()); 270 DCHECK_EQ(1u, sources.size());
267 271
268 const blink::WebScriptSource& source = sources.front(); 272 const blink::WebScriptSource& source = sources.front();
269 if (expects_results) 273 if (expects_results)
270 script_value = frame->executeScriptAndReturnValue(source); 274 script_value = frame->executeScriptAndReturnValue(source);
271 else 275 else
272 frame->executeScript(source); 276 frame->executeScript(source);
273 } else { // in isolated world 277 } else { // in isolated world
274 scoped_ptr<blink::WebVector<v8::Local<v8::Value> > > results; 278 scoped_ptr<blink::WebVector<v8::Local<v8::Value> > > results;
275 if (expects_results) 279 if (expects_results)
276 results.reset(new blink::WebVector<v8::Local<v8::Value> >()); 280 results.reset(new blink::WebVector<v8::Local<v8::Value> >());
277 frame->executeScriptInIsolatedWorld(world_id, 281 frame->executeScriptInIsolatedWorld(world_id,
278 &sources.front(), 282 &sources.front(),
279 sources.size(), 283 sources.size(),
280 EXTENSION_GROUP_CONTENT_SCRIPTS, 284 EXTENSION_GROUP_CONTENT_SCRIPTS,
281 results.get()); 285 results.get());
282 if (expects_results && !results->isEmpty()) 286 if (expects_results && !results->isEmpty())
283 script_value = (*results)[0]; 287 script_value = (*results)[0];
284 } 288 }
285 289
286 if (injection_host->id().type() == HostID::EXTENSIONS) 290 if (injection_host_->id().type() == HostID::EXTENSIONS)
287 UMA_HISTOGRAM_TIMES("Extensions.InjectScriptTime", exec_timer.Elapsed()); 291 UMA_HISTOGRAM_TIMES("Extensions.InjectScriptTime", exec_timer.Elapsed());
288 292
289 if (expects_results) { 293 if (expects_results) {
290 // Right now, we only support returning single results (per frame). 294 // Right now, we only support returning single results (per frame).
291 scoped_ptr<content::V8ValueConverter> v8_converter( 295 scoped_ptr<content::V8ValueConverter> v8_converter(
292 content::V8ValueConverter::create()); 296 content::V8ValueConverter::create());
293 // It's safe to always use the main world context when converting 297 // It's safe to always use the main world context when converting
294 // here. V8ValueConverterImpl shouldn't actually care about the 298 // here. V8ValueConverterImpl shouldn't actually care about the
295 // context scope, and it switches to v8::Object's creation context 299 // context scope, and it switches to v8::Object's creation context
296 // when encountered. 300 // when encountered.
(...skipping 11 matching lines...) Expand all
308 std::vector<std::string> css_sources = 312 std::vector<std::string> css_sources =
309 injector_->GetCssSources(run_location_); 313 injector_->GetCssSources(run_location_);
310 for (std::vector<std::string>::const_iterator iter = css_sources.begin(); 314 for (std::vector<std::string>::const_iterator iter = css_sources.begin();
311 iter != css_sources.end(); 315 iter != css_sources.end();
312 ++iter) { 316 ++iter) {
313 frame->document().insertStyleSheet(blink::WebString::fromUTF8(*iter)); 317 frame->document().insertStyleSheet(blink::WebString::fromUTF8(*iter));
314 } 318 }
315 } 319 }
316 320
317 } // namespace extensions 321 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698