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 "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 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 void ScriptInjectionManager::RVOHelper::InvalidateFrame( | 220 void ScriptInjectionManager::RVOHelper::InvalidateFrame( |
221 blink::WebFrame* frame) { | 221 blink::WebFrame* frame) { |
222 pending_idle_frames_.erase(frame); | 222 pending_idle_frames_.erase(frame); |
223 manager_->InvalidateForFrame(frame); | 223 manager_->InvalidateForFrame(frame); |
224 } | 224 } |
225 | 225 |
226 ScriptInjectionManager::ScriptInjectionManager( | 226 ScriptInjectionManager::ScriptInjectionManager( |
227 const ExtensionSet* extensions, | 227 const ExtensionSet* extensions, |
228 UserScriptSetManager* user_script_set_manager) | 228 UserScriptSetManager* user_script_set_manager) |
229 : extensions_(extensions), | 229 : extensions_(extensions), |
230 injecting_scripts_(false), | |
231 user_script_set_manager_(user_script_set_manager), | 230 user_script_set_manager_(user_script_set_manager), |
232 user_script_set_manager_observer_(this) { | 231 user_script_set_manager_observer_(this) { |
233 user_script_set_manager_observer_.Add(user_script_set_manager_); | 232 user_script_set_manager_observer_.Add(user_script_set_manager_); |
234 } | 233 } |
235 | 234 |
236 ScriptInjectionManager::~ScriptInjectionManager() { | 235 ScriptInjectionManager::~ScriptInjectionManager() { |
237 } | 236 } |
238 | 237 |
239 void ScriptInjectionManager::OnRenderViewCreated( | 238 void ScriptInjectionManager::OnRenderViewCreated( |
240 content::RenderView* render_view) { | 239 content::RenderView* render_view) { |
241 rvo_helpers_.push_back(new RVOHelper(render_view, this)); | 240 rvo_helpers_.push_back(new RVOHelper(render_view, this)); |
242 } | 241 } |
243 | 242 |
243 void ScriptInjectionManager::OnInjectionFinished( | |
244 ScriptInjection* injection, | |
245 ScriptsRunInfo* scripts_run_info) { | |
246 if (IsFrameValid(injection->web_frame())) | |
247 scripts_run_info->LogRun(injection->web_frame(), injection->run_location()); | |
248 | |
249 ScopedVector<ScriptInjection>::iterator it; | |
250 for (it = running_injections_.begin(); it != running_injections_.end(); ++it){ | |
251 running_injections_.erase(it); | |
252 break; | |
253 } | |
254 } | |
255 | |
244 void ScriptInjectionManager::OnUserScriptsUpdated( | 256 void ScriptInjectionManager::OnUserScriptsUpdated( |
245 const std::set<std::string>& changed_extensions, | 257 const std::set<std::string>& changed_extensions, |
246 const std::vector<UserScript*>& scripts) { | 258 const std::vector<UserScript*>& scripts) { |
247 for (ScopedVector<ScriptInjection>::iterator iter = | 259 for (ScopedVector<ScriptInjection>::iterator iter = |
248 pending_injections_.begin(); | 260 pending_injections_.begin(); |
249 iter != pending_injections_.end();) { | 261 iter != pending_injections_.end();) { |
250 if (changed_extensions.count((*iter)->extension_id()) > 0) | 262 if (changed_extensions.count((*iter)->extension_id()) > 0) |
251 iter = pending_injections_.erase(iter); | 263 iter = pending_injections_.erase(iter); |
252 else | 264 else |
253 ++iter; | 265 ++iter; |
254 } | 266 } |
255 | |
256 // If we are currently injecting scripts, we need to make a note that these | |
257 // extensions were updated. | |
258 if (injecting_scripts_) { | |
259 invalidated_while_injecting_.insert(changed_extensions.begin(), | |
260 changed_extensions.end()); | |
261 } | |
262 } | 267 } |
263 | 268 |
264 void ScriptInjectionManager::RemoveObserver(RVOHelper* helper) { | 269 void ScriptInjectionManager::RemoveObserver(RVOHelper* helper) { |
265 for (ScopedVector<RVOHelper>::iterator iter = rvo_helpers_.begin(); | 270 for (ScopedVector<RVOHelper>::iterator iter = rvo_helpers_.begin(); |
266 iter != rvo_helpers_.end(); | 271 iter != rvo_helpers_.end(); |
267 ++iter) { | 272 ++iter) { |
268 if (*iter == helper) { | 273 if (*iter == helper) { |
269 rvo_helpers_.erase(iter); | 274 rvo_helpers_.erase(iter); |
270 break; | 275 break; |
271 } | 276 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
315 // Certain run location signals (like DidCreateDocumentElement) can happen | 320 // Certain run location signals (like DidCreateDocumentElement) can happen |
316 // multiple times. Ignore the subsequent signals. | 321 // multiple times. Ignore the subsequent signals. |
317 return; | 322 return; |
318 } | 323 } |
319 | 324 |
320 // Otherwise, all is right in the world, and we can get on with the | 325 // Otherwise, all is right in the world, and we can get on with the |
321 // injections! | 326 // injections! |
322 | 327 |
323 frame_statuses_[frame] = run_location; | 328 frame_statuses_[frame] = run_location; |
324 | 329 |
325 // If a content script injects blocking code (such as a javascript alert()), | 330 InjectScripts(frame, run_location); |
326 // then there is a chance that we are running in a nested message loop, and | 331 // As above, we might have been blocked, but that means that, in the mean |
327 // shouldn't inject scripts right now (to avoid conflicts). | 332 // time, it's possible the frame advanced. Inject any scripts for run |
328 if (!injecting_scripts_) { | 333 // locations that were registered, but never ran. |
334 while ((iter = frame_statuses_.find(frame)) != frame_statuses_.end() && | |
335 iter->second > run_location) { | |
336 run_location = NextRunLocation(run_location); | |
337 DCHECK_LE(run_location, UserScript::DOCUMENT_IDLE); | |
329 InjectScripts(frame, run_location); | 338 InjectScripts(frame, run_location); |
330 // As above, we might have been blocked, but that means that, in the mean | |
331 // time, it's possible the frame advanced. Inject any scripts for run | |
332 // locations that were registered, but never ran. | |
333 while ((iter = frame_statuses_.find(frame)) != frame_statuses_.end() && | |
334 iter->second > run_location) { | |
335 run_location = NextRunLocation(run_location); | |
336 DCHECK_LE(run_location, UserScript::DOCUMENT_IDLE); | |
337 InjectScripts(frame, run_location); | |
338 } | |
339 } | 339 } |
340 } | 340 } |
341 | 341 |
342 void ScriptInjectionManager::InjectScripts( | 342 void ScriptInjectionManager::InjectScripts( |
343 blink::WebFrame* frame, | 343 blink::WebFrame* frame, |
344 UserScript::RunLocation run_location) { | 344 UserScript::RunLocation run_location) { |
345 DCHECK(!injecting_scripts_); | |
346 DCHECK(invalidated_while_injecting_.empty()); | |
347 base::AutoReset<bool>(&injecting_scripts_, true); | |
348 | |
349 // Find any injections that want to run on the given frame. | 345 // Find any injections that want to run on the given frame. |
350 // We create a separate vector for these because there is a chance that | 346 // We create a separate vector for these because there is a chance that |
351 // injected scripts can block, which can create a nested message loop. When | 347 // injected scripts can block, which can create a nested message loop. When |
352 // this happens, other signals (like IPCs) can cause |pending_injections_| to | 348 // this happens, other signals (like IPCs) can cause |pending_injections_| to |
353 // be changed, so we don't want to risk that. | 349 // be changed, so we don't want to risk that. |
354 ScopedVector<ScriptInjection> frame_injections; | 350 ScopedVector<ScriptInjection> frame_injections; |
355 for (ScopedVector<ScriptInjection>::iterator iter = | 351 for (ScopedVector<ScriptInjection>::iterator iter = |
356 pending_injections_.begin(); | 352 pending_injections_.begin(); |
357 iter != pending_injections_.end();) { | 353 iter != pending_injections_.end();) { |
358 if ((*iter)->web_frame() == frame) { | 354 if ((*iter)->web_frame() == frame) { |
359 frame_injections.push_back(*iter); | 355 frame_injections.push_back(*iter); |
360 iter = pending_injections_.weak_erase(iter); | 356 iter = pending_injections_.weak_erase(iter); |
361 } else { | 357 } else { |
362 ++iter; | 358 ++iter; |
363 } | 359 } |
364 } | 360 } |
365 | 361 |
366 // Add any injections for user scripts. | 362 // Add any injections for user scripts. |
367 int tab_id = ExtensionHelper::Get(content::RenderView::FromWebView( | 363 int tab_id = ExtensionHelper::Get(content::RenderView::FromWebView( |
368 frame->top()->view()))->tab_id(); | 364 frame->top()->view()))->tab_id(); |
369 user_script_set_manager_->GetAllInjections( | 365 user_script_set_manager_->GetAllInjections( |
370 &frame_injections, frame, tab_id, run_location); | 366 &frame_injections, frame, tab_id, run_location); |
371 | 367 |
372 ScriptsRunInfo scripts_run_info; | |
Devlin
2015/02/11 17:49:58
Having each injection own a ScriptsRunInfo makes t
Devlin
2015/02/19 17:13:00
Still waiting on this?
| |
373 for (ScopedVector<ScriptInjection>::iterator iter = frame_injections.begin(); | 368 for (ScopedVector<ScriptInjection>::iterator iter = frame_injections.begin(); |
374 iter != frame_injections.end();) { | 369 iter != frame_injections.end();) { |
375 // If a blocking script was injected, there is potentially a possibility | 370 // If a blocking script was injected, there is potentially a possibility |
376 // that the frame has been invalidated in the time since. Check. | 371 // that the frame has been invalidated in the time since. Check. |
377 if (!IsFrameValid(frame)) | 372 if (!IsFrameValid(frame)) |
378 break; | 373 break; |
379 | 374 |
380 // Try to inject the script if the extension is not "dirty" (invalidated by | 375 // Try to inject the script. If the injection does not started |
381 // an update). If the injection does not finish (i.e., it is waiting for | 376 // (i.e., it is waiting for permission), add it to the list of pending |
382 // permission), add it to the list of pending injections. | 377 // injections. If the injection does not finished, add it to the list of |
383 if (invalidated_while_injecting_.count((*iter)->extension_id()) == 0 && | 378 // running injections. |
Devlin
2015/02/11 17:49:58
I don't think it's safe to remove this - can't scr
| |
384 !(*iter)->TryToInject(run_location, | 379 ScriptInjection* injection = *iter; |
385 extensions_->GetByID((*iter)->extension_id()), | 380 injection->SetScriptInjectionManager(this); |
386 &scripts_run_info)) { | 381 if (!injection->TryToInject(run_location, |
382 extensions_->GetByID((*iter)->extension_id()))) { | |
387 pending_injections_.insert(pending_injections_.begin(), *iter); | 383 pending_injections_.insert(pending_injections_.begin(), *iter); |
388 iter = frame_injections.weak_erase(iter); | 384 iter = frame_injections.weak_erase(iter); |
385 } else if (!injection->is_complete()) { | |
386 running_injections_.insert(running_injections_.begin(), *iter); | |
387 iter = frame_injections.weak_erase(iter); | |
389 } else { | 388 } else { |
390 ++iter; | 389 ++iter; |
391 } | 390 } |
392 } | 391 } |
393 | |
394 if (IsFrameValid(frame)) | |
395 scripts_run_info.LogRun(frame, run_location); | |
396 | |
397 invalidated_while_injecting_.clear(); | |
398 } | 392 } |
399 | 393 |
400 void ScriptInjectionManager::HandleExecuteCode( | 394 void ScriptInjectionManager::HandleExecuteCode( |
401 const ExtensionMsg_ExecuteCode_Params& params, | 395 const ExtensionMsg_ExecuteCode_Params& params, |
402 content::RenderView* render_view) { | 396 content::RenderView* render_view) { |
403 // TODO(dcheng): Not sure how this can happen today. In an OOPI world, it | 397 // TODO(dcheng): Not sure how this can happen today. In an OOPI world, it |
404 // would indicate a logic error--the browser must direct this request to the | 398 // would indicate a logic error--the browser must direct this request to the |
405 // right renderer process to begin with. | 399 // right renderer process to begin with. |
406 blink::WebLocalFrame* main_frame = | 400 blink::WebLocalFrame* main_frame = |
407 render_view->GetWebView()->mainFrame()->toWebLocalFrame(); | 401 render_view->GetWebView()->mainFrame()->toWebLocalFrame(); |
408 if (!main_frame) { | 402 if (!main_frame) { |
409 render_view->Send( | 403 render_view->Send( |
410 new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(), | 404 new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(), |
411 params.request_id, | 405 params.request_id, |
412 "No main frame", | 406 "No main frame", |
413 GURL(std::string()), | 407 GURL(std::string()), |
414 base::ListValue())); | 408 base::ListValue())); |
415 return; | 409 return; |
416 } | 410 } |
417 | 411 |
418 scoped_ptr<ScriptInjection> injection(new ScriptInjection( | 412 scoped_ptr<ScriptInjection> injection(new ScriptInjection( |
419 scoped_ptr<ScriptInjector>( | 413 scoped_ptr<ScriptInjector>( |
420 new ProgrammaticScriptInjector(params, main_frame)), | 414 new ProgrammaticScriptInjector(params, main_frame)), |
421 main_frame, | 415 main_frame, |
422 params.extension_id, | 416 params.extension_id, |
423 static_cast<UserScript::RunLocation>(params.run_at), | 417 static_cast<UserScript::RunLocation>(params.run_at), |
424 ExtensionHelper::Get(render_view)->tab_id())); | 418 ExtensionHelper::Get(render_view)->tab_id())); |
425 | 419 |
426 ScriptsRunInfo scripts_run_info; | |
427 FrameStatusMap::const_iterator iter = frame_statuses_.find(main_frame); | 420 FrameStatusMap::const_iterator iter = frame_statuses_.find(main_frame); |
421 injection->SetScriptInjectionManager(this); | |
428 if (!injection->TryToInject( | 422 if (!injection->TryToInject( |
429 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second, | 423 iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second, |
430 extensions_->GetByID(injection->extension_id()), | 424 extensions_->GetByID(injection->extension_id()))) { |
431 &scripts_run_info)) { | |
432 pending_injections_.push_back(injection.release()); | 425 pending_injections_.push_back(injection.release()); |
426 } else if (!injection->is_complete()) { | |
427 running_injections_.push_back(injection.release()); | |
433 } | 428 } |
434 } | 429 } |
435 | 430 |
436 void ScriptInjectionManager::HandleExecuteDeclarativeScript( | 431 void ScriptInjectionManager::HandleExecuteDeclarativeScript( |
437 blink::WebFrame* web_frame, | 432 blink::WebFrame* web_frame, |
438 int tab_id, | 433 int tab_id, |
439 const ExtensionId& extension_id, | 434 const ExtensionId& extension_id, |
440 int script_id, | 435 int script_id, |
441 const GURL& url) { | 436 const GURL& url) { |
442 const Extension* extension = extensions_->GetByID(extension_id); | 437 const Extension* extension = extensions_->GetByID(extension_id); |
443 // TODO(dcheng): This function signature should really be a WebLocalFrame, | 438 // TODO(dcheng): This function signature should really be a WebLocalFrame, |
444 // rather than trying to coerce it here. | 439 // rather than trying to coerce it here. |
445 scoped_ptr<ScriptInjection> injection = | 440 scoped_ptr<ScriptInjection> injection = |
446 user_script_set_manager_->GetInjectionForDeclarativeScript( | 441 user_script_set_manager_->GetInjectionForDeclarativeScript( |
447 script_id, | 442 script_id, |
448 web_frame->toWebLocalFrame(), | 443 web_frame->toWebLocalFrame(), |
449 tab_id, | 444 tab_id, |
450 url, | 445 url, |
451 extension); | 446 extension); |
452 if (injection.get()) { | 447 if (injection.get()) { |
453 ScriptsRunInfo scripts_run_info; | 448 injection->SetScriptInjectionManager(this); |
454 // TODO(markdittmer): Use return value of TryToInject for error handling. | 449 // TODO(markdittmer): Use return value of TryToInject for error handling. |
455 injection->TryToInject(UserScript::BROWSER_DRIVEN, | 450 if (injection->TryToInject(UserScript::BROWSER_DRIVEN, |
456 extension, | 451 extension)) { |
457 &scripts_run_info); | 452 if (!injection->is_complete()) |
458 scripts_run_info.LogRun(web_frame, UserScript::BROWSER_DRIVEN); | 453 running_injections_.push_back(injection.release()); |
454 } | |
459 } | 455 } |
460 } | 456 } |
461 | 457 |
462 void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) { | 458 void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) { |
463 ScopedVector<ScriptInjection>::iterator iter = | 459 ScopedVector<ScriptInjection>::iterator iter = |
464 pending_injections_.begin(); | 460 pending_injections_.begin(); |
465 for (; iter != pending_injections_.end(); ++iter) { | 461 for (; iter != pending_injections_.end(); ++iter) { |
466 if ((*iter)->request_id() == request_id) | 462 if ((*iter)->request_id() == request_id) |
467 break; | 463 break; |
468 } | 464 } |
469 if (iter == pending_injections_.end()) | 465 if (iter == pending_injections_.end()) |
470 return; | 466 return; |
471 | 467 |
472 // At this point, because the request is present in pending_injections_, we | 468 // At this point, because the request is present in pending_injections_, we |
473 // know that this is the same page that issued the request (otherwise, | 469 // know that this is the same page that issued the request (otherwise, |
474 // RVOHelper's DidStartProvisionalLoad callback would have caused it to be | 470 // RVOHelper's DidStartProvisionalLoad callback would have caused it to be |
475 // cleared out). | 471 // cleared out). |
476 | 472 |
477 scoped_ptr<ScriptInjection> injection(*iter); | 473 scoped_ptr<ScriptInjection> injection(*iter); |
478 pending_injections_.weak_erase(iter); | 474 pending_injections_.weak_erase(iter); |
479 | 475 |
480 ScriptsRunInfo scripts_run_info; | 476 injection->SetScriptInjectionManager(this); |
481 if (injection->OnPermissionGranted(extensions_->GetByID( | 477 if (injection->OnPermissionGranted(extensions_->GetByID( |
482 injection->extension_id()), | 478 injection->extension_id()))) { |
483 &scripts_run_info)) { | 479 if (!injection->is_complete()) |
484 scripts_run_info.LogRun(injection->web_frame(), UserScript::RUN_DEFERRED); | 480 running_injections_.push_back(injection.Pass()); |
485 } | 481 } |
486 } | 482 } |
487 | 483 |
488 } // namespace extensions | 484 } // namespace extensions |
OLD | NEW |