summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/common/extensions')
-rw-r--r--chrome/common/extensions/extension.cc52
-rw-r--r--chrome/common/extensions/extension.h16
-rw-r--r--chrome/common/extensions/extension_constants.cc7
-rw-r--r--chrome/common/extensions/extension_constants.h5
-rw-r--r--chrome/common/extensions/extension_error_utils.cc18
-rw-r--r--chrome/common/extensions/extension_error_utils.h16
-rw-r--r--chrome/common/extensions/user_script.cc75
-rw-r--r--chrome/common/extensions/user_script.h55
-rw-r--r--chrome/common/extensions/user_script_unittest.cc34
9 files changed, 253 insertions, 25 deletions
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index c617232..0aad3de 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -248,6 +248,17 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
result->add_url_pattern(pattern);
}
+ // include/exclude globs (mostly for Greasemonkey compat)
+ if (!LoadGlobsHelper(content_script, definition_index, keys::kIncludeGlobs,
+ error, &UserScript::add_glob, result)) {
+ return false;
+ }
+
+ if (!LoadGlobsHelper(content_script, definition_index, keys::kExcludeGlobs,
+ error, &UserScript::add_exclude_glob, result)) {
+ return false;
+ }
+
// js and css keys
ListValue* js = NULL;
if (content_script->HasKey(keys::kJs) &&
@@ -311,6 +322,38 @@ bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
return true;
}
+bool Extension::LoadGlobsHelper(
+ const DictionaryValue* content_script,
+ int content_script_index,
+ const wchar_t* globs_property_name,
+ std::string* error,
+ void (UserScript::*add_method) (const std::string& glob),
+ UserScript *instance) {
+ if (!content_script->HasKey(globs_property_name))
+ return true; // they are optional
+
+ ListValue* list = NULL;
+ if (!content_script->GetList(globs_property_name, &list)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidGlobList,
+ IntToString(content_script_index), WideToASCII(globs_property_name));
+ return false;
+ }
+
+ for (size_t i = 0; i < list->GetSize(); ++i) {
+ std::string glob;
+ if (!list->GetString(i, &glob)) {
+ *error = ExtensionErrorUtils::FormatErrorMessage(errors::kInvalidGlob,
+ IntToString(content_script_index), WideToASCII(globs_property_name),
+ IntToString(i));
+ return false;
+ }
+
+ (instance->*add_method)(glob);
+ }
+
+ return true;
+}
+
ExtensionAction* Extension::LoadExtensionActionHelper(
const DictionaryValue* extension_action, std::string* error) {
scoped_ptr<ExtensionAction> result(new ExtensionAction());
@@ -450,7 +493,8 @@ ExtensionResource Extension::GetResource(const FilePath& extension_path,
}
Extension::Extension(const FilePath& path)
- : is_theme_(false), background_page_ready_(false) {
+ : converted_from_user_script_(false), is_theme_(false),
+ background_page_ready_(false) {
DCHECK(path.IsAbsolute());
location_ = INVALID;
@@ -668,6 +712,10 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_id,
}
}
+ // Initialize converted_from_user_script (if present)
+ source.GetBoolean(keys::kConvertedFromUserScript,
+ &converted_from_user_script_);
+
// Initialize icons (if present).
if (source.HasKey(keys::kIcons)) {
DictionaryValue* icons_value = NULL;
@@ -943,6 +991,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, bool require_id,
if (!LoadUserScriptHelper(content_script, i, error, &script))
return false; // Failed to parse script context definition
script.set_extension_id(id());
+ if (converted_from_user_script_)
+ script.set_emulate_greasemonkey(true);
content_scripts_.push_back(script);
}
}
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 050515b..d240388 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -195,6 +195,9 @@ class Extension {
const std::string& name() const { return name_; }
const std::string& public_key() const { return public_key_; }
const std::string& description() const { return description_; }
+ bool converted_from_user_script() const {
+ return converted_from_user_script_;
+ }
const UserScriptList& content_scripts() const { return content_scripts_; }
ExtensionAction* page_action() const { return page_action_.get(); }
ExtensionAction* browser_action() const { return browser_action_.get(); }
@@ -290,6 +293,15 @@ class Extension {
std::string* error,
UserScript* result);
+ // Helper method that loads either the include_globs or exclude_globs list
+ // from an entry in the content_script lists of the manifest.
+ bool LoadGlobsHelper(const DictionaryValue* content_script,
+ int content_script_index,
+ const wchar_t* globs_property_name,
+ std::string* error,
+ void (UserScript::*add_method) (const std::string& glob),
+ UserScript *instance);
+
// Helper method to load an ExtensionAction from the page_action or
// browser_action entries in the manifest.
ExtensionAction* LoadExtensionActionHelper(
@@ -325,6 +337,10 @@ class Extension {
// An optional longer description of the extension.
std::string description_;
+ // True if the extension was generated from a user script. (We show slightly
+ // different UI if so).
+ bool converted_from_user_script_;
+
// Paths to the content scripts the extension contains.
UserScriptList content_scripts_;
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 59e7c14..0dbab1f 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -10,12 +10,15 @@ const wchar_t* kBackground = L"background_page";
const wchar_t* kBrowserAction = L"browser_action";
const wchar_t* kChromeURLOverrides = L"chrome_url_overrides";
const wchar_t* kContentScripts = L"content_scripts";
+const wchar_t* kConvertedFromUserScript = L"converted_from_user_script";
const wchar_t* kCss = L"css";
const wchar_t* kDefaultLocale = L"default_locale";
const wchar_t* kDescription = L"description";
const wchar_t* kIcons = L"icons";
const wchar_t* kJs = L"js";
const wchar_t* kMatches = L"matches";
+const wchar_t* kIncludeGlobs = L"include_globs";
+const wchar_t* kExcludeGlobs = L"exclude_globs";
const wchar_t* kName = L"name";
const wchar_t* kPageActionId = L"id";
const wchar_t* kPageAction = L"page_action";
@@ -76,6 +79,10 @@ const char* kInvalidCssList =
"Required value 'content_scripts[*].css is invalid.";
const char* kInvalidDescription =
"Invalid value for 'description'.";
+const char* kInvalidGlobList =
+ "Invalid value for 'content_scripts[*].*'.";
+const char* kInvalidGlob =
+ "Invalid value for 'content_scripts[*].*[*]'.";
const char* kInvalidIcons =
"Invalid value for 'icons'.";
const char* kInvalidIconPath =
diff --git a/chrome/common/extensions/extension_constants.h b/chrome/common/extensions/extension_constants.h
index b7826a7..d44f7b9 100644
--- a/chrome/common/extensions/extension_constants.h
+++ b/chrome/common/extensions/extension_constants.h
@@ -11,10 +11,13 @@ namespace extension_manifest_keys {
extern const wchar_t* kBrowserAction;
extern const wchar_t* kChromeURLOverrides;
extern const wchar_t* kContentScripts;
+ extern const wchar_t* kConvertedFromUserScript;
extern const wchar_t* kCss;
extern const wchar_t* kDefaultLocale;
extern const wchar_t* kDescription;
+ extern const wchar_t* kExcludeGlobs;
extern const wchar_t* kIcons;
+ extern const wchar_t* kIncludeGlobs;
extern const wchar_t* kJs;
extern const wchar_t* kMatches;
extern const wchar_t* kName;
@@ -70,6 +73,8 @@ namespace extension_manifest_errors {
extern const char* kInvalidDescription;
extern const char* kInvalidIcons;
extern const char* kInvalidIconPath;
+ extern const char* kInvalidGlobList;
+ extern const char* kInvalidGlob;
extern const char* kInvalidJs;
extern const char* kInvalidJsList;
extern const char* kInvalidKey;
diff --git a/chrome/common/extensions/extension_error_utils.cc b/chrome/common/extensions/extension_error_utils.cc
index 724cdcd..0256c8d8 100644
--- a/chrome/common/extensions/extension_error_utils.cc
+++ b/chrome/common/extensions/extension_error_utils.cc
@@ -8,7 +8,7 @@
std::string ExtensionErrorUtils::FormatErrorMessage(
const std::string& format,
- const std::string s1) {
+ const std::string& s1) {
std::string ret_val = format;
ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
return ret_val;
@@ -16,10 +16,22 @@ std::string ExtensionErrorUtils::FormatErrorMessage(
std::string ExtensionErrorUtils::FormatErrorMessage(
const std::string& format,
- const std::string s1,
- const std::string s2) {
+ const std::string& s1,
+ const std::string& s2) {
std::string ret_val = format;
ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2);
return ret_val;
}
+
+std::string ExtensionErrorUtils::FormatErrorMessage(
+ const std::string& format,
+ const std::string& s1,
+ const std::string& s2,
+ const std::string& s3) {
+ std::string ret_val = format;
+ ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s1);
+ ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s2);
+ ReplaceFirstSubstringAfterOffset(&ret_val, 0, "*", s3);
+ return ret_val;
+}
diff --git a/chrome/common/extensions/extension_error_utils.h b/chrome/common/extensions/extension_error_utils.h
index f9f1e7c..fdd9b03 100644
--- a/chrome/common/extensions/extension_error_utils.h
+++ b/chrome/common/extensions/extension_error_utils.h
@@ -9,16 +9,18 @@
class ExtensionErrorUtils {
public:
- // Creates an error messages from a pattern. Places first instance if "*"
- // with |s1|.
+ // Creates an error messages from a pattern.
static std::string FormatErrorMessage(const std::string& format,
- const std::string s1);
+ const std::string& s1);
- // Creates an error messages from a pattern. Places first instance if "*"
- // with |s1| and second instance of "*" with |s2|.
static std::string FormatErrorMessage(const std::string& format,
- const std::string s1,
- const std::string s2);
+ const std::string& s1,
+ const std::string& s2);
+
+ static std::string FormatErrorMessage(const std::string& format,
+ const std::string& s1,
+ const std::string& s2,
+ const std::string& s3);
};
#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_ERROR_UTILS_H_
diff --git a/chrome/common/extensions/user_script.cc b/chrome/common/extensions/user_script.cc
index df34e52..10d0b60 100644
--- a/chrome/common/extensions/user_script.cc
+++ b/chrome/common/extensions/user_script.cc
@@ -7,21 +7,59 @@
#include "base/pickle.h"
#include "base/string_util.h"
-bool UserScript::MatchesUrl(const GURL& url) const {
- for (std::vector<std::string>::const_iterator glob = globs_.begin();
- glob != globs_.end(); ++glob) {
- if (MatchPattern(url.spec(), *glob))
+namespace {
+static bool UrlMatchesPatterns(const UserScript::PatternList* patterns,
+ const GURL& url) {
+ for (UserScript::PatternList::const_iterator pattern = patterns->begin();
+ pattern != patterns->end(); ++pattern) {
+ if (pattern->MatchesUrl(url))
return true;
}
- for (PatternList::const_iterator pattern = url_patterns_.begin();
- pattern != url_patterns_.end(); ++pattern) {
- if (pattern->MatchesUrl(url))
+ return false;
+}
+
+static bool UrlMatchesGlobs(const std::vector<std::string>* globs,
+ const GURL& url) {
+ for (std::vector<std::string>::const_iterator glob = globs->begin();
+ glob != globs->end(); ++glob) {
+ if (MatchPattern(url.spec(), *glob))
return true;
}
return false;
}
+}
+
+const char UserScript::kFileExtension[] = ".user.js";
+
+bool UserScript::HasUserScriptFileExtension(const GURL& url) {
+ return EndsWith(url.ExtractFileName(), kFileExtension, false);
+}
+
+bool UserScript::HasUserScriptFileExtension(const FilePath& path) {
+ static FilePath extension(FilePath().AppendASCII(kFileExtension));
+ return EndsWith(path.BaseName().value(), extension.value(), false);
+}
+
+bool UserScript::MatchesUrl(const GURL& url) const {
+ if (url_patterns_.size() > 0) {
+ if (!UrlMatchesPatterns(&url_patterns_, url))
+ return false;
+ }
+
+ if (globs_.size() > 0) {
+ if (!UrlMatchesGlobs(&globs_, url))
+ return false;
+ }
+
+ if (exclude_globs_.size() > 0) {
+ if (UrlMatchesGlobs(&exclude_globs_, url))
+ return false;
+ }
+
+ return true;
+}
void UserScript::File::Pickle(::Pickle* pickle) const {
pickle->WriteString(url_.spec());
@@ -43,10 +81,17 @@ void UserScript::Pickle(::Pickle* pickle) const {
// Write the extension id.
pickle->WriteString(extension_id());
+ // Write Greasemonkey emulation.
+ pickle->WriteBool(emulate_greasemonkey());
+
// Write globs.
+ std::vector<std::string>::const_iterator glob;
pickle->WriteSize(globs_.size());
- for (std::vector<std::string>::const_iterator glob = globs_.begin();
- glob != globs_.end(); ++glob) {
+ for (glob = globs_.begin(); glob != globs_.end(); ++glob) {
+ pickle->WriteString(*glob);
+ }
+ pickle->WriteSize(exclude_globs_.size());
+ for (glob = exclude_globs_.begin(); glob != exclude_globs_.end(); ++glob) {
pickle->WriteString(*glob);
}
@@ -82,10 +127,12 @@ void UserScript::Unpickle(const ::Pickle& pickle, void** iter) {
// Read the extension ID.
CHECK(pickle.ReadString(iter, &extension_id_));
+ // Read Greasemonkey emulation.
+ CHECK(pickle.ReadBool(iter, &emulate_greasemonkey_));
+
// Read globs.
size_t num_globs = 0;
CHECK(pickle.ReadSize(iter, &num_globs));
-
globs_.clear();
for (size_t i = 0; i < num_globs; ++i) {
std::string glob;
@@ -93,6 +140,14 @@ void UserScript::Unpickle(const ::Pickle& pickle, void** iter) {
globs_.push_back(glob);
}
+ CHECK(pickle.ReadSize(iter, &num_globs));
+ exclude_globs_.clear();
+ for (size_t i = 0; i < num_globs; ++i) {
+ std::string glob;
+ CHECK(pickle.ReadString(iter, &glob));
+ exclude_globs_.push_back(glob);
+ }
+
// Read url patterns.
size_t num_patterns = 0;
CHECK(pickle.ReadSize(iter, &num_patterns));
diff --git a/chrome/common/extensions/user_script.h b/chrome/common/extensions/user_script.h
index bdd1e54..adcfa3f 100644
--- a/chrome/common/extensions/user_script.h
+++ b/chrome/common/extensions/user_script.h
@@ -22,6 +22,13 @@ class UserScript {
public:
typedef std::vector<URLPattern> PatternList;
+ // The file extension for standalone user scripts.
+ static const char kFileExtension[];
+
+ // Check if a file or URL has the user script file extension.
+ static bool HasUserScriptFileExtension(const GURL& url);
+ static bool HasUserScriptFileExtension(const FilePath& path);
+
// Locations that user scripts can be run inside the document.
enum RunLocation {
DOCUMENT_START, // After the documentElemnet is created, but before
@@ -92,20 +99,45 @@ class UserScript {
typedef std::vector<File> FileList;
- // Constructor. Default the run location to document idle, which is similar
- // to Greasemonkey but should result in better page load times for fast-
- // loading pages.
- UserScript() : run_location_(DOCUMENT_IDLE) {}
+ // Constructor. Default the run location to document end, which is like
+ // Greasemonkey and probably more useful for typical scripts.
+ UserScript()
+ : run_location_(DOCUMENT_IDLE), emulate_greasemonkey_(false) {
+ }
+
+ const std::string& name_space() const { return name_space_; }
+ void set_name_space(const std::string& name_space) {
+ name_space_ = name_space;
+ }
+
+ const std::string& name() const { return name_; }
+ void set_name(const std::string& name) { name_ = name; }
+
+ const std::string& description() const { return description_; }
+ void set_description(const std::string& description) {
+ description_ = description;
+ }
// The place in the document to run the script.
RunLocation run_location() const { return run_location_; }
void set_run_location(RunLocation location) { run_location_ = location; }
+ // Whether to emulate greasemonkey when running this script.
+ bool emulate_greasemonkey() const { return emulate_greasemonkey_; }
+ void set_emulate_greasemonkey(bool val) { emulate_greasemonkey_ = val; }
+
// The globs, if any, that determine which pages this script runs against.
// These are only used with "standalone" Greasemonkey-like user scripts.
const std::vector<std::string>& globs() const { return globs_; }
void add_glob(const std::string& glob) { globs_.push_back(glob); }
void clear_globs() { globs_.clear(); }
+ const std::vector<std::string>& exclude_globs() const {
+ return exclude_globs_;
+ }
+ void add_exclude_glob(const std::string& glob) {
+ exclude_globs_.push_back(glob);
+ }
+ void clear_exclude_globs() { exclude_globs_.clear(); }
// The URLPatterns, if any, that determine which pages this script runs
// against.
@@ -145,9 +177,20 @@ class UserScript {
// The location to run the script inside the document.
RunLocation run_location_;
+ // The namespace of the script. This is used by Greasemonkey in the same way
+ // as XML namespaces. Only used when parsing Greasemonkey-style scripts.
+ std::string name_space_;
+
+ // The script's name. Only used when parsing Greasemonkey-style scripts.
+ std::string name_;
+
+ // A longer description. Only used when parsing Greasemonkey-style scripts.
+ std::string description_;
+
// Greasemonkey-style globs that determine pages to inject the script into.
// These are only used with standalone scripts.
std::vector<std::string> globs_;
+ std::vector<std::string> exclude_globs_;
// URLPatterns that determine pages to inject the script into. These are
// only used with scripts that are part of extensions.
@@ -162,6 +205,10 @@ class UserScript {
// The ID of the extension this script is a part of, if any. Can be empty if
// the script is a "standlone" user script.
std::string extension_id_;
+
+ // Whether we should try to emulate Greasemonkey's APIs when running this
+ // script.
+ bool emulate_greasemonkey_;
};
typedef std::vector<UserScript> UserScriptList;
diff --git a/chrome/common/extensions/user_script_unittest.cc b/chrome/common/extensions/user_script_unittest.cc
index 58ef77e..7b5cc6d 100644
--- a/chrome/common/extensions/user_script_unittest.cc
+++ b/chrome/common/extensions/user_script_unittest.cc
@@ -21,6 +21,10 @@ TEST(UserScriptTest, Match1) {
EXPECT_TRUE(script.MatchesUrl(GURL("http://mail.yahoo.com/bar")));
EXPECT_TRUE(script.MatchesUrl(GURL("http://mail.msn.com/baz")));
EXPECT_FALSE(script.MatchesUrl(GURL("http://www.hotmail.com")));
+
+ script.add_exclude_glob("*foo*");
+ EXPECT_TRUE(script.MatchesUrl(GURL("http://mail.google.com")));
+ EXPECT_FALSE(script.MatchesUrl(GURL("http://mail.google.com/foo")));
}
TEST(UserScriptTest, Match2) {
@@ -70,6 +74,36 @@ TEST(UserScriptTest, Match6) {
// NOTE: URLPattern is tested more extensively in url_pattern_unittest.cc.
}
+TEST(UserScriptTest, UrlPatternGlobInteraction) {
+ // If there are both, match intersection(union(globs), union(urlpatterns)).
+ UserScript script;
+
+ URLPattern pattern;
+ ASSERT_TRUE(pattern.Parse("http://www.google.com/*"));
+ script.add_url_pattern(pattern);
+
+ script.add_glob("*bar*");
+
+ // No match, because it doesn't match the glob.
+ EXPECT_FALSE(script.MatchesUrl(GURL("http://www.google.com/foo")));
+
+ script.add_exclude_glob("*baz*");
+
+ // No match, because it matches the exclude glob.
+ EXPECT_FALSE(script.MatchesUrl(GURL("http://www.google.com/baz")));
+
+ // Match, because it matches the glob, doesn't match the exclude glob.
+ EXPECT_TRUE(script.MatchesUrl(GURL("http://www.google.com/bar")));
+
+ // Try with just a single exclude glob.
+ script.clear_globs();
+ EXPECT_TRUE(script.MatchesUrl(GURL("http://www.google.com/foo")));
+
+ // Try with no globs or exclude globs.
+ script.clear_exclude_globs();
+ EXPECT_TRUE(script.MatchesUrl(GURL("http://www.google.com/foo")));
+}
+
TEST(UserScriptTest, Pickle) {
URLPattern pattern1;
URLPattern pattern2;