summaryrefslogtreecommitdiff
path: root/extensions
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2013-07-23 11:17:05 +0100
committerBen Murdoch <benm@google.com>2013-07-23 11:17:05 +0100
commitca12bfac764ba476d6cd062bf1dde12cc64c3f40 (patch)
tree1cd09db25ea5de98e73c8efbe572e103daee8b2b /extensions
parentfcb3e05bdd21d752df9c3dff28b6bbf29b5b733b (diff)
downloadchromium_org-ca12bfac764ba476d6cd062bf1dde12cc64c3f40.tar.gz
Merge from Chromium at DEPS revision r213057
This commit was generated by merge_to_master.py. Change-Id: I3e2e2506eb9b0080157e9c5f133559df3e600388
Diffstat (limited to 'extensions')
-rw-r--r--extensions/common/switches.cc32
-rw-r--r--extensions/common/switches.h23
-rw-r--r--extensions/common/user_script.cc236
-rw-r--r--extensions/common/user_script.h260
-rw-r--r--extensions/common/user_script_unittest.cc220
5 files changed, 771 insertions, 0 deletions
diff --git a/extensions/common/switches.cc b/extensions/common/switches.cc
new file mode 100644
index 0000000000..f85ff4b9f8
--- /dev/null
+++ b/extensions/common/switches.cc
@@ -0,0 +1,32 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/switches.h"
+
+namespace extensions {
+
+namespace switches {
+
+// Allows the browser to load extensions that lack a modern manifest when that
+// would otherwise be forbidden.
+const char kAllowLegacyExtensionManifests[] =
+ "allow-legacy-extension-manifests";
+
+// Allows injecting extensions and user scripts on the extensions gallery
+// site. Normally prevented for security reasons, but can be useful for
+// automation testing of the gallery.
+const char kAllowScriptingGallery[] = "allow-scripting-gallery";
+
+// Enables extensions running scripts on chrome:// URLs.
+// Extensions still need to explicitly request access to chrome:// URLs in the
+// manifest.
+const char kExtensionsOnChromeURLs[] = "extensions-on-chrome-urls";
+
+// Makes component extensions appear in chrome://settings/extensions.
+const char kShowComponentExtensionOptions[] =
+ "show-component-extension-options";
+
+} // namespace switches
+
+} // namespace extensions
diff --git a/extensions/common/switches.h b/extensions/common/switches.h
new file mode 100644
index 0000000000..c24d35b757
--- /dev/null
+++ b/extensions/common/switches.h
@@ -0,0 +1,23 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_COMMON_SWITCHES_H_
+#define EXTENSIONS_COMMON_SWITCHES_H_
+
+// All switches in alphabetical order. The switches should be documented
+// alongside the definition of their values in the .cc file.
+namespace extensions {
+
+namespace switches {
+
+extern const char kAllowLegacyExtensionManifests[];
+extern const char kAllowScriptingGallery[];
+extern const char kExtensionsOnChromeURLs[];
+extern const char kShowComponentExtensionOptions[];
+
+} // namespace switches
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_SWITCHES_H_
diff --git a/extensions/common/user_script.cc b/extensions/common/user_script.cc
new file mode 100644
index 0000000000..84c1236c60
--- /dev/null
+++ b/extensions/common/user_script.cc
@@ -0,0 +1,236 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "extensions/common/user_script.h"
+
+#include "base/command_line.h"
+#include "base/pickle.h"
+#include "base/strings/string_util.h"
+#include "extensions/common/switches.h"
+
+namespace {
+
+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;
+}
+
+} // namespace
+
+namespace extensions {
+
+// The bitmask for valid user script injectable schemes used by URLPattern.
+enum {
+ kValidUserScriptSchemes = URLPattern::SCHEME_CHROMEUI |
+ URLPattern::SCHEME_HTTP |
+ URLPattern::SCHEME_HTTPS |
+ URLPattern::SCHEME_FILE |
+ URLPattern::SCHEME_FTP
+};
+
+// static
+const char UserScript::kFileExtension[] = ".user.js";
+
+bool UserScript::IsURLUserScript(const GURL& url,
+ const std::string& mime_type) {
+ return EndsWith(url.ExtractFileName(), kFileExtension, false) &&
+ mime_type != "text/html";
+}
+
+// static
+int UserScript::ValidUserScriptSchemes(bool canExecuteScriptEverywhere) {
+ if (canExecuteScriptEverywhere)
+ return URLPattern::SCHEME_ALL;
+ int valid_schemes = kValidUserScriptSchemes;
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kExtensionsOnChromeURLs)) {
+ valid_schemes &= ~URLPattern::SCHEME_CHROMEUI;
+ }
+ return valid_schemes;
+}
+
+UserScript::File::File(const base::FilePath& extension_root,
+ const base::FilePath& relative_path,
+ const GURL& url)
+ : extension_root_(extension_root),
+ relative_path_(relative_path),
+ url_(url) {
+}
+
+UserScript::File::File() {}
+
+UserScript::File::~File() {}
+
+UserScript::UserScript()
+ : run_location_(DOCUMENT_IDLE), emulate_greasemonkey_(false),
+ match_all_frames_(false), incognito_enabled_(false) {
+}
+
+UserScript::~UserScript() {
+}
+
+void UserScript::add_url_pattern(const URLPattern& pattern) {
+ url_set_.AddPattern(pattern);
+}
+
+void UserScript::add_exclude_url_pattern(const URLPattern& pattern) {
+ exclude_url_set_.AddPattern(pattern);
+}
+
+bool UserScript::MatchesURL(const GURL& url) const {
+ if (!url_set_.is_empty()) {
+ if (!url_set_.MatchesURL(url))
+ return false;
+ }
+
+ if (!exclude_url_set_.is_empty()) {
+ if (exclude_url_set_.MatchesURL(url))
+ return false;
+ }
+
+ if (!globs_.empty()) {
+ if (!UrlMatchesGlobs(&globs_, url))
+ return false;
+ }
+
+ if (!exclude_globs_.empty()) {
+ if (UrlMatchesGlobs(&exclude_globs_, url))
+ return false;
+ }
+
+ return true;
+}
+
+void UserScript::File::Pickle(::Pickle* pickle) const {
+ pickle->WriteString(url_.spec());
+ // Do not write path. It's not needed in the renderer.
+ // Do not write content. It will be serialized by other means.
+}
+
+void UserScript::File::Unpickle(const ::Pickle& pickle, PickleIterator* iter) {
+ // Read the url from the pickle.
+ std::string url;
+ CHECK(pickle.ReadString(iter, &url));
+ set_url(GURL(url));
+}
+
+void UserScript::Pickle(::Pickle* pickle) const {
+ // Write the simple types to the pickle.
+ pickle->WriteInt(run_location());
+ pickle->WriteString(extension_id());
+ pickle->WriteBool(emulate_greasemonkey());
+ pickle->WriteBool(match_all_frames());
+ pickle->WriteBool(is_incognito_enabled());
+
+ PickleGlobs(pickle, globs_);
+ PickleGlobs(pickle, exclude_globs_);
+ PickleURLPatternSet(pickle, url_set_);
+ PickleURLPatternSet(pickle, exclude_url_set_);
+ PickleScripts(pickle, js_scripts_);
+ PickleScripts(pickle, css_scripts_);
+}
+
+void UserScript::PickleGlobs(::Pickle* pickle,
+ const std::vector<std::string>& globs) const {
+ pickle->WriteUInt64(globs.size());
+ for (std::vector<std::string>::const_iterator glob = globs.begin();
+ glob != globs.end(); ++glob) {
+ pickle->WriteString(*glob);
+ }
+}
+
+void UserScript::PickleURLPatternSet(::Pickle* pickle,
+ const URLPatternSet& pattern_list) const {
+ pickle->WriteUInt64(pattern_list.patterns().size());
+ for (URLPatternSet::const_iterator pattern = pattern_list.begin();
+ pattern != pattern_list.end(); ++pattern) {
+ pickle->WriteInt(pattern->valid_schemes());
+ pickle->WriteString(pattern->GetAsString());
+ }
+}
+
+void UserScript::PickleScripts(::Pickle* pickle,
+ const FileList& scripts) const {
+ pickle->WriteUInt64(scripts.size());
+ for (FileList::const_iterator file = scripts.begin();
+ file != scripts.end(); ++file) {
+ file->Pickle(pickle);
+ }
+}
+
+void UserScript::Unpickle(const ::Pickle& pickle, PickleIterator* iter) {
+ // Read the run location.
+ int run_location = 0;
+ CHECK(pickle.ReadInt(iter, &run_location));
+ CHECK(run_location >= 0 && run_location < RUN_LOCATION_LAST);
+ run_location_ = static_cast<RunLocation>(run_location);
+
+ CHECK(pickle.ReadString(iter, &extension_id_));
+ CHECK(pickle.ReadBool(iter, &emulate_greasemonkey_));
+ CHECK(pickle.ReadBool(iter, &match_all_frames_));
+ CHECK(pickle.ReadBool(iter, &incognito_enabled_));
+
+ UnpickleGlobs(pickle, iter, &globs_);
+ UnpickleGlobs(pickle, iter, &exclude_globs_);
+ UnpickleURLPatternSet(pickle, iter, &url_set_);
+ UnpickleURLPatternSet(pickle, iter, &exclude_url_set_);
+ UnpickleScripts(pickle, iter, &js_scripts_);
+ UnpickleScripts(pickle, iter, &css_scripts_);
+}
+
+void UserScript::UnpickleGlobs(const ::Pickle& pickle, PickleIterator* iter,
+ std::vector<std::string>* globs) {
+ uint64 num_globs = 0;
+ CHECK(pickle.ReadUInt64(iter, &num_globs));
+ globs->clear();
+ for (uint64 i = 0; i < num_globs; ++i) {
+ std::string glob;
+ CHECK(pickle.ReadString(iter, &glob));
+ globs->push_back(glob);
+ }
+}
+
+void UserScript::UnpickleURLPatternSet(const ::Pickle& pickle,
+ PickleIterator* iter,
+ URLPatternSet* pattern_list) {
+ uint64 num_patterns = 0;
+ CHECK(pickle.ReadUInt64(iter, &num_patterns));
+
+ pattern_list->ClearPatterns();
+ for (uint64 i = 0; i < num_patterns; ++i) {
+ int valid_schemes;
+ CHECK(pickle.ReadInt(iter, &valid_schemes));
+
+ std::string pattern_str;
+ CHECK(pickle.ReadString(iter, &pattern_str));
+
+ URLPattern pattern(kValidUserScriptSchemes);
+ URLPattern::ParseResult result = pattern.Parse(pattern_str);
+ CHECK(URLPattern::PARSE_SUCCESS == result) <<
+ URLPattern::GetParseResultString(result) << " " << pattern_str.c_str();
+
+ pattern.SetValidSchemes(valid_schemes);
+ pattern_list->AddPattern(pattern);
+ }
+}
+
+void UserScript::UnpickleScripts(const ::Pickle& pickle, PickleIterator* iter,
+ FileList* scripts) {
+ uint64 num_files = 0;
+ CHECK(pickle.ReadUInt64(iter, &num_files));
+ scripts->clear();
+ for (uint64 i = 0; i < num_files; ++i) {
+ File file;
+ file.Unpickle(pickle, iter);
+ scripts->push_back(file);
+ }
+}
+
+} // namespace extensions
diff --git a/extensions/common/user_script.h b/extensions/common/user_script.h
new file mode 100644
index 0000000000..76b64d459a
--- /dev/null
+++ b/extensions/common/user_script.h
@@ -0,0 +1,260 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef EXTENSIONS_COMMON_USER_SCRIPT_H_
+#define EXTENSIONS_COMMON_USER_SCRIPT_H_
+
+#include <string>
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/strings/string_piece.h"
+#include "extensions/common/url_pattern.h"
+#include "extensions/common/url_pattern_set.h"
+#include "url/gurl.h"
+
+class Pickle;
+class PickleIterator;
+
+namespace extensions {
+
+// Represents a user script, either a standalone one, or one that is part of an
+// extension.
+class UserScript {
+ public:
+ // The file extension for standalone user scripts.
+ static const char kFileExtension[];
+
+ // Check if a URL should be treated as a user script and converted to an
+ // extension.
+ static bool IsURLUserScript(const GURL& url, const std::string& mime_type);
+
+ // Get the valid user script schemes for the current process. If
+ // canExecuteScriptEverywhere is true, this will return ALL_SCHEMES.
+ static int ValidUserScriptSchemes(bool canExecuteScriptEverywhere = false);
+
+ // Locations that user scripts can be run inside the document.
+ enum RunLocation {
+ UNDEFINED,
+ DOCUMENT_START, // After the documentElement is created, but before
+ // anything else happens.
+ DOCUMENT_END, // After the entire document is parsed. Same as
+ // DOMContentLoaded.
+ DOCUMENT_IDLE, // Sometime after DOMContentLoaded, as soon as the document
+ // is "idle". Currently this uses the simple heuristic of:
+ // min(DOM_CONTENT_LOADED + TIMEOUT, ONLOAD), but no
+ // particular injection point is guaranteed.
+ RUN_LOCATION_LAST // Leave this as the last item.
+ };
+
+ // Holds actual script file info.
+ class File {
+ public:
+ File(const base::FilePath& extension_root,
+ const base::FilePath& relative_path,
+ const GURL& url);
+ File();
+ ~File();
+
+ const base::FilePath& extension_root() const { return extension_root_; }
+ const base::FilePath& relative_path() const { return relative_path_; }
+
+ const GURL& url() const { return url_; }
+ void set_url(const GURL& url) { url_ = url; }
+
+ // If external_content_ is set returns it as content otherwise it returns
+ // content_
+ const base::StringPiece GetContent() const {
+ if (external_content_.data())
+ return external_content_;
+ else
+ return content_;
+ }
+ void set_external_content(const base::StringPiece& content) {
+ external_content_ = content;
+ }
+ void set_content(const base::StringPiece& content) {
+ content_.assign(content.begin(), content.end());
+ }
+
+ // Serialization support. The content and FilePath members will not be
+ // serialized!
+ void Pickle(::Pickle* pickle) const;
+ void Unpickle(const ::Pickle& pickle, PickleIterator* iter);
+
+ private:
+ // Where the script file lives on the disk. We keep the path split so that
+ // it can be localized at will.
+ base::FilePath extension_root_;
+ base::FilePath relative_path_;
+
+ // The url to this scipt file.
+ GURL url_;
+
+ // The script content. It can be set to either loaded_content_ or
+ // externally allocated string.
+ base::StringPiece external_content_;
+
+ // Set when the content is loaded by LoadContent
+ std::string content_;
+ };
+
+ typedef std::vector<File> FileList;
+
+ // Constructor. Default the run location to document end, which is like
+ // Greasemonkey and probably more useful for typical scripts.
+ UserScript();
+ ~UserScript();
+
+ 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& version() const { return version_; }
+ void set_version(const std::string& version) {
+ version_ = version;
+ }
+
+ 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; }
+
+ // Whether to match all frames, or only the top one.
+ bool match_all_frames() const { return match_all_frames_; }
+ void set_match_all_frames(bool val) { match_all_frames_ = 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.
+ const URLPatternSet& url_patterns() const { return url_set_; }
+ void add_url_pattern(const URLPattern& pattern);
+ const URLPatternSet& exclude_url_patterns() const {
+ return exclude_url_set_;
+ }
+ void add_exclude_url_pattern(const URLPattern& pattern);
+
+ // List of js scripts for this user script
+ FileList& js_scripts() { return js_scripts_; }
+ const FileList& js_scripts() const { return js_scripts_; }
+
+ // List of css scripts for this user script
+ FileList& css_scripts() { return css_scripts_; }
+ const FileList& css_scripts() const { return css_scripts_; }
+
+ const std::string& extension_id() const { return extension_id_; }
+ void set_extension_id(const std::string& id) { extension_id_ = id; }
+
+ bool is_incognito_enabled() const { return incognito_enabled_; }
+ void set_incognito_enabled(bool enabled) { incognito_enabled_ = enabled; }
+
+ bool is_standalone() const { return extension_id_.empty(); }
+
+ // Returns true if the script should be applied to the specified URL, false
+ // otherwise.
+ bool MatchesURL(const GURL& url) const;
+
+ // Serialize the UserScript into a pickle. The content of the scripts and
+ // paths to UserScript::Files will not be serialized!
+ void Pickle(::Pickle* pickle) const;
+
+ // Deserialize the script from a pickle. Note that this always succeeds
+ // because presumably we were the one that pickled it, and we did it
+ // correctly.
+ void Unpickle(const ::Pickle& pickle, PickleIterator* iter);
+
+ private:
+ // Pickle helper functions used to pickle the individual types of components.
+ void PickleGlobs(::Pickle* pickle,
+ const std::vector<std::string>& globs) const;
+ void PickleURLPatternSet(::Pickle* pickle,
+ const URLPatternSet& pattern_list) const;
+ void PickleScripts(::Pickle* pickle, const FileList& scripts) const;
+
+ // Unpickle helper functions used to unpickle individual types of components.
+ void UnpickleGlobs(const ::Pickle& pickle, PickleIterator* iter,
+ std::vector<std::string>* globs);
+ void UnpickleURLPatternSet(const ::Pickle& pickle, PickleIterator* iter,
+ URLPatternSet* pattern_list);
+ void UnpickleScripts(const ::Pickle& pickle, PickleIterator* iter,
+ FileList* scripts);
+
+ // 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_;
+
+ // A version number of the script. Only used when parsing Greasemonkey-style
+ // scripts.
+ std::string version_;
+
+ // 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.
+ URLPatternSet url_set_;
+ URLPatternSet exclude_url_set_;
+
+ // List of js scripts defined in content_scripts
+ FileList js_scripts_;
+
+ // List of css scripts defined in content_scripts
+ FileList css_scripts_;
+
+ // 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_;
+
+ // Whether the user script should run in all frames, or only just the top one.
+ // Defaults to false.
+ bool match_all_frames_;
+
+ // True if the script should be injected into an incognito tab.
+ bool incognito_enabled_;
+};
+
+typedef std::vector<UserScript> UserScriptList;
+
+} // namespace extensions
+
+#endif // EXTENSIONS_COMMON_USER_SCRIPT_H_
diff --git a/extensions/common/user_script_unittest.cc b/extensions/common/user_script_unittest.cc
new file mode 100644
index 0000000000..ffec4f0e1d
--- /dev/null
+++ b/extensions/common/user_script_unittest.cc
@@ -0,0 +1,220 @@
+// Copyright 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/files/file_path.h"
+#include "base/pickle.h"
+#include "extensions/common/user_script.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+
+namespace extensions {
+
+static const int kAllSchemes =
+ URLPattern::SCHEME_HTTP |
+ URLPattern::SCHEME_HTTPS |
+ URLPattern::SCHEME_FILE |
+ URLPattern::SCHEME_FTP |
+ URLPattern::SCHEME_CHROMEUI;
+
+TEST(ExtensionUserScriptTest, Glob_HostString) {
+ UserScript script;
+ script.add_glob("*mail.google.com*");
+ script.add_glob("*mail.yahoo.com*");
+ script.add_glob("*mail.msn.com*");
+ EXPECT_TRUE(script.MatchesURL(GURL("http://mail.google.com")));
+ EXPECT_TRUE(script.MatchesURL(GURL("http://mail.google.com/foo")));
+ EXPECT_TRUE(script.MatchesURL(GURL("https://mail.google.com/foo")));
+ EXPECT_TRUE(script.MatchesURL(GURL("ftp://mail.google.com/foo")));
+ EXPECT_TRUE(script.MatchesURL(GURL("http://woo.mail.google.com/foo")));
+ 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(ExtensionUserScriptTest, Glob_TrailingSlash) {
+ UserScript script;
+ script.add_glob("*mail.google.com/");
+ // GURL normalizes the URL to have a trailing "/"
+ EXPECT_TRUE(script.MatchesURL(GURL("http://mail.google.com")));
+ EXPECT_TRUE(script.MatchesURL(GURL("http://mail.google.com/")));
+ EXPECT_FALSE(script.MatchesURL(GURL("http://mail.google.com/foo")));
+}
+
+TEST(ExtensionUserScriptTest, Glob_TrailingSlashStar) {
+ UserScript script;
+ script.add_glob("http://mail.google.com/*");
+ // GURL normalizes the URL to have a trailing "/"
+ EXPECT_TRUE(script.MatchesURL(GURL("http://mail.google.com")));
+ EXPECT_TRUE(script.MatchesURL(GURL("http://mail.google.com/foo")));
+ EXPECT_FALSE(script.MatchesURL(GURL("https://mail.google.com/foo")));
+}
+
+TEST(ExtensionUserScriptTest, Glob_Star) {
+ UserScript script;
+ script.add_glob("*");
+ EXPECT_TRUE(script.MatchesURL(GURL("http://foo.com/bar")));
+ EXPECT_TRUE(script.MatchesURL(GURL("http://hot.com/dog")));
+ EXPECT_TRUE(script.MatchesURL(GURL("https://hot.com/dog")));
+ EXPECT_TRUE(script.MatchesURL(GURL("file:///foo/bar")));
+ EXPECT_TRUE(script.MatchesURL(GURL("file://localhost/foo/bar")));
+}
+
+TEST(ExtensionUserScriptTest, Glob_StringAnywhere) {
+ UserScript script;
+ script.add_glob("*foo*");
+ EXPECT_TRUE(script.MatchesURL(GURL("http://foo.com/bar")));
+ EXPECT_TRUE(script.MatchesURL(GURL("http://baz.org/foo/bar")));
+ EXPECT_FALSE(script.MatchesURL(GURL("http://baz.org")));
+}
+
+TEST(ExtensionUserScriptTest, UrlPattern) {
+ URLPattern pattern(kAllSchemes);
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*/foo*"));
+
+ UserScript script;
+ script.add_url_pattern(pattern);
+ EXPECT_TRUE(script.MatchesURL(GURL("http://monkey.com/foobar")));
+ EXPECT_FALSE(script.MatchesURL(GURL("http://monkey.com/hotdog")));
+
+ // NOTE: URLPattern is tested more extensively in url_pattern_unittest.cc.
+}
+
+TEST(ExtensionUserScriptTest, ExcludeUrlPattern) {
+ UserScript script;
+
+ URLPattern pattern(kAllSchemes);
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.nytimes.com/*"));
+ script.add_url_pattern(pattern);
+
+ URLPattern exclude(kAllSchemes);
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS, exclude.Parse("*://*/*business*"));
+ script.add_exclude_url_pattern(exclude);
+
+ EXPECT_TRUE(script.MatchesURL(GURL("http://www.nytimes.com/health")));
+ EXPECT_FALSE(script.MatchesURL(GURL("http://www.nytimes.com/business")));
+ EXPECT_TRUE(script.MatchesURL(GURL("http://business.nytimes.com")));
+}
+
+TEST(ExtensionUserScriptTest, UrlPatternAndIncludeGlobs) {
+ UserScript script;
+
+ URLPattern pattern(kAllSchemes);
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.nytimes.com/*"));
+ script.add_url_pattern(pattern);
+
+ script.add_glob("*nytimes.com/???s/*");
+
+ EXPECT_TRUE(script.MatchesURL(GURL("http://www.nytimes.com/arts/1.html")));
+ EXPECT_TRUE(script.MatchesURL(GURL("http://www.nytimes.com/jobs/1.html")));
+ EXPECT_FALSE(script.MatchesURL(GURL("http://www.nytimes.com/sports/1.html")));
+}
+
+TEST(ExtensionUserScriptTest, UrlPatternAndExcludeGlobs) {
+ UserScript script;
+
+ URLPattern pattern(kAllSchemes);
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS, pattern.Parse("http://*.nytimes.com/*"));
+ script.add_url_pattern(pattern);
+
+ script.add_exclude_glob("*science*");
+
+ EXPECT_TRUE(script.MatchesURL(GURL("http://www.nytimes.com")));
+ EXPECT_FALSE(script.MatchesURL(GURL("http://science.nytimes.com")));
+ EXPECT_FALSE(script.MatchesURL(GURL("http://www.nytimes.com/science")));
+}
+
+TEST(ExtensionUserScriptTest, UrlPatternGlobInteraction) {
+ // If there are both, match intersection(union(globs), union(urlpatterns)).
+ UserScript script;
+
+ URLPattern pattern(kAllSchemes);
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS,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(ExtensionUserScriptTest, Pickle) {
+ URLPattern pattern1(kAllSchemes);
+ URLPattern pattern2(kAllSchemes);
+ URLPattern exclude1(kAllSchemes);
+ URLPattern exclude2(kAllSchemes);
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS, pattern1.Parse("http://*/foo*"));
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS, pattern2.Parse("http://bar/baz*"));
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS, exclude1.Parse("*://*/*bar"));
+ ASSERT_EQ(URLPattern::PARSE_SUCCESS, exclude2.Parse("https://*/*"));
+
+ UserScript script1;
+ script1.js_scripts().push_back(UserScript::File(
+ base::FilePath(FILE_PATH_LITERAL("c:\\foo\\")),
+ base::FilePath(FILE_PATH_LITERAL("foo.user.js")),
+ GURL("chrome-extension://abc/foo.user.js")));
+ script1.css_scripts().push_back(UserScript::File(
+ base::FilePath(FILE_PATH_LITERAL("c:\\foo\\")),
+ base::FilePath(FILE_PATH_LITERAL("foo.user.css")),
+ GURL("chrome-extension://abc/foo.user.css")));
+ script1.css_scripts().push_back(UserScript::File(
+ base::FilePath(FILE_PATH_LITERAL("c:\\foo\\")),
+ base::FilePath(FILE_PATH_LITERAL("foo2.user.css")),
+ GURL("chrome-extension://abc/foo2.user.css")));
+ script1.set_run_location(UserScript::DOCUMENT_START);
+
+ script1.add_url_pattern(pattern1);
+ script1.add_url_pattern(pattern2);
+ script1.add_exclude_url_pattern(exclude1);
+ script1.add_exclude_url_pattern(exclude2);
+
+ Pickle pickle;
+ script1.Pickle(&pickle);
+
+ PickleIterator iter(pickle);
+ UserScript script2;
+ script2.Unpickle(pickle, &iter);
+
+ EXPECT_EQ(1U, script2.js_scripts().size());
+ EXPECT_EQ(script1.js_scripts()[0].url(), script2.js_scripts()[0].url());
+
+ EXPECT_EQ(2U, script2.css_scripts().size());
+ for (size_t i = 0; i < script2.js_scripts().size(); ++i) {
+ EXPECT_EQ(script1.css_scripts()[i].url(), script2.css_scripts()[i].url());
+ }
+
+ ASSERT_EQ(script1.globs().size(), script2.globs().size());
+ for (size_t i = 0; i < script1.globs().size(); ++i) {
+ EXPECT_EQ(script1.globs()[i], script2.globs()[i]);
+ }
+
+ ASSERT_EQ(script1.url_patterns(), script2.url_patterns());
+ ASSERT_EQ(script1.exclude_url_patterns(), script2.exclude_url_patterns());
+}
+
+TEST(ExtensionUserScriptTest, Defaults) {
+ UserScript script;
+ ASSERT_EQ(UserScript::DOCUMENT_IDLE, script.run_location());
+}
+
+} // namespace extensions