[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 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 |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "extensions/renderer/script_injection_manager.h" |
| 6 | |
| 7 | #include "base/bind.h" |
| 8 | #include "base/memory/weak_ptr.h" |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 9 | #include "base/values.h" |
| 10 | #include "content/public/renderer/render_view.h" |
| 11 | #include "content/public/renderer/render_view_observer.h" |
| 12 | #include "extensions/common/extension.h" |
| 13 | #include "extensions/common/extension_messages.h" |
| 14 | #include "extensions/common/extension_set.h" |
| 15 | #include "extensions/renderer/extension_helper.h" |
[email protected] | c11e659 | 2014-06-27 17:07:34 | [diff] [blame] | 16 | #include "extensions/renderer/programmatic_script_injector.h" |
| 17 | #include "extensions/renderer/script_injection.h" |
| 18 | #include "extensions/renderer/scripts_run_info.h" |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 19 | #include "ipc/ipc_message_macros.h" |
markdittmer | 9ea140f | 2014-08-29 02:46:15 | [diff] [blame] | 20 | #include "third_party/WebKit/public/web/WebDocument.h" |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 21 | #include "third_party/WebKit/public/web/WebFrame.h" |
| 22 | #include "third_party/WebKit/public/web/WebLocalFrame.h" |
| 23 | #include "third_party/WebKit/public/web/WebView.h" |
| 24 | #include "url/gurl.h" |
| 25 | |
| 26 | namespace extensions { |
| 27 | |
| 28 | namespace { |
| 29 | |
| 30 | // The length of time to wait after the DOM is complete to try and run user |
| 31 | // scripts. |
| 32 | const int kScriptIdleTimeoutInMs = 200; |
| 33 | |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 34 | } // namespace |
| 35 | |
| 36 | class ScriptInjectionManager::RVOHelper : public content::RenderViewObserver { |
| 37 | public: |
| 38 | RVOHelper(content::RenderView* render_view, ScriptInjectionManager* manager); |
dcheng | 9168b2f | 2014-10-21 12:38:24 | [diff] [blame^] | 39 | ~RVOHelper() override; |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 40 | |
| 41 | private: |
| 42 | // RenderViewObserver implementation. |
dcheng | 9168b2f | 2014-10-21 12:38:24 | [diff] [blame^] | 43 | bool OnMessageReceived(const IPC::Message& message) override; |
| 44 | void DidCreateDocumentElement(blink::WebLocalFrame* frame) override; |
| 45 | void DidFinishDocumentLoad(blink::WebLocalFrame* frame) override; |
| 46 | void DidFinishLoad(blink::WebLocalFrame* frame) override; |
| 47 | void DidStartProvisionalLoad(blink::WebLocalFrame* frame) override; |
| 48 | void FrameDetached(blink::WebFrame* frame) override; |
| 49 | void OnDestruct() override; |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 50 | |
| 51 | virtual void OnExecuteCode(const ExtensionMsg_ExecuteCode_Params& params); |
markdittmer | 9ea140f | 2014-08-29 02:46:15 | [diff] [blame] | 52 | virtual void OnExecuteDeclarativeScript(int tab_id, |
| 53 | const ExtensionId& extension_id, |
| 54 | int script_id, |
| 55 | const GURL& url); |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 56 | virtual void OnPermitScriptInjection(int64 request_id); |
| 57 | |
| 58 | // Tells the ScriptInjectionManager to run tasks associated with |
| 59 | // document_idle. |
| 60 | void RunIdle(blink::WebFrame* frame); |
| 61 | |
[email protected] | 5672620d | 2014-07-30 10:07:17 | [diff] [blame] | 62 | // Indicate that the given |frame| is no longer valid because it is starting |
| 63 | // a new load or closing. |
| 64 | void InvalidateFrame(blink::WebFrame* frame); |
| 65 | |
| 66 | // The owning ScriptInjectionManager. |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 67 | ScriptInjectionManager* manager_; |
[email protected] | 5672620d | 2014-07-30 10:07:17 | [diff] [blame] | 68 | |
| 69 | // The set of frames that we are about to notify for DOCUMENT_IDLE. We keep |
| 70 | // a set of those that are valid, so we don't notify that an invalid frame |
| 71 | // became idle. |
| 72 | std::set<blink::WebFrame*> pending_idle_frames_; |
| 73 | |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 74 | base::WeakPtrFactory<RVOHelper> weak_factory_; |
| 75 | }; |
| 76 | |
| 77 | ScriptInjectionManager::RVOHelper::RVOHelper( |
| 78 | content::RenderView* render_view, |
| 79 | ScriptInjectionManager* manager) |
| 80 | : content::RenderViewObserver(render_view), |
| 81 | manager_(manager), |
| 82 | weak_factory_(this) { |
| 83 | } |
| 84 | |
| 85 | ScriptInjectionManager::RVOHelper::~RVOHelper() { |
| 86 | } |
| 87 | |
| 88 | bool ScriptInjectionManager::RVOHelper::OnMessageReceived( |
| 89 | const IPC::Message& message) { |
| 90 | bool handled = true; |
| 91 | IPC_BEGIN_MESSAGE_MAP(ScriptInjectionManager::RVOHelper, message) |
| 92 | IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteCode, OnExecuteCode) |
| 93 | IPC_MESSAGE_HANDLER(ExtensionMsg_PermitScriptInjection, |
| 94 | OnPermitScriptInjection) |
markdittmer | 9ea140f | 2014-08-29 02:46:15 | [diff] [blame] | 95 | IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteDeclarativeScript, |
| 96 | OnExecuteDeclarativeScript) |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 97 | IPC_MESSAGE_UNHANDLED(handled = false) |
| 98 | IPC_END_MESSAGE_MAP() |
| 99 | return handled; |
| 100 | } |
| 101 | |
| 102 | void ScriptInjectionManager::RVOHelper::DidCreateDocumentElement( |
| 103 | blink::WebLocalFrame* frame) { |
| 104 | manager_->InjectScripts(frame, UserScript::DOCUMENT_START); |
| 105 | } |
| 106 | |
| 107 | void ScriptInjectionManager::RVOHelper::DidFinishDocumentLoad( |
| 108 | blink::WebLocalFrame* frame) { |
| 109 | manager_->InjectScripts(frame, UserScript::DOCUMENT_END); |
[email protected] | 5672620d | 2014-07-30 10:07:17 | [diff] [blame] | 110 | pending_idle_frames_.insert(frame); |
| 111 | // We try to run idle in two places: here and DidFinishLoad. |
| 112 | // DidFinishDocumentLoad() corresponds to completing the document's load, |
| 113 | // whereas DidFinishLoad corresponds to completing the document and all |
| 114 | // subresources' load. We don't want to hold up script injection for a |
| 115 | // particularly slow subresource, so we set a delayed task from here - but if |
| 116 | // we finish everything before that point (i.e., DidFinishLoad() is |
| 117 | // triggered), then there's no reason to keep waiting. |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 118 | base::MessageLoop::current()->PostDelayedTask( |
| 119 | FROM_HERE, |
| 120 | base::Bind(&ScriptInjectionManager::RVOHelper::RunIdle, |
| 121 | weak_factory_.GetWeakPtr(), |
| 122 | frame), |
| 123 | base::TimeDelta::FromMilliseconds(kScriptIdleTimeoutInMs)); |
| 124 | } |
| 125 | |
| 126 | void ScriptInjectionManager::RVOHelper::DidFinishLoad( |
| 127 | blink::WebLocalFrame* frame) { |
[email protected] | 5672620d | 2014-07-30 10:07:17 | [diff] [blame] | 128 | // Ensure that we don't block any UI progress by running scripts. |
| 129 | // We *don't* add the frame to |pending_idle_frames_| here because |
| 130 | // DidFinishDocumentLoad should strictly come before DidFinishLoad, so the |
| 131 | // first posted task to RunIdle() pops it out of the set. This ensures we |
| 132 | // don't try to run idle twice. |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 133 | base::MessageLoop::current()->PostTask( |
| 134 | FROM_HERE, |
| 135 | base::Bind(&ScriptInjectionManager::RVOHelper::RunIdle, |
| 136 | weak_factory_.GetWeakPtr(), |
| 137 | frame)); |
| 138 | } |
| 139 | |
| 140 | void ScriptInjectionManager::RVOHelper::DidStartProvisionalLoad( |
| 141 | blink::WebLocalFrame* frame) { |
[email protected] | 5672620d | 2014-07-30 10:07:17 | [diff] [blame] | 142 | // We're starting a new load - invalidate. |
| 143 | InvalidateFrame(frame); |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 144 | } |
| 145 | |
| 146 | void ScriptInjectionManager::RVOHelper::FrameDetached(blink::WebFrame* frame) { |
[email protected] | 5672620d | 2014-07-30 10:07:17 | [diff] [blame] | 147 | // The frame is closing - invalidate. |
| 148 | InvalidateFrame(frame); |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 149 | } |
| 150 | |
| 151 | void ScriptInjectionManager::RVOHelper::OnDestruct() { |
| 152 | manager_->RemoveObserver(this); |
| 153 | } |
| 154 | |
| 155 | void ScriptInjectionManager::RVOHelper::OnExecuteCode( |
| 156 | const ExtensionMsg_ExecuteCode_Params& params) { |
| 157 | manager_->HandleExecuteCode(params, render_view()); |
| 158 | } |
| 159 | |
markdittmer | 9ea140f | 2014-08-29 02:46:15 | [diff] [blame] | 160 | void ScriptInjectionManager::RVOHelper::OnExecuteDeclarativeScript( |
| 161 | int tab_id, |
| 162 | const ExtensionId& extension_id, |
| 163 | int script_id, |
| 164 | const GURL& url) { |
| 165 | blink::WebFrame* main_frame = render_view()->GetWebView()->mainFrame(); |
| 166 | CHECK(main_frame); |
| 167 | |
| 168 | // TODO(markdittmer): This would be cleaner if we compared page_ids instead. |
| 169 | // Begin script injeciton workflow only if the current URL is identical to |
| 170 | // the one that matched declarative conditions in the browser. |
| 171 | if (main_frame->top()->document().url() == url) { |
| 172 | manager_->HandleExecuteDeclarativeScript(main_frame, |
| 173 | tab_id, |
| 174 | extension_id, |
| 175 | script_id, |
| 176 | url); |
| 177 | } |
| 178 | } |
| 179 | |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 180 | void ScriptInjectionManager::RVOHelper::OnPermitScriptInjection( |
| 181 | int64 request_id) { |
| 182 | manager_->HandlePermitScriptInjection(request_id); |
| 183 | } |
| 184 | |
| 185 | void ScriptInjectionManager::RVOHelper::RunIdle(blink::WebFrame* frame) { |
[email protected] | 5672620d | 2014-07-30 10:07:17 | [diff] [blame] | 186 | // Only notify the manager if the frame hasn't either been removed or already |
| 187 | // had idle run since the task to RunIdle() was posted. |
| 188 | if (pending_idle_frames_.count(frame) > 0) { |
| 189 | manager_->InjectScripts(frame, UserScript::DOCUMENT_IDLE); |
| 190 | pending_idle_frames_.erase(frame); |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | void ScriptInjectionManager::RVOHelper::InvalidateFrame( |
| 195 | blink::WebFrame* frame) { |
| 196 | pending_idle_frames_.erase(frame); |
| 197 | manager_->InvalidateForFrame(frame); |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 198 | } |
| 199 | |
| 200 | ScriptInjectionManager::ScriptInjectionManager( |
| 201 | const ExtensionSet* extensions, |
[email protected] | 4c35690 | 2014-07-30 09:52:02 | [diff] [blame] | 202 | UserScriptSetManager* user_script_set_manager) |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 203 | : extensions_(extensions), |
[email protected] | 4c35690 | 2014-07-30 09:52:02 | [diff] [blame] | 204 | user_script_set_manager_(user_script_set_manager), |
| 205 | user_script_set_manager_observer_(this) { |
| 206 | user_script_set_manager_observer_.Add(user_script_set_manager_); |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 207 | } |
| 208 | |
| 209 | ScriptInjectionManager::~ScriptInjectionManager() { |
| 210 | } |
| 211 | |
| 212 | void ScriptInjectionManager::OnRenderViewCreated( |
| 213 | content::RenderView* render_view) { |
| 214 | rvo_helpers_.push_back(new RVOHelper(render_view, this)); |
| 215 | } |
| 216 | |
| 217 | void ScriptInjectionManager::OnUserScriptsUpdated( |
| 218 | const std::set<std::string>& changed_extensions, |
| 219 | const std::vector<UserScript*>& scripts) { |
| 220 | for (ScopedVector<ScriptInjection>::iterator iter = |
| 221 | pending_injections_.begin(); |
| 222 | iter != pending_injections_.end();) { |
| 223 | if (changed_extensions.count((*iter)->extension_id()) > 0) |
| 224 | iter = pending_injections_.erase(iter); |
| 225 | else |
| 226 | ++iter; |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | void ScriptInjectionManager::RemoveObserver(RVOHelper* helper) { |
| 231 | for (ScopedVector<RVOHelper>::iterator iter = rvo_helpers_.begin(); |
| 232 | iter != rvo_helpers_.end(); |
| 233 | ++iter) { |
| 234 | if (*iter == helper) { |
| 235 | rvo_helpers_.erase(iter); |
| 236 | break; |
| 237 | } |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | void ScriptInjectionManager::InvalidateForFrame(blink::WebFrame* frame) { |
| 242 | for (ScopedVector<ScriptInjection>::iterator iter = |
| 243 | pending_injections_.begin(); |
| 244 | iter != pending_injections_.end();) { |
| 245 | if ((*iter)->web_frame() == frame) |
| 246 | iter = pending_injections_.erase(iter); |
| 247 | else |
| 248 | ++iter; |
| 249 | } |
| 250 | |
| 251 | frame_statuses_.erase(frame); |
| 252 | } |
| 253 | |
| 254 | void ScriptInjectionManager::InjectScripts( |
| 255 | blink::WebFrame* frame, UserScript::RunLocation run_location) { |
| 256 | FrameStatusMap::iterator iter = frame_statuses_.find(frame); |
[email protected] | 5672620d | 2014-07-30 10:07:17 | [diff] [blame] | 257 | // We also don't execute if we detect that the run location is somehow out of |
| 258 | // order. This can happen if: |
| 259 | // - The first run location reported for the frame isn't DOCUMENT_START, or |
| 260 | // - The run location reported doesn't immediately follow the previous |
| 261 | // reported run location. |
| 262 | // We don't want to run because extensions may have requirements that scripts |
| 263 | // running in an earlier run location have run by the time a later script |
| 264 | // runs. Better to just not run. |
| 265 | if ((iter == frame_statuses_.end() && |
| 266 | run_location != UserScript::DOCUMENT_START) || |
| 267 | (iter != frame_statuses_.end() && run_location - iter->second > 1)) { |
| 268 | // We also invalidate the frame, because the run order of pending injections |
| 269 | // may also be bad. |
| 270 | InvalidateForFrame(frame); |
| 271 | return; |
| 272 | } else if (iter != frame_statuses_.end() && iter->second > run_location) { |
| 273 | // Certain run location signals (like DidCreateDocumentElement) can happen |
| 274 | // multiple times. Ignore the subsequent signals. |
| 275 | return; |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 276 | } |
| 277 | |
[email protected] | 5672620d | 2014-07-30 10:07:17 | [diff] [blame] | 278 | // Otherwise, all is right in the world, and we can get on with the |
| 279 | // injections! |
| 280 | |
| 281 | frame_statuses_[frame] = run_location; |
| 282 | |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 283 | // Inject any scripts that were waiting for the right run location. |
[email protected] | c11e659 | 2014-06-27 17:07:34 | [diff] [blame] | 284 | ScriptsRunInfo scripts_run_info; |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 285 | for (ScopedVector<ScriptInjection>::iterator iter = |
| 286 | pending_injections_.begin(); |
| 287 | iter != pending_injections_.end();) { |
| 288 | if ((*iter)->web_frame() == frame && |
| 289 | (*iter)->TryToInject(run_location, |
| 290 | extensions_->GetByID((*iter)->extension_id()), |
| 291 | &scripts_run_info)) { |
| 292 | iter = pending_injections_.erase(iter); |
| 293 | } else { |
| 294 | ++iter; |
| 295 | } |
| 296 | } |
| 297 | |
| 298 | // Try to inject any user scripts that should run for this location. If they |
| 299 | // don't complete their injection (for example, waiting for a permission |
| 300 | // response) then they will be added to |pending_injections_|. |
| 301 | ScopedVector<ScriptInjection> user_script_injections; |
| 302 | int tab_id = ExtensionHelper::Get(content::RenderView::FromWebView( |
| 303 | frame->top()->view()))->tab_id(); |
[email protected] | 4c35690 | 2014-07-30 09:52:02 | [diff] [blame] | 304 | user_script_set_manager_->GetAllInjections( |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 305 | &user_script_injections, frame, tab_id, run_location); |
| 306 | for (ScopedVector<ScriptInjection>::iterator iter = |
| 307 | user_script_injections.begin(); |
| 308 | iter != user_script_injections.end();) { |
| 309 | scoped_ptr<ScriptInjection> injection(*iter); |
| 310 | iter = user_script_injections.weak_erase(iter); |
| 311 | if (!injection->TryToInject(run_location, |
| 312 | extensions_->GetByID(injection->extension_id()), |
| 313 | &scripts_run_info)) { |
| 314 | pending_injections_.push_back(injection.release()); |
| 315 | } |
| 316 | } |
| 317 | |
[email protected] | c11e659 | 2014-06-27 17:07:34 | [diff] [blame] | 318 | scripts_run_info.LogRun(frame, run_location); |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 319 | } |
| 320 | |
| 321 | void ScriptInjectionManager::HandleExecuteCode( |
| 322 | const ExtensionMsg_ExecuteCode_Params& params, |
| 323 | content::RenderView* render_view) { |
dcheng | 2e44917 | 2014-09-24 04:30:56 | [diff] [blame] | 324 | // TODO(dcheng): Not sure how this can happen today. In an OOPI world, it |
| 325 | // would indicate a logic error--the browser must direct this request to the |
| 326 | // right renderer process to begin with. |
| 327 | blink::WebLocalFrame* main_frame = |
| 328 | render_view->GetWebView()->mainFrame()->toWebLocalFrame(); |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 329 | if (!main_frame) { |
| 330 | render_view->Send( |
| 331 | new ExtensionHostMsg_ExecuteCodeFinished(render_view->GetRoutingID(), |
| 332 | params.request_id, |
| 333 | "No main frame", |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 334 | GURL(std::string()), |
| 335 | base::ListValue())); |
| 336 | return; |
| 337 | } |
| 338 | |
[email protected] | c11e659 | 2014-06-27 17:07:34 | [diff] [blame] | 339 | scoped_ptr<ScriptInjection> injection(new ScriptInjection( |
| 340 | scoped_ptr<ScriptInjector>( |
| 341 | new ProgrammaticScriptInjector(params, main_frame)), |
| 342 | main_frame, |
| 343 | params.extension_id, |
| 344 | static_cast<UserScript::RunLocation>(params.run_at), |
| 345 | ExtensionHelper::Get(render_view)->tab_id())); |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 346 | |
[email protected] | c11e659 | 2014-06-27 17:07:34 | [diff] [blame] | 347 | ScriptsRunInfo scripts_run_info; |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 348 | FrameStatusMap::const_iterator iter = frame_statuses_.find(main_frame); |
| 349 | if (!injection->TryToInject( |
| 350 | iter == frame_statuses_.end() ? UserScript::UNDEFINED : iter->second, |
| 351 | extensions_->GetByID(injection->extension_id()), |
| 352 | &scripts_run_info)) { |
| 353 | pending_injections_.push_back(injection.release()); |
| 354 | } |
| 355 | } |
| 356 | |
markdittmer | 9ea140f | 2014-08-29 02:46:15 | [diff] [blame] | 357 | void ScriptInjectionManager::HandleExecuteDeclarativeScript( |
| 358 | blink::WebFrame* web_frame, |
| 359 | int tab_id, |
| 360 | const ExtensionId& extension_id, |
| 361 | int script_id, |
| 362 | const GURL& url) { |
| 363 | const Extension* extension = extensions_->GetByID(extension_id); |
dcheng | 2e44917 | 2014-09-24 04:30:56 | [diff] [blame] | 364 | // TODO(dcheng): This function signature should really be a WebLocalFrame, |
| 365 | // rather than trying to coerce it here. |
markdittmer | 9ea140f | 2014-08-29 02:46:15 | [diff] [blame] | 366 | scoped_ptr<ScriptInjection> injection = |
| 367 | user_script_set_manager_->GetInjectionForDeclarativeScript( |
| 368 | script_id, |
dcheng | 2e44917 | 2014-09-24 04:30:56 | [diff] [blame] | 369 | web_frame->toWebLocalFrame(), |
markdittmer | 9ea140f | 2014-08-29 02:46:15 | [diff] [blame] | 370 | tab_id, |
| 371 | url, |
| 372 | extension); |
| 373 | if (injection.get()) { |
| 374 | ScriptsRunInfo scripts_run_info; |
| 375 | // TODO(markdittmer): Use return value of TryToInject for error handling. |
| 376 | injection->TryToInject(UserScript::BROWSER_DRIVEN, |
| 377 | extension, |
| 378 | &scripts_run_info); |
| 379 | scripts_run_info.LogRun(web_frame, UserScript::BROWSER_DRIVEN); |
| 380 | } |
| 381 | } |
| 382 | |
[email protected] | d205600 | 2014-07-03 06:18:06 | [diff] [blame] | 383 | void ScriptInjectionManager::HandlePermitScriptInjection(int64 request_id) { |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 384 | ScopedVector<ScriptInjection>::iterator iter = |
| 385 | pending_injections_.begin(); |
| 386 | for (; iter != pending_injections_.end(); ++iter) { |
| 387 | if ((*iter)->request_id() == request_id) |
| 388 | break; |
| 389 | } |
| 390 | if (iter == pending_injections_.end()) |
| 391 | return; |
| 392 | |
[email protected] | d205600 | 2014-07-03 06:18:06 | [diff] [blame] | 393 | // At this point, because the request is present in pending_injections_, we |
| 394 | // know that this is the same page that issued the request (otherwise, |
| 395 | // RVOHelper's DidStartProvisionalLoad callback would have caused it to be |
| 396 | // cleared out). |
| 397 | |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 398 | scoped_ptr<ScriptInjection> injection(*iter); |
| 399 | pending_injections_.weak_erase(iter); |
| 400 | |
[email protected] | c11e659 | 2014-06-27 17:07:34 | [diff] [blame] | 401 | ScriptsRunInfo scripts_run_info; |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 402 | if (injection->OnPermissionGranted(extensions_->GetByID( |
| 403 | injection->extension_id()), |
| 404 | &scripts_run_info)) { |
[email protected] | c11e659 | 2014-06-27 17:07:34 | [diff] [blame] | 405 | scripts_run_info.LogRun(injection->web_frame(), UserScript::RUN_DEFERRED); |
[email protected] | ac2f8937 | 2014-06-23 21:44:25 | [diff] [blame] | 406 | } |
| 407 | } |
| 408 | |
| 409 | } // namespace extensions |