[BackgroundSync] Clean up some tests
[chromium-blink-merge.git] / extensions / renderer / user_script_set.cc
blob330475540c5ca52f7fc833a37904ec9b9eebbc88
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.
5 #include "extensions/renderer/user_script_set.h"
7 #include "base/memory/ref_counted.h"
8 #include "content/public/common/url_constants.h"
9 #include "content/public/renderer/render_frame.h"
10 #include "content/public/renderer/render_thread.h"
11 #include "extensions/common/extension.h"
12 #include "extensions/common/extension_set.h"
13 #include "extensions/common/extensions_client.h"
14 #include "extensions/common/permissions/permissions_data.h"
15 #include "extensions/renderer/extension_injection_host.h"
16 #include "extensions/renderer/extensions_renderer_client.h"
17 #include "extensions/renderer/injection_host.h"
18 #include "extensions/renderer/script_context.h"
19 #include "extensions/renderer/script_injection.h"
20 #include "extensions/renderer/user_script_injector.h"
21 #include "extensions/renderer/web_ui_injection_host.h"
22 #include "third_party/WebKit/public/web/WebDocument.h"
23 #include "third_party/WebKit/public/web/WebFrame.h"
24 #include "third_party/WebKit/public/web/WebLocalFrame.h"
25 #include "url/gurl.h"
27 namespace extensions {
29 namespace {
31 GURL GetDocumentUrlForFrame(blink::WebLocalFrame* frame) {
32 GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame);
33 if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) {
34 data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
35 data_source_url.spec());
38 return data_source_url;
41 } // namespace
43 UserScriptSet::UserScriptSet(const ExtensionSet* extensions)
44 : extensions_(extensions) {
47 UserScriptSet::~UserScriptSet() {
50 void UserScriptSet::AddObserver(Observer* observer) {
51 observers_.AddObserver(observer);
54 void UserScriptSet::RemoveObserver(Observer* observer) {
55 observers_.RemoveObserver(observer);
58 void UserScriptSet::GetActiveExtensionIds(
59 std::set<std::string>* ids) const {
60 for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
61 iter != scripts_.end();
62 ++iter) {
63 if ((*iter)->host_id().type() != HostID::EXTENSIONS)
64 continue;
65 DCHECK(!(*iter)->extension_id().empty());
66 ids->insert((*iter)->extension_id());
70 void UserScriptSet::GetInjections(
71 ScopedVector<ScriptInjection>* injections,
72 content::RenderFrame* render_frame,
73 int tab_id,
74 UserScript::RunLocation run_location) {
75 GURL document_url = GetDocumentUrlForFrame(render_frame->GetWebFrame());
76 for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
77 iter != scripts_.end();
78 ++iter) {
79 scoped_ptr<ScriptInjection> injection = GetInjectionForScript(
80 *iter,
81 render_frame,
82 tab_id,
83 run_location,
84 document_url,
85 false /* is_declarative */);
86 if (injection.get())
87 injections->push_back(injection.Pass());
91 bool UserScriptSet::UpdateUserScripts(base::SharedMemoryHandle shared_memory,
92 const std::set<HostID>& changed_hosts,
93 bool whitelisted_only) {
94 bool only_inject_incognito =
95 ExtensionsRendererClient::Get()->IsIncognitoProcess();
97 // Create the shared memory object (read only).
98 shared_memory_.reset(new base::SharedMemory(shared_memory, true));
99 if (!shared_memory_.get())
100 return false;
102 // First get the size of the memory block.
103 if (!shared_memory_->Map(sizeof(base::Pickle::Header)))
104 return false;
105 base::Pickle::Header* pickle_header =
106 reinterpret_cast<base::Pickle::Header*>(shared_memory_->memory());
108 // Now map in the rest of the block.
109 int pickle_size = sizeof(base::Pickle::Header) + pickle_header->payload_size;
110 shared_memory_->Unmap();
111 if (!shared_memory_->Map(pickle_size))
112 return false;
114 // Unpickle scripts.
115 size_t num_scripts = 0;
116 base::Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()),
117 pickle_size);
118 base::PickleIterator iter(pickle);
119 CHECK(iter.ReadSizeT(&num_scripts));
121 scripts_.clear();
122 scripts_.reserve(num_scripts);
123 for (size_t i = 0; i < num_scripts; ++i) {
124 scoped_ptr<UserScript> script(new UserScript());
125 script->Unpickle(pickle, &iter);
127 // Note that this is a pointer into shared memory. We don't own it. It gets
128 // cleared up when the last renderer or browser process drops their
129 // reference to the shared memory.
130 for (size_t j = 0; j < script->js_scripts().size(); ++j) {
131 const char* body = NULL;
132 int body_length = 0;
133 CHECK(iter.ReadData(&body, &body_length));
134 script->js_scripts()[j].set_external_content(
135 base::StringPiece(body, body_length));
137 for (size_t j = 0; j < script->css_scripts().size(); ++j) {
138 const char* body = NULL;
139 int body_length = 0;
140 CHECK(iter.ReadData(&body, &body_length));
141 script->css_scripts()[j].set_external_content(
142 base::StringPiece(body, body_length));
145 if (only_inject_incognito && !script->is_incognito_enabled())
146 continue; // This script shouldn't run in an incognito tab.
148 const Extension* extension = extensions_->GetByID(script->extension_id());
149 if (whitelisted_only &&
150 (!extension ||
151 !PermissionsData::CanExecuteScriptEverywhere(extension))) {
152 continue;
155 scripts_.push_back(script.Pass());
158 FOR_EACH_OBSERVER(Observer,
159 observers_,
160 OnUserScriptsUpdated(changed_hosts, scripts_.get()));
161 return true;
164 scoped_ptr<ScriptInjection> UserScriptSet::GetDeclarativeScriptInjection(
165 int script_id,
166 content::RenderFrame* render_frame,
167 int tab_id,
168 UserScript::RunLocation run_location,
169 const GURL& document_url) {
170 for (ScopedVector<UserScript>::const_iterator it = scripts_.begin();
171 it != scripts_.end();
172 ++it) {
173 if ((*it)->id() == script_id) {
174 return GetInjectionForScript(*it,
175 render_frame,
176 tab_id,
177 run_location,
178 document_url,
179 true /* is_declarative */);
182 return scoped_ptr<ScriptInjection>();
185 scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
186 UserScript* script,
187 content::RenderFrame* render_frame,
188 int tab_id,
189 UserScript::RunLocation run_location,
190 const GURL& document_url,
191 bool is_declarative) {
192 scoped_ptr<ScriptInjection> injection;
193 scoped_ptr<const InjectionHost> injection_host;
194 blink::WebLocalFrame* web_frame = render_frame->GetWebFrame();
196 const HostID& host_id = script->host_id();
197 if (host_id.type() == HostID::EXTENSIONS) {
198 injection_host = ExtensionInjectionHost::Create(host_id.id(), extensions_);
199 if (!injection_host)
200 return injection.Pass();
201 } else {
202 DCHECK_EQ(host_id.type(), HostID::WEBUI);
203 injection_host.reset(new WebUIInjectionHost(host_id));
206 if (web_frame->parent() && !script->match_all_frames())
207 return injection.Pass(); // Only match subframes if the script declared it.
209 GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
210 web_frame, document_url, script->match_about_blank());
212 if (!script->MatchesURL(effective_document_url))
213 return injection.Pass();
215 scoped_ptr<ScriptInjector> injector(new UserScriptInjector(script,
216 this,
217 is_declarative));
219 blink::WebFrame* top_frame = web_frame->top();
220 // It doesn't make sense to do script injection for remote frames, since they
221 // cannot host any documents or content.
222 // TODO(kalman): Fix this properly by moving all security checks into the
223 // browser. See http://crbug.com/466373 for ongoing work here.
224 if (top_frame->isWebRemoteFrame())
225 return injection.Pass();
227 if (injector->CanExecuteOnFrame(
228 injection_host.get(),
229 web_frame,
230 -1 /* Content scripts are not tab-specific. */) ==
231 PermissionsData::ACCESS_DENIED) {
232 return injection.Pass();
235 bool inject_css = !script->css_scripts().empty() &&
236 run_location == UserScript::DOCUMENT_START;
237 bool inject_js =
238 !script->js_scripts().empty() && script->run_location() == run_location;
239 if (inject_css || inject_js) {
240 injection.reset(new ScriptInjection(
241 injector.Pass(),
242 render_frame,
243 injection_host.Pass(),
244 run_location,
245 tab_id));
247 return injection.Pass();
250 } // namespace extensions