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

Side by Side Diff: chrome/browser/extensions/api/declarative_content/content_action.cc

Issue 492133002: Renderer changes for wiring up shared memory with declarative injection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fix final nits Created 6 years, 3 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "chrome/browser/extensions/api/declarative_content/content_action.h" 5 #include "chrome/browser/extensions/api/declarative_content/content_action.h"
6 6
7 #include <map> 7 #include <map>
8 8
9 #include "base/lazy_instance.h" 9 #include "base/lazy_instance.h"
10 #include "base/strings/stringprintf.h" 10 #include "base/strings/stringprintf.h"
11 #include "base/values.h" 11 #include "base/values.h"
12 #include "chrome/browser/extensions/api/declarative_content/content_constants.h" 12 #include "chrome/browser/extensions/api/declarative_content/content_constants.h"
13 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" 13 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
14 #include "chrome/browser/extensions/declarative_user_script_master.h"
15 #include "chrome/browser/extensions/extension_action.h" 14 #include "chrome/browser/extensions/extension_action.h"
16 #include "chrome/browser/extensions/extension_action_manager.h" 15 #include "chrome/browser/extensions/extension_action_manager.h"
17 #include "chrome/browser/extensions/extension_tab_util.h" 16 #include "chrome/browser/extensions/extension_tab_util.h"
18 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/sessions/session_tab_helper.h"
19 #include "content/public/browser/invalidate_type.h" 19 #include "content/public/browser/invalidate_type.h"
20 #include "content/public/browser/render_view_host.h"
20 #include "content/public/browser/web_contents.h" 21 #include "content/public/browser/web_contents.h"
21 #include "extensions/browser/extension_registry.h" 22 #include "extensions/browser/extension_registry.h"
22 #include "extensions/browser/extension_system.h" 23 #include "extensions/browser/extension_system.h"
23 #include "extensions/common/extension.h" 24 #include "extensions/common/extension.h"
25 #include "extensions/common/extension_messages.h"
24 26
25 namespace extensions { 27 namespace extensions {
26 28
27 namespace keys = declarative_content_constants; 29 namespace keys = declarative_content_constants;
28 30
29 namespace { 31 namespace {
30 // Error messages. 32 // Error messages.
31 const char kInvalidInstanceTypeError[] = 33 const char kInvalidInstanceTypeError[] =
32 "An action has an invalid instanceType: %s"; 34 "An action has an invalid instanceType: %s";
33 const char kNoPageAction[] = 35 const char kNoPageAction[] =
34 "Can't use declarativeContent.ShowPageAction without a page action"; 36 "Can't use declarativeContent.ShowPageAction without a page action";
35 const char kMissingParameter[] = "Missing parameter is required: %s"; 37 const char kMissingParameter[] = "Missing parameter is required: %s";
36 38
37 #define INPUT_FORMAT_VALIDATE(test) do { \ 39 #define INPUT_FORMAT_VALIDATE(test) do { \
38 if (!(test)) { \ 40 if (!(test)) { \
39 *bad_message = true; \ 41 *bad_message = true; \
40 return scoped_refptr<ContentAction>(NULL); \ 42 return false; \
41 } \ 43 } \
42 } while (0) 44 } while (0)
43 45
44 // 46 //
45 // The following are concrete actions. 47 // The following are concrete actions.
46 // 48 //
47 49
48 // Action that instructs to show an extension's page action. 50 // Action that instructs to show an extension's page action.
49 class ShowPageAction : public ContentAction { 51 class ShowPageAction : public ContentAction {
50 public: 52 public:
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); 99 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING);
98 if (!extension) 100 if (!extension)
99 return NULL; 101 return NULL;
100 return ExtensionActionManager::Get(profile)->GetPageAction(*extension); 102 return ExtensionActionManager::Get(profile)->GetPageAction(*extension);
101 } 103 }
102 virtual ~ShowPageAction() {} 104 virtual ~ShowPageAction() {}
103 105
104 DISALLOW_COPY_AND_ASSIGN(ShowPageAction); 106 DISALLOW_COPY_AND_ASSIGN(ShowPageAction);
105 }; 107 };
106 108
107 // Action that injects a content script.
108 class RequestContentScript : public ContentAction {
109 public:
110 RequestContentScript(content::BrowserContext* browser_context,
111 const Extension* extension,
112 const std::vector<std::string>& css_file_names,
113 const std::vector<std::string>& js_file_names,
114 bool all_frames,
115 bool match_about_blank);
116
117 static scoped_refptr<ContentAction> Create(
118 content::BrowserContext* browser_context,
119 const Extension* extension,
120 const base::DictionaryValue* dict,
121 std::string* error,
122 bool* bad_message);
123
124 // Implementation of ContentAction:
125 virtual Type GetType() const OVERRIDE {
126 return ACTION_REQUEST_CONTENT_SCRIPT;
127 }
128
129 virtual void Apply(const std::string& extension_id,
130 const base::Time& extension_install_time,
131 ApplyInfo* apply_info) const OVERRIDE {
132 InstructRenderProcessToInject(apply_info->tab, extension_id);
133 }
134
135 virtual void Reapply(const std::string& extension_id,
136 const base::Time& extension_install_time,
137 ApplyInfo* apply_info) const OVERRIDE {
138 InstructRenderProcessToInject(apply_info->tab, extension_id);
139 }
140
141 virtual void Revert(const std::string& extension_id,
142 const base::Time& extension_install_time,
143 ApplyInfo* apply_info) const OVERRIDE {
144 }
145
146 private:
147 virtual ~RequestContentScript() {
148 DCHECK(master_);
149 master_->RemoveScript(script_);
150 }
151
152 void InstructRenderProcessToInject(content::WebContents* contents,
153 const std::string& extension_id) const;
154
155 UserScript script_;
156 DeclarativeUserScriptMaster* master_;
157
158 DISALLOW_COPY_AND_ASSIGN(RequestContentScript);
159 };
160
161 // Helper for getting JS collections into C++. 109 // Helper for getting JS collections into C++.
162 static bool AppendJSStringsToCPPStrings(const base::ListValue& append_strings, 110 static bool AppendJSStringsToCPPStrings(const base::ListValue& append_strings,
163 std::vector<std::string>* append_to) { 111 std::vector<std::string>* append_to) {
164 for (base::ListValue::const_iterator it = append_strings.begin(); 112 for (base::ListValue::const_iterator it = append_strings.begin();
165 it != append_strings.end(); 113 it != append_strings.end();
166 ++it) { 114 ++it) {
167 std::string value; 115 std::string value;
168 if ((*it)->GetAsString(&value)) { 116 if ((*it)->GetAsString(&value)) {
169 append_to->push_back(value); 117 append_to->push_back(value);
170 } else { 118 } else {
171 return false; 119 return false;
172 } 120 }
173 } 121 }
174 122
175 return true; 123 return true;
176 } 124 }
177 125
126 struct ContentActionFactory {
127 // Factory methods for ContentAction instances. |extension| is the extension
128 // for which the action is being created. |dict| contains the json dictionary
129 // that describes the action. |error| is used to return error messages in case
130 // the extension passed an action that was syntactically correct but
131 // semantically incorrect. |bad_message| is set to true in case |dict| does
132 // not confirm to the validated JSON specification.
133 typedef scoped_refptr<ContentAction>(*FactoryMethod)(
134 content::BrowserContext* /* browser_context */,
135 const Extension* /* extension */,
136 const base::DictionaryValue* /* dict */,
137 std::string* /* error */,
138 bool* /* bad_message */);
139 // Maps the name of a declarativeContent action type to the factory
140 // function creating it.
141 std::map<std::string, FactoryMethod> factory_methods;
142
143 ContentActionFactory() {
144 factory_methods[keys::kShowPageAction] =
145 &ShowPageAction::Create;
146 factory_methods[keys::kRequestContentScript] =
147 &RequestContentScript::Create;
148 }
149 };
150
151 base::LazyInstance<ContentActionFactory>::Leaky
152 g_content_action_factory = LAZY_INSTANCE_INITIALIZER;
153
154 } // namespace
155
156 //
157 // RequestContentScript
158 //
159
160 RequestContentScript::ScriptData::ScriptData() {}
161 RequestContentScript::ScriptData::~ScriptData() {}
162
178 // static 163 // static
179 scoped_refptr<ContentAction> RequestContentScript::Create( 164 scoped_refptr<ContentAction> RequestContentScript::Create(
180 content::BrowserContext* browser_context, 165 content::BrowserContext* browser_context,
181 const Extension* extension, 166 const Extension* extension,
182 const base::DictionaryValue* dict, 167 const base::DictionaryValue* dict,
183 std::string* error, 168 std::string* error,
184 bool* bad_message) { 169 bool* bad_message) {
185 std::vector<std::string> css_file_names; 170 ScriptData script_data;
186 std::vector<std::string> js_file_names; 171 if (!InitScriptData(dict, error, bad_message, &script_data))
187 bool all_frames = false; 172 return scoped_refptr<ContentAction>();
188 bool match_about_blank = false; 173
189 const base::ListValue* list_value; 174 return scoped_refptr<ContentAction>(new RequestContentScript(
175 browser_context,
176 extension,
177 script_data));
178 }
179
180 // static
181 scoped_refptr<ContentAction> RequestContentScript::CreateForTest(
182 DeclarativeUserScriptMaster* master,
183 const Extension* extension,
184 const base::Value& json_action,
185 std::string* error,
186 bool* bad_message) {
187 // Simulate ContentAction-level initialization. Check that instance type is
188 // RequestContentScript.
189 ContentAction::ResetErrorData(error, bad_message);
190 const base::DictionaryValue* action_dict = NULL;
191 std::string instance_type;
192 if (!ContentAction::Validate(
193 json_action,
194 error,
195 bad_message,
196 &action_dict,
197 &instance_type) ||
198 instance_type != std::string(keys::kRequestContentScript))
199 return scoped_refptr<ContentAction>();
200
201 // Normal RequestContentScript data initialization.
202 ScriptData script_data;
203 if (!InitScriptData(action_dict, error, bad_message, &script_data))
204 return scoped_refptr<ContentAction>();
205
206 // Inject provided DeclarativeUserScriptMaster, rather than looking it up
207 // using a BrowserContext.
208 return scoped_refptr<ContentAction>(new RequestContentScript(
209 master,
210 extension,
211 script_data));
212 }
213
214 // static
215 bool RequestContentScript::InitScriptData(const base::DictionaryValue* dict,
216 std::string* error,
217 bool* bad_message,
218 ScriptData* script_data) {
219 const base::ListValue* list_value = NULL;
190 220
191 if (!dict->HasKey(keys::kCss) && !dict->HasKey(keys::kJs)) { 221 if (!dict->HasKey(keys::kCss) && !dict->HasKey(keys::kJs)) {
192 *error = base::StringPrintf(kMissingParameter, "css or js"); 222 *error = base::StringPrintf(kMissingParameter, "css or js");
193 return scoped_refptr<ContentAction>(); 223 return false;
194 } 224 }
195 if (dict->HasKey(keys::kCss)) { 225 if (dict->HasKey(keys::kCss)) {
196 INPUT_FORMAT_VALIDATE(dict->GetList(keys::kCss, &list_value)); 226 INPUT_FORMAT_VALIDATE(dict->GetList(keys::kCss, &list_value));
197 INPUT_FORMAT_VALIDATE( 227 INPUT_FORMAT_VALIDATE(
198 AppendJSStringsToCPPStrings(*list_value, &css_file_names)); 228 AppendJSStringsToCPPStrings(*list_value, &script_data->css_file_names));
199 } 229 }
200 if (dict->HasKey(keys::kJs)) { 230 if (dict->HasKey(keys::kJs)) {
201 INPUT_FORMAT_VALIDATE(dict->GetList(keys::kJs, &list_value)); 231 INPUT_FORMAT_VALIDATE(dict->GetList(keys::kJs, &list_value));
202 INPUT_FORMAT_VALIDATE( 232 INPUT_FORMAT_VALIDATE(
203 AppendJSStringsToCPPStrings(*list_value, &js_file_names)); 233 AppendJSStringsToCPPStrings(*list_value, &script_data->js_file_names));
204 } 234 }
205 if (dict->HasKey(keys::kAllFrames)) { 235 if (dict->HasKey(keys::kAllFrames)) {
206 INPUT_FORMAT_VALIDATE(dict->GetBoolean(keys::kAllFrames, &all_frames)); 236 INPUT_FORMAT_VALIDATE(
237 dict->GetBoolean(keys::kAllFrames, &script_data->all_frames));
207 } 238 }
208 if (dict->HasKey(keys::kMatchAboutBlank)) { 239 if (dict->HasKey(keys::kMatchAboutBlank)) {
209 INPUT_FORMAT_VALIDATE( 240 INPUT_FORMAT_VALIDATE(
210 dict->GetBoolean(keys::kMatchAboutBlank, &match_about_blank)); 241 dict->GetBoolean(
242 keys::kMatchAboutBlank,
243 &script_data->match_about_blank));
211 } 244 }
212 245
213 return scoped_refptr<ContentAction>(new RequestContentScript( 246 return true;
214 browser_context,
215 extension,
216 css_file_names,
217 js_file_names,
218 all_frames,
219 match_about_blank));
220 } 247 }
221 248
222 RequestContentScript::RequestContentScript( 249 RequestContentScript::RequestContentScript(
223 content::BrowserContext* browser_context, 250 content::BrowserContext* browser_context,
224 const Extension* extension, 251 const Extension* extension,
225 const std::vector<std::string>& css_file_names, 252 const ScriptData& script_data) {
226 const std::vector<std::string>& js_file_names, 253 InitScript(extension, script_data);
227 bool all_frames, 254
228 bool match_about_blank) { 255 master_ =
256 ExtensionSystem::Get(browser_context)->
257 GetDeclarativeUserScriptMasterByExtension(extension->id());
258 AddScript();
259 }
260
261 RequestContentScript::RequestContentScript(
262 DeclarativeUserScriptMaster* master,
263 const Extension* extension,
264 const ScriptData& script_data) {
265 InitScript(extension, script_data);
266
267 master_ = master;
268 AddScript();
269 }
270
271 RequestContentScript::~RequestContentScript() {
272 DCHECK(master_);
273 master_->RemoveScript(script_);
274 }
275
276 void RequestContentScript::InitScript(const Extension* extension,
277 const ScriptData& script_data) {
229 script_.set_id(UserScript::GenerateUserScriptID()); 278 script_.set_id(UserScript::GenerateUserScriptID());
230 script_.set_extension_id(extension->id()); 279 script_.set_extension_id(extension->id());
231 script_.set_run_location(UserScript::BROWSER_DRIVEN); 280 script_.set_run_location(UserScript::BROWSER_DRIVEN);
232 script_.set_match_all_frames(all_frames); 281 script_.set_match_all_frames(script_data.all_frames);
233 script_.set_match_about_blank(match_about_blank); 282 script_.set_match_about_blank(script_data.match_about_blank);
234 for (std::vector<std::string>::const_iterator it = css_file_names.begin(); 283 for (std::vector<std::string>::const_iterator it =
235 it != css_file_names.end(); ++it) { 284 script_data.css_file_names.begin();
285 it != script_data.css_file_names.end(); ++it) {
236 GURL url = extension->GetResourceURL(*it); 286 GURL url = extension->GetResourceURL(*it);
237 ExtensionResource resource = extension->GetResource(*it); 287 ExtensionResource resource = extension->GetResource(*it);
238 script_.css_scripts().push_back(UserScript::File( 288 script_.css_scripts().push_back(UserScript::File(
239 resource.extension_root(), resource.relative_path(), url)); 289 resource.extension_root(), resource.relative_path(), url));
240 } 290 }
241 for (std::vector<std::string>::const_iterator it = js_file_names.begin(); 291 for (std::vector<std::string>::const_iterator it =
242 it != js_file_names.end(); ++it) { 292 script_data.js_file_names.begin();
293 it != script_data.js_file_names.end(); ++it) {
243 GURL url = extension->GetResourceURL(*it); 294 GURL url = extension->GetResourceURL(*it);
244 ExtensionResource resource = extension->GetResource(*it); 295 ExtensionResource resource = extension->GetResource(*it);
245 script_.js_scripts().push_back(UserScript::File( 296 script_.js_scripts().push_back(UserScript::File(
246 resource.extension_root(), resource.relative_path(), url)); 297 resource.extension_root(), resource.relative_path(), url));
247 } 298 }
299 }
248 300
249 master_ = 301 ContentAction::Type RequestContentScript::GetType() const {
250 ExtensionSystem::Get(browser_context)-> 302 return ACTION_REQUEST_CONTENT_SCRIPT;
251 GetDeclarativeUserScriptMasterByExtension(extension->id());
252 DCHECK(master_);
253 master_->AddScript(script_);
254 } 303 }
255 304
305 void RequestContentScript::Apply(const std::string& extension_id,
306 const base::Time& extension_install_time,
307 ApplyInfo* apply_info) const {
308 InstructRenderProcessToInject(apply_info->tab, extension_id);
309 }
310
311 void RequestContentScript::Reapply(const std::string& extension_id,
312 const base::Time& extension_install_time,
313 ApplyInfo* apply_info) const {
314 InstructRenderProcessToInject(apply_info->tab, extension_id);
315 }
316
317 void RequestContentScript::Revert(const std::string& extension_id,
318 const base::Time& extension_install_time,
319 ApplyInfo* apply_info) const {}
320
256 void RequestContentScript::InstructRenderProcessToInject( 321 void RequestContentScript::InstructRenderProcessToInject(
257 content::WebContents* contents, 322 content::WebContents* contents,
258 const std::string& extension_id) const { 323 const std::string& extension_id) const {
259 // TODO(markdittmer): Send ExtensionMsg to renderer. 324 content::RenderViewHost* render_view_host = contents->GetRenderViewHost();
325 render_view_host->Send(new ExtensionMsg_ExecuteDeclarativeScript(
326 render_view_host->GetRoutingID(),
327 SessionTabHelper::IdForTab(contents),
328 extension_id,
329 script_.id(),
330 contents->GetLastCommittedURL()));
260 } 331 }
261 332
262 struct ContentActionFactory {
263 // Factory methods for ContentAction instances. |extension| is the extension
264 // for which the action is being created. |dict| contains the json dictionary
265 // that describes the action. |error| is used to return error messages in case
266 // the extension passed an action that was syntactically correct but
267 // semantically incorrect. |bad_message| is set to true in case |dict| does
268 // not confirm to the validated JSON specification.
269 typedef scoped_refptr<ContentAction>(*FactoryMethod)(
270 content::BrowserContext* /* browser_context */,
271 const Extension* /* extension */,
272 const base::DictionaryValue* /* dict */,
273 std::string* /* error */,
274 bool* /* bad_message */);
275 // Maps the name of a declarativeContent action type to the factory
276 // function creating it.
277 std::map<std::string, FactoryMethod> factory_methods;
278
279 ContentActionFactory() {
280 factory_methods[keys::kShowPageAction] =
281 &ShowPageAction::Create;
282 factory_methods[keys::kRequestContentScript] =
283 &RequestContentScript::Create;
284 }
285 };
286
287 base::LazyInstance<ContentActionFactory>::Leaky
288 g_content_action_factory = LAZY_INSTANCE_INITIALIZER;
289
290 } // namespace
291
292 // 333 //
293 // ContentAction 334 // ContentAction
294 // 335 //
295 336
296 ContentAction::ContentAction() {} 337 ContentAction::ContentAction() {}
297 338
298 ContentAction::~ContentAction() {} 339 ContentAction::~ContentAction() {}
299 340
300 // static 341 // static
301 scoped_refptr<ContentAction> ContentAction::Create( 342 scoped_refptr<ContentAction> ContentAction::Create(
302 content::BrowserContext* browser_context, 343 content::BrowserContext* browser_context,
303 const Extension* extension, 344 const Extension* extension,
304 const base::Value& json_action, 345 const base::Value& json_action,
305 std::string* error, 346 std::string* error,
306 bool* bad_message) { 347 bool* bad_message) {
307 *error = ""; 348 ResetErrorData(error, bad_message);
308 *bad_message = false;
309
310 const base::DictionaryValue* action_dict = NULL; 349 const base::DictionaryValue* action_dict = NULL;
311 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict));
312
313 std::string instance_type; 350 std::string instance_type;
314 INPUT_FORMAT_VALIDATE( 351 if (!Validate(json_action, error, bad_message, &action_dict, &instance_type))
315 action_dict->GetString(keys::kInstanceType, &instance_type)); 352 return scoped_refptr<ContentAction>();
316 353
317 ContentActionFactory& factory = g_content_action_factory.Get(); 354 ContentActionFactory& factory = g_content_action_factory.Get();
318 std::map<std::string, ContentActionFactory::FactoryMethod>::iterator 355 std::map<std::string, ContentActionFactory::FactoryMethod>::iterator
319 factory_method_iter = factory.factory_methods.find(instance_type); 356 factory_method_iter = factory.factory_methods.find(instance_type);
320 if (factory_method_iter != factory.factory_methods.end()) 357 if (factory_method_iter != factory.factory_methods.end())
321 return (*factory_method_iter->second)( 358 return (*factory_method_iter->second)(
322 browser_context, extension, action_dict, error, bad_message); 359 browser_context, extension, action_dict, error, bad_message);
323 360
324 *error = base::StringPrintf(kInvalidInstanceTypeError, instance_type.c_str()); 361 *error = base::StringPrintf(kInvalidInstanceTypeError, instance_type.c_str());
325 return scoped_refptr<ContentAction>(); 362 return scoped_refptr<ContentAction>();
326 } 363 }
327 364
365 bool ContentAction::Validate(const base::Value& json_action,
366 std::string* error,
367 bool* bad_message,
368 const base::DictionaryValue** action_dict,
369 std::string* instance_type) {
370 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(action_dict));
371 INPUT_FORMAT_VALIDATE(
372 (*action_dict)->GetString(keys::kInstanceType, instance_type));
373 return true;
374 }
375
328 } // namespace extensions 376 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698