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 "content/public/common/url_constants.h"
8 #include "content/public/renderer/render_thread.h"
9 #include "extensions/common/extension.h"
10 #include "extensions/common/extension_messages.h"
11 #include "extensions/common/extension_set.h"
12 #include "extensions/common/permissions/permissions_data.h"
13 #include "extensions/renderer/extensions_renderer_client.h"
14 #include "extensions/renderer/script_context.h"
15 #include "extensions/renderer/script_injection.h"
16 #include "extensions/renderer/user_script_injector.h"
17 #include "third_party/WebKit/public/web/WebDocument.h"
18 #include "third_party/WebKit/public/web/WebFrame.h"
21 namespace extensions
{
25 GURL
GetDocumentUrlForFrame(blink::WebFrame
* frame
) {
26 GURL data_source_url
= ScriptContext::GetDataSourceURLForFrame(frame
);
27 if (!data_source_url
.is_empty() && frame
->isViewSourceModeEnabled()) {
28 data_source_url
= GURL(content::kViewSourceScheme
+ std::string(":") +
29 data_source_url
.spec());
32 return data_source_url
;
37 UserScriptSet::UserScriptSet(const ExtensionSet
* extensions
)
38 : extensions_(extensions
) {
41 UserScriptSet::~UserScriptSet() {
44 void UserScriptSet::AddObserver(Observer
* observer
) {
45 observers_
.AddObserver(observer
);
48 void UserScriptSet::RemoveObserver(Observer
* observer
) {
49 observers_
.RemoveObserver(observer
);
52 void UserScriptSet::GetActiveExtensionIds(
53 std::set
<std::string
>* ids
) const {
54 for (ScopedVector
<UserScript
>::const_iterator iter
= scripts_
.begin();
55 iter
!= scripts_
.end();
57 DCHECK(!(*iter
)->extension_id().empty());
58 ids
->insert((*iter
)->extension_id());
62 void UserScriptSet::GetInjections(
63 ScopedVector
<ScriptInjection
>* injections
,
64 blink::WebFrame
* web_frame
,
66 UserScript::RunLocation run_location
) {
67 GURL document_url
= GetDocumentUrlForFrame(web_frame
);
68 for (ScopedVector
<UserScript
>::const_iterator iter
= scripts_
.begin();
69 iter
!= scripts_
.end();
71 const Extension
* extension
= extensions_
->GetByID((*iter
)->extension_id());
74 scoped_ptr
<ScriptInjection
> injection
= GetInjectionForScript(
75 *iter
, web_frame
, tab_id
, run_location
, document_url
, extension
);
77 injections
->push_back(injection
.release());
81 bool UserScriptSet::UpdateUserScripts(
82 base::SharedMemoryHandle shared_memory
,
83 const std::set
<std::string
>& changed_extensions
) {
84 bool only_inject_incognito
=
85 ExtensionsRendererClient::Get()->IsIncognitoProcess();
87 // Create the shared memory object (read only).
88 shared_memory_
.reset(new base::SharedMemory(shared_memory
, true));
89 if (!shared_memory_
.get())
92 // First get the size of the memory block.
93 if (!shared_memory_
->Map(sizeof(Pickle::Header
)))
95 Pickle::Header
* pickle_header
=
96 reinterpret_cast<Pickle::Header
*>(shared_memory_
->memory());
98 // Now map in the rest of the block.
99 int pickle_size
= sizeof(Pickle::Header
) + pickle_header
->payload_size
;
100 shared_memory_
->Unmap();
101 if (!shared_memory_
->Map(pickle_size
))
105 uint64 num_scripts
= 0;
106 Pickle
pickle(reinterpret_cast<char*>(shared_memory_
->memory()), pickle_size
);
107 PickleIterator
iter(pickle
);
108 CHECK(pickle
.ReadUInt64(&iter
, &num_scripts
));
111 scripts_
.reserve(num_scripts
);
112 for (uint64 i
= 0; i
< num_scripts
; ++i
) {
113 scoped_ptr
<UserScript
> script(new UserScript());
114 script
->Unpickle(pickle
, &iter
);
116 // Note that this is a pointer into shared memory. We don't own it. It gets
117 // cleared up when the last renderer or browser process drops their
118 // reference to the shared memory.
119 for (size_t j
= 0; j
< script
->js_scripts().size(); ++j
) {
120 const char* body
= NULL
;
122 CHECK(pickle
.ReadData(&iter
, &body
, &body_length
));
123 script
->js_scripts()[j
].set_external_content(
124 base::StringPiece(body
, body_length
));
126 for (size_t j
= 0; j
< script
->css_scripts().size(); ++j
) {
127 const char* body
= NULL
;
129 CHECK(pickle
.ReadData(&iter
, &body
, &body_length
));
130 script
->css_scripts()[j
].set_external_content(
131 base::StringPiece(body
, body_length
));
134 if (only_inject_incognito
&& !script
->is_incognito_enabled())
135 continue; // This script shouldn't run in an incognito tab.
137 scripts_
.push_back(script
.release());
140 FOR_EACH_OBSERVER(Observer
,
142 OnUserScriptsUpdated(changed_extensions
, scripts_
.get()));
146 scoped_ptr
<ScriptInjection
> UserScriptSet::GetInjectionForScript(
148 blink::WebFrame
* web_frame
,
150 UserScript::RunLocation run_location
,
151 const GURL
& document_url
,
152 const Extension
* extension
) {
153 scoped_ptr
<ScriptInjection
> injection
;
154 if (web_frame
->parent() && !script
->match_all_frames())
155 return injection
.Pass(); // Only match subframes if the script declared it.
157 GURL effective_document_url
= ScriptContext::GetEffectiveDocumentURL(
158 web_frame
, document_url
, script
->match_about_blank());
160 if (!script
->MatchesURL(effective_document_url
))
161 return injection
.Pass();
163 if (extension
->permissions_data()->GetContentScriptAccess(
165 effective_document_url
,
166 web_frame
->top()->document().url(),
167 -1, // Content scripts are not tab-specific.
168 -1, // We don't have a process id in this context.
169 NULL
/* ignore error */) == PermissionsData::ACCESS_DENIED
) {
170 return injection
.Pass();
173 bool inject_css
= !script
->css_scripts().empty() &&
174 run_location
== UserScript::DOCUMENT_START
;
176 !script
->js_scripts().empty() && script
->run_location() == run_location
;
177 if (inject_css
|| inject_js
) {
178 injection
.reset(new ScriptInjection(
179 scoped_ptr
<ScriptInjector
>(new UserScriptInjector(script
, this)),
185 return injection
.Pass();
188 } // namespace extensions