OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |