Update To 11.40.268.0
[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_set.h"
11 #include "extensions/common/permissions/permissions_data.h"
12 #include "extensions/renderer/extensions_renderer_client.h"
13 #include "extensions/renderer/script_context.h"
14 #include "extensions/renderer/script_injection.h"
15 #include "extensions/renderer/user_script_injector.h"
16 #include "third_party/WebKit/public/web/WebDocument.h"
17 #include "third_party/WebKit/public/web/WebFrame.h"
18 #include "url/gurl.h"
19
20 namespace extensions {
21
22 namespace {
23
24 GURL GetDocumentUrlForFrame(blink::WebFrame* frame) {
25   GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame);
26   if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) {
27     data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
28                            data_source_url.spec());
29   }
30
31   return data_source_url;
32 }
33
34 }  // namespace
35
36 UserScriptSet::UserScriptSet(const ExtensionSet* extensions)
37     : extensions_(extensions) {
38 }
39
40 UserScriptSet::~UserScriptSet() {
41 }
42
43 void UserScriptSet::AddObserver(Observer* observer) {
44   observers_.AddObserver(observer);
45 }
46
47 void UserScriptSet::RemoveObserver(Observer* observer) {
48   observers_.RemoveObserver(observer);
49 }
50
51 void UserScriptSet::GetActiveExtensionIds(
52     std::set<std::string>* ids) const {
53   for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
54        iter != scripts_.end();
55        ++iter) {
56     DCHECK(!(*iter)->extension_id().empty());
57     ids->insert((*iter)->extension_id());
58   }
59 }
60
61 void UserScriptSet::GetInjections(
62     ScopedVector<ScriptInjection>* injections,
63     blink::WebFrame* web_frame,
64     int tab_id,
65     UserScript::RunLocation run_location) {
66   GURL document_url = GetDocumentUrlForFrame(web_frame);
67   for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
68        iter != scripts_.end();
69        ++iter) {
70     const Extension* extension = extensions_->GetByID((*iter)->extension_id());
71     if (!extension)
72       continue;
73     scoped_ptr<ScriptInjection> injection = GetInjectionForScript(
74         *iter,
75         web_frame,
76         tab_id,
77         run_location,
78         document_url,
79         extension,
80         false /* is_declarative */);
81     if (injection.get())
82       injections->push_back(injection.release());
83   }
84 }
85
86 bool UserScriptSet::UpdateUserScripts(
87     base::SharedMemoryHandle shared_memory,
88     const std::set<std::string>& changed_extensions) {
89   bool only_inject_incognito =
90       ExtensionsRendererClient::Get()->IsIncognitoProcess();
91
92   // Create the shared memory object (read only).
93   shared_memory_.reset(new base::SharedMemory(shared_memory, true));
94   if (!shared_memory_.get())
95     return false;
96
97   // First get the size of the memory block.
98   if (!shared_memory_->Map(sizeof(Pickle::Header)))
99     return false;
100   Pickle::Header* pickle_header =
101       reinterpret_cast<Pickle::Header*>(shared_memory_->memory());
102
103   // Now map in the rest of the block.
104   int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size;
105   shared_memory_->Unmap();
106   if (!shared_memory_->Map(pickle_size))
107     return false;
108
109   // Unpickle scripts.
110   size_t num_scripts = 0;
111   Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()), pickle_size);
112   PickleIterator iter(pickle);
113   CHECK(pickle.ReadSizeT(&iter, &num_scripts));
114
115   scripts_.clear();
116   scripts_.reserve(num_scripts);
117   for (size_t i = 0; i < num_scripts; ++i) {
118     scoped_ptr<UserScript> script(new UserScript());
119     script->Unpickle(pickle, &iter);
120
121     // Note that this is a pointer into shared memory. We don't own it. It gets
122     // cleared up when the last renderer or browser process drops their
123     // reference to the shared memory.
124     for (size_t j = 0; j < script->js_scripts().size(); ++j) {
125       const char* body = NULL;
126       int body_length = 0;
127       CHECK(pickle.ReadData(&iter, &body, &body_length));
128       script->js_scripts()[j].set_external_content(
129           base::StringPiece(body, body_length));
130     }
131     for (size_t j = 0; j < script->css_scripts().size(); ++j) {
132       const char* body = NULL;
133       int body_length = 0;
134       CHECK(pickle.ReadData(&iter, &body, &body_length));
135       script->css_scripts()[j].set_external_content(
136           base::StringPiece(body, body_length));
137     }
138
139     if (only_inject_incognito && !script->is_incognito_enabled())
140       continue;  // This script shouldn't run in an incognito tab.
141
142     scripts_.push_back(script.release());
143   }
144
145   FOR_EACH_OBSERVER(Observer,
146                     observers_,
147                     OnUserScriptsUpdated(changed_extensions, scripts_.get()));
148   return true;
149 }
150
151 scoped_ptr<ScriptInjection> UserScriptSet::GetDeclarativeScriptInjection(
152     int script_id,
153     blink::WebFrame* web_frame,
154     int tab_id,
155     UserScript::RunLocation run_location,
156     const GURL& document_url,
157     const Extension* extension) {
158   for (ScopedVector<UserScript>::const_iterator it = scripts_.begin();
159        it != scripts_.end();
160        ++it) {
161     if ((*it)->id() == script_id) {
162       return GetInjectionForScript(*it,
163                                    web_frame,
164                                    tab_id,
165                                    run_location,
166                                    document_url,
167                                    extension,
168                                    true /* is_declarative */);
169     }
170   }
171   return scoped_ptr<ScriptInjection>();
172 }
173
174 // TODO(dcheng): Scripts can't be injected on a remote frame, so this function
175 // signature needs to be updated.
176 scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
177     UserScript* script,
178     blink::WebFrame* web_frame,
179     int tab_id,
180     UserScript::RunLocation run_location,
181     const GURL& document_url,
182     const Extension* extension,
183     bool is_declarative) {
184   scoped_ptr<ScriptInjection> injection;
185   if (web_frame->parent() && !script->match_all_frames())
186     return injection.Pass();  // Only match subframes if the script declared it.
187
188   GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
189       web_frame, document_url, script->match_about_blank());
190
191   if (!script->MatchesURL(effective_document_url))
192     return injection.Pass();
193
194   scoped_ptr<ScriptInjector> injector(new UserScriptInjector(script,
195                                                              this,
196                                                              is_declarative));
197   if (injector->CanExecuteOnFrame(
198           extension,
199           web_frame,
200           -1,  // Content scripts are not tab-specific.
201           web_frame->top()->document().url()) ==
202       PermissionsData::ACCESS_DENIED) {
203     return injection.Pass();
204   }
205
206   bool inject_css = !script->css_scripts().empty() &&
207                     run_location == UserScript::DOCUMENT_START;
208   bool inject_js =
209       !script->js_scripts().empty() && script->run_location() == run_location;
210   if (inject_css || inject_js) {
211     injection.reset(new ScriptInjection(
212         injector.Pass(),
213         web_frame->toWebLocalFrame(),
214         extension->id(),
215         run_location,
216         tab_id));
217   }
218   return injection.Pass();
219 }
220
221 }  // namespace extensions