8582184bbb68a0a703b40c5934e7da5065b076fb
[platform/framework/web/crosswalk.git] / src / extensions / renderer / user_script_set.cc
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.
4
5 #include "extensions/renderer/user_script_set.h"
6
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"
19 #include "url/gurl.h"
20
21 namespace extensions {
22
23 namespace {
24
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());
30   }
31
32   return data_source_url;
33 }
34
35 }  // namespace
36
37 UserScriptSet::UserScriptSet(const ExtensionSet* extensions)
38     : extensions_(extensions) {
39 }
40
41 UserScriptSet::~UserScriptSet() {
42 }
43
44 void UserScriptSet::AddObserver(Observer* observer) {
45   observers_.AddObserver(observer);
46 }
47
48 void UserScriptSet::RemoveObserver(Observer* observer) {
49   observers_.RemoveObserver(observer);
50 }
51
52 void UserScriptSet::GetActiveExtensionIds(
53     std::set<std::string>* ids) const {
54   for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
55        iter != scripts_.end();
56        ++iter) {
57     DCHECK(!(*iter)->extension_id().empty());
58     ids->insert((*iter)->extension_id());
59   }
60 }
61
62 void UserScriptSet::GetInjections(
63     ScopedVector<ScriptInjection>* injections,
64     blink::WebFrame* web_frame,
65     int tab_id,
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();
70        ++iter) {
71     const Extension* extension = extensions_->GetByID((*iter)->extension_id());
72     if (!extension)
73       continue;
74     scoped_ptr<ScriptInjection> injection = GetInjectionForScript(
75         *iter, web_frame, tab_id, run_location, document_url, extension);
76     if (injection.get())
77       injections->push_back(injection.release());
78   }
79 }
80
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();
86
87   // Create the shared memory object (read only).
88   shared_memory_.reset(new base::SharedMemory(shared_memory, true));
89   if (!shared_memory_.get())
90     return false;
91
92   // First get the size of the memory block.
93   if (!shared_memory_->Map(sizeof(Pickle::Header)))
94     return false;
95   Pickle::Header* pickle_header =
96       reinterpret_cast<Pickle::Header*>(shared_memory_->memory());
97
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))
102     return false;
103
104   // Unpickle scripts.
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));
109
110   scripts_.clear();
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);
115
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;
121       int body_length = 0;
122       CHECK(pickle.ReadData(&iter, &body, &body_length));
123       script->js_scripts()[j].set_external_content(
124           base::StringPiece(body, body_length));
125     }
126     for (size_t j = 0; j < script->css_scripts().size(); ++j) {
127       const char* body = NULL;
128       int body_length = 0;
129       CHECK(pickle.ReadData(&iter, &body, &body_length));
130       script->css_scripts()[j].set_external_content(
131           base::StringPiece(body, body_length));
132     }
133
134     if (only_inject_incognito && !script->is_incognito_enabled())
135       continue;  // This script shouldn't run in an incognito tab.
136
137     scripts_.push_back(script.release());
138   }
139
140   FOR_EACH_OBSERVER(Observer,
141                     observers_,
142                     OnUserScriptsUpdated(changed_extensions, scripts_.get()));
143   return true;
144 }
145
146 scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
147     UserScript* script,
148     blink::WebFrame* web_frame,
149     int tab_id,
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.
156
157   GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
158       web_frame, document_url, script->match_about_blank());
159
160   if (!script->MatchesURL(effective_document_url))
161     return injection.Pass();
162
163   if (extension->permissions_data()->GetContentScriptAccess(
164           extension,
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();
171   }
172
173   bool inject_css = !script->css_scripts().empty() &&
174                     run_location == UserScript::DOCUMENT_START;
175   bool inject_js =
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)),
180         web_frame,
181         extension->id(),
182         run_location,
183         tab_id));
184   }
185   return injection.Pass();
186 }
187
188 }  // namespace extensions