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 <utility> | 7 #include <utility> |
8 | 8 |
9 #include "base/auto_reset.h" | 9 #include "base/auto_reset.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
12 #include "base/memory/weak_ptr.h" | 12 #include "base/memory/weak_ptr.h" |
13 #include "base/values.h" | 13 #include "base/values.h" |
14 #include "content/public/renderer/render_frame.h" | 14 #include "content/public/renderer/render_frame.h" |
15 #include "content/public/renderer/render_frame_observer.h" | 15 #include "content/public/renderer/render_frame_observer.h" |
16 #include "content/public/renderer/render_thread.h" | 16 #include "content/public/renderer/render_thread.h" |
17 #include "extensions/common/extension.h" | 17 #include "extensions/common/extension.h" |
18 #include "extensions/common/extension_messages.h" | 18 #include "extensions/common/extension_messages.h" |
19 #include "extensions/common/extension_set.h" | 19 #include "extensions/common/extension_set.h" |
20 #include "extensions/renderer/extension_frame_helper.h" | 20 #include "extensions/renderer/extension_frame_helper.h" |
21 #include "extensions/renderer/extension_injection_host.h" | 21 #include "extensions/renderer/extension_injection_host.h" |
22 #include "extensions/renderer/programmatic_script_injector.h" | 22 #include "extensions/renderer/programmatic_script_injector.h" |
23 #include "extensions/renderer/renderer_extension_registry.h" | 23 #include "extensions/renderer/renderer_extension_registry.h" |
24 #include "extensions/renderer/script_injection.h" | 24 #include "extensions/renderer/script_injection.h" |
25 #include "extensions/renderer/scripts_run_info.h" | 25 #include "extensions/renderer/scripts_run_info.h" |
26 #include "extensions/renderer/web_ui_injection_host.h" | 26 #include "extensions/renderer/web_ui_injection_host.h" |
27 #include "ipc/ipc_message_macros.h" | 27 #include "ipc/ipc_message_macros.h" |
28 #include "third_party/WebKit/public/web/WebDocument.h" | 28 #include "third_party/WebKit/public/web/WebDocument.h" |
29 #include "third_party/WebKit/public/web/WebFrame.h" | 29 #include "third_party/WebKit/public/web/WebFrame.h" |
| 30 #include "third_party/WebKit/public/web/WebKit.h" |
30 #include "third_party/WebKit/public/web/WebLocalFrame.h" | 31 #include "third_party/WebKit/public/web/WebLocalFrame.h" |
31 #include "third_party/WebKit/public/web/WebView.h" | 32 #include "third_party/WebKit/public/web/WebView.h" |
32 #include "url/gurl.h" | 33 #include "url/gurl.h" |
33 | 34 |
34 namespace extensions { | 35 namespace extensions { |
35 | 36 |
36 namespace { | 37 namespace { |
37 | 38 |
38 // The length of time to wait after the DOM is complete to try and run user | 39 // The length of time to wait after the DOM is complete to try and run user |
39 // scripts. | 40 // scripts. |
(...skipping 20 matching lines...) Expand all Loading... |
60 | 61 |
61 } // namespace | 62 } // namespace |
62 | 63 |
63 class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver { | 64 class ScriptInjectionManager::RFOHelper : public content::RenderFrameObserver { |
64 public: | 65 public: |
65 RFOHelper(content::RenderFrame* render_frame, | 66 RFOHelper(content::RenderFrame* render_frame, |
66 ScriptInjectionManager* manager); | 67 ScriptInjectionManager* manager); |
67 ~RFOHelper() override; | 68 ~RFOHelper() override; |
68 | 69 |
69 private: | 70 private: |
| 71 class ScheduledScriptInjection; |
| 72 |
70 // RenderFrameObserver implementation. | 73 // RenderFrameObserver implementation. |
71 bool OnMessageReceived(const IPC::Message& message) override; | 74 bool OnMessageReceived(const IPC::Message& message) override; |
72 void DidCreateNewDocument() override; | 75 void DidCreateNewDocument() override; |
73 void DidCreateDocumentElement() override; | 76 void DidCreateDocumentElement() override; |
74 void DidFailProvisionalLoad(const blink::WebURLError& error) override; | 77 void DidFailProvisionalLoad(const blink::WebURLError& error) override; |
75 void DidFinishDocumentLoad() override; | 78 void DidFinishDocumentLoad() override; |
76 void DidFinishLoad() override; | 79 void DidFinishLoad() override; |
77 void FrameDetached() override; | 80 void FrameDetached() override; |
78 void OnDestruct() override; | 81 void OnDestruct() override; |
79 | 82 |
(...skipping 24 matching lines...) Expand all Loading... |
104 ScriptInjectionManager* manager) | 107 ScriptInjectionManager* manager) |
105 : content::RenderFrameObserver(render_frame), | 108 : content::RenderFrameObserver(render_frame), |
106 manager_(manager), | 109 manager_(manager), |
107 should_run_idle_(true), | 110 should_run_idle_(true), |
108 weak_factory_(this) { | 111 weak_factory_(this) { |
109 } | 112 } |
110 | 113 |
111 ScriptInjectionManager::RFOHelper::~RFOHelper() { | 114 ScriptInjectionManager::RFOHelper::~RFOHelper() { |
112 } | 115 } |
113 | 116 |
| 117 // This class schedules a script injection at |run_location| in the frame. |
| 118 class ScriptInjectionManager::RFOHelper::ScheduledScriptInjection { |
| 119 public: |
| 120 ScheduledScriptInjection(base::WeakPtr<RFOHelper> rfo_helper_weak, |
| 121 UserScript::RunLocation run_location) |
| 122 : rfo_helper_weak_(rfo_helper_weak), run_location_(run_location) { |
| 123 v8::Isolate* isolate = blink::mainThreadIsolate(); |
| 124 isolate->EnqueueMicrotask(RunScheduledScriptInjection, this); |
| 125 } |
| 126 |
| 127 private: |
| 128 // This is called once when V8 runs the microtask. |
| 129 static void RunScheduledScriptInjection(void* data) { |
| 130 ScheduledScriptInjection* scheduled_script_injection = |
| 131 static_cast<ScheduledScriptInjection*>(data); |
| 132 scheduled_script_injection->StartInjectScripts(); |
| 133 delete scheduled_script_injection; |
| 134 } |
| 135 |
| 136 void StartInjectScripts() { |
| 137 RFOHelper* rfo_helper = rfo_helper_weak_.get(); |
| 138 if (!rfo_helper) |
| 139 return; |
| 140 rfo_helper->manager_->StartInjectScripts(rfo_helper->render_frame(), |
| 141 run_location_); |
| 142 } |
| 143 |
| 144 base::WeakPtr<RFOHelper> rfo_helper_weak_; |
| 145 UserScript::RunLocation run_location_; |
| 146 |
| 147 DISALLOW_COPY_AND_ASSIGN(ScheduledScriptInjection); |
| 148 }; |
| 149 |
114 bool ScriptInjectionManager::RFOHelper::OnMessageReceived( | 150 bool ScriptInjectionManager::RFOHelper::OnMessageReceived( |
115 const IPC::Message& message) { | 151 const IPC::Message& message) { |
116 bool handled = true; | 152 bool handled = true; |
117 IPC_BEGIN_MESSAGE_MAP(ScriptInjectionManager::RFOHelper, message) | 153 IPC_BEGIN_MESSAGE_MAP(ScriptInjectionManager::RFOHelper, message) |
118 IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteCode, OnExecuteCode) | 154 IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteCode, OnExecuteCode) |
119 IPC_MESSAGE_HANDLER(ExtensionMsg_PermitScriptInjection, | 155 IPC_MESSAGE_HANDLER(ExtensionMsg_PermitScriptInjection, |
120 OnPermitScriptInjection) | 156 OnPermitScriptInjection) |
121 IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteDeclarativeScript, | 157 IPC_MESSAGE_HANDLER(ExtensionMsg_ExecuteDeclarativeScript, |
122 OnExecuteDeclarativeScript) | 158 OnExecuteDeclarativeScript) |
123 IPC_MESSAGE_UNHANDLED(handled = false) | 159 IPC_MESSAGE_UNHANDLED(handled = false) |
124 IPC_END_MESSAGE_MAP() | 160 IPC_END_MESSAGE_MAP() |
125 return handled; | 161 return handled; |
126 } | 162 } |
127 | 163 |
128 void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() { | 164 void ScriptInjectionManager::RFOHelper::DidCreateNewDocument() { |
129 // A new document is going to be shown, so invalidate the old document state. | 165 // A new document is going to be shown, so invalidate the old document state. |
130 // Check that the frame's state is known before invalidating the frame, | 166 // Check that the frame's state is known before invalidating the frame, |
131 // because it is possible that a script injection was scheduled before the | 167 // because it is possible that a script injection was scheduled before the |
132 // page was loaded, e.g. by navigating to a javascript: URL before the page | 168 // page was loaded, e.g. by navigating to a javascript: URL before the page |
133 // has loaded. | 169 // has loaded. |
134 if (manager_->frame_statuses_.count(render_frame()) != 0) | 170 if (manager_->frame_statuses_.count(render_frame()) != 0) |
135 InvalidateAndResetFrame(); | 171 InvalidateAndResetFrame(); |
136 } | 172 } |
137 | 173 |
138 void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() { | 174 void ScriptInjectionManager::RFOHelper::DidCreateDocumentElement() { |
139 manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_START); | 175 new ScheduledScriptInjection( |
| 176 weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_START); |
140 } | 177 } |
141 | 178 |
142 void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad( | 179 void ScriptInjectionManager::RFOHelper::DidFailProvisionalLoad( |
143 const blink::WebURLError& error) { | 180 const blink::WebURLError& error) { |
144 FrameStatusMap::iterator it = manager_->frame_statuses_.find(render_frame()); | 181 FrameStatusMap::iterator it = manager_->frame_statuses_.find(render_frame()); |
145 if (it != manager_->frame_statuses_.end() && | 182 if (it != manager_->frame_statuses_.end() && |
146 it->second == UserScript::DOCUMENT_START) { | 183 it->second == UserScript::DOCUMENT_START) { |
147 // Since the provisional load failed, the frame stays at its previous loaded | 184 // Since the provisional load failed, the frame stays at its previous loaded |
148 // state and origin (or the parent's origin for new/about:blank frames). | 185 // state and origin (or the parent's origin for new/about:blank frames). |
149 // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is | 186 // Reset the frame to DOCUMENT_IDLE in order to reflect that the frame is |
150 // done loading, and avoid any deadlock in the system. | 187 // done loading, and avoid any deadlock in the system. |
151 // | 188 // |
152 // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the | 189 // We skip injection of DOCUMENT_END and DOCUMENT_IDLE scripts, because the |
153 // injections closely follow the DOMContentLoaded (and onload) events, which | 190 // injections closely follow the DOMContentLoaded (and onload) events, which |
154 // are not triggered after a failed provisional load. | 191 // are not triggered after a failed provisional load. |
155 // This assumption is verified in the checkDOMContentLoadedEvent subtest of | 192 // This assumption is verified in the checkDOMContentLoadedEvent subtest of |
156 // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests). | 193 // ExecuteScriptApiTest.FrameWithHttp204 (browser_tests). |
157 InvalidateAndResetFrame(); | 194 InvalidateAndResetFrame(); |
158 should_run_idle_ = false; | 195 should_run_idle_ = false; |
159 manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE; | 196 manager_->frame_statuses_[render_frame()] = UserScript::DOCUMENT_IDLE; |
160 } | 197 } |
161 } | 198 } |
162 | 199 |
163 void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() { | 200 void ScriptInjectionManager::RFOHelper::DidFinishDocumentLoad() { |
164 DCHECK(content::RenderThread::Get()); | 201 DCHECK(content::RenderThread::Get()); |
165 manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_END); | 202 new ScheduledScriptInjection( |
| 203 weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_END); |
| 204 |
166 // We try to run idle in two places: here and DidFinishLoad. | 205 // We try to run idle in two places: here and DidFinishLoad. |
167 // DidFinishDocumentLoad() corresponds to completing the document's load, | 206 // DidFinishDocumentLoad() corresponds to completing the document's load, |
168 // whereas DidFinishLoad corresponds to completing the document and all | 207 // whereas DidFinishLoad corresponds to completing the document and all |
169 // subresources' load. We don't want to hold up script injection for a | 208 // subresources' load. We don't want to hold up script injection for a |
170 // particularly slow subresource, so we set a delayed task from here - but if | 209 // particularly slow subresource, so we set a delayed task from here - but if |
171 // we finish everything before that point (i.e., DidFinishLoad() is | 210 // we finish everything before that point (i.e., DidFinishLoad() is |
172 // triggered), then there's no reason to keep waiting. | 211 // triggered), then there's no reason to keep waiting. |
173 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 212 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
174 FROM_HERE, | 213 FROM_HERE, |
175 base::Bind(&ScriptInjectionManager::RFOHelper::RunIdle, | 214 base::Bind(&ScriptInjectionManager::RFOHelper::RunIdle, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 void ScriptInjectionManager::RFOHelper::OnPermitScriptInjection( | 259 void ScriptInjectionManager::RFOHelper::OnPermitScriptInjection( |
221 int64_t request_id) { | 260 int64_t request_id) { |
222 manager_->HandlePermitScriptInjection(request_id); | 261 manager_->HandlePermitScriptInjection(request_id); |
223 } | 262 } |
224 | 263 |
225 void ScriptInjectionManager::RFOHelper::RunIdle() { | 264 void ScriptInjectionManager::RFOHelper::RunIdle() { |
226 // Only notify the manager if the frame hasn't either been removed or already | 265 // Only notify the manager if the frame hasn't either been removed or already |
227 // had idle run since the task to RunIdle() was posted. | 266 // had idle run since the task to RunIdle() was posted. |
228 if (should_run_idle_) { | 267 if (should_run_idle_) { |
229 should_run_idle_ = false; | 268 should_run_idle_ = false; |
230 manager_->StartInjectScripts(render_frame(), UserScript::DOCUMENT_IDLE); | 269 new ScheduledScriptInjection( |
| 270 weak_factory_.GetWeakPtr(), UserScript::DOCUMENT_IDLE); |
231 } | 271 } |
232 } | 272 } |
233 | 273 |
234 void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame() { | 274 void ScriptInjectionManager::RFOHelper::InvalidateAndResetFrame() { |
235 // Invalidate any pending idle injections, and reset the frame inject on idle. | 275 // Invalidate any pending idle injections, and reset the frame inject on idle. |
236 weak_factory_.InvalidateWeakPtrs(); | 276 weak_factory_.InvalidateWeakPtrs(); |
237 // We reset to inject on idle, because the frame can be reused (in the case of | 277 // We reset to inject on idle, because the frame can be reused (in the case of |
238 // navigation). | 278 // navigation). |
239 should_run_idle_ = true; | 279 should_run_idle_ = true; |
240 manager_->InvalidateForFrame(render_frame()); | 280 manager_->InvalidateForFrame(render_frame()); |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
491 ScriptsRunInfo scripts_run_info(injection->render_frame(), | 531 ScriptsRunInfo scripts_run_info(injection->render_frame(), |
492 UserScript::RUN_DEFERRED); | 532 UserScript::RUN_DEFERRED); |
493 ScriptInjection::InjectionResult res = injection->OnPermissionGranted( | 533 ScriptInjection::InjectionResult res = injection->OnPermissionGranted( |
494 &scripts_run_info); | 534 &scripts_run_info); |
495 if (res == ScriptInjection::INJECTION_BLOCKED) | 535 if (res == ScriptInjection::INJECTION_BLOCKED) |
496 running_injections_.push_back(std::move(injection)); | 536 running_injections_.push_back(std::move(injection)); |
497 scripts_run_info.LogRun(); | 537 scripts_run_info.LogRun(); |
498 } | 538 } |
499 | 539 |
500 } // namespace extensions | 540 } // namespace extensions |
OLD | NEW |