OLD | NEW |
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" |
14 #include "chrome/browser/extensions/extension_action.h" | 15 #include "chrome/browser/extensions/extension_action.h" |
15 #include "chrome/browser/extensions/extension_action_manager.h" | 16 #include "chrome/browser/extensions/extension_action_manager.h" |
16 #include "chrome/browser/extensions/extension_tab_util.h" | 17 #include "chrome/browser/extensions/extension_tab_util.h" |
17 #include "chrome/browser/profiles/profile.h" | 18 #include "chrome/browser/profiles/profile.h" |
| 19 #include "chrome/browser/sessions/session_tab_helper.h" |
| 20 #include "chrome/common/extensions/manifest_handlers/content_scripts_handler.h" |
18 #include "content/public/browser/invalidate_type.h" | 21 #include "content/public/browser/invalidate_type.h" |
| 22 #include "content/public/browser/render_process_host.h" |
| 23 #include "content/public/browser/render_view_host.h" |
19 #include "content/public/browser/web_contents.h" | 24 #include "content/public/browser/web_contents.h" |
20 #include "extensions/browser/extension_registry.h" | 25 #include "extensions/browser/extension_registry.h" |
| 26 #include "extensions/browser/extension_system.h" |
21 #include "extensions/common/extension.h" | 27 #include "extensions/common/extension.h" |
| 28 #include "extensions/common/extension_messages.h" |
22 | 29 |
23 namespace extensions { | 30 namespace extensions { |
24 | 31 |
25 namespace keys = declarative_content_constants; | 32 namespace keys = declarative_content_constants; |
26 | 33 |
27 namespace { | 34 namespace { |
28 // Error messages. | 35 // Error messages. |
29 const char kInvalidInstanceTypeError[] = | 36 const char kInvalidInstanceTypeError[] = |
30 "An action has an invalid instanceType: %s"; | 37 "An action has an invalid instanceType: %s"; |
31 const char kNoPageAction[] = | 38 const char kNoPageAction[] = |
32 "Can't use declarativeContent.ShowPageAction without a page action"; | 39 "Can't use declarativeContent.ShowPageAction without a page action"; |
33 const char kMissingParameter[] = "Missing parameter is required: %s"; | 40 const char kMissingParameter[] = "Missing parameter is required: %s"; |
34 | 41 |
35 #define INPUT_FORMAT_VALIDATE(test) do { \ | 42 #define INPUT_FORMAT_VALIDATE(test) do { \ |
36 if (!(test)) { \ | 43 if (!(test)) { \ |
37 *bad_message = true; \ | 44 *bad_message = true; \ |
38 return scoped_refptr<ContentAction>(NULL); \ | 45 return scoped_refptr<ContentAction>(NULL); \ |
39 } \ | 46 } \ |
40 } while (0) | 47 } while (0) |
41 | 48 |
42 // | 49 // |
43 // The following are concrete actions. | 50 // The following are concrete actions. |
44 // | 51 // |
45 | 52 |
46 // Action that instructs to show an extension's page action. | 53 // Action that instructs to show an extension's page action. |
47 class ShowPageAction : public ContentAction { | 54 class ShowPageAction : public ContentAction { |
48 public: | 55 public: |
49 ShowPageAction() {} | 56 ShowPageAction() {} |
50 | 57 |
51 static scoped_refptr<ContentAction> Create(const Extension* extension, | 58 static scoped_refptr<ContentAction> Create(Profile* profile, |
| 59 const Extension* extension, |
52 const base::DictionaryValue* dict, | 60 const base::DictionaryValue* dict, |
53 std::string* error, | 61 std::string* error, |
54 bool* bad_message) { | 62 bool* bad_message) { |
55 // We can't show a page action if the extension doesn't have one. | 63 // We can't show a page action if the extension doesn't have one. |
56 if (ActionInfo::GetPageActionInfo(extension) == NULL) { | 64 if (ActionInfo::GetPageActionInfo(extension) == NULL) { |
57 *error = kNoPageAction; | 65 *error = kNoPageAction; |
58 return scoped_refptr<ContentAction>(); | 66 return scoped_refptr<ContentAction>(); |
59 } | 67 } |
60 return scoped_refptr<ContentAction>(new ShowPageAction); | 68 return scoped_refptr<ContentAction>(new ShowPageAction); |
61 } | 69 } |
(...skipping 11 matching lines...) Expand all Loading... |
73 virtual void Revert(const std::string& extension_id, | 81 virtual void Revert(const std::string& extension_id, |
74 const base::Time& extension_install_time, | 82 const base::Time& extension_install_time, |
75 ApplyInfo* apply_info) const OVERRIDE { | 83 ApplyInfo* apply_info) const OVERRIDE { |
76 if (ExtensionAction* action = | 84 if (ExtensionAction* action = |
77 GetPageAction(apply_info->profile, extension_id)) { | 85 GetPageAction(apply_info->profile, extension_id)) { |
78 action->UndoDeclarativeShow(ExtensionTabUtil::GetTabId(apply_info->tab)); | 86 action->UndoDeclarativeShow(ExtensionTabUtil::GetTabId(apply_info->tab)); |
79 ExtensionActionAPI::Get(apply_info->profile)->NotifyChange( | 87 ExtensionActionAPI::Get(apply_info->profile)->NotifyChange( |
80 action, apply_info->tab); | 88 action, apply_info->tab); |
81 } | 89 } |
82 } | 90 } |
| 91 virtual void Reapply(const std::string& extension_id, |
| 92 const base::Time& extension_install_time, |
| 93 ApplyInfo* apply_info) const OVERRIDE { |
| 94 } |
83 | 95 |
84 private: | 96 private: |
85 static ExtensionAction* GetPageAction(Profile* profile, | 97 static ExtensionAction* GetPageAction(Profile* profile, |
86 const std::string& extension_id) { | 98 const std::string& extension_id) { |
87 const Extension* extension = | 99 const Extension* extension = |
88 ExtensionRegistry::Get(profile) | 100 ExtensionRegistry::Get(profile) |
89 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); | 101 ->GetExtensionById(extension_id, ExtensionRegistry::EVERYTHING); |
90 if (!extension) | 102 if (!extension) |
91 return NULL; | 103 return NULL; |
92 return ExtensionActionManager::Get(profile)->GetPageAction(*extension); | 104 return ExtensionActionManager::Get(profile)->GetPageAction(*extension); |
93 } | 105 } |
94 virtual ~ShowPageAction() {} | 106 virtual ~ShowPageAction() {} |
95 | 107 |
96 DISALLOW_COPY_AND_ASSIGN(ShowPageAction); | 108 DISALLOW_COPY_AND_ASSIGN(ShowPageAction); |
97 }; | 109 }; |
98 | 110 |
99 // Action that injects a content script. | 111 // Action that injects a content script. |
100 class RequestContentScript : public ContentAction { | 112 class RequestContentScript : public ContentAction { |
101 public: | 113 public: |
102 RequestContentScript(const std::vector<std::string>& css_file_names, | 114 static scoped_refptr<ContentAction> Create(Profile* profile, |
103 const std::vector<std::string>& js_file_names, | 115 const Extension* extension, |
104 bool all_frames, | |
105 bool match_about_blank) | |
106 : css_file_names_(css_file_names), | |
107 js_file_names_(js_file_names), | |
108 all_frames_(all_frames), | |
109 match_about_blank_(match_about_blank) {} | |
110 | |
111 static scoped_refptr<ContentAction> Create(const Extension* extension, | |
112 const base::DictionaryValue* dict, | 116 const base::DictionaryValue* dict, |
113 std::string* error, | 117 std::string* error, |
114 bool* bad_message); | 118 bool* bad_message); |
115 | 119 |
| 120 RequestContentScript(Profile* profile, |
| 121 const Extension* extension, |
| 122 const std::vector<std::string>& css_file_names, |
| 123 const std::vector<std::string>& js_file_names, |
| 124 bool all_frames, |
| 125 bool match_about_blank); |
| 126 |
116 // Implementation of ContentAction: | 127 // Implementation of ContentAction: |
117 virtual Type GetType() const OVERRIDE { | 128 virtual Type GetType() const OVERRIDE { |
118 return ACTION_REQUEST_CONTENT_SCRIPT; | 129 return ACTION_REQUEST_CONTENT_SCRIPT; |
119 } | 130 } |
120 | 131 |
121 virtual void Apply(const std::string& extension_id, | 132 virtual void Apply(const std::string& extension_id, |
122 const base::Time& extension_install_time, | 133 const base::Time& extension_install_time, |
123 ApplyInfo* apply_info) const OVERRIDE { | 134 ApplyInfo* apply_info) const OVERRIDE { |
124 // TODO(markdittmer): Invoke UserScriptMaster declarative script loader: | 135 InstructRenderProcessToInject(apply_info->tab, extension_id); |
125 // load new user script. | |
126 } | 136 } |
127 | 137 |
128 virtual void Revert(const std::string& extension_id, | 138 virtual void Revert(const std::string& extension_id, |
129 const base::Time& extension_install_time, | 139 const base::Time& extension_install_time, |
130 ApplyInfo* apply_info) const OVERRIDE { | 140 ApplyInfo* apply_info) const OVERRIDE { |
131 // TODO(markdittmer): Invoke UserScriptMaster declarative script loader: | 141 } |
132 // do not load user script if Apply() runs again on the same page. | 142 virtual void Reapply(const std::string& extension_id, |
| 143 const base::Time& extension_install_time, |
| 144 ApplyInfo* apply_info) const OVERRIDE { |
| 145 InstructRenderProcessToInject(apply_info->tab, extension_id); |
133 } | 146 } |
134 | 147 |
135 private: | 148 private: |
136 virtual ~RequestContentScript() {} | 149 virtual ~RequestContentScript() { |
| 150 DCHECK(master_); |
| 151 master_->RemoveScript(script_); |
| 152 } |
137 | 153 |
138 std::vector<std::string> css_file_names_; | 154 void InstructRenderProcessToInject(content::WebContents* contents, |
139 std::vector<std::string> js_file_names_; | 155 const std::string& extension_id) const; |
140 bool all_frames_; | 156 |
141 bool match_about_blank_; | 157 UserScript script_; |
| 158 DeclarativeUserScriptMaster* master_; |
142 | 159 |
143 DISALLOW_COPY_AND_ASSIGN(RequestContentScript); | 160 DISALLOW_COPY_AND_ASSIGN(RequestContentScript); |
144 }; | 161 }; |
145 | 162 |
146 // Helper for getting JS collections into C++. | 163 // Helper for getting JS collections into C++. |
147 static bool AppendJSStringsToCPPStrings(const base::ListValue& append_strings, | 164 static bool AppendJSStringsToCPPStrings(const base::ListValue& append_strings, |
148 std::vector<std::string>* append_to) { | 165 std::vector<std::string>* append_to) { |
149 for (base::ListValue::const_iterator it = append_strings.begin(); | 166 for (base::ListValue::const_iterator it = append_strings.begin(); |
150 it != append_strings.end(); | 167 it != append_strings.end(); |
151 ++it) { | 168 ++it) { |
152 std::string value; | 169 std::string value; |
153 if ((*it)->GetAsString(&value)) { | 170 if ((*it)->GetAsString(&value)) { |
154 append_to->push_back(value); | 171 append_to->push_back(value); |
155 } else { | 172 } else { |
156 return false; | 173 return false; |
157 } | 174 } |
158 } | 175 } |
159 | 176 |
160 return true; | 177 return true; |
161 } | 178 } |
162 | 179 |
163 // static | 180 // static |
164 scoped_refptr<ContentAction> RequestContentScript::Create( | 181 scoped_refptr<ContentAction> RequestContentScript::Create( |
| 182 Profile* profile, |
165 const Extension* extension, | 183 const Extension* extension, |
166 const base::DictionaryValue* dict, | 184 const base::DictionaryValue* dict, |
167 std::string* error, | 185 std::string* error, |
168 bool* bad_message) { | 186 bool* bad_message) { |
169 std::vector<std::string> css_file_names; | 187 std::vector<std::string> css_file_names; |
170 std::vector<std::string> js_file_names; | 188 std::vector<std::string> js_file_names; |
171 bool all_frames = false; | 189 bool all_frames = false; |
172 bool match_about_blank = false; | 190 bool match_about_blank = false; |
173 const base::ListValue* list_value; | 191 const base::ListValue* list_value; |
174 | 192 |
(...skipping 13 matching lines...) Expand all Loading... |
188 } | 206 } |
189 if (dict->HasKey(keys::kAllFrames)) { | 207 if (dict->HasKey(keys::kAllFrames)) { |
190 INPUT_FORMAT_VALIDATE(dict->GetBoolean(keys::kAllFrames, &all_frames)); | 208 INPUT_FORMAT_VALIDATE(dict->GetBoolean(keys::kAllFrames, &all_frames)); |
191 } | 209 } |
192 if (dict->HasKey(keys::kMatchAboutBlank)) { | 210 if (dict->HasKey(keys::kMatchAboutBlank)) { |
193 INPUT_FORMAT_VALIDATE( | 211 INPUT_FORMAT_VALIDATE( |
194 dict->GetBoolean(keys::kMatchAboutBlank, &match_about_blank)); | 212 dict->GetBoolean(keys::kMatchAboutBlank, &match_about_blank)); |
195 } | 213 } |
196 | 214 |
197 return scoped_refptr<ContentAction>(new RequestContentScript( | 215 return scoped_refptr<ContentAction>(new RequestContentScript( |
198 css_file_names, js_file_names, all_frames, match_about_blank)); | 216 profile, |
| 217 extension, |
| 218 css_file_names, |
| 219 js_file_names, |
| 220 all_frames, |
| 221 match_about_blank)); |
| 222 } |
| 223 |
| 224 RequestContentScript::RequestContentScript( |
| 225 Profile* profile, |
| 226 const Extension* extension, |
| 227 const std::vector<std::string>& css_file_names, |
| 228 const std::vector<std::string>& js_file_names, |
| 229 bool all_frames, |
| 230 bool match_about_blank) { |
| 231 script_.set_id(ContentScriptsHandler::GetNextUserScriptID()); |
| 232 script_.set_extension_id(extension->id()); |
| 233 script_.set_run_location(UserScript::BROWSER_DRIVEN); |
| 234 script_.set_match_all_frames(all_frames); |
| 235 script_.set_match_about_blank(match_about_blank); |
| 236 for (std::vector<std::string>::const_iterator it = css_file_names.begin(); |
| 237 it != css_file_names.end(); ++it) { |
| 238 GURL url = extension->GetResourceURL(*it); |
| 239 ExtensionResource resource = extension->GetResource(*it); |
| 240 script_.css_scripts().push_back(UserScript::File( |
| 241 resource.extension_root(), resource.relative_path(), url)); |
| 242 } |
| 243 for (std::vector<std::string>::const_iterator it = js_file_names.begin(); |
| 244 it != js_file_names.end(); ++it) { |
| 245 GURL url = extension->GetResourceURL(*it); |
| 246 ExtensionResource resource = extension->GetResource(*it); |
| 247 script_.js_scripts().push_back(UserScript::File( |
| 248 resource.extension_root(), resource.relative_path(), url)); |
| 249 } |
| 250 |
| 251 master_ = |
| 252 ExtensionSystem::Get(profile)->GetDeclarativeUserScriptMasterByExtension( |
| 253 extension->id()); |
| 254 DCHECK(master_); |
| 255 master_->AddScript(script_); |
| 256 } |
| 257 |
| 258 void RequestContentScript::InstructRenderProcessToInject( |
| 259 content::WebContents* contents, |
| 260 const std::string& extension_id) const { |
| 261 // TODO(markdittmer): Send ExtensionMsg to renderer. |
199 } | 262 } |
200 | 263 |
201 struct ContentActionFactory { | 264 struct ContentActionFactory { |
202 // Factory methods for ContentAction instances. |extension| is the extension | 265 // Factory methods for ContentAction instances. |extension| is the extension |
203 // for which the action is being created. |dict| contains the json dictionary | 266 // for which the action is being created. |dict| contains the json dictionary |
204 // that describes the action. |error| is used to return error messages in case | 267 // that describes the action. |error| is used to return error messages in case |
205 // the extension passed an action that was syntactically correct but | 268 // the extension passed an action that was syntactically correct but |
206 // semantically incorrect. |bad_message| is set to true in case |dict| does | 269 // semantically incorrect. |bad_message| is set to true in case |dict| does |
207 // not confirm to the validated JSON specification. | 270 // not confirm to the validated JSON specification. |
208 typedef scoped_refptr<ContentAction>(*FactoryMethod)( | 271 typedef scoped_refptr<ContentAction>(*FactoryMethod)( |
| 272 Profile* /* profile */, |
209 const Extension* /* extension */, | 273 const Extension* /* extension */, |
210 const base::DictionaryValue* /* dict */, | 274 const base::DictionaryValue* /* dict */, |
211 std::string* /* error */, | 275 std::string* /* error */, |
212 bool* /* bad_message */); | 276 bool* /* bad_message */); |
213 // Maps the name of a declarativeContent action type to the factory | 277 // Maps the name of a declarativeContent action type to the factory |
214 // function creating it. | 278 // function creating it. |
215 std::map<std::string, FactoryMethod> factory_methods; | 279 std::map<std::string, FactoryMethod> factory_methods; |
216 | 280 |
217 ContentActionFactory() { | 281 ContentActionFactory() { |
218 factory_methods[keys::kShowPageAction] = | 282 factory_methods[keys::kShowPageAction] = |
(...skipping 11 matching lines...) Expand all Loading... |
230 // | 294 // |
231 // ContentAction | 295 // ContentAction |
232 // | 296 // |
233 | 297 |
234 ContentAction::ContentAction() {} | 298 ContentAction::ContentAction() {} |
235 | 299 |
236 ContentAction::~ContentAction() {} | 300 ContentAction::~ContentAction() {} |
237 | 301 |
238 // static | 302 // static |
239 scoped_refptr<ContentAction> ContentAction::Create( | 303 scoped_refptr<ContentAction> ContentAction::Create( |
| 304 Profile* profile, |
240 const Extension* extension, | 305 const Extension* extension, |
241 const base::Value& json_action, | 306 const base::Value& json_action, |
242 std::string* error, | 307 std::string* error, |
243 bool* bad_message) { | 308 bool* bad_message) { |
244 *error = ""; | 309 *error = ""; |
245 *bad_message = false; | 310 *bad_message = false; |
246 | 311 |
247 const base::DictionaryValue* action_dict = NULL; | 312 const base::DictionaryValue* action_dict = NULL; |
248 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict)); | 313 INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict)); |
249 | 314 |
250 std::string instance_type; | 315 std::string instance_type; |
251 INPUT_FORMAT_VALIDATE( | 316 INPUT_FORMAT_VALIDATE( |
252 action_dict->GetString(keys::kInstanceType, &instance_type)); | 317 action_dict->GetString(keys::kInstanceType, &instance_type)); |
253 | 318 |
254 ContentActionFactory& factory = g_content_action_factory.Get(); | 319 ContentActionFactory& factory = g_content_action_factory.Get(); |
255 std::map<std::string, ContentActionFactory::FactoryMethod>::iterator | 320 std::map<std::string, ContentActionFactory::FactoryMethod>::iterator |
256 factory_method_iter = factory.factory_methods.find(instance_type); | 321 factory_method_iter = factory.factory_methods.find(instance_type); |
257 if (factory_method_iter != factory.factory_methods.end()) | 322 if (factory_method_iter != factory.factory_methods.end()) |
258 return (*factory_method_iter->second)( | 323 return (*factory_method_iter->second)( |
259 extension, action_dict, error, bad_message); | 324 profile, extension, action_dict, error, bad_message); |
260 | 325 |
261 *error = base::StringPrintf(kInvalidInstanceTypeError, instance_type.c_str()); | 326 *error = base::StringPrintf(kInvalidInstanceTypeError, instance_type.c_str()); |
262 return scoped_refptr<ContentAction>(); | 327 return scoped_refptr<ContentAction>(); |
263 } | 328 } |
264 | 329 |
265 } // namespace extensions | 330 } // namespace extensions |
OLD | NEW |