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

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

Issue 313453002: Resubmit: Block content scripts from executing until user grants permission (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix 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
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 if (only_inject_incognito && !script->is_incognito_enabled())
158 continue; // This script shouldn't run in an incognito tab. 177 continue; // This script shouldn't run in an incognito tab.
159 178
160 script_injections_.push_back(new ScriptInjection(script.Pass(), this)); 179 // If we include all extensions or the given extension changed, we add a
180 // new script injection.
181 if (include_all_extensions ||
182 changed_extensions.count(script->extension_id()) > 0) {
183 script_injections_.push_back(new ScriptInjection(script.Pass(), this));
184 } else {
185 // Otherwise, we need to update the existing script injection with the
186 // new user script (since the old content was invalidated).
187 for (ScopedVector<ScriptInjection>::iterator iter =
not at google - send to devlin 2014/06/02 18:42:55 O(n^2) makes me nervous. It seems like using a std
Devlin 2014/06/02 21:04:31 Per in-person chat, vectors will likely be faster
188 script_injections_.begin();
189 iter != script_injections_.end();
190 ++iter) {
191 if ((*iter)->script()->id() == script->id()) {
192 (*iter)->SetScript(script.Pass());
193 break;
194 }
195 }
196 }
161 } 197 }
162 198
163 return true; 199 return true;
164 } 200 }
165 201
166 void UserScriptSlave::InjectScripts(WebFrame* frame, 202 void UserScriptSlave::InjectScripts(WebFrame* frame,
167 UserScript::RunLocation location) { 203 UserScript::RunLocation location) {
168 GURL document_url = ScriptInjection::GetDocumentUrlForFrame(frame); 204 GURL document_url = ScriptInjection::GetDocumentUrlForFrame(frame);
169 if (document_url.is_empty()) 205 if (document_url.is_empty())
170 return; 206 return;
171 207
172 content::RenderView* top_render_view =
173 content::RenderView::FromWebView(frame->top()->view());
174
175 ScriptInjection::ScriptsRunInfo scripts_run_info; 208 ScriptInjection::ScriptsRunInfo scripts_run_info;
176 for (ScopedVector<ScriptInjection>::const_iterator iter = 209 for (ScopedVector<ScriptInjection>::const_iterator iter =
177 script_injections_.begin(); 210 script_injections_.begin();
178 iter != script_injections_.end(); 211 iter != script_injections_.end();
179 ++iter) { 212 ++iter) {
180 ScriptInjection* injection = *iter; 213 (*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 } 214 }
202 215
203 LogScriptsRun(frame, location, scripts_run_info); 216 LogScriptsRun(frame, location, scripts_run_info);
204 } 217 }
205 218
219 void UserScriptSlave::OnContentScriptGrantedPermission(
220 content::RenderView* render_view, int request_id) {
221 ScriptInjection::ScriptsRunInfo run_info;
222 blink::WebFrame* frame = NULL;
223 // Notify the injections that a request to inject has been granted.
224 for (ScopedVector<ScriptInjection>::iterator iter =
225 script_injections_.begin();
226 iter != script_injections_.end();
227 ++iter) {
228 if ((*iter)->NotifyScriptPermitted(request_id,
229 render_view,
230 &run_info,
231 &frame)) {
232 DCHECK(frame);
233 LogScriptsRun(frame, UserScript::RUN_DEFERRED, run_info);
234 break;
235 }
236 }
237 }
238
239 void UserScriptSlave::FrameDetached(blink::WebFrame* frame) {
240 for (ScopedVector<ScriptInjection>::iterator iter =
241 script_injections_.begin();
242 iter != script_injections_.end();
243 ++iter) {
244 (*iter)->FrameDetached(frame);
245 }
246 }
247
206 void UserScriptSlave::LogScriptsRun( 248 void UserScriptSlave::LogScriptsRun(
207 blink::WebFrame* frame, 249 blink::WebFrame* frame,
208 UserScript::RunLocation location, 250 UserScript::RunLocation location,
209 const ScriptInjection::ScriptsRunInfo& info) { 251 const ScriptInjection::ScriptsRunInfo& info) {
210 // Notify the browser if any extensions are now executing scripts. 252 // Notify the browser if any extensions are now executing scripts.
211 if (!info.executing_scripts.empty()) { 253 if (!info.executing_scripts.empty()) {
212 content::RenderView* render_view = 254 content::RenderView* render_view =
213 content::RenderView::FromWebView(frame->view()); 255 content::RenderView::FromWebView(frame->view());
214 render_view->Send(new ExtensionHostMsg_ContentScriptsExecuting( 256 render_view->Send(new ExtensionHostMsg_ContentScriptsExecuting(
215 render_view->GetRoutingID(), 257 render_view->GetRoutingID(),
216 info.executing_scripts, 258 info.executing_scripts,
217 render_view->GetPageId(), 259 render_view->GetPageId(),
218 ScriptContext::GetDataSourceURLForFrame(frame))); 260 ScriptContext::GetDataSourceURLForFrame(frame)));
219 } 261 }
220 262
221 if (location == UserScript::DOCUMENT_START) { 263 switch (location) {
222 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount", 264 case UserScript::DOCUMENT_START:
223 info.num_css); 265 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_CssCount",
224 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount", info.num_js); 266 info.num_css);
225 if (info.num_css || info.num_js) 267 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectStart_ScriptCount",
226 UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time", info.timer.Elapsed()); 268 info.num_js);
227 } else if (location == UserScript::DOCUMENT_END) { 269 if (info.num_css || info.num_js)
228 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", info.num_js); 270 UMA_HISTOGRAM_TIMES("Extensions.InjectStart_Time",
229 if (info.num_js) 271 info.timer.Elapsed());
230 UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", info.timer.Elapsed()); 272 break;
231 } else if (location == UserScript::DOCUMENT_IDLE) { 273 case UserScript::DOCUMENT_END:
232 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount", info.num_js); 274 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectEnd_ScriptCount", info.num_js);
233 if (info.num_js) 275 if (info.num_js)
234 UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", info.timer.Elapsed()); 276 UMA_HISTOGRAM_TIMES("Extensions.InjectEnd_Time", info.timer.Elapsed());
235 } else { 277 break;
236 NOTREACHED(); 278 case UserScript::DOCUMENT_IDLE:
279 UMA_HISTOGRAM_COUNTS_100("Extensions.InjectIdle_ScriptCount",
280 info.num_js);
281 if (info.num_js)
282 UMA_HISTOGRAM_TIMES("Extensions.InjectIdle_Time", info.timer.Elapsed());
283 break;
284 case UserScript::RUN_DEFERRED:
285 // TODO(rdevlin.cronin): Add histograms.
286 break;
287 case UserScript::UNDEFINED:
288 case UserScript::RUN_LOCATION_LAST:
289 NOTREACHED();
237 } 290 }
238 } 291 }
239 292
240 } // namespace extensions 293 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698