summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorgeorged@chromium.org <georged@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-18 21:26:24 +0000
committergeorged@chromium.org <georged@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-03-18 21:26:24 +0000
commit3cfbd0eb2afd2cf0b8b248d6bb97ec39b064cd23 (patch)
treeeaa3eddbc15cf6bac88d04c4766778fd545f95c0 /chrome/browser
parent836827406c7135b0225474d24b9d08dd8edff27a (diff)
downloadchromium_src-3cfbd0eb2afd2cf0b8b248d6bb97ec39b064cd23.zip
chromium_src-3cfbd0eb2afd2cf0b8b248d6bb97ec39b064cd23.tar.gz
chromium_src-3cfbd0eb2afd2cf0b8b248d6bb97ec39b064cd23.tar.bz2
Review URL: http://codereview.chromium.org/42288
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@12016 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/extensions/extension.cc220
-rw-r--r--chrome/browser/extensions/extension.h20
-rw-r--r--chrome/browser/extensions/extension_unittest.cc25
-rw-r--r--chrome/browser/extensions/extensions_service.cc29
-rw-r--r--chrome/browser/extensions/extensions_service_unittest.cc8
-rw-r--r--chrome/browser/extensions/extensions_ui.cc38
-rw-r--r--chrome/browser/extensions/user_script_master.cc125
-rw-r--r--chrome/browser/extensions/user_script_master.h15
8 files changed, 323 insertions, 157 deletions
diff --git a/chrome/browser/extensions/extension.cc b/chrome/browser/extensions/extension.cc
index 75d8930..924c4ed 100644
--- a/chrome/browser/extensions/extension.cc
+++ b/chrome/browser/extensions/extension.cc
@@ -19,6 +19,7 @@ const wchar_t* Extension::kDescriptionKey = L"description";
const wchar_t* Extension::kFormatVersionKey = L"format_version";
const wchar_t* Extension::kIdKey = L"id";
const wchar_t* Extension::kJsKey = L"js";
+const wchar_t* Extension::kCssKey = L"css";
const wchar_t* Extension::kMatchesKey = L"matches";
const wchar_t* Extension::kNameKey = L"name";
const wchar_t* Extension::kRunAtKey = L"run_at";
@@ -39,6 +40,10 @@ const char* Extension::kInvalidContentScriptError =
"Invalid value for 'content_scripts[*]'.";
const char* Extension::kInvalidContentScriptsListError =
"Invalid value for 'content_scripts'.";
+const char* Extension::kInvalidCssError =
+ "Invalid value for 'content_scripts[*].css[*]'.";
+const char* Extension::kInvalidCssListError =
+ "Required value 'content_scripts[*].css is invalid.";
const char* Extension::kInvalidDescriptionError =
"Invalid value for 'description'.";
const char* Extension::kInvalidFormatVersionError =
@@ -51,7 +56,7 @@ const char* Extension::kInvalidJsCountError =
const char* Extension::kInvalidJsError =
"Invalid value for 'content_scripts[*].js[*]'.";
const char* Extension::kInvalidJsListError =
- "Required value 'content_scripts[*].js is missing or invalid.";
+ "Required value 'content_scripts[*].js is invalid.";
const char* Extension::kInvalidManifestError =
"Manifest is missing or invalid.";
const char* Extension::kInvalidMatchCountError =
@@ -63,16 +68,18 @@ const char* Extension::kInvalidMatchesError =
"Required value 'content_scripts[*].matches' is missing or invalid.";
const char* Extension::kInvalidNameError =
"Required value 'name' is missing or invalid.";
+const char* Extension::kInvalidPluginsDirError =
+ "Invalid value for 'plugins_dir'.";
const char* Extension::kInvalidRunAtError =
"Invalid value for 'content_scripts[*].run_at'.";
+const char* Extension::kInvalidToolstripError =
+ "Invalid value for 'toolstrip'.";
const char* Extension::kInvalidVersionError =
"Required value 'version' is missing or invalid.";
const char* Extension::kInvalidZipHashError =
"Required key 'zip_hash' is missing or invalid.";
-const char* Extension::kInvalidPluginsDirError =
- "Invalid value for 'plugins_dir'.";
-const char* Extension::kInvalidToolstripError =
- "Invalid value for 'toolstrip'.";
+const char* Extension::kMissingFileError =
+ "At least one js or css file is required for 'content_scripts[*]'.";
const size_t Extension::kIdSize = 20; // SHA1 (160 bits) == 20 bytes
@@ -185,6 +192,135 @@ Extension::Extension(const FilePath& path) {
#endif
}
+// Helper method that loads a UserScript object from a dictionary in the
+// content_script list of the manifest.
+bool Extension::LoadUserScriptHelper(const DictionaryValue* content_script,
+ int definition_index, std::string* error,
+ UserScript* result) {
+ // run_at
+ if (content_script->HasKey(kRunAtKey)) {
+ std::string run_location;
+ if (!content_script->GetString(kRunAtKey, &run_location)) {
+ *error = FormatErrorMessage(kInvalidRunAtError,
+ IntToString(definition_index));
+ return false;
+ }
+
+ if (run_location == kRunAtDocumentStartValue) {
+ result->set_run_location(UserScript::DOCUMENT_START);
+ } else if (run_location == kRunAtDocumentEndValue) {
+ result->set_run_location(UserScript::DOCUMENT_END);
+ } else {
+ *error = FormatErrorMessage(kInvalidRunAtError,
+ IntToString(definition_index));
+ return false;
+ }
+ }
+
+ // matches
+ ListValue* matches = NULL;
+ if (!content_script->GetList(kMatchesKey, &matches)) {
+ *error = FormatErrorMessage(kInvalidMatchesError,
+ IntToString(definition_index));
+ return false;
+ }
+
+ if (matches->GetSize() == 0) {
+ *error = FormatErrorMessage(kInvalidMatchCountError,
+ IntToString(definition_index));
+ return false;
+ }
+ for (size_t j = 0; j < matches->GetSize(); ++j) {
+ std::string match_str;
+ if (!matches->GetString(j, &match_str)) {
+ *error = FormatErrorMessage(kInvalidMatchError,
+ IntToString(definition_index),
+ IntToString(j));
+ return false;
+ }
+
+ URLPattern pattern;
+ if (!pattern.Parse(match_str)) {
+ *error = FormatErrorMessage(kInvalidMatchError,
+ IntToString(definition_index),
+ IntToString(j));
+ return false;
+ }
+
+ result->add_url_pattern(pattern);
+ }
+
+ // js and css keys
+ ListValue* js = NULL;
+ if (content_script->HasKey(kJsKey) &&
+ !content_script->GetList(kJsKey, &js)) {
+ *error = FormatErrorMessage(kInvalidJsListError,
+ IntToString(definition_index));
+ return false;
+ }
+
+ ListValue* css = NULL;
+ if (content_script->HasKey(kCssKey) &&
+ !content_script->GetList(kCssKey, &css)) {
+ *error = FormatErrorMessage(kInvalidCssListError,
+ IntToString(definition_index));
+ return false;
+ }
+
+ // The manifest needs to have at least one js or css user script definition.
+ if (((js ? js->GetSize() : 0) + (css ? css->GetSize() : 0)) == 0) {
+ *error = FormatErrorMessage(kMissingFileError,
+ IntToString(definition_index));
+ return false;
+ }
+
+ // NOTE: Only one js file is supported for now.
+ // TODO(aa): Add support for multiple js files.
+ if (js && js->GetSize() != 1) {
+ *error = FormatErrorMessage(kInvalidJsCountError,
+ IntToString(definition_index));
+ return false;
+ }
+
+ if (js) {
+ for (size_t script_index = 0; script_index < js->GetSize();
+ ++script_index) {
+ Value* value;
+ std::wstring relative;
+ if (!js->Get(script_index, &value) || !value->GetAsString(&relative)) {
+ *error = FormatErrorMessage(kInvalidJsError,
+ IntToString(definition_index),
+ IntToString(script_index));
+ return false;
+ }
+ // TODO(georged): Make GetResourceURL accept wstring too
+ GURL url = GetResourceURL(WideToUTF8(relative));
+ FilePath path = GetResourcePath(WideToUTF8(relative));
+ result->js_scripts().push_back(UserScript::File(path, url));
+ }
+ }
+
+ if (css) {
+ for (size_t script_index = 0; script_index < css->GetSize();
+ ++script_index) {
+ Value* value;
+ std::wstring relative;
+ if (!css->Get(script_index, &value) || !value->GetAsString(&relative)) {
+ *error = FormatErrorMessage(kInvalidCssError,
+ IntToString(definition_index),
+ IntToString(script_index));
+ return false;
+ }
+ // TODO(georged): Make GetResourceURL accept wstring too
+ GURL url = GetResourceURL(WideToUTF8(relative));
+ FilePath path = GetResourcePath(WideToUTF8(relative));
+ result->css_scripts().push_back(UserScript::File(path, url));
+ }
+ }
+
+ return true;
+}
+
bool Extension::InitFromValue(const DictionaryValue& source,
std::string* error) {
// Check format version.
@@ -300,80 +436,14 @@ bool Extension::InitFromValue(const DictionaryValue& source,
for (size_t i = 0; i < list_value->GetSize(); ++i) {
DictionaryValue* content_script;
if (!list_value->GetDictionary(i, &content_script)) {
- *error = FormatErrorMessage(kInvalidContentScriptError, IntToString(i));
- return false;
- }
-
- ListValue* matches;
- ListValue* js;
-
- if (!content_script->GetList(kMatchesKey, &matches)) {
- *error = FormatErrorMessage(kInvalidMatchesError, IntToString(i));
- return false;
- }
-
- if (!content_script->GetList(kJsKey, &js)) {
- *error = FormatErrorMessage(kInvalidJsListError, IntToString(i));
- return false;
- }
-
- if (matches->GetSize() == 0) {
- *error = FormatErrorMessage(kInvalidMatchCountError, IntToString(i));
- return false;
- }
-
- // NOTE: Only one file is supported right now.
- if (js->GetSize() != 1) {
- *error = FormatErrorMessage(kInvalidJsCountError, IntToString(i));
+ *error = FormatErrorMessage(kInvalidContentScriptError,
+ IntToString(i));
return false;
}
UserScript script;
- if (content_script->HasKey(kRunAtKey)) {
- std::string run_location;
- if (!content_script->GetString(kRunAtKey, &run_location)) {
- *error = FormatErrorMessage(kInvalidRunAtError, IntToString(i));
- return false;
- }
-
- if (run_location == kRunAtDocumentStartValue) {
- script.set_run_location(UserScript::DOCUMENT_START);
- } else if (run_location == kRunAtDocumentEndValue) {
- script.set_run_location(UserScript::DOCUMENT_END);
- } else {
- *error = FormatErrorMessage(kInvalidRunAtError, IntToString(i));
- return false;
- }
- }
-
- for (size_t j = 0; j < matches->GetSize(); ++j) {
- std::string match_str;
- if (!matches->GetString(j, &match_str)) {
- *error = FormatErrorMessage(kInvalidMatchError, IntToString(i),
- IntToString(j));
- return false;
- }
-
- URLPattern pattern;
- if (!pattern.Parse(match_str)) {
- *error = FormatErrorMessage(kInvalidMatchError, IntToString(i),
- IntToString(j));
- return false;
- }
-
- script.add_url_pattern(pattern);
- }
-
- // TODO(aa): Support multiple files.
- std::string file;
- if (!js->GetString(0, &file)) {
- *error = FormatErrorMessage(kInvalidJsError, IntToString(i),
- IntToString(0));
- return false;
- }
- script.set_path(Extension::GetResourcePath(path(), file));
- script.set_url(Extension::GetResourceURL(url(), file));
-
+ if (!LoadUserScriptHelper(content_script, i, error, &script))
+ return false; // Failed to parse script context definition
content_scripts_.push_back(script);
}
}
diff --git a/chrome/browser/extensions/extension.h b/chrome/browser/extensions/extension.h
index 87290ca..fafe33a 100644
--- a/chrome/browser/extensions/extension.h
+++ b/chrome/browser/extensions/extension.h
@@ -35,6 +35,7 @@ class Extension {
static const wchar_t* kFormatVersionKey;
static const wchar_t* kIdKey;
static const wchar_t* kJsKey;
+ static const wchar_t* kCssKey;
static const wchar_t* kMatchesKey;
static const wchar_t* kNameKey;
static const wchar_t* kRunAtKey;
@@ -51,6 +52,8 @@ class Extension {
// Error messages returned from InitFromValue().
static const char* kInvalidContentScriptError;
static const char* kInvalidContentScriptsListError;
+ static const char* kInvalidCssError;
+ static const char* kInvalidCssListError;
static const char* kInvalidDescriptionError;
static const char* kInvalidFormatVersionError;
static const char* kInvalidIdError;
@@ -62,11 +65,12 @@ class Extension {
static const char* kInvalidMatchError;
static const char* kInvalidMatchesError;
static const char* kInvalidNameError;
+ static const char* kInvalidPluginsDirError;
static const char* kInvalidRunAtError;
+ static const char* kInvalidToolstripError;
static const char* kInvalidVersionError;
static const char* kInvalidZipHashError;
- static const char* kInvalidPluginsDirError;
- static const char* kInvalidToolstripError;
+ static const char* kMissingFileError;
// The number of bytes in a legal id.
static const size_t kIdSize;
@@ -78,6 +82,9 @@ class Extension {
// NOTE: Static so that it can be used from multiple threads.
static GURL GetResourceURL(const GURL& extension_url,
const std::string& relative_path);
+ GURL GetResourceURL(const std::string& relative_path) {
+ return GetResourceURL(url(), relative_path);
+ }
// Returns an absolute path to a resource inside of an extension. The
// |extension_path| argument should be the path() from an Extension object.
@@ -86,6 +93,9 @@ class Extension {
// NOTE: Static so that it can be used from multiple threads.
static FilePath GetResourcePath(const FilePath& extension_path,
const std::string& relative_path);
+ FilePath GetResourcePath(const std::string& relative_path) {
+ return GetResourcePath(path(), relative_path);
+ }
// Initialize the extension from a parsed manifest.
bool InitFromValue(const DictionaryValue& value, std::string* error);
@@ -110,6 +120,12 @@ class Extension {
const GURL& toolstrip_url() const { return toolstrip_url_; }
private:
+ // Helper method that loads a UserScript object from a
+ // dictionary in the content_script list of the manifest.
+ bool LoadUserScriptHelper(const DictionaryValue* content_script,
+ int definition_index,
+ std::string* error,
+ UserScript* result);
// The absolute path to the directory the extension is stored in.
FilePath path_;
diff --git a/chrome/browser/extensions/extension_unittest.cc b/chrome/browser/extensions/extension_unittest.cc
index aa8d791..646a0f4 100644
--- a/chrome/browser/extensions/extension_unittest.cc
+++ b/chrome/browser/extensions/extension_unittest.cc
@@ -134,17 +134,24 @@ TEST(ExtensionTest, InitFromValueInvalid) {
input_value->GetList(Extension::kContentScriptsKey, &content_scripts);
content_scripts->GetDictionary(0, &user_script);
user_script->Remove(Extension::kJsKey, NULL);
+ user_script->Remove(Extension::kCssKey, NULL);
EXPECT_FALSE(extension.InitFromValue(*input_value, &error));
- EXPECT_TRUE(MatchPattern(error, Extension::kInvalidJsListError));
+ EXPECT_TRUE(MatchPattern(error, Extension::kMissingFileError));
user_script->Set(Extension::kJsKey, Value::CreateIntegerValue(42));
EXPECT_FALSE(extension.InitFromValue(*input_value, &error));
EXPECT_TRUE(MatchPattern(error, Extension::kInvalidJsListError));
+ user_script->Set(Extension::kCssKey, new ListValue);
+ user_script->Set(Extension::kJsKey, new ListValue);
+ EXPECT_FALSE(extension.InitFromValue(*input_value, &error));
+ EXPECT_TRUE(MatchPattern(error, Extension::kMissingFileError));
+ user_script->Remove(Extension::kCssKey, NULL);
+
ListValue* files = new ListValue;
user_script->Set(Extension::kJsKey, files);
EXPECT_FALSE(extension.InitFromValue(*input_value, &error));
- EXPECT_TRUE(MatchPattern(error, Extension::kInvalidJsCountError));
+ EXPECT_TRUE(MatchPattern(error, Extension::kMissingFileError));
// Test invalid file element
files->Set(0, Value::CreateIntegerValue(42));
@@ -156,6 +163,20 @@ TEST(ExtensionTest, InitFromValueInvalid) {
files->Set(1, Value::CreateStringValue("bar.js"));
EXPECT_FALSE(extension.InitFromValue(*input_value, &error));
EXPECT_TRUE(MatchPattern(error, Extension::kInvalidJsCountError));
+
+ // Remove all script files
+ user_script->Remove(Extension::kJsKey, NULL);
+ // Test the css element
+ user_script->Set(Extension::kCssKey, Value::CreateIntegerValue(42));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, &error));
+ EXPECT_TRUE(MatchPattern(error, Extension::kInvalidCssListError));
+
+ // Test invalid file element
+ ListValue* css_files = new ListValue;
+ user_script->Set(Extension::kCssKey, css_files);
+ css_files->Set(0, Value::CreateIntegerValue(42));
+ EXPECT_FALSE(extension.InitFromValue(*input_value, &error));
+ EXPECT_TRUE(MatchPattern(error, Extension::kInvalidCssError));
}
TEST(ExtensionTest, InitFromValueValid) {
diff --git a/chrome/browser/extensions/extensions_service.cc b/chrome/browser/extensions/extensions_service.cc
index 1b66bea..2c3451b 100644
--- a/chrome/browser/extensions/extensions_service.cc
+++ b/chrome/browser/extensions/extensions_service.cc
@@ -298,14 +298,27 @@ Extension* ExtensionsServiceBackend::LoadExtension(
}
// Validate that claimed resources actually exist.
- for (UserScriptList::const_iterator iter =
- extension->content_scripts().begin();
- iter != extension->content_scripts().end(); ++iter) {
- if (!file_util::PathExists(iter->path())) {
- ReportExtensionLoadError(extension_path,
- StringPrintf("Could not load content script '%s'.",
- WideToUTF8(iter->path().ToWStringHack()).c_str()));
- return NULL;
+ for (size_t i = 0; i < extension->content_scripts().size(); ++i) {
+ const UserScript& script = extension->content_scripts()[i];
+
+ for (size_t j = 0; j < script.js_scripts().size(); j++) {
+ const FilePath& path = script.js_scripts()[j].path();
+ if (!file_util::PathExists(path)) {
+ ReportExtensionLoadError(extension_path,
+ StringPrintf("Could not load '%s' for content script.",
+ WideToUTF8(path.ToWStringHack()).c_str()));
+ return NULL;
+ }
+ }
+
+ for (size_t j = 0; j < script.css_scripts().size(); j++) {
+ const FilePath& path = script.css_scripts()[j].path();
+ if (!file_util::PathExists(path)) {
+ ReportExtensionLoadError(extension_path,
+ StringPrintf("Could not load '%s' for content script.",
+ WideToUTF8(path.ToWStringHack()).c_str()));
+ return NULL;
+ }
}
}
diff --git a/chrome/browser/extensions/extensions_service_unittest.cc b/chrome/browser/extensions/extensions_service_unittest.cc
index 304aba4..493551c3 100644
--- a/chrome/browser/extensions/extensions_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_service_unittest.cc
@@ -176,15 +176,15 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectorySuccess) {
EXPECT_EQ("https://*.google.com/*",
scripts[0].url_patterns()[1].GetAsString());
EXPECT_EQ(extension->path().AppendASCII("script1.js").value(),
- scripts[0].path().value());
+ scripts[0].js_scripts()[0].path().value());
EXPECT_EQ(1u, scripts[1].url_patterns().size());
EXPECT_EQ("http://*.yahoo.com/*", scripts[1].url_patterns()[0].GetAsString());
EXPECT_EQ(extension->path().AppendASCII("script2.js").value(),
- scripts[1].path().value());
+ scripts[1].js_scripts()[0].path().value());
EXPECT_EQ(1u, scripts[2].url_patterns().size());
EXPECT_EQ("http://*.news.com/*", scripts[2].url_patterns()[0].GetAsString());
EXPECT_EQ(extension->path().AppendASCII("js_files").AppendASCII("script3.js")
- .value(), scripts[2].path().value());
+ .value(), scripts[2].js_scripts()[0].path().value());
EXPECT_EQ(std::string("10123456789abcdef0123456789abcdef0123456"),
frontend->extensions()->at(1)->id());
@@ -231,7 +231,7 @@ TEST_F(ExtensionsServiceTest, LoadAllExtensionsFromDirectoryFail) {
EXPECT_TRUE(MatchPattern(GetErrors()[1],
std::string("Could not load extension from '*'. ") +
- Extension::kInvalidJsListError)) << GetErrors()[1];
+ Extension::kMissingFileError)) << GetErrors()[1];
EXPECT_TRUE(MatchPattern(GetErrors()[2],
std::string("Could not load extension from '*'. ") +
diff --git a/chrome/browser/extensions/extensions_ui.cc b/chrome/browser/extensions/extensions_ui.cc
index 3048172..ee273dc 100644
--- a/chrome/browser/extensions/extensions_ui.cc
+++ b/chrome/browser/extensions/extensions_ui.cc
@@ -85,23 +85,35 @@ void ExtensionsDOMHandler::HandleRequestExtensionsData(const Value* value) {
dom_ui_->CallJavascriptFunction(L"returnExtensionsData", results);
}
+static void CreateScriptFileDetailValue(
+ const FilePath& extension_path, const UserScript::FileList& scripts,
+ const wchar_t* key, DictionaryValue* script_data) {
+ if (scripts.empty())
+ return;
+
+ ListValue *list = new ListValue();
+ for (size_t i = 0; i < scripts.size(); ++i) {
+ const UserScript::File &file = scripts[i];
+ // We are passing through GURLs to canonicalize the output to a valid
+ // URL path fragment.
+ GURL script_url = net::FilePathToFileURL(file.path());
+ GURL extension_url = net::FilePathToFileURL(extension_path);
+ std::string relative_path =
+ script_url.spec().substr(extension_url.spec().length() + 1);
+
+ list->Append(new StringValue(relative_path));
+ }
+ script_data->Set(key, list);
+}
+
// Static
DictionaryValue* ExtensionsDOMHandler::CreateContentScriptDetailValue(
const UserScript& script, const FilePath& extension_path) {
DictionaryValue* script_data = new DictionaryValue();
-
- // TODO(rafaelw): When UserScript supports multiple js, this will have to
- // put them all in this list;
- ListValue *js_list = new ListValue();
- // We are passing through GURLs to canonicalize the output to a valid
- // URL path fragment.
- GURL script_url = net::FilePathToFileURL(script.path());
- GURL extension_url = net::FilePathToFileURL(extension_path);
- std::string relative_js_path =
- script_url.spec().substr(extension_url.spec().length() + 1);
-
- js_list->Append(new StringValue(relative_js_path));
- script_data->Set(L"js", js_list);
+ CreateScriptFileDetailValue(extension_path, script.js_scripts(), L"js",
+ script_data);
+ CreateScriptFileDetailValue(extension_path, script.css_scripts(), L"css",
+ script_data);
// Get list of glob "matches" strings
ListValue *url_pattern_list = new ListValue();
diff --git a/chrome/browser/extensions/user_script_master.cc b/chrome/browser/extensions/user_script_master.cc
index 2f50371..bf0ba7e 100644
--- a/chrome/browser/extensions/user_script_master.cc
+++ b/chrome/browser/extensions/user_script_master.cc
@@ -16,9 +16,11 @@
#include "chrome/common/url_constants.h"
#include "net/base/net_util.h"
-// static
-bool GetDeclarationValue(const StringPiece& line, const StringPiece& prefix,
- std::string* value) {
+
+// Helper function to parse greasesmonkey headers
+static bool GetDeclarationValue(const StringPiece& line,
+ const StringPiece& prefix,
+ std::string* value) {
if (!line.starts_with(prefix))
return false;
@@ -126,20 +128,17 @@ void UserScriptMaster::ScriptReloader::NotifyMaster(
Release();
}
-void UserScriptMaster::ScriptReloader::RunScan(
- const FilePath script_dir, const UserScriptList lone_scripts) {
- base::SharedMemory* shared_memory = GetNewScripts(script_dir, lone_scripts);
-
- // Post the new scripts back to the master's message loop.
- master_message_loop_->PostTask(FROM_HERE,
- NewRunnableMethod(this,
- &UserScriptMaster::ScriptReloader::NotifyMaster,
- shared_memory));
+static void LoadScriptContent(UserScript::File* script_file) {
+ std::string content;
+ CHECK(file_util::ReadFileToString(script_file->path(), &content)) <<
+ "Failed to read script content: " << script_file->path().value();
+ script_file->set_content(content);
}
-base::SharedMemory* UserScriptMaster::ScriptReloader::GetNewScripts(
- const FilePath& script_dir, const UserScriptList& lone_scripts) {
- UserScriptList all_scripts;
+void UserScriptMaster::ScriptReloader::LoadScriptsFromDirectory(
+ const FilePath script_dir, UserScriptList* result) {
+ // Clear the list. We will populate it with the scrips found in script_dir.
+ result->clear();
// Find all the scripts in |script_dir|.
if (!script_dir.value().empty()) {
@@ -152,42 +151,55 @@ base::SharedMemory* UserScriptMaster::ScriptReloader::GetNewScripts(
FILE_PATH_LITERAL("*.user.js"));
for (FilePath file = enumerator.Next(); !file.value().empty();
file = enumerator.Next()) {
- all_scripts.push_back(UserScript());
- UserScript& info = all_scripts.back();
- info.set_url(GURL(std::string(chrome::kUserScriptScheme) + ":/" +
- net::FilePathToFileURL(file.ToWStringHack()).ExtractFileName()));
- info.set_path(file);
+ result->push_back(UserScript());
+ UserScript& user_script = result->back();
+ // Push single js file in this UserScript.
+ GURL url(std::string(chrome::kUserScriptScheme) + ":/" +
+ net::FilePathToFileURL(file.ToWStringHack()).ExtractFileName());
+ user_script.js_scripts().push_back(UserScript::File(file, url));
+ UserScript::File& script_file = user_script.js_scripts().back();
+ LoadScriptContent(&script_file);
+ ParseMetadataHeader(script_file.GetContent(), &user_script);
}
}
+}
- if (all_scripts.empty() && lone_scripts.empty())
- return NULL;
-
- // Add all the lone scripts.
- all_scripts.insert(all_scripts.end(), lone_scripts.begin(),
- lone_scripts.end());
-
- // Load and pickle each script. Look for a metadata header if there are no
- // url_patterns specified already.
- Pickle pickle;
- pickle.WriteSize(all_scripts.size());
- for (UserScriptList::iterator iter = all_scripts.begin();
- iter != all_scripts.end(); ++iter) {
- // TODO(aa): Support unicode script files.
- std::string contents;
- file_util::ReadFileToString(iter->path().ToWStringHack(), &contents);
-
- if (iter->url_patterns().empty()) {
- // TODO(aa): Handle errors parsing header.
- if (!ParseMetadataHeader(contents, &(*iter)))
- return NULL;
+static void LoadLoneScripts(UserScriptList lone_script) {
+ for (size_t i = 0; i < lone_script.size(); ++i) {
+ for (size_t k = 0; k < lone_script[i].js_scripts().size(); ++k) {
+ UserScript::File& script_file = lone_script[i].js_scripts()[k];
+ if (script_file.GetContent().empty()) {
+ LoadScriptContent(&script_file);
+ }
}
+ for (size_t k = 0; k < lone_script[i].css_scripts().size(); ++k) {
+ UserScript::File& script_file = lone_script[i].css_scripts()[k];
+ if (script_file.GetContent().empty()) {
+ LoadScriptContent(&script_file);
+ }
+ }
+ }
+}
- iter->Pickle(&pickle);
-
+// Pickle user scripts and return pointer to the shared memory.
+static base::SharedMemory* Serialize(UserScriptList& scripts) {
+ if (scripts.empty())
+ return NULL; // Nothing to serialize
+ Pickle pickle;
+ pickle.WriteSize(scripts.size());
+ for (size_t i = 0; i < scripts.size(); i++) {
+ UserScript& script = scripts[i];
+ script.Pickle(&pickle);
// Write scripts as 'data' so that we can read it out in the slave without
// allocating a new string.
- pickle.WriteData(contents.c_str(), contents.length());
+ for (size_t j = 0; j < script.js_scripts().size(); j++) {
+ StringPiece contents = script.js_scripts()[j].GetContent();
+ pickle.WriteData(contents.data(), contents.length());
+ }
+ for (size_t j = 0; j < script.css_scripts().size(); j++) {
+ StringPiece contents = script.css_scripts()[j].GetContent();
+ pickle.WriteData(contents.data(), contents.length());
+ }
}
// Create the shared memory object.
@@ -210,6 +222,31 @@ base::SharedMemory* UserScriptMaster::ScriptReloader::GetNewScripts(
return shared_memory.release();
}
+// This method will be called from the file thread
+void UserScriptMaster::ScriptReloader::RunScan(
+ const FilePath script_dir, UserScriptList lone_script) {
+ UserScriptList scripts;
+ // Get list of user scripts.
+ if (!script_dir.empty())
+ LoadScriptsFromDirectory(script_dir, &scripts);
+
+ LoadLoneScripts(lone_script);
+
+ // Merge with the explicit scripts
+ scripts.reserve(scripts.size() + lone_script.size());
+ scripts.insert(scripts.end(),
+ lone_script.begin(), lone_script.end());
+
+ // Scripts now contains list of up-to-date scripts. Load the content in the
+ // shared memory and let the master know it's ready. We need to post the task
+ // back even if no scripts ware found to balance the AddRef/Release calls
+ master_message_loop_->PostTask(FROM_HERE,
+ NewRunnableMethod(this,
+ &ScriptReloader::NotifyMaster,
+ Serialize(scripts)));
+}
+
+
UserScriptMaster::UserScriptMaster(MessageLoop* worker_loop,
const FilePath& script_dir)
: user_script_dir_(script_dir),
diff --git a/chrome/browser/extensions/user_script_master.h b/chrome/browser/extensions/user_script_master.h
index f156180..d546b62 100644
--- a/chrome/browser/extensions/user_script_master.h
+++ b/chrome/browser/extensions/user_script_master.h
@@ -74,6 +74,9 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
static bool ParseMetadataHeader(const StringPiece& script_text,
UserScript* script);
+ static void LoadScriptsFromDirectory(const FilePath script_dir,
+ UserScriptList* result);
+
ScriptReloader(UserScriptMaster* master)
: master_(master), master_message_loop_(MessageLoop::current()) {}
@@ -91,8 +94,8 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
// Where functions are run:
// master file
// StartScan -> RunScan
- // GetNewScripts()
- // ParseMetadataHeader()
+ // LoadScriptsFromDirectory()
+ // LoadLoneScripts()
// NotifyMaster <- RunScan
// Runs on the master thread.
@@ -103,13 +106,7 @@ class UserScriptMaster : public base::RefCounted<UserScriptMaster>,
// Scan the specified directory and lone scripts, calling NotifyMaster when
// done. The parameters are intentionally passed by value so their lifetimes
// aren't tied to the caller.
- void RunScan(const FilePath script_dir, const UserScriptList lone_scripts);
-
- // Runs on the File thread.
- // Scan the script directory and lone scripts, returning either a new
- // SharedMemory or NULL on error.
- base::SharedMemory* GetNewScripts(const FilePath& script_dir,
- const UserScriptList& lone_scripts);
+ void RunScan(const FilePath script_dir, UserScriptList lone_scripts);
// A pointer back to our master.
// May be NULL if DisownMaster() is called.