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