Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(316)

Side by Side Diff: extensions/renderer/script_injection_manager.cc

Issue 1642283002: Deal with frame removal by content scripts (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Schedule microtask for document_end scripts Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698