|
@@ -51,9 +51,7 @@ constexpr char kDuplicateFileSpecifiedError[] =
|
|
|
"Duplicate file specified: '*'.";
|
|
|
constexpr char kExactlyOneOfCssAndFilesError[] =
|
|
|
"Exactly one of 'css' and 'files' must be specified.";
|
|
|
-constexpr char kFilesExceededSizeLimitError[] =
|
|
|
- "Scripts could not be loaded because '*' exceeds the maximum script size "
|
|
|
- "or the extension's maximum total script size.";
|
|
|
+constexpr char kNonExistentScriptIdError[] = "Nonexistent script ID '*'";
|
|
|
|
|
|
// Note: CSS always injects as soon as possible, so we default to
|
|
|
// document_start. Because of tab loading, there's no guarantee this will
|
|
@@ -61,45 +59,6 @@ constexpr char kFilesExceededSizeLimitError[] =
|
|
|
constexpr mojom::RunLocation kCSSRunLocation =
|
|
|
mojom::RunLocation::kDocumentStart;
|
|
|
|
|
|
-// Returns if the extension provided `script_id` (without an internal UserScript
|
|
|
-// prefix) is valid and populates `error` if invalid.
|
|
|
-bool IsScriptIDValid(const std::string& script_id, std::string* error) {
|
|
|
- if (script_id.empty()) {
|
|
|
- *error = "Script's ID must not be empty";
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if (script_id[0] == UserScript::kReservedScriptIDPrefix) {
|
|
|
- *error = base::StringPrintf("Script's ID '%s' must not start with '%c'",
|
|
|
- script_id.c_str(),
|
|
|
- UserScript::kReservedScriptIDPrefix);
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
-// Iterates over `scripts` and adds a prefix to each script's id to indicate
|
|
|
-// that the script is a dynamic content script. Returns false and populates
|
|
|
-// `error` if any extension provided id in `scripts` is invalid. While this
|
|
|
-// might result in only some of the ids in `scripts` being modified, this should
|
|
|
-// have no effect on API calls as the API method handler will return with
|
|
|
-// `error`.
|
|
|
-bool AddDynamicScriptPrefixToScriptIDs(
|
|
|
- std::vector<api::scripting::RegisteredContentScript>& scripts,
|
|
|
- std::string* error) {
|
|
|
- CHECK(error);
|
|
|
- for (auto& script : scripts) {
|
|
|
- if (!IsScriptIDValid(script.id, error)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- script.id = scripting::CreateDynamicScriptID(script.id);
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
-}
|
|
|
-
|
|
|
// Converts the given `style_origin` to a CSSOrigin.
|
|
|
mojom::CSSOrigin ConvertStyleOriginToCSSOrigin(
|
|
|
api::scripting::StyleOrigin style_origin) {
|
|
@@ -537,37 +496,12 @@ std::unique_ptr<UserScript> ParseUserScript(
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-ValidateContentScriptsResult ValidateParsedScriptsOnFileThread(
|
|
|
- ExtensionResource::SymlinkPolicy symlink_policy,
|
|
|
- std::unique_ptr<UserScriptList> scripts) {
|
|
|
- DCHECK(GetExtensionFileTaskRunner()->RunsTasksInCurrentSequence());
|
|
|
-
|
|
|
- // Validate that claimed script resources actually exist, and are UTF-8
|
|
|
- // encoded.
|
|
|
- std::string error;
|
|
|
- std::vector<InstallWarning> warnings;
|
|
|
- bool are_script_files_valid = script_parsing::ValidateFileSources(
|
|
|
- *scripts, symlink_policy, &error, &warnings);
|
|
|
-
|
|
|
- // Script files over the per script/extension limit are recorded as warnings.
|
|
|
- // However, for the scripting API we should treat "install warnings" as
|
|
|
- // errors by turning this call into a no-op and returning an error.
|
|
|
- if (!warnings.empty() && error.empty()) {
|
|
|
- error = ErrorUtils::FormatErrorMessage(kFilesExceededSizeLimitError,
|
|
|
- warnings[0].specific);
|
|
|
- are_script_files_valid = false;
|
|
|
- }
|
|
|
-
|
|
|
- return std::make_pair(std::move(scripts), are_script_files_valid
|
|
|
- ? absl::nullopt
|
|
|
- : absl::make_optional(error));
|
|
|
-}
|
|
|
-
|
|
|
// Converts a UserScript object to a api::scripting::RegisteredContentScript
|
|
|
// object, used for getRegisteredContentScripts.
|
|
|
api::scripting::RegisteredContentScript CreateRegisteredContentScriptInfo(
|
|
|
const UserScript& script) {
|
|
|
api::scripting::RegisteredContentScript script_info;
|
|
|
+ CHECK_EQ(UserScript::Source::kDynamicContentScript, script.GetSource());
|
|
|
script_info.id = script.id();
|
|
|
|
|
|
script_info.matches.emplace();
|
|
@@ -965,18 +899,23 @@ ScriptingRegisterContentScriptsFunction::
|
|
|
ScriptingRegisterContentScriptsFunction::
|
|
|
~ScriptingRegisterContentScriptsFunction() = default;
|
|
|
|
|
|
-ExtensionFunction::ResponseAction
|
|
|
-ScriptingRegisterContentScriptsFunction::Run() {
|
|
|
- absl::optional<api::scripting::RegisterContentScripts::Params> params =
|
|
|
- api::scripting::RegisterContentScripts::Params::Create(args());
|
|
|
+ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
|
|
+ absl::optional<api::scripting::UpdateContentScripts::Params> params =
|
|
|
+ api::scripting::UpdateContentScripts::Params::Create(args());
|
|
|
EXTENSION_FUNCTION_VALIDATE(params);
|
|
|
|
|
|
std::vector<api::scripting::RegisteredContentScript>& scripts =
|
|
|
params->scripts;
|
|
|
std::string error;
|
|
|
+
|
|
|
// Add the prefix for dynamic content scripts onto the IDs of all scripts in
|
|
|
// `scripts` before continuing.
|
|
|
- if (!AddDynamicScriptPrefixToScriptIDs(scripts, &error)) {
|
|
|
+ std::set<std::string> ids_to_update = scripting::CreateDynamicScriptIds(
|
|
|
+ scripts, UserScript::Source::kDynamicContentScript,
|
|
|
+ std::set<std::string>(), &error);
|
|
|
+
|
|
|
+ if (!error.empty()) {
|
|
|
+ CHECK(ids_to_update.empty());
|
|
|
return RespondNow(Error(std::move(error)));
|
|
|
}
|
|
|
|
|
@@ -984,64 +923,100 @@ ScriptingRegisterContentScriptsFunction::Run() {
|
|
|
ExtensionSystem::Get(browser_context())
|
|
|
->user_script_manager()
|
|
|
->GetUserScriptLoaderForExtension(extension()->id());
|
|
|
- std::set<std::string> existing_script_ids = loader->GetDynamicScriptIDs();
|
|
|
- std::set<std::string> new_script_ids;
|
|
|
|
|
|
- for (const auto& script : scripts) {
|
|
|
- if (base::Contains(existing_script_ids, script.id) ||
|
|
|
- base::Contains(new_script_ids, script.id)) {
|
|
|
- std::string error_script_id =
|
|
|
- UserScript::TrimPrefixFromScriptID(script.id);
|
|
|
- return RespondNow(Error(base::StringPrintf("Duplicate script ID '%s'",
|
|
|
- error_script_id.c_str())));
|
|
|
+ std::map<std::string, api::scripting::RegisteredContentScript>
|
|
|
+ loaded_scripts_metadata;
|
|
|
+ const UserScriptList& dynamic_scripts = loader->GetLoadedDynamicScripts();
|
|
|
+ for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
|
|
|
+ if (script->GetSource() == UserScript::Source::kDynamicContentScript) {
|
|
|
+ loaded_scripts_metadata.emplace(
|
|
|
+ script->id(), CreateRegisteredContentScriptInfo(*script));
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- new_script_ids.insert(script.id);
|
|
|
+ for (const auto& script : scripts) {
|
|
|
+ std::string error_script_id = UserScript::TrimPrefixFromScriptID(script.id);
|
|
|
+ if (loaded_scripts_metadata.find(script.id) ==
|
|
|
+ loaded_scripts_metadata.end()) {
|
|
|
+ return RespondNow(
|
|
|
+ Error(base::StringPrintf("Script with ID '%s' does not exist "
|
|
|
+ "or is not fully registered",
|
|
|
+ error_script_id.c_str())));
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
std::u16string parse_error;
|
|
|
auto parsed_scripts = std::make_unique<UserScriptList>();
|
|
|
- std::set<std::string> persistent_script_ids;
|
|
|
const int valid_schemes = UserScript::ValidUserScriptSchemes(
|
|
|
scripting::kScriptsCanExecuteEverywhere);
|
|
|
|
|
|
+ std::set<std::string> updated_script_ids_to_persist;
|
|
|
+ std::set<std::string> persistent_script_ids =
|
|
|
+ loader->GetPersistentDynamicScriptIDs();
|
|
|
+
|
|
|
parsed_scripts->reserve(scripts.size());
|
|
|
for (size_t i = 0; i < scripts.size(); ++i) {
|
|
|
- if (!scripts[i].matches) {
|
|
|
- std::string error_script_id =
|
|
|
- UserScript::TrimPrefixFromScriptID(scripts[i].id);
|
|
|
- return RespondNow(
|
|
|
- Error(base::StringPrintf("Script with ID '%s' must specify 'matches'",
|
|
|
- error_script_id.c_str())));
|
|
|
+ api::scripting::RegisteredContentScript& update_delta = scripts[i];
|
|
|
+ DCHECK(base::Contains(loaded_scripts_metadata, update_delta.id));
|
|
|
+
|
|
|
+ api::scripting::RegisteredContentScript& updated_script =
|
|
|
+ loaded_scripts_metadata[update_delta.id];
|
|
|
+
|
|
|
+ if (update_delta.matches)
|
|
|
+ updated_script.matches = std::move(update_delta.matches);
|
|
|
+
|
|
|
+ if (update_delta.exclude_matches)
|
|
|
+ updated_script.exclude_matches = std::move(update_delta.exclude_matches);
|
|
|
+
|
|
|
+ if (update_delta.js)
|
|
|
+ updated_script.js = std::move(update_delta.js);
|
|
|
+
|
|
|
+ if (update_delta.css)
|
|
|
+ updated_script.css = std::move(update_delta.css);
|
|
|
+
|
|
|
+ if (update_delta.all_frames)
|
|
|
+ *updated_script.all_frames = *update_delta.all_frames;
|
|
|
+
|
|
|
+ if (update_delta.match_origin_as_fallback) {
|
|
|
+ *updated_script.match_origin_as_fallback =
|
|
|
+ *update_delta.match_origin_as_fallback;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (update_delta.run_at != api::extension_types::RunAt::kNone) {
|
|
|
+ updated_script.run_at = update_delta.run_at;
|
|
|
}
|
|
|
|
|
|
// Parse/Create user script.
|
|
|
std::unique_ptr<UserScript> user_script =
|
|
|
- ParseUserScript(browser_context(), *extension(), scripts[i], i,
|
|
|
+ ParseUserScript(browser_context(), *extension(), updated_script, i,
|
|
|
valid_schemes, &parse_error);
|
|
|
if (!user_script)
|
|
|
return RespondNow(Error(base::UTF16ToASCII(parse_error)));
|
|
|
|
|
|
- // Scripts will persist across sessions by default.
|
|
|
- if (!scripts[i].persist_across_sessions ||
|
|
|
- *scripts[i].persist_across_sessions) {
|
|
|
- persistent_script_ids.insert(user_script->id());
|
|
|
+ // Persist the updated script if the flag is specified as true, or if the
|
|
|
+ // original script is persisted and the flag is not specified.
|
|
|
+ if ((update_delta.persist_across_sessions &&
|
|
|
+ *update_delta.persist_across_sessions) ||
|
|
|
+ (!update_delta.persist_across_sessions &&
|
|
|
+ base::Contains(persistent_script_ids, update_delta.id))) {
|
|
|
+ updated_script_ids_to_persist.insert(update_delta.id);
|
|
|
}
|
|
|
+
|
|
|
parsed_scripts->push_back(std::move(user_script));
|
|
|
}
|
|
|
|
|
|
// Add new script IDs now in case another call with the same script IDs is
|
|
|
// made immediately following this one.
|
|
|
- loader->AddPendingDynamicScriptIDs(std::move(new_script_ids));
|
|
|
+ loader->AddPendingDynamicScriptIDs(std::move(ids_to_update));
|
|
|
|
|
|
GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult(
|
|
|
FROM_HERE,
|
|
|
- base::BindOnce(&ValidateParsedScriptsOnFileThread,
|
|
|
+ base::BindOnce(&scripting::ValidateParsedScriptsOnFileThread,
|
|
|
script_parsing::GetSymlinkPolicy(extension()),
|
|
|
std::move(parsed_scripts)),
|
|
|
- base::BindOnce(&ScriptingRegisterContentScriptsFunction::
|
|
|
- OnContentScriptFilesValidated,
|
|
|
- this, std::move(persistent_script_ids)));
|
|
|
+ base::BindOnce(
|
|
|
+ &ScriptingUpdateContentScriptsFunction::OnContentScriptFilesValidated,
|
|
|
+ this, std::move(updated_script_ids_to_persist)));
|
|
|
|
|
|
// Balanced in `OnContentScriptFilesValidated()` or
|
|
|
// `OnContentScriptsRegistered()`.
|
|
@@ -1051,10 +1026,11 @@ ScriptingRegisterContentScriptsFunction::Run() {
|
|
|
|
|
|
void ScriptingRegisterContentScriptsFunction::OnContentScriptFilesValidated(
|
|
|
std::set<std::string> persistent_script_ids,
|
|
|
- ValidateContentScriptsResult result) {
|
|
|
+ scripting::ValidateScriptsResult result) {
|
|
|
// We cannot proceed if the `browser_context` is not valid as the
|
|
|
// `ExtensionSystem` will not exist.
|
|
|
if (!browser_context()) {
|
|
|
+ Release(); // Matches the `AddRef()` in `Run()`.
|
|
|
return;
|
|
|
}
|
|
|
|
|
@@ -1067,8 +1043,9 @@ void ScriptingRegisterContentScriptsFunction::OnContentScriptFilesValidated(
|
|
|
|
|
|
if (error.has_value()) {
|
|
|
std::set<std::string> ids_to_remove;
|
|
|
- for (const auto& script : *scripts)
|
|
|
+ for (const auto& script : *scripts) {
|
|
|
ids_to_remove.insert(script->id());
|
|
|
+ }
|
|
|
|
|
|
loader->RemovePendingDynamicScriptIDs(std::move(ids_to_remove));
|
|
|
Respond(Error(std::move(*error)));
|
|
@@ -1108,7 +1085,8 @@ ScriptingGetRegisteredContentScriptsFunction::Run() {
|
|
|
std::set<std::string> id_filter;
|
|
|
if (filter && filter->ids) {
|
|
|
for (const std::string& id : *(filter->ids)) {
|
|
|
- id_filter.insert(scripting::CreateDynamicScriptID(id));
|
|
|
+ id_filter.insert(scripting::AddPrefixToDynamicScriptId(
|
|
|
+ id, UserScript::Source::kDynamicContentScript));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1122,16 +1100,19 @@ ScriptingGetRegisteredContentScriptsFunction::Run() {
|
|
|
std::set<std::string> persistent_script_ids =
|
|
|
loader->GetPersistentDynamicScriptIDs();
|
|
|
for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
|
|
|
- if (id_filter.empty() || base::Contains(id_filter, script->id())) {
|
|
|
- auto registered_script = CreateRegisteredContentScriptInfo(*script);
|
|
|
- registered_script.persist_across_sessions =
|
|
|
- base::Contains(persistent_script_ids, script->id());
|
|
|
-
|
|
|
- // Remove the internally used prefix from the `script`'s ID before
|
|
|
- // returning.
|
|
|
- registered_script.id = script->GetIDWithoutPrefix();
|
|
|
- script_infos.push_back(std::move(registered_script));
|
|
|
+ if (script->GetSource() != UserScript::Source::kDynamicContentScript) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ if (!id_filter.empty() && !base::Contains(id_filter, script->id())) {
|
|
|
+ continue;
|
|
|
}
|
|
|
+ auto registered_script = CreateRegisteredContentScriptInfo(*script);
|
|
|
+ registered_script.persist_across_sessions =
|
|
|
+ base::Contains(persistent_script_ids, script->id());
|
|
|
+ // Remove the internally used prefix from the `script`'s ID before
|
|
|
+ // returning.
|
|
|
+ registered_script.id = script->GetIDWithoutPrefix();
|
|
|
+ script_infos.push_back(std::move(registered_script));
|
|
|
}
|
|
|
|
|
|
return RespondNow(
|
|
@@ -1151,48 +1132,50 @@ ScriptingUnregisterContentScriptsFunction::Run() {
|
|
|
EXTENSION_FUNCTION_VALIDATE(params);
|
|
|
|
|
|
absl::optional<api::scripting::ContentScriptFilter>& filter = params->filter;
|
|
|
- std::set<std::string> ids_to_remove;
|
|
|
-
|
|
|
ExtensionUserScriptLoader* loader =
|
|
|
ExtensionSystem::Get(browser_context())
|
|
|
->user_script_manager()
|
|
|
->GetUserScriptLoaderForExtension(extension()->id());
|
|
|
- std::set<std::string> existing_script_ids = loader->GetDynamicScriptIDs();
|
|
|
- if (filter && filter->ids) {
|
|
|
- for (const auto& provided_id : *filter->ids) {
|
|
|
- std::string error;
|
|
|
- if (!IsScriptIDValid(provided_id, &error)) {
|
|
|
- return RespondNow(Error(std::move(error)));
|
|
|
- }
|
|
|
-
|
|
|
- // Add the dynamic content script prefix to `provided_id` before checking
|
|
|
- // against `existing_script_ids`.
|
|
|
- std::string id_with_prefix =
|
|
|
- scripting::CreateDynamicScriptID(provided_id);
|
|
|
- if (!base::Contains(existing_script_ids, id_with_prefix)) {
|
|
|
- return RespondNow(Error(base::StringPrintf("Nonexistent script ID '%s'",
|
|
|
- provided_id.c_str())));
|
|
|
- }
|
|
|
-
|
|
|
- ids_to_remove.insert(id_with_prefix);
|
|
|
- }
|
|
|
- }
|
|
|
|
|
|
// TODO(crbug.com/1300657): Only clear all scripts if `filter` did not specify
|
|
|
// the list of scripts ids to remove.
|
|
|
- if (ids_to_remove.empty()) {
|
|
|
+ if (!filter || !filter->ids || filter->ids->empty()) {
|
|
|
loader->ClearDynamicScripts(
|
|
|
+ UserScript::Source::kDynamicContentScript,
|
|
|
base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
|
|
|
OnContentScriptsUnregistered,
|
|
|
this));
|
|
|
- } else {
|
|
|
- loader->RemoveDynamicScripts(
|
|
|
- std::move(ids_to_remove),
|
|
|
- base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
|
|
|
- OnContentScriptsUnregistered,
|
|
|
- this));
|
|
|
+ return RespondLater();
|
|
|
+ }
|
|
|
+
|
|
|
+ std::set<std::string> ids_to_remove;
|
|
|
+ std::set<std::string> existing_script_ids =
|
|
|
+ loader->GetDynamicScriptIDs(UserScript::Source::kDynamicContentScript);
|
|
|
+
|
|
|
+ std::string error;
|
|
|
+ for (const auto& provided_id : *filter->ids) {
|
|
|
+ if (!scripting::IsScriptIdValid(provided_id, &error)) {
|
|
|
+ return RespondNow(Error(std::move(error)));
|
|
|
+ }
|
|
|
+
|
|
|
+ // Add the dynamic content script prefix to `provided_id` before checking
|
|
|
+ // against `existing_script_ids`.
|
|
|
+ std::string id_with_prefix = scripting::AddPrefixToDynamicScriptId(
|
|
|
+ provided_id, UserScript::Source::kDynamicContentScript);
|
|
|
+ if (!base::Contains(existing_script_ids, id_with_prefix)) {
|
|
|
+ return RespondNow(Error(ErrorUtils::FormatErrorMessage(
|
|
|
+ kNonExistentScriptIdError, provided_id.c_str())));
|
|
|
+ }
|
|
|
+
|
|
|
+ ids_to_remove.insert(id_with_prefix);
|
|
|
}
|
|
|
|
|
|
+ loader->RemoveDynamicScripts(
|
|
|
+ std::move(ids_to_remove),
|
|
|
+ base::BindOnce(&ScriptingUnregisterContentScriptsFunction::
|
|
|
+ OnContentScriptsUnregistered,
|
|
|
+ this));
|
|
|
+
|
|
|
return RespondLater();
|
|
|
}
|
|
|
|
|
@@ -1209,124 +1192,75 @@ ScriptingUpdateContentScriptsFunction::ScriptingUpdateContentScriptsFunction() =
|
|
|
ScriptingUpdateContentScriptsFunction::
|
|
|
~ScriptingUpdateContentScriptsFunction() = default;
|
|
|
|
|
|
-ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
|
|
- absl::optional<api::scripting::UpdateContentScripts::Params> params =
|
|
|
- api::scripting::UpdateContentScripts::Params::Create(args());
|
|
|
+ExtensionFunction::ResponseAction
|
|
|
+ScriptingRegisterContentScriptsFunction::Run() {
|
|
|
+ absl::optional<api::scripting::RegisterContentScripts::Params> params =
|
|
|
+ api::scripting::RegisterContentScripts::Params::Create(args());
|
|
|
EXTENSION_FUNCTION_VALIDATE(params);
|
|
|
|
|
|
std::vector<api::scripting::RegisteredContentScript>& scripts =
|
|
|
params->scripts;
|
|
|
- std::string error;
|
|
|
- // Add the prefix for dynamic content scripts onto the IDs of all scripts in
|
|
|
- // `scripts` before continuing.
|
|
|
- if (!AddDynamicScriptPrefixToScriptIDs(scripts, &error)) {
|
|
|
- return RespondNow(Error(std::move(error)));
|
|
|
- }
|
|
|
-
|
|
|
ExtensionUserScriptLoader* loader =
|
|
|
ExtensionSystem::Get(browser_context())
|
|
|
->user_script_manager()
|
|
|
->GetUserScriptLoaderForExtension(extension()->id());
|
|
|
|
|
|
- std::map<std::string, api::scripting::RegisteredContentScript>
|
|
|
- loaded_scripts_metadata;
|
|
|
- const UserScriptList& dynamic_scripts = loader->GetLoadedDynamicScripts();
|
|
|
- for (const std::unique_ptr<UserScript>& script : dynamic_scripts) {
|
|
|
- loaded_scripts_metadata.emplace(script->id(),
|
|
|
- CreateRegisteredContentScriptInfo(*script));
|
|
|
- }
|
|
|
-
|
|
|
- std::set<std::string> ids_to_update;
|
|
|
- for (const auto& script : scripts) {
|
|
|
- std::string error_script_id = UserScript::TrimPrefixFromScriptID(script.id);
|
|
|
- if (loaded_scripts_metadata.find(script.id) ==
|
|
|
- loaded_scripts_metadata.end()) {
|
|
|
- return RespondNow(
|
|
|
- Error(base::StringPrintf("Script with ID '%s' does not exist "
|
|
|
- "or is not fully registered",
|
|
|
- error_script_id.c_str())));
|
|
|
- }
|
|
|
-
|
|
|
- if (base::Contains(ids_to_update, script.id)) {
|
|
|
- return RespondNow(Error(base::StringPrintf("Duplicate script ID '%s'",
|
|
|
- error_script_id.c_str())));
|
|
|
- }
|
|
|
-
|
|
|
- ids_to_update.insert(script.id);
|
|
|
+ // Create script ids for dynamic content scripts.
|
|
|
+ std::string error;
|
|
|
+ std::set<std::string> existing_script_ids =
|
|
|
+ loader->GetDynamicScriptIDs(UserScript::Source::kDynamicContentScript);
|
|
|
+ std::set<std::string> new_script_ids = scripting::CreateDynamicScriptIds(
|
|
|
+ scripts, UserScript::Source::kDynamicContentScript, existing_script_ids,
|
|
|
+ &error);
|
|
|
+
|
|
|
+ if (!error.empty()) {
|
|
|
+ CHECK(new_script_ids.empty());
|
|
|
+ return RespondNow(Error(std::move(error)));
|
|
|
}
|
|
|
|
|
|
+ // Parse content scripts.
|
|
|
std::u16string parse_error;
|
|
|
auto parsed_scripts = std::make_unique<UserScriptList>();
|
|
|
+ std::set<std::string> persistent_script_ids;
|
|
|
const int valid_schemes = UserScript::ValidUserScriptSchemes(
|
|
|
scripting::kScriptsCanExecuteEverywhere);
|
|
|
|
|
|
- std::set<std::string> updated_script_ids_to_persist;
|
|
|
- std::set<std::string> persistent_script_ids =
|
|
|
- loader->GetPersistentDynamicScriptIDs();
|
|
|
-
|
|
|
parsed_scripts->reserve(scripts.size());
|
|
|
for (size_t i = 0; i < scripts.size(); ++i) {
|
|
|
- api::scripting::RegisteredContentScript& update_delta = scripts[i];
|
|
|
- DCHECK(base::Contains(loaded_scripts_metadata, update_delta.id));
|
|
|
-
|
|
|
- api::scripting::RegisteredContentScript& updated_script =
|
|
|
- loaded_scripts_metadata[update_delta.id];
|
|
|
-
|
|
|
- if (update_delta.matches)
|
|
|
- updated_script.matches = std::move(update_delta.matches);
|
|
|
-
|
|
|
- if (update_delta.exclude_matches)
|
|
|
- updated_script.exclude_matches = std::move(update_delta.exclude_matches);
|
|
|
-
|
|
|
- if (update_delta.js)
|
|
|
- updated_script.js = std::move(update_delta.js);
|
|
|
-
|
|
|
- if (update_delta.css)
|
|
|
- updated_script.css = std::move(update_delta.css);
|
|
|
-
|
|
|
- if (update_delta.all_frames)
|
|
|
- *updated_script.all_frames = *update_delta.all_frames;
|
|
|
-
|
|
|
- if (update_delta.match_origin_as_fallback) {
|
|
|
- *updated_script.match_origin_as_fallback =
|
|
|
- *update_delta.match_origin_as_fallback;
|
|
|
- }
|
|
|
-
|
|
|
- if (update_delta.run_at != api::extension_types::RunAt::kNone) {
|
|
|
- updated_script.run_at = update_delta.run_at;
|
|
|
+ if (!scripts[i].matches) {
|
|
|
+ std::string error_script_id =
|
|
|
+ UserScript::TrimPrefixFromScriptID(scripts[i].id);
|
|
|
+ return RespondNow(
|
|
|
+ Error(base::StringPrintf("Script with ID '%s' must specify 'matches'",
|
|
|
+ error_script_id.c_str())));
|
|
|
}
|
|
|
|
|
|
- // Parse/Create user script.
|
|
|
std::unique_ptr<UserScript> user_script =
|
|
|
- ParseUserScript(browser_context(), *extension(), updated_script, i,
|
|
|
+ ParseUserScript(browser_context(), *extension(), scripts[i], i,
|
|
|
valid_schemes, &parse_error);
|
|
|
if (!user_script)
|
|
|
return RespondNow(Error(base::UTF16ToASCII(parse_error)));
|
|
|
|
|
|
- // Persist the updated script if the flag is specified as true, or if the
|
|
|
- // original script is persisted and the flag is not specified.
|
|
|
- if ((update_delta.persist_across_sessions &&
|
|
|
- *update_delta.persist_across_sessions) ||
|
|
|
- (!update_delta.persist_across_sessions &&
|
|
|
- base::Contains(persistent_script_ids, update_delta.id))) {
|
|
|
- updated_script_ids_to_persist.insert(update_delta.id);
|
|
|
+ // Scripts will persist across sessions by default.
|
|
|
+ if (!scripts[i].persist_across_sessions ||
|
|
|
+ *scripts[i].persist_across_sessions) {
|
|
|
+ persistent_script_ids.insert(user_script->id());
|
|
|
}
|
|
|
-
|
|
|
parsed_scripts->push_back(std::move(user_script));
|
|
|
}
|
|
|
|
|
|
// Add new script IDs now in case another call with the same script IDs is
|
|
|
// made immediately following this one.
|
|
|
- loader->AddPendingDynamicScriptIDs(std::move(ids_to_update));
|
|
|
+ loader->AddPendingDynamicScriptIDs(std::move(new_script_ids));
|
|
|
|
|
|
GetExtensionFileTaskRunner()->PostTaskAndReplyWithResult(
|
|
|
FROM_HERE,
|
|
|
- base::BindOnce(&ValidateParsedScriptsOnFileThread,
|
|
|
+ base::BindOnce(&scripting::ValidateParsedScriptsOnFileThread,
|
|
|
script_parsing::GetSymlinkPolicy(extension()),
|
|
|
std::move(parsed_scripts)),
|
|
|
- base::BindOnce(
|
|
|
- &ScriptingUpdateContentScriptsFunction::OnContentScriptFilesValidated,
|
|
|
- this, std::move(updated_script_ids_to_persist)));
|
|
|
+ base::BindOnce(&ScriptingRegisterContentScriptsFunction::
|
|
|
+ OnContentScriptFilesValidated,
|
|
|
+ this, std::move(persistent_script_ids)));
|
|
|
|
|
|
// Balanced in `OnContentScriptFilesValidated()` or
|
|
|
// `OnContentScriptsRegistered()`.
|
|
@@ -1336,10 +1270,11 @@ ExtensionFunction::ResponseAction ScriptingUpdateContentScriptsFunction::Run() {
|
|
|
|
|
|
void ScriptingUpdateContentScriptsFunction::OnContentScriptFilesValidated(
|
|
|
std::set<std::string> persistent_script_ids,
|
|
|
- ValidateContentScriptsResult result) {
|
|
|
+ scripting::ValidateScriptsResult result) {
|
|
|
// We cannot proceed if the `browser_context` is not valid as the
|
|
|
// `ExtensionSystem` will not exist.
|
|
|
if (!browser_context()) {
|
|
|
+ Release(); // Matches the `AddRef()` in `Run()`.
|
|
|
return;
|
|
|
}
|
|
|
|