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

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

Issue 2134613002: Stop injection when injections are invalidated Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Expand scope of ScriptInjectionWatchers Created 4 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 <deque>
7 #include <memory> 8 #include <memory>
8 #include <utility> 9 #include <utility>
9 10
10 #include "base/auto_reset.h" 11 #include "base/auto_reset.h"
11 #include "base/bind.h" 12 #include "base/bind.h"
12 #include "base/memory/ptr_util.h" 13 #include "base/memory/ptr_util.h"
13 #include "base/memory/weak_ptr.h" 14 #include "base/memory/weak_ptr.h"
14 #include "base/values.h" 15 #include "base/values.h"
15 #include "content/public/renderer/render_frame.h" 16 #include "content/public/renderer/render_frame.h"
16 #include "content/public/renderer/render_frame_observer.h" 17 #include "content/public/renderer/render_frame_observer.h"
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
96 void InvalidateAndResetFrame(); 97 void InvalidateAndResetFrame();
97 98
98 // The owning ScriptInjectionManager. 99 // The owning ScriptInjectionManager.
99 ScriptInjectionManager* manager_; 100 ScriptInjectionManager* manager_;
100 101
101 bool should_run_idle_; 102 bool should_run_idle_;
102 103
103 base::WeakPtrFactory<RFOHelper> weak_factory_; 104 base::WeakPtrFactory<RFOHelper> weak_factory_;
104 }; 105 };
105 106
107 // Keeps track of a ScriptInjection while it is injected. The caller must make
108 // sure that the ScriptInjection is not destructed when the Invalidate* methods
109 // are called.
110 class ScriptInjectionManager::ScriptInjectionWatcher {
Devlin 2016/07/11 23:30:55 I'm still not quite happy with this implementation
robwu 2016/07/12 08:59:36 We only need to be careful when InjectJs() is call
111 public:
112 ScriptInjectionWatcher(ScriptInjection* injection,
113 ScriptInjectionManager* manager)
114 : injection_(injection), manager_(manager), host_id_(injection->host_id()) {
115 manager_->injection_watchers_.push_back(this);
116 }
117
118 ~ScriptInjectionWatcher() {
119 auto& watchers = manager_->injection_watchers_;
120 for (auto it = watchers.begin(); it != watchers.end(); ++it) {
121 if (*it == this) {
122 watchers.erase(it);
123 break;
124 }
125 }
126 }
127
128 // Mark the injection as invalid because the extension disappeared.
129 // This method can safely be called multiple times.
130 void InvalidateHost() {
131 injection_->OnHostRemoved();
132 }
133
134 // Mark the injection as invalid because the frame was invalidated.
135 // This method can safely be called multiple times.
136 void InvalidateIfFrameEquals(content::RenderFrame* frame) {
137 if (injection_->render_frame() == frame)
138 injection_->invalidate_render_frame();
139 }
140
141 const HostID& host_id() const { return host_id_; }
142
143 private:
144 ScriptInjection* injection_; // Not owned, must outlive us.
145 ScriptInjectionManager* manager_; // Owns us.
146 HostID host_id_;
147
148 DISALLOW_COPY_AND_ASSIGN(ScriptInjectionWatcher);
149 };
150
106 ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame, 151 ScriptInjectionManager::RFOHelper::RFOHelper(content::RenderFrame* render_frame,
107 ScriptInjectionManager* manager) 152 ScriptInjectionManager* manager)
108 : content::RenderFrameObserver(render_frame), 153 : content::RenderFrameObserver(render_frame),
109 manager_(manager), 154 manager_(manager),
110 should_run_idle_(true), 155 should_run_idle_(true),
111 weak_factory_(this) { 156 weak_factory_(this) {
112 } 157 }
113 158
114 ScriptInjectionManager::RFOHelper::~RFOHelper() { 159 ScriptInjectionManager::RFOHelper::~RFOHelper() {
115 } 160 }
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 : user_script_set_manager_(user_script_set_manager), 305 : user_script_set_manager_(user_script_set_manager),
261 user_script_set_manager_observer_(this) { 306 user_script_set_manager_observer_(this) {
262 user_script_set_manager_observer_.Add(user_script_set_manager_); 307 user_script_set_manager_observer_.Add(user_script_set_manager_);
263 } 308 }
264 309
265 ScriptInjectionManager::~ScriptInjectionManager() { 310 ScriptInjectionManager::~ScriptInjectionManager() {
266 for (const auto& injection : pending_injections_) 311 for (const auto& injection : pending_injections_)
267 injection->invalidate_render_frame(); 312 injection->invalidate_render_frame();
268 for (const auto& injection : running_injections_) 313 for (const auto& injection : running_injections_)
269 injection->invalidate_render_frame(); 314 injection->invalidate_render_frame();
315 DCHECK(injection_watchers_.empty());
270 } 316 }
271 317
272 void ScriptInjectionManager::OnRenderFrameCreated( 318 void ScriptInjectionManager::OnRenderFrameCreated(
273 content::RenderFrame* render_frame) { 319 content::RenderFrame* render_frame) {
274 rfo_helpers_.push_back(base::WrapUnique(new RFOHelper(render_frame, this))); 320 rfo_helpers_.push_back(base::WrapUnique(new RFOHelper(render_frame, this)));
275 } 321 }
276 322
277 void ScriptInjectionManager::OnExtensionUnloaded( 323 void ScriptInjectionManager::OnExtensionUnloaded(
278 const std::string& extension_id) { 324 const std::string& extension_id) {
279 for (auto iter = pending_injections_.begin(); 325 for (auto iter = pending_injections_.begin();
280 iter != pending_injections_.end();) { 326 iter != pending_injections_.end();) {
281 if ((*iter)->host_id().id() == extension_id) { 327 if ((*iter)->host_id().id() == extension_id) {
282 (*iter)->OnHostRemoved(); 328 (*iter)->OnHostRemoved();
283 iter = pending_injections_.erase(iter); 329 iter = pending_injections_.erase(iter);
284 } else { 330 } else {
285 ++iter; 331 ++iter;
286 } 332 }
287 } 333 }
334
335 for (auto watcher : injection_watchers_) {
336 if (watcher->host_id().id() == extension_id)
337 watcher->InvalidateHost();
338 }
288 } 339 }
289 340
290 void ScriptInjectionManager::OnInjectionFinished( 341 void ScriptInjectionManager::OnInjectionFinished(
291 ScriptInjection* injection) { 342 ScriptInjection* injection) {
292 auto iter = 343 auto iter =
293 std::find_if(running_injections_.begin(), running_injections_.end(), 344 std::find_if(running_injections_.begin(), running_injections_.end(),
294 [injection](const std::unique_ptr<ScriptInjection>& mode) { 345 [injection](const std::unique_ptr<ScriptInjection>& mode) {
295 return injection == mode.get(); 346 return injection == mode.get();
296 }); 347 });
297 if (iter != running_injections_.end()) 348 if (iter != running_injections_.end())
298 running_injections_.erase(iter); 349 running_injections_.erase(iter);
299 } 350 }
300 351
301 void ScriptInjectionManager::OnUserScriptsUpdated( 352 void ScriptInjectionManager::OnUserScriptsUpdated(
302 const std::set<HostID>& changed_hosts, 353 const std::set<HostID>& changed_hosts,
303 const std::vector<UserScript*>& scripts) { 354 const std::vector<UserScript*>& scripts) {
304 for (auto iter = pending_injections_.begin(); 355 for (auto iter = pending_injections_.begin();
305 iter != pending_injections_.end();) { 356 iter != pending_injections_.end();) {
306 if (changed_hosts.count((*iter)->host_id()) > 0) 357 if (changed_hosts.count((*iter)->host_id()) > 0) {
358 (*iter)->OnHostRemoved();
307 iter = pending_injections_.erase(iter); 359 iter = pending_injections_.erase(iter);
308 else 360 } else {
309 ++iter; 361 ++iter;
362 }
363 }
364
365 for (auto watcher : injection_watchers_) {
366 if (changed_hosts.count(watcher->host_id()) > 0)
367 watcher->InvalidateHost();
310 } 368 }
311 } 369 }
312 370
313 void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) { 371 void ScriptInjectionManager::RemoveObserver(RFOHelper* helper) {
314 for (auto iter = rfo_helpers_.begin(); iter != rfo_helpers_.end(); ++iter) { 372 for (auto iter = rfo_helpers_.begin(); iter != rfo_helpers_.end(); ++iter) {
315 if (iter->get() == helper) { 373 if (iter->get() == helper) {
316 rfo_helpers_.erase(iter); 374 rfo_helpers_.erase(iter);
317 break; 375 break;
318 } 376 }
319 } 377 }
320 } 378 }
321 379
322 void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) { 380 void ScriptInjectionManager::InvalidateForFrame(content::RenderFrame* frame) {
323 // If the frame invalidated is the frame being injected into, we need to
324 // note it.
325 active_injection_frames_.erase(frame);
326
327 for (auto iter = pending_injections_.begin(); 381 for (auto iter = pending_injections_.begin();
328 iter != pending_injections_.end();) { 382 iter != pending_injections_.end();) {
329 if ((*iter)->render_frame() == frame) 383 if ((*iter)->render_frame() == frame)
330 iter = pending_injections_.erase(iter); 384 iter = pending_injections_.erase(iter);
331 else 385 else
332 ++iter; 386 ++iter;
333 } 387 }
334 388
389 for (auto watcher : injection_watchers_) {
390 watcher->InvalidateIfFrameEquals(frame);
391 }
392
335 frame_statuses_.erase(frame); 393 frame_statuses_.erase(frame);
336 } 394 }
337 395
338 void ScriptInjectionManager::StartInjectScripts( 396 void ScriptInjectionManager::StartInjectScripts(
339 content::RenderFrame* frame, 397 content::RenderFrame* frame,
340 UserScript::RunLocation run_location) { 398 UserScript::RunLocation run_location) {
341 FrameStatusMap::iterator iter = frame_statuses_.find(frame); 399 FrameStatusMap::iterator iter = frame_statuses_.find(frame);
342 // We also don't execute if we detect that the run location is somehow out of 400 // We also don't execute if we detect that the run location is somehow out of
343 // order. This can happen if: 401 // order. This can happen if:
344 // - The first run location reported for the frame isn't DOCUMENT_START, or 402 // - The first run location reported for the frame isn't DOCUMENT_START, or
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
383 } else { 441 } else {
384 ++iter; 442 ++iter;
385 } 443 }
386 } 444 }
387 445
388 // Add any injections for user scripts. 446 // Add any injections for user scripts.
389 int tab_id = ExtensionFrameHelper::Get(frame)->tab_id(); 447 int tab_id = ExtensionFrameHelper::Get(frame)->tab_id();
390 user_script_set_manager_->GetAllInjections(&frame_injections, frame, tab_id, 448 user_script_set_manager_->GetAllInjections(&frame_injections, frame, tab_id,
391 run_location); 449 run_location);
392 450
393 // Note that we are running in |frame|. 451 // At this point the ScriptInjections in frame_injections are not reference
394 active_injection_frames_.insert(frame); 452 // anywhere else. Set up ScriptInjectionWatchers so that the injections can be
453 // invalidated if any of the scripts destroys the frame or injection host.
454 std::deque<std::unique_ptr<ScriptInjectionWatcher>> scoped_watchers;
455 for (auto& iter : frame_injections) {
456 scoped_watchers.push_back(
457 base::MakeUnique<ScriptInjectionWatcher>(iter.get(), this));
458 }
395 459
396 ScriptsRunInfo scripts_run_info(frame, run_location); 460 ScriptsRunInfo scripts_run_info(frame, run_location);
397 for (auto iter = frame_injections.begin(); iter != frame_injections.end();) { 461 for (auto iter = frame_injections.begin(); iter != frame_injections.end();) {
398 // It's possible for the frame to be invalidated in the course of injection 462 // It's possible for the frame to be invalidated in the course of injection
399 // (if a script removes its own frame, for example). If this happens, abort. 463 // (if a script removes its own frame, for example). If this happens, abort.
400 if (!active_injection_frames_.count(frame)) 464 if (!(*iter)->render_frame())
401 break; 465 break;
402 std::unique_ptr<ScriptInjection> injection(std::move(*iter)); 466 std::unique_ptr<ScriptInjection> injection(std::move(*iter));
403 iter = frame_injections.erase(iter); 467 iter = frame_injections.erase(iter);
404 TryToInject(std::move(injection), run_location, &scripts_run_info); 468 TryToInject(std::move(injection), run_location, &scripts_run_info);
469
470 // Destroy the watcher because the ScriptInjection* may be invalid, and
471 // running the next iteration of the loop may trigger observers that touch
472 // the active watchers.
473 scoped_watchers.pop_front();
405 } 474 }
406 475
407 // We are done running in the frame.
408 active_injection_frames_.erase(frame);
409
410 scripts_run_info.LogRun(activity_logging_enabled_); 476 scripts_run_info.LogRun(activity_logging_enabled_);
411 } 477 }
412 478
413 void ScriptInjectionManager::TryToInject( 479 void ScriptInjectionManager::TryToInject(
414 std::unique_ptr<ScriptInjection> injection, 480 std::unique_ptr<ScriptInjection> injection,
415 UserScript::RunLocation run_location, 481 UserScript::RunLocation run_location,
416 ScriptsRunInfo* scripts_run_info) { 482 ScriptsRunInfo* scripts_run_info) {
417 // Try to inject the script. If the injection is waiting (i.e., for 483 // Try to inject the script. If the injection is waiting (i.e., for
418 // permission), add it to the list of pending injections. If the injection 484 // permission), add it to the list of pending injections. If the injection
419 // has blocked, add it to the list of running injections. 485 // has blocked, add it to the list of running injections.
420 // The Unretained below is safe because this object owns all the 486 // The Unretained below is safe because this object owns all the
421 // ScriptInjections, so is guaranteed to outlive them. 487 // ScriptInjections, so is guaranteed to outlive them.
422 switch (injection->TryToInject( 488 switch (injection->TryToInject(
423 run_location, 489 run_location,
424 scripts_run_info, 490 scripts_run_info,
425 base::Bind(&ScriptInjectionManager::OnInjectionFinished, 491 base::Bind(&ScriptInjectionManager::OnInjectionFinished,
426 base::Unretained(this)))) { 492 base::Unretained(this)))) {
427 case ScriptInjection::INJECTION_WAITING: 493 case ScriptInjection::INJECTION_WAITING:
428 pending_injections_.push_back(std::move(injection)); 494 pending_injections_.push_back(std::move(injection));
429 break; 495 break;
430 case ScriptInjection::INJECTION_BLOCKED: 496 case ScriptInjection::INJECTION_BLOCKED:
431 running_injections_.push_back(std::move(injection)); 497 running_injections_.push_back(std::move(injection));
432 break; 498 break;
433 case ScriptInjection::INJECTION_FINISHED: 499 case ScriptInjection::INJECTION_FINISHED:
500 case ScriptInjection::INJECTION_CANCELED:
434 break; 501 break;
435 } 502 }
436 } 503 }
437 504
438 void ScriptInjectionManager::HandleExecuteCode( 505 void ScriptInjectionManager::HandleExecuteCode(
439 const ExtensionMsg_ExecuteCode_Params& params, 506 const ExtensionMsg_ExecuteCode_Params& params,
440 content::RenderFrame* render_frame) { 507 content::RenderFrame* render_frame) {
441 std::unique_ptr<const InjectionHost> injection_host; 508 std::unique_ptr<const InjectionHost> injection_host;
442 if (params.host_id.type() == HostID::EXTENSIONS) { 509 if (params.host_id.type() == HostID::EXTENSIONS) {
443 injection_host = ExtensionInjectionHost::Create(params.host_id.id()); 510 injection_host = ExtensionInjectionHost::Create(params.host_id.id());
444 if (!injection_host) 511 if (!injection_host)
445 return; 512 return;
446 } else if (params.host_id.type() == HostID::WEBUI) { 513 } else if (params.host_id.type() == HostID::WEBUI) {
447 injection_host.reset( 514 injection_host.reset(
448 new WebUIInjectionHost(params.host_id)); 515 new WebUIInjectionHost(params.host_id));
449 } 516 }
450 517
451 std::unique_ptr<ScriptInjection> injection(new ScriptInjection( 518 std::unique_ptr<ScriptInjection> injection(new ScriptInjection(
452 std::unique_ptr<ScriptInjector>( 519 std::unique_ptr<ScriptInjector>(
453 new ProgrammaticScriptInjector(params, render_frame)), 520 new ProgrammaticScriptInjector(params, render_frame)),
454 render_frame, std::move(injection_host), 521 render_frame, std::move(injection_host),
455 static_cast<UserScript::RunLocation>(params.run_at), 522 static_cast<UserScript::RunLocation>(params.run_at),
456 activity_logging_enabled_)); 523 activity_logging_enabled_));
457 524
458 FrameStatusMap::const_iterator iter = frame_statuses_.find(render_frame); 525 FrameStatusMap::const_iterator iter = frame_statuses_.find(render_frame);
459 UserScript::RunLocation run_location = 526 UserScript::RunLocation run_location =
460 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second; 527 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second;
461 528
462 ScriptsRunInfo scripts_run_info(render_frame, run_location); 529 ScriptsRunInfo scripts_run_info(render_frame, run_location);
530 ScriptInjectionWatcher watcher(injection.get(), this);
463 TryToInject(std::move(injection), run_location, &scripts_run_info); 531 TryToInject(std::move(injection), run_location, &scripts_run_info);
464 } 532 }
465 533
466 void ScriptInjectionManager::HandleExecuteDeclarativeScript( 534 void ScriptInjectionManager::HandleExecuteDeclarativeScript(
467 content::RenderFrame* render_frame, 535 content::RenderFrame* render_frame,
468 int tab_id, 536 int tab_id,
469 const ExtensionId& extension_id, 537 const ExtensionId& extension_id,
470 int script_id, 538 int script_id,
471 const GURL& url) { 539 const GURL& url) {
472 std::unique_ptr<ScriptInjection> injection = 540 std::unique_ptr<ScriptInjection> injection =
473 user_script_set_manager_->GetInjectionForDeclarativeScript( 541 user_script_set_manager_->GetInjectionForDeclarativeScript(
474 script_id, render_frame, tab_id, url, extension_id); 542 script_id, render_frame, tab_id, url, extension_id);
475 if (injection.get()) { 543 if (injection.get()) {
476 ScriptsRunInfo scripts_run_info(render_frame, UserScript::BROWSER_DRIVEN); 544 ScriptsRunInfo scripts_run_info(render_frame, UserScript::BROWSER_DRIVEN);
545 ScriptInjectionWatcher watcher(injection.get(), this);
477 // TODO(markdittmer): Use return value of TryToInject for error handling. 546 // TODO(markdittmer): Use return value of TryToInject for error handling.
478 TryToInject(std::move(injection), UserScript::BROWSER_DRIVEN, 547 TryToInject(std::move(injection), UserScript::BROWSER_DRIVEN,
479 &scripts_run_info); 548 &scripts_run_info);
480 549
481 scripts_run_info.LogRun(activity_logging_enabled_); 550 scripts_run_info.LogRun(activity_logging_enabled_);
482 } 551 }
483 } 552 }
484 553
485 void ScriptInjectionManager::HandlePermitScriptInjection(int64_t request_id) { 554 void ScriptInjectionManager::HandlePermitScriptInjection(int64_t request_id) {
486 auto iter = pending_injections_.begin(); 555 auto iter = pending_injections_.begin();
487 for (; iter != pending_injections_.end(); ++iter) { 556 for (; iter != pending_injections_.end(); ++iter) {
488 if ((*iter)->request_id() == request_id) { 557 if ((*iter)->request_id() == request_id) {
489 DCHECK((*iter)->host_id().type() == HostID::EXTENSIONS); 558 DCHECK((*iter)->host_id().type() == HostID::EXTENSIONS);
490 break; 559 break;
491 } 560 }
492 } 561 }
493 if (iter == pending_injections_.end()) 562 if (iter == pending_injections_.end())
494 return; 563 return;
495 564
496 // At this point, because the request is present in pending_injections_, we 565 // At this point, because the request is present in pending_injections_, we
497 // know that this is the same page that issued the request (otherwise, 566 // know that this is the same page that issued the request (otherwise,
498 // RFOHelper::InvalidateAndResetFrame would have caused it to be cleared out). 567 // RFOHelper::InvalidateAndResetFrame would have caused it to be cleared out).
499 568
500 std::unique_ptr<ScriptInjection> injection(std::move(*iter)); 569 std::unique_ptr<ScriptInjection> injection(std::move(*iter));
501 pending_injections_.erase(iter); 570 pending_injections_.erase(iter);
502 571
503 ScriptsRunInfo scripts_run_info(injection->render_frame(), 572 ScriptsRunInfo scripts_run_info(injection->render_frame(),
504 UserScript::RUN_DEFERRED); 573 UserScript::RUN_DEFERRED);
574 ScriptInjectionWatcher watcher(injection.get(), this);
505 ScriptInjection::InjectionResult res = injection->OnPermissionGranted( 575 ScriptInjection::InjectionResult res = injection->OnPermissionGranted(
506 &scripts_run_info); 576 &scripts_run_info);
507 if (res == ScriptInjection::INJECTION_BLOCKED) 577 if (res == ScriptInjection::INJECTION_BLOCKED)
508 running_injections_.push_back(std::move(injection)); 578 running_injections_.push_back(std::move(injection));
509 scripts_run_info.LogRun(activity_logging_enabled_); 579 scripts_run_info.LogRun(activity_logging_enabled_);
510 } 580 }
511 581
512 } // namespace extensions 582 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/script_injection_manager.h ('k') | extensions/renderer/user_script_injector.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698