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

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

Issue 1216453002: [Extensions] Handle some funny cases in script injection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 5 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_manager.h" 5 #include "extensions/renderer/script_injection_manager.h"
6 6
7 #include "base/auto_reset.h" 7 #include "base/auto_reset.h"
8 #include "base/bind.h" 8 #include "base/bind.h"
9 #include "base/memory/weak_ptr.h" 9 #include "base/memory/weak_ptr.h"
10 #include "base/values.h" 10 #include "base/values.h"
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 // document_idle. 83 // document_idle.
84 void RunIdle(); 84 void RunIdle();
85 85
86 // Indicate that the frame is no longer valid because it is starting 86 // Indicate that the frame is no longer valid because it is starting
87 // a new load or closing. 87 // a new load or closing.
88 void InvalidateFrame(); 88 void InvalidateFrame();
89 89
90 // The owning ScriptInjectionManager. 90 // The owning ScriptInjectionManager.
91 ScriptInjectionManager* manager_; 91 ScriptInjectionManager* manager_;
92 92
93 // The set of frames that we are about to notify for DOCUMENT_IDLE. We keep 93 bool should_run_idle_;
94 // a set of those that are valid, so we don't notify that an invalid frame
95 // became idle.
96 std::set<content::RenderFrame*> pending_idle_frames_;
97 94
98 base::WeakPtrFactory<RFOHelper> weak_factory_; 95 base::WeakPtrFactory<RFOHelper> weak_factory_;
99 }; 96 };
100 97
101 ScriptInjectionManager::RFOHelper::RFOHelper( 98 ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
102 content::RenderFrame* render_frame, 99 ScriptInjectionManager* manager)
103 ScriptInjectionManager* manager)
104 : content::RenderFrameObserver(render_frame), 100 : content::RenderFrameObserver(render_frame),
105 manager_(manager), 101 manager_(manager),
102 should_run_idle_(true),
106 weak_factory_(this) { 103 weak_factory_(this) {
107 } 104 }
108 105
109 ScriptInjectionManager::RFOHelper::~RFOHelper() { 106 ScriptInjectionManager::RFOHelper::~RFOHelper() {
110 } 107 }
111 108
112 bool ScriptInjectionManager::RFOHelper::OnMessageReceived( 109 bool ScriptInjectionManager::RFOHelper::OnMessageReceived(
113 const IPC::Message& message) { 110 const IPC::Message& message) {
114 bool handled = true; 111 bool handled = true;
115 IPC_BEGIN_MESSAGE_MAP(ScriptInjectionManager::RFOHelper, message) 112 IPC_BEGIN_MESSAGE_MAP(ScriptInjectionManager::RFOHelper, message)
(...skipping 16 matching lines...) Expand all
132 if (manager_->frame_statuses_.count(render_frame()) != 0) 129 if (manager_->frame_statuses_.count(render_frame()) != 0)
133 InvalidateFrame(); 130 InvalidateFrame();
134 } 131 }
135 132
136 void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() { 133 void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() {
137 manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_START); 134 manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_START);
138 } 135 }
139 136
140 void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() { 137 void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() {
141 manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_END); 138 manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_END);
142 pending_idle_frames_.insert(render_frame());
143 // We try to run idle in two places: here and DidFinishLoad. 139 // We try to run idle in two places: here and DidFinishLoad.
144 // DidFinishDocumentLoad() corresponds to completing the document's load, 140 // DidFinishDocumentLoad() corresponds to completing the document's load,
145 // whereas DidFinishLoad corresponds to completing the document and all 141 // whereas DidFinishLoad corresponds to completing the document and all
146 // subresources' load. We don't want to hold up script injection for a 142 // subresources' load. We don't want to hold up script injection for a
147 // particularly slow subresource, so we set a delayed task from here - but if 143 // particularly slow subresource, so we set a delayed task from here - but if
148 // we finish everything before that point (i.e., DidFinishLoad() is 144 // we finish everything before that point (i.e., DidFinishLoad() is
149 // triggered), then there's no reason to keep waiting. 145 // triggered), then there's no reason to keep waiting.
150 content::RenderThread::Get()->GetTaskRunner()->PostDelayedTask( 146 content::RenderThread::Get()->GetTaskRunner()->PostDelayedTask(
151 FROM_HERE, 147 FROM_HERE,
152 base::Bind(&ScriptInjectionManager::RFOHelper::RunIdle, 148 base::Bind(&ScriptInjectionManager::RFOHelper::RunIdle,
153 weak_factory_.GetWeakPtr()), 149 weak_factory_.GetWeakPtr()),
154 base::TimeDelta::FromMilliseconds(kScriptIdleTimeoutInMs)); 150 base::TimeDelta::FromMilliseconds(kScriptIdleTimeoutInMs));
155 } 151 }
156 152
157 void ScriptInjectionManager::RFOHelper::DidFinishLoad() { 153 void ScriptInjectionManager::RFOHelper::DidFinishLoad() {
158 // Ensure that we don't block any UI progress by running scripts. 154 // Ensure that we don't block any UI progress by running scripts.
159 // We *don't* add the frame to |pending_idle_frames_| here because
160 // DidFinishDocumentLoad should strictly come before DidFinishLoad, so the
161 // first posted task to RunIdle() pops it out of the set. This ensures we
162 // don't try to run idle twice.
163 content::RenderThread::Get()->GetTaskRunner()->PostTask( 155 content::RenderThread::Get()->GetTaskRunner()->PostTask(
164 FROM_HERE, 156 FROM_HERE,
165 base::Bind(&ScriptInjectionManager::RFOHelper::RunIdle, 157 base::Bind(&ScriptInjectionManager::RFOHelper::RunIdle,
166 weak_factory_.GetWeakPtr())); 158 weak_factory_.GetWeakPtr()));
167 } 159 }
168 160
169 void ScriptInjectionManager::RFOHelper::FrameDetached() { 161 void ScriptInjectionManager::RFOHelper::FrameDetached() {
170 // The frame is closing - invalidate. 162 // The frame is closing - invalidate.
171 InvalidateFrame(); 163 InvalidateFrame();
172 } 164 }
(...skipping 25 matching lines...) Expand all
198 } 190 }
199 191
200 void ScriptInjectionManager::RFOHelper::OnPermitScriptInjection( 192 void ScriptInjectionManager::RFOHelper::OnPermitScriptInjection(
201 int64 request_id) { 193 int64 request_id) {
202 manager_->HandlePermitScriptInjection(request_id); 194 manager_->HandlePermitScriptInjection(request_id);
203 } 195 }
204 196
205 void ScriptInjectionManager::RFOHelper::RunIdle() { 197 void ScriptInjectionManager::RFOHelper::RunIdle() {
206 // Only notify the manager if the frame hasn't either been removed or already 198 // Only notify the manager if the frame hasn't either been removed or already
207 // had idle run since the task to RunIdle() was posted. 199 // had idle run since the task to RunIdle() was posted.
208 if (pending_idle_frames_.count(render_frame()) > 0) { 200 if (should_run_idle_) {
201 should_run_idle_ = false;
209 manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE); 202 manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE);
210 pending_idle_frames_.erase(render_frame());
211 } 203 }
212 } 204 }
213 205
214 void ScriptInjectionManager::RFOHelper::InvalidateFrame() { 206 void ScriptInjectionManager::RFOHelper::InvalidateFrame() {
215 pending_idle_frames_.erase(render_frame()); 207 // Invalidate any pending idle injections, and reset the frame inject on idle.
208 weak_factory_.InvalidateWeakPtrs();
209 should_run_idle_ = true;
not at google - send to devlin 2015/06/29 18:28:11 = false?
Devlin 2015/06/29 19:41:44 = false = false; = true.
216 manager_->InvalidateForFrame(render_frame()); 210 manager_->InvalidateForFrame(render_frame());
217 } 211 }
218 212
219 ScriptInjectionManager::ScriptInjectionManager( 213 ScriptInjectionManager::ScriptInjectionManager(
220 const ExtensionSet* extensions, 214 const ExtensionSet* extensions,
221 UserScriptSetManager* user_script_set_manager) 215 UserScriptSetManager* user_script_set_manager)
222 : extensions_(extensions), 216 : extensions_(extensions),
217 valid_running_injection_frame_(nullptr),
223 user_script_set_manager_(user_script_set_manager), 218 user_script_set_manager_(user_script_set_manager),
224 user_script_set_manager_observer_(this) { 219 user_script_set_manager_observer_(this) {
225 user_script_set_manager_observer_.Add(user_script_set_manager_); 220 user_script_set_manager_observer_.Add(user_script_set_manager_);
226 } 221 }
227 222
228 ScriptInjectionManager::~ScriptInjectionManager() { 223 ScriptInjectionManager::~ScriptInjectionManager() {
229 } 224 }
230 225
231 void ScriptInjectionManager::OnRenderFrameCreated( 226 void ScriptInjectionManager::OnRenderFrameCreated(
232 content::RenderFrame* render_frame) { 227 content::RenderFrame* render_frame) {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 iter != rfo_helpers_.end(); 269 iter != rfo_helpers_.end();
275 ++iter) { 270 ++iter) {
276 if (*iter == helper) { 271 if (*iter == helper) {
277 rfo_helpers_.erase(iter); 272 rfo_helpers_.erase(iter);
278 break; 273 break;
279 } 274 }
280 } 275 }
281 } 276 }
282 277
283 void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) { 278 void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
279 // If the frame invalidated is the frame being injected into, we need to
280 // note it.
not at google - send to devlin 2015/06/29 18:28:11 This looks a little fishy to me. Is it really not
Devlin 2015/06/29 19:41:44 DCHECK'd to account for potential craziness. I bel
281 if (frame == valid_running_injection_frame_)
282 valid_running_injection_frame_ = nullptr;
283
284 for (ScopedVector<ScriptInjection>::iterator iter = 284 for (ScopedVector<ScriptInjection>::iterator iter =
285 pending_injections_.begin(); 285 pending_injections_.begin();
286 iter != pending_injections_.end();) { 286 iter != pending_injections_.end();) {
287 if ((*iter)->render_frame() == frame) 287 if ((*iter)->render_frame() == frame)
288 iter = pending_injections_.erase(iter); 288 iter = pending_injections_.erase(iter);
289 else 289 else
290 ++iter; 290 ++iter;
291 } 291 }
292 292
293 frame_statuses_.erase(frame); 293 frame_statuses_.erase(frame);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 } else { 342 } else {
343 ++iter; 343 ++iter;
344 } 344 }
345 } 345 }
346 346
347 // Add any injections for user scripts. 347 // Add any injections for user scripts.
348 int tab_id = ExtensionFrameHelper::Get(frame)->tab_id(); 348 int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
349 user_script_set_manager_->GetAllInjections( 349 user_script_set_manager_->GetAllInjections(
350 &frame_injections, frame, tab_id, run_location); 350 &frame_injections, frame, tab_id, run_location);
351 351
352 ScriptsRunInfo scripts_run_info; 352 // Note that we are running in |frame|.
353 valid_running_injection_frame_ = frame;
354
355 ScriptsRunInfo scripts_run_info(frame, run_location);
353 std::vector<ScriptInjection*> released_injections; 356 std::vector<ScriptInjection*> released_injections;
354 frame_injections.release(&released_injections); 357 frame_injections.release(&released_injections);
355 for (ScriptInjection* injection : released_injections) 358 for (ScriptInjection* injection : released_injections) {
359 // It's possible for the frame to be invalidated in the course of injection
360 // (if a script removes its own frame, for example). If this happens, abort.
361 if (!valid_running_injection_frame_)
362 break;
356 TryToInject(make_scoped_ptr(injection), run_location, &scripts_run_info); 363 TryToInject(make_scoped_ptr(injection), run_location, &scripts_run_info);
364 }
357 365
358 scripts_run_info.LogRun(frame->GetWebFrame(), run_location); 366 scripts_run_info.LogRun();
359 } 367 }
360 368
361 void ScriptInjectionManager::TryToInject( 369 void ScriptInjectionManager::TryToInject(
362 scoped_ptr<ScriptInjection> injection, 370 scoped_ptr<ScriptInjection> injection,
363 UserScript::RunLocation run_location, 371 UserScript::RunLocation run_location,
364 ScriptsRunInfo* scripts_run_info) { 372 ScriptsRunInfo* scripts_run_info) {
365 // Try to inject the script. If the injection is waiting (i.e., for 373 // Try to inject the script. If the injection is waiting (i.e., for
366 // permission), add it to the list of pending injections. If the injection 374 // permission), add it to the list of pending injections. If the injection
367 // has blocked, add it to the list of running injections. 375 // has blocked, add it to the list of running injections.
368 // The Unretained below is safe because this object owns all the 376 // The Unretained below is safe because this object owns all the
(...skipping 29 matching lines...) Expand all
398 } 406 }
399 407
400 scoped_ptr<ScriptInjection> injection(new ScriptInjection( 408 scoped_ptr<ScriptInjection> injection(new ScriptInjection(
401 scoped_ptr<ScriptInjector>( 409 scoped_ptr<ScriptInjector>(
402 new ProgrammaticScriptInjector(params, render_frame)), 410 new ProgrammaticScriptInjector(params, render_frame)),
403 render_frame, 411 render_frame,
404 injection_host.Pass(), 412 injection_host.Pass(),
405 static_cast<UserScript::RunLocation>(params.run_at), 413 static_cast<UserScript::RunLocation>(params.run_at),
406 ExtensionFrameHelper::Get(render_frame)->tab_id())); 414 ExtensionFrameHelper::Get(render_frame)->tab_id()));
407 415
408 ScriptsRunInfo scripts_run_info;
409 FrameStatusMap::const_iterator iter = frame_statuses_.find(render_frame); 416 FrameStatusMap::const_iterator iter = frame_statuses_.find(render_frame);
417 UserScript::RunLocation run_location =
418 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second;
410 419
411 TryToInject( 420 ScriptsRunInfo scripts_run_info(render_frame, run_location);
412 injection.Pass(), 421 TryToInject(injection.Pass(), run_location, &scripts_run_info);
413 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second,
414 &scripts_run_info);
415 } 422 }
416 423
417 void ScriptInjectionManager::HandleExecuteDeclarativeScript( 424 void ScriptInjectionManager::HandleExecuteDeclarativeScript(
418 content::RenderFrame* render_frame, 425 content::RenderFrame* render_frame,
419 int tab_id, 426 int tab_id,
420 const ExtensionId& extension_id, 427 const ExtensionId& extension_id,
421 int script_id, 428 int script_id,
422 const GURL& url) { 429 const GURL& url) {
423 scoped_ptr<ScriptInjection> injection = 430 scoped_ptr<ScriptInjection> injection =
424 user_script_set_manager_->GetInjectionForDeclarativeScript( 431 user_script_set_manager_->GetInjectionForDeclarativeScript(
425 script_id, 432 script_id,
426 render_frame, 433 render_frame,
427 tab_id, 434 tab_id,
428 url, 435 url,
429 extension_id); 436 extension_id);
430 if (injection.get()) { 437 if (injection.get()) {
431 ScriptsRunInfo scripts_run_info; 438 ScriptsRunInfo scripts_run_info(render_frame, UserScript::BROWSER_DRIVEN);
432 // TODO(markdittmer): Use return value of TryToInject for error handling. 439 // TODO(markdittmer): Use return value of TryToInject for error handling.
433 TryToInject(injection.Pass(), 440 TryToInject(injection.Pass(),
434 UserScript::BROWSER_DRIVEN, 441 UserScript::BROWSER_DRIVEN,
435 &scripts_run_info); 442 &scripts_run_info);
436 443
437 scripts_run_info.LogRun(render_frame->GetWebFrame(), 444 scripts_run_info.LogRun();
438 UserScript::BROWSER_DRIVEN);
439 } 445 }
440 } 446 }
441 447
442 void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) { 448 void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) {
443 ScopedVector<ScriptInjection>::iterator iter = 449 ScopedVector<ScriptInjection>::iterator iter =
444 pending_injections_.begin(); 450 pending_injections_.begin();
445 for (; iter != pending_injections_.end(); ++iter) { 451 for (; iter != pending_injections_.end(); ++iter) {
446 if ((*iter)->request_id() == request_id) { 452 if ((*iter)->request_id() == request_id) {
447 DCHECK((*iter)->host_id().type() == HostID::EXTENSIONS); 453 DCHECK((*iter)->host_id().type() == HostID::EXTENSIONS);
448 break; 454 break;
449 } 455 }
450 } 456 }
451 if (iter == pending_injections_.end()) 457 if (iter == pending_injections_.end())
452 return; 458 return;
453 459
454 // At this point, because the request is present in pending_injections_, we 460 // At this point, because the request is present in pending_injections_, we
455 // know that this is the same page that issued the request (otherwise, 461 // know that this is the same page that issued the request (otherwise,
456 // RFOHelper's DidStartProvisionalLoad callback would have caused it to be 462 // RFOHelper's DidStartProvisionalLoad callback would have caused it to be
457 // cleared out). 463 // cleared out).
458 464
459 scoped_ptr<ScriptInjection> injection(*iter); 465 scoped_ptr<ScriptInjection> injection(*iter);
460 pending_injections_.weak_erase(iter); 466 pending_injections_.weak_erase(iter);
461 467
462 ScriptsRunInfo scripts_run_info; 468 ScriptsRunInfo scripts_run_info(injection->render_frame(),
469 UserScript::RUN_DEFERRED);
463 ScriptInjection::InjectionResult res = injection->OnPermissionGranted( 470 ScriptInjection::InjectionResult res = injection->OnPermissionGranted(
464 &scripts_run_info); 471 &scripts_run_info);
465 if (res == ScriptInjection::INJECTION_BLOCKED) 472 if (res == ScriptInjection::INJECTION_BLOCKED)
466 running_injections_.push_back(injection.Pass()); 473 running_injections_.push_back(injection.Pass());
467 scripts_run_info.LogRun(injection->render_frame()->GetWebFrame(), 474 scripts_run_info.LogRun();
468 UserScript::RUN_DEFERRED);
469 } 475 }
470 476
471 } // namespace extensions 477 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698