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

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

Issue 288053002: Block content scripts from executing until user grants permission (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: CQ Time! Created 6 years, 6 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 | Annotate | Revision Log
« no previous file with comments | « extensions/renderer/user_script_slave.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/user_script_slave.h" 5 #include "extensions/renderer/user_script_slave.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/shared_memory.h" 10 #include "base/memory/shared_memory.h"
(...skipping 13 matching lines...) Expand all
24 #include "third_party/WebKit/public/web/WebFrame.h" 24 #include "third_party/WebKit/public/web/WebFrame.h"
25 #include "third_party/WebKit/public/web/WebSecurityOrigin.h" 25 #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
26 #include "third_party/WebKit/public/web/WebSecurityPolicy.h" 26 #include "third_party/WebKit/public/web/WebSecurityPolicy.h"
27 #include "third_party/WebKit/public/web/WebView.h" 27 #include "third_party/WebKit/public/web/WebView.h"
28 #include "url/gurl.h" 28 #include "url/gurl.h"
29 29
30 using blink::WebFrame; 30 using blink::WebFrame;
31 using blink::WebSecurityOrigin; 31 using blink::WebSecurityOrigin;
32 using blink::WebSecurityPolicy; 32 using blink::WebSecurityPolicy;
33 using blink::WebString; 33 using blink::WebString;
34 using blink::WebView;
35 using content::RenderThread; 34 using content::RenderThread;
36 35
37 namespace extensions { 36 namespace extensions {
38 37
39 int UserScriptSlave::GetIsolatedWorldIdForExtension(const Extension* extension, 38 int UserScriptSlave::GetIsolatedWorldIdForExtension(const Extension* extension,
40 WebFrame* frame) { 39 WebFrame* frame) {
41 static int g_next_isolated_world_id = 40 static int g_next_isolated_world_id =
42 ExtensionsRendererClient::Get()->GetLowestIsolatedWorldId(); 41 ExtensionsRendererClient::Get()->GetLowestIsolatedWorldId();
43 42
44 int id = 0; 43 int id = 0;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 DCHECK(!(*iter)->extension_id().empty()); 94 DCHECK(!(*iter)->extension_id().empty());
96 extension_ids->insert((*iter)->extension_id()); 95 extension_ids->insert((*iter)->extension_id());
97 } 96 }
98 } 97 }
99 98
100 const Extension* UserScriptSlave::GetExtension( 99 const Extension* UserScriptSlave::GetExtension(
101 const std::string& extension_id) { 100 const std::string& extension_id) {
102 return extensions_->GetByID(extension_id); 101 return extensions_->GetByID(extension_id);
103 } 102 }
104 103
105 bool UserScriptSlave::UpdateScripts(base::SharedMemoryHandle shared_memory) { 104 bool UserScriptSlave::UpdateScripts(
106 script_injections_.clear(); 105 base::SharedMemoryHandle shared_memory,
107 106 const std::set<std::string>& changed_extensions) {
108 bool only_inject_incognito = 107 bool only_inject_incognito =
109 ExtensionsRendererClient::Get()->IsIncognitoProcess(); 108 ExtensionsRendererClient::Get()->IsIncognitoProcess();
110 109
111 // Create the shared memory object (read only). 110 // Create the shared memory object (read only).
112 shared_memory_.reset(new base::SharedMemory(shared_memory, true)); 111 shared_memory_.reset(new base::SharedMemory(shared_memory, true));
113 if (!shared_memory_.get()) 112 if (!shared_memory_.get())
114 return false; 113 return false;
115 114
116 // First get the size of the memory block. 115 // First get the size of the memory block.
117 if (!shared_memory_->Map(sizeof(Pickle::Header))) 116 if (!shared_memory_->Map(sizeof(Pickle::Header)))
118 return false; 117 return false;
119 Pickle::Header* pickle_header = 118 Pickle::Header* pickle_header =
120 reinterpret_cast<Pickle::Header*>(shared_memory_->memory()); 119 reinterpret_cast<Pickle::Header*>(shared_memory_->memory());
121 120
122 // Now map in the rest of the block. 121 // Now map in the rest of the block.
123 int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size; 122 int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size;
124 shared_memory_->Unmap(); 123 shared_memory_->Unmap();
125 if (!shared_memory_->Map(pickle_size)) 124 if (!shared_memory_->Map(pickle_size))
126 return false; 125 return false;
127 126
128 // Unpickle scripts. 127 // Unpickle scripts.
129 uint64 num_scripts = 0; 128 uint64 num_scripts = 0;
130 Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()), pickle_size); 129 Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()), pickle_size);
131 PickleIterator iter(pickle); 130 PickleIterator iter(pickle);
132 CHECK(pickle.ReadUInt64(&iter, &num_scripts)); 131 CHECK(pickle.ReadUInt64(&iter, &num_scripts));
133 132
133 // If we pass no explicit extension ids, we should refresh all extensions.
134 bool include_all_extensions = changed_extensions.empty();
135
136 // If we include all extensions, then we clear the script injections and
137 // start from scratch. If not, then clear only the scripts for extension ids
138 // that we are updating. This is important to maintain pending script
139 // injection state for each ScriptInjection.
140 if (include_all_extensions) {
141 script_injections_.clear();
142 } else {
143 for (ScopedVector<ScriptInjection>::iterator iter =
144 script_injections_.begin();
145 iter != script_injections_.end();) {
146 if (changed_extensions.count((*iter)->extension_id()) > 0)
147 iter = script_injections_.erase(iter);
148 else
149 ++iter;
150 }
151 }
152
134 script_injections_.reserve(num_scripts); 153 script_injections_.reserve(num_scripts);
135 for (uint64 i = 0; i < num_scripts; ++i) { 154 for (uint64 i = 0; i < num_scripts; ++i) {
136 scoped_ptr<UserScript> script(new UserScript()); 155 scoped_ptr<UserScript> script(new UserScript());
137 script->Unpickle(pickle, &iter); 156 script->Unpickle(pickle, &iter);
138 157
139 // Note that this is a pointer into shared memory. We don't own it. It gets 158 // Note that this is a pointer into shared memory. We don't own it. It gets
140 // cleared up when the last renderer or browser process drops their 159 // cleared up when the last renderer or browser process drops their
141 // reference to the shared memory. 160 // reference to the shared memory.
142 for (size_t j = 0; j < script->js_scripts().size(); ++j) { 161 for (size_t j = 0; j < script->js_scripts().size(); ++j) {
143 const char* body = NULL; 162 const char* body = NULL;
144 int body_length = 0; 163 int body_length = 0;
145 CHECK(pickle.ReadData(&iter, &body, &body_length)); 164 CHECK(pickle.ReadData(&iter, &body, &body_length));
146 script->js_scripts()[j].set_external_content( 165 script->js_scripts()[j].set_external_content(
147 base::StringPiece(body, body_length)); 166 base::StringPiece(body, body_length));
148 } 167 }
149 for (size_t j = 0; j < script->css_scripts().size(); ++j) { 168 for (size_t j = 0; j < script->css_scripts().size(); ++j) {
150 const char* body = NULL; 169 const char* body = NULL;
151 int body_length = 0; 170 int body_length = 0;
152 CHECK(pickle.ReadData(&iter, &body, &body_length)); 171 CHECK(pickle.ReadData(&iter, &body, &body_length));
153 script->css_scripts()[j].set_external_content( 172 script->css_scripts()[j].set_external_content(
154 base::StringPiece(body, body_length)); 173 base::StringPiece(body, body_length));
155 } 174 }
156 175
157 if (only_inject_incognito && !script->is_incognito_enabled()) 176 // Don't add the script if it shouldn't shouldn't run in this tab, or if
158 continue; // This script shouldn't run in an incognito tab. 177 // we don't need to reload that extension.
178 // It's a shame we don't catch this sooner, but since we lump all the user
179 // scripts together, we can't skip parsing any.
180 if ((only_inject_incognito && !script->is_incognito_enabled()) ||
181 (!include_all_extensions &&
182 changed_extensions.count(script->extension_id()) == 0)) {
183 continue;
184 }
159 185
160 script_injections_.push_back(new ScriptInjection(script.Pass(), this)); 186 script_injections_.push_back(new ScriptInjection(script.Pass(), this));
161 } 187 }
162 188
163 return true; 189 return true;
164 } 190 }
165 191
166 void UserScriptSlave::InjectScripts(WebFrame* frame, 192 void UserScriptSlave::InjectScripts(WebFrame* frame,
167 UserScript::RunLocation location) { 193 UserScript::RunLocation location) {
168 GURL document_url = ScriptInjection::GetDocumentUrlForFrame(frame); 194 GURL document_url = ScriptInjection::GetDocumentUrlForFrame(frame);
169 if (document_url.is_empty()) 195 if (document_url.is_empty())
170 return; 196 return;
171 197
172 content::RenderView* top_render_view =
173 content::RenderView::FromWebView(frame->top()->view());
174
175 ScriptInjection::ScriptsRunInfo scripts_run_info; 198 ScriptInjection::ScriptsRunInfo scripts_run_info;
176 for (ScopedVector<ScriptInjection>::const_iterator iter = 199 for (ScopedVector<ScriptInjection>::const_iterator iter =
177 script_injections_.begin(); 200 script_injections_.begin();
178 iter != script_injections_.end(); 201 iter != script_injections_.end();
179 ++iter) { 202 ++iter) {
180 ScriptInjection* injection = *iter; 203 (*iter)->InjectIfAllowed(frame, location, document_url, &scripts_run_info);
181 if (!injection->WantsToRun(frame, location, document_url))
182 continue;
183
184 const Extension* extension = GetExtension(injection->extension_id());
185 DCHECK(extension);
186
187 if (PermissionsData::RequiresActionForScriptExecution(
188 extension,
189 ExtensionHelper::Get(top_render_view)->tab_id(),
190 document_url)) {
191 // TODO(rdevlin.cronin): Right now, this is just a notification, but soon
192 // we should block without user consent.
193 top_render_view->Send(
194 new ExtensionHostMsg_NotifyExtensionScriptExecution(
195 top_render_view->GetRoutingID(),
196 extension->id(),
197 top_render_view->GetPageId()));
198 }
199
200 injection->Inject(frame, location, &scripts_run_info);
201 } 204 }
202 205
203 LogScriptsRun(frame, location, scripts_run_info); 206 LogScriptsRun(frame, location, scripts_run_info);
204 } 207 }
205 208
209 void UserScriptSlave::OnContentScriptGrantedPermission(
210 content::RenderView* render_view, int request_id) {
211 ScriptInjection::ScriptsRunInfo run_info;
212 blink::WebFrame* frame = NULL;
213 // Notify the injections that a request to inject has been granted.
214 for (ScopedVector<ScriptInjection>::iterator iter =
215 script_injections_.begin();
216 iter != script_injections_.end();
217 ++iter) {
218 if ((*iter)->NotifyScriptPermitted(request_id,
219 render_view,
220 &run_info,
221 &frame)) {
222 DCHECK(frame);
223 LogScriptsRun(frame, UserScript::RUN_DEFERRED, run_info);
224 break;
225 }
226 }
227 }
228
229 void UserScriptSlave::FrameDetached(blink::WebFrame* frame) {
230 for (ScopedVector<ScriptInjection>::iterator iter =
231 script_injections_.begin();
232 iter != script_injections_.end();
233 ++iter) {
234 (*iter)->FrameDetached(frame);
235 }
236 }
237
206 void UserScriptSlave::LogScriptsRun( 238 void UserScriptSlave::LogScriptsRun(
207 blink::WebFrame* frame, 239 blink::WebFrame* frame,
208 UserScript::RunLocation location, 240 UserScript::RunLocation location,
209 const ScriptInjection::ScriptsRunInfo& info) { 241 const ScriptInjection::ScriptsRunInfo& info) {
210 // Notify the browser if any extensions are now executing scripts. 242 // Notify the browser if any extensions are now executing scripts.
211 if (!info.executing_scripts.empty()) { 243 if (!info.executing_scripts.empty()) {
212 content::RenderView* render_view = 244 content::RenderView* render_view =
213 content::RenderView::FromWebView(frame->view()); 245 content::RenderView::FromWebView(frame->view());
214 render_view->Send(new ExtensionHostMsg_ContentScriptsExecuting( 246 render_view->Send(new ExtensionHostMsg_ContentScriptsExecuting(
215 render_view->GetRoutingID(), 247 render_view->GetRoutingID(),
216 info.executing_scripts, 248 info.executing_scripts,
217 render_view->GetPageId(), 249 render_view->GetPageId(),
218 ScriptContext::GetDataSourceURLForFrame(frame))); 250 ScriptContext::GetDataSourceURLForFrame(frame)));
219 } 251 }
220 252
221 if (location == UserScript::DOCUMENT_START) { 253 switch (location) {
222 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount", 254 case UserScript::DOCUMENT_START:
223 info.num_css); 255 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount",
224 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", info.num_js); 256 info.num_css);
225 if (info.num_css || info.num_js) 257 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount",
226 UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", info.timer.Elapsed()); 258 info.num_js);
227 } else if (location == UserScript::DOCUMENT_END) { 259 if (info.num_css || info.num_js)
228 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", info.num_js); 260 UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time",
229 if (info.num_js) 261 info.timer.Elapsed());
230 UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", info.timer.Elapsed()); 262 break;
231 } else if (location == UserScript::DOCUMENT_IDLE) { 263 case UserScript::DOCUMENT_END:
232 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount", info.num_js); 264 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", info.num_js);
233 if (info.num_js) 265 if (info.num_js)
234 UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", info.timer.Elapsed()); 266 UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", info.timer.Elapsed());
235 } else { 267 break;
236 NOTREACHED(); 268 case UserScript::DOCUMENT_IDLE:
269 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount",
270 info.num_js);
271 if (info.num_js)
272 UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", info.timer.Elapsed());
273 break;
274 case UserScript::RUN_DEFERRED:
275 // TODO(rdevlin.cronin): Add histograms.
276 break;
277 case UserScript::UNDEFINED:
278 case UserScript::RUN_LOCATION_LAST:
279 NOTREACHED();
237 } 280 }
238 } 281 }
239 282
240 } // namespace extensions 283 } // namespace extensions
OLDNEW
« no previous file with comments | « extensions/renderer/user_script_slave.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698