diff options
author | georged@chromium.org <georged@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-18 21:26:24 +0000 |
---|---|---|
committer | georged@chromium.org <georged@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-03-18 21:26:24 +0000 |
commit | 3cfbd0eb2afd2cf0b8b248d6bb97ec39b064cd23 (patch) | |
tree | eaa3eddbc15cf6bac88d04c4766778fd545f95c0 /chrome/browser | |
parent | 836827406c7135b0225474d24b9d08dd8edff27a (diff) | |
download | chromium_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.cc | 220 | ||||
-rw-r--r-- | chrome/browser/extensions/extension.h | 20 | ||||
-rw-r--r-- | chrome/browser/extensions/extension_unittest.cc | 25 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service.cc | 29 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_service_unittest.cc | 8 | ||||
-rw-r--r-- | chrome/browser/extensions/extensions_ui.cc | 38 | ||||
-rw-r--r-- | chrome/browser/extensions/user_script_master.cc | 125 | ||||
-rw-r--r-- | chrome/browser/extensions/user_script_master.h | 15 |
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. |