Index: chrome/browser/extensions/api/declarative_content/content_action.cc |
diff --git a/chrome/browser/extensions/api/declarative_content/content_action.cc b/chrome/browser/extensions/api/declarative_content/content_action.cc |
index 3271fdde23b568cc9803fa7668947954dd966eea..b97a29f61237b89cd6bf84b47a790074587ba718 100644 |
--- a/chrome/browser/extensions/api/declarative_content/content_action.cc |
+++ b/chrome/browser/extensions/api/declarative_content/content_action.cc |
@@ -11,16 +11,18 @@ |
#include "base/values.h" |
#include "chrome/browser/extensions/api/declarative_content/content_constants.h" |
#include "chrome/browser/extensions/api/extension_action/extension_action_api.h" |
-#include "chrome/browser/extensions/declarative_user_script_master.h" |
#include "chrome/browser/extensions/extension_action.h" |
#include "chrome/browser/extensions/extension_action_manager.h" |
#include "chrome/browser/extensions/extension_tab_util.h" |
#include "chrome/browser/profiles/profile.h" |
+#include "chrome/browser/sessions/session_tab_helper.h" |
#include "content/public/browser/invalidate_type.h" |
+#include "content/public/browser/render_view_host.h" |
#include "content/public/browser/web_contents.h" |
#include "extensions/browser/extension_registry.h" |
#include "extensions/browser/extension_system.h" |
#include "extensions/common/extension.h" |
+#include "extensions/common/extension_messages.h" |
namespace extensions { |
@@ -37,7 +39,7 @@ const char kMissingParameter[] = "Missing parameter is required: %s"; |
#define INPUT_FORMAT_VALIDATE(test) do { \ |
if (!(test)) { \ |
*bad_message = true; \ |
- return scoped_refptr<ContentAction>(NULL); \ |
+ return false; \ |
} \ |
} while (0) |
@@ -104,60 +106,6 @@ class ShowPageAction : public ContentAction { |
DISALLOW_COPY_AND_ASSIGN(ShowPageAction); |
}; |
-// Action that injects a content script. |
-class RequestContentScript : public ContentAction { |
- public: |
- RequestContentScript(content::BrowserContext* browser_context, |
- const Extension* extension, |
- const std::vector<std::string>& css_file_names, |
- const std::vector<std::string>& js_file_names, |
- bool all_frames, |
- bool match_about_blank); |
- |
- static scoped_refptr<ContentAction> Create( |
- content::BrowserContext* browser_context, |
- const Extension* extension, |
- const base::DictionaryValue* dict, |
- std::string* error, |
- bool* bad_message); |
- |
- // Implementation of ContentAction: |
- virtual Type GetType() const OVERRIDE { |
- return ACTION_REQUEST_CONTENT_SCRIPT; |
- } |
- |
- virtual void Apply(const std::string& extension_id, |
- const base::Time& extension_install_time, |
- ApplyInfo* apply_info) const OVERRIDE { |
- InstructRenderProcessToInject(apply_info->tab, extension_id); |
- } |
- |
- virtual void Reapply(const std::string& extension_id, |
- const base::Time& extension_install_time, |
- ApplyInfo* apply_info) const OVERRIDE { |
- InstructRenderProcessToInject(apply_info->tab, extension_id); |
- } |
- |
- virtual void Revert(const std::string& extension_id, |
- const base::Time& extension_install_time, |
- ApplyInfo* apply_info) const OVERRIDE { |
- } |
- |
- private: |
- virtual ~RequestContentScript() { |
- DCHECK(master_); |
- master_->RemoveScript(script_); |
- } |
- |
- void InstructRenderProcessToInject(content::WebContents* contents, |
- const std::string& extension_id) const; |
- |
- UserScript script_; |
- DeclarativeUserScriptMaster* master_; |
- |
- DISALLOW_COPY_AND_ASSIGN(RequestContentScript); |
-}; |
- |
// Helper for getting JS collections into C++. |
static bool AppendJSStringsToCPPStrings(const base::ListValue& append_strings, |
std::vector<std::string>* append_to) { |
@@ -175,6 +123,43 @@ static bool AppendJSStringsToCPPStrings(const base::ListValue& append_strings, |
return true; |
} |
+struct ContentActionFactory { |
+ // Factory methods for ContentAction instances. |extension| is the extension |
+ // for which the action is being created. |dict| contains the json dictionary |
+ // that describes the action. |error| is used to return error messages in case |
+ // the extension passed an action that was syntactically correct but |
+ // semantically incorrect. |bad_message| is set to true in case |dict| does |
+ // not confirm to the validated JSON specification. |
+ typedef scoped_refptr<ContentAction>(*FactoryMethod)( |
+ content::BrowserContext* /* browser_context */, |
+ const Extension* /* extension */, |
+ const base::DictionaryValue* /* dict */, |
+ std::string* /* error */, |
+ bool* /* bad_message */); |
+ // Maps the name of a declarativeContent action type to the factory |
+ // function creating it. |
+ std::map<std::string, FactoryMethod> factory_methods; |
+ |
+ ContentActionFactory() { |
+ factory_methods[keys::kShowPageAction] = |
+ &ShowPageAction::Create; |
+ factory_methods[keys::kRequestContentScript] = |
+ &RequestContentScript::Create; |
+ } |
+}; |
+ |
+base::LazyInstance<ContentActionFactory>::Leaky |
+ g_content_action_factory = LAZY_INSTANCE_INITIALIZER; |
+ |
+} // namespace |
+ |
+// |
+// RequestContentScript |
+// |
+ |
+RequestContentScript::ScriptData::ScriptData() {} |
+RequestContentScript::ScriptData::~ScriptData() {} |
+ |
// static |
scoped_refptr<ContentAction> RequestContentScript::Create( |
content::BrowserContext* browser_context, |
@@ -182,112 +167,168 @@ scoped_refptr<ContentAction> RequestContentScript::Create( |
const base::DictionaryValue* dict, |
std::string* error, |
bool* bad_message) { |
- std::vector<std::string> css_file_names; |
- std::vector<std::string> js_file_names; |
- bool all_frames = false; |
- bool match_about_blank = false; |
- const base::ListValue* list_value; |
+ ScriptData script_data; |
+ if (!InitScriptData(dict, error, bad_message, &script_data)) |
+ return scoped_refptr<ContentAction>(); |
+ |
+ return scoped_refptr<ContentAction>(new RequestContentScript( |
+ browser_context, |
+ extension, |
+ script_data)); |
+} |
+ |
+// static |
+scoped_refptr<ContentAction> RequestContentScript::CreateForTest( |
+ DeclarativeUserScriptMaster* master, |
+ const Extension* extension, |
+ const base::Value& json_action, |
+ std::string* error, |
+ bool* bad_message) { |
+ // Simulate ContentAction-level initialization. Check that instance type is |
+ // RequestContentScript. |
+ ContentAction::ResetErrorData(error, bad_message); |
+ const base::DictionaryValue* action_dict = NULL; |
+ std::string instance_type; |
+ if (!ContentAction::Validate( |
+ json_action, |
+ error, |
+ bad_message, |
+ &action_dict, |
+ &instance_type) || |
+ instance_type != std::string(keys::kRequestContentScript)) |
+ return scoped_refptr<ContentAction>(); |
+ |
+ // Normal RequestContentScript data initialization. |
+ ScriptData script_data; |
+ if (!InitScriptData(action_dict, error, bad_message, &script_data)) |
+ return scoped_refptr<ContentAction>(); |
+ |
+ // Inject provided DeclarativeUserScriptMaster, rather than looking it up |
+ // using a BrowserContext. |
+ return scoped_refptr<ContentAction>(new RequestContentScript( |
+ master, |
+ extension, |
+ script_data)); |
+} |
+ |
+// static |
+bool RequestContentScript::InitScriptData(const base::DictionaryValue* dict, |
+ std::string* error, |
+ bool* bad_message, |
+ ScriptData* script_data) { |
+ const base::ListValue* list_value = NULL; |
if (!dict->HasKey(keys::kCss) && !dict->HasKey(keys::kJs)) { |
*error = base::StringPrintf(kMissingParameter, "css or js"); |
- return scoped_refptr<ContentAction>(); |
+ return false; |
} |
if (dict->HasKey(keys::kCss)) { |
INPUT_FORMAT_VALIDATE(dict->GetList(keys::kCss, &list_value)); |
INPUT_FORMAT_VALIDATE( |
- AppendJSStringsToCPPStrings(*list_value, &css_file_names)); |
+ AppendJSStringsToCPPStrings(*list_value, &script_data->css_file_names)); |
} |
if (dict->HasKey(keys::kJs)) { |
INPUT_FORMAT_VALIDATE(dict->GetList(keys::kJs, &list_value)); |
INPUT_FORMAT_VALIDATE( |
- AppendJSStringsToCPPStrings(*list_value, &js_file_names)); |
+ AppendJSStringsToCPPStrings(*list_value, &script_data->js_file_names)); |
} |
if (dict->HasKey(keys::kAllFrames)) { |
- INPUT_FORMAT_VALIDATE(dict->GetBoolean(keys::kAllFrames, &all_frames)); |
+ INPUT_FORMAT_VALIDATE( |
+ dict->GetBoolean(keys::kAllFrames, &script_data->all_frames)); |
} |
if (dict->HasKey(keys::kMatchAboutBlank)) { |
INPUT_FORMAT_VALIDATE( |
- dict->GetBoolean(keys::kMatchAboutBlank, &match_about_blank)); |
+ dict->GetBoolean( |
+ keys::kMatchAboutBlank, |
+ &script_data->match_about_blank)); |
} |
- return scoped_refptr<ContentAction>(new RequestContentScript( |
- browser_context, |
- extension, |
- css_file_names, |
- js_file_names, |
- all_frames, |
- match_about_blank)); |
+ return true; |
} |
RequestContentScript::RequestContentScript( |
content::BrowserContext* browser_context, |
const Extension* extension, |
- const std::vector<std::string>& css_file_names, |
- const std::vector<std::string>& js_file_names, |
- bool all_frames, |
- bool match_about_blank) { |
+ const ScriptData& script_data) { |
+ InitScript(extension, script_data); |
+ |
+ master_ = |
+ ExtensionSystem::Get(browser_context)-> |
+ GetDeclarativeUserScriptMasterByExtension(extension->id()); |
+ AddScript(); |
+} |
+ |
+RequestContentScript::RequestContentScript( |
+ DeclarativeUserScriptMaster* master, |
+ const Extension* extension, |
+ const ScriptData& script_data) { |
+ InitScript(extension, script_data); |
+ |
+ master_ = master; |
+ AddScript(); |
+} |
+ |
+RequestContentScript::~RequestContentScript() { |
+ DCHECK(master_); |
+ master_->RemoveScript(script_); |
+} |
+ |
+void RequestContentScript::InitScript(const Extension* extension, |
+ const ScriptData& script_data) { |
script_.set_id(UserScript::GenerateUserScriptID()); |
script_.set_extension_id(extension->id()); |
script_.set_run_location(UserScript::BROWSER_DRIVEN); |
- script_.set_match_all_frames(all_frames); |
- script_.set_match_about_blank(match_about_blank); |
- for (std::vector<std::string>::const_iterator it = css_file_names.begin(); |
- it != css_file_names.end(); ++it) { |
+ script_.set_match_all_frames(script_data.all_frames); |
+ script_.set_match_about_blank(script_data.match_about_blank); |
+ for (std::vector<std::string>::const_iterator it = |
+ script_data.css_file_names.begin(); |
+ it != script_data.css_file_names.end(); ++it) { |
GURL url = extension->GetResourceURL(*it); |
ExtensionResource resource = extension->GetResource(*it); |
script_.css_scripts().push_back(UserScript::File( |
resource.extension_root(), resource.relative_path(), url)); |
} |
- for (std::vector<std::string>::const_iterator it = js_file_names.begin(); |
- it != js_file_names.end(); ++it) { |
+ for (std::vector<std::string>::const_iterator it = |
+ script_data.js_file_names.begin(); |
+ it != script_data.js_file_names.end(); ++it) { |
GURL url = extension->GetResourceURL(*it); |
ExtensionResource resource = extension->GetResource(*it); |
script_.js_scripts().push_back(UserScript::File( |
resource.extension_root(), resource.relative_path(), url)); |
} |
- |
- master_ = |
- ExtensionSystem::Get(browser_context)-> |
- GetDeclarativeUserScriptMasterByExtension(extension->id()); |
- DCHECK(master_); |
- master_->AddScript(script_); |
} |
-void RequestContentScript::InstructRenderProcessToInject( |
- content::WebContents* contents, |
- const std::string& extension_id) const { |
- // TODO(markdittmer): Send ExtensionMsg to renderer. |
+ContentAction::Type RequestContentScript::GetType() const { |
+ return ACTION_REQUEST_CONTENT_SCRIPT; |
} |
-struct ContentActionFactory { |
- // Factory methods for ContentAction instances. |extension| is the extension |
- // for which the action is being created. |dict| contains the json dictionary |
- // that describes the action. |error| is used to return error messages in case |
- // the extension passed an action that was syntactically correct but |
- // semantically incorrect. |bad_message| is set to true in case |dict| does |
- // not confirm to the validated JSON specification. |
- typedef scoped_refptr<ContentAction>(*FactoryMethod)( |
- content::BrowserContext* /* browser_context */, |
- const Extension* /* extension */, |
- const base::DictionaryValue* /* dict */, |
- std::string* /* error */, |
- bool* /* bad_message */); |
- // Maps the name of a declarativeContent action type to the factory |
- // function creating it. |
- std::map<std::string, FactoryMethod> factory_methods; |
+void RequestContentScript::Apply(const std::string& extension_id, |
+ const base::Time& extension_install_time, |
+ ApplyInfo* apply_info) const { |
+ InstructRenderProcessToInject(apply_info->tab, extension_id); |
+} |
- ContentActionFactory() { |
- factory_methods[keys::kShowPageAction] = |
- &ShowPageAction::Create; |
- factory_methods[keys::kRequestContentScript] = |
- &RequestContentScript::Create; |
- } |
-}; |
+void RequestContentScript::Reapply(const std::string& extension_id, |
+ const base::Time& extension_install_time, |
+ ApplyInfo* apply_info) const { |
+ InstructRenderProcessToInject(apply_info->tab, extension_id); |
+} |
-base::LazyInstance<ContentActionFactory>::Leaky |
- g_content_action_factory = LAZY_INSTANCE_INITIALIZER; |
+void RequestContentScript::Revert(const std::string& extension_id, |
+ const base::Time& extension_install_time, |
+ ApplyInfo* apply_info) const {} |
-} // namespace |
+void RequestContentScript::InstructRenderProcessToInject( |
+ content::WebContents* contents, |
+ const std::string& extension_id) const { |
+ content::RenderViewHost* render_view_host = contents->GetRenderViewHost(); |
+ render_view_host->Send(new ExtensionMsg_ExecuteDeclarativeScript( |
+ render_view_host->GetRoutingID(), |
+ SessionTabHelper::IdForTab(contents), |
+ extension_id, |
+ script_.id(), |
+ contents->GetLastCommittedURL())); |
+} |
// |
// ContentAction |
@@ -304,15 +345,11 @@ scoped_refptr<ContentAction> ContentAction::Create( |
const base::Value& json_action, |
std::string* error, |
bool* bad_message) { |
- *error = ""; |
- *bad_message = false; |
- |
+ ResetErrorData(error, bad_message); |
const base::DictionaryValue* action_dict = NULL; |
- INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(&action_dict)); |
- |
std::string instance_type; |
- INPUT_FORMAT_VALIDATE( |
- action_dict->GetString(keys::kInstanceType, &instance_type)); |
+ if (!Validate(json_action, error, bad_message, &action_dict, &instance_type)) |
+ return scoped_refptr<ContentAction>(); |
ContentActionFactory& factory = g_content_action_factory.Get(); |
std::map<std::string, ContentActionFactory::FactoryMethod>::iterator |
@@ -325,4 +362,15 @@ scoped_refptr<ContentAction> ContentAction::Create( |
return scoped_refptr<ContentAction>(); |
} |
+bool ContentAction::Validate(const base::Value& json_action, |
+ std::string* error, |
+ bool* bad_message, |
+ const base::DictionaryValue** action_dict, |
+ std::string* instance_type) { |
+ INPUT_FORMAT_VALIDATE(json_action.GetAsDictionary(action_dict)); |
+ INPUT_FORMAT_VALIDATE( |
+ (*action_dict)->GetString(keys::kInstanceType, instance_type)); |
+ return true; |
+} |
+ |
} // namespace extensions |