Index: extensions/browser/api/guest_view/web_view/web_view_internal_api.cc |
diff --git a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc |
index 74c89c6346f931030692756356d28be189b178e3..12e9686c48bbe77cc5e40e9554b9588c5221545d 100644 |
--- a/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc |
+++ b/extensions/browser/api/guest_view/web_view/web_view_internal_api.cc |
@@ -4,6 +4,7 @@ |
#include "extensions/browser/api/guest_view/web_view/web_view_internal_api.h" |
+#include "base/strings/string_number_conversions.h" |
#include "base/strings/stringprintf.h" |
#include "base/strings/utf_string_conversions.h" |
#include "content/public/browser/browser_context.h" |
@@ -13,17 +14,26 @@ |
#include "content/public/common/stop_find_action.h" |
#include "content/public/common/url_fetcher.h" |
#include "extensions/browser/guest_view/web_view/web_view_constants.h" |
+#include "extensions/browser/guest_view/web_view/web_view_content_script_manager.h" |
#include "extensions/common/api/web_view_internal.h" |
#include "extensions/common/error_utils.h" |
+#include "extensions/common/manifest_constants.h" |
+#include "extensions/common/permissions/permissions_data.h" |
+#include "extensions/common/user_script.h" |
#include "net/base/load_flags.h" |
#include "net/url_request/url_fetcher.h" |
#include "net/url_request/url_fetcher_delegate.h" |
#include "third_party/WebKit/public/web/WebFindOptions.h" |
using content::WebContents; |
+using extensions::ExtensionResource; |
+using extensions::core_api::web_view_internal::ContentScriptDetails; |
using extensions::core_api::web_view_internal::SetPermission::Params; |
using extensions::core_api::extension_types::InjectDetails; |
+using extensions::UserScript; |
using ui_zoom::ZoomController; |
+// error messages for content scripts: |
+namespace errors = extensions::manifest_errors; |
namespace web_view_internal = extensions::core_api::web_view_internal; |
namespace { |
@@ -37,6 +47,9 @@ const char kLocalStorageKey[] = "localStorage"; |
const char kWebSQLKey[] = "webSQL"; |
const char kSinceKey[] = "since"; |
const char kLoadFileError[] = "Failed to load file: \"*\". "; |
+const char kViewInstanceIdError[] = "view_instance_id is missing."; |
+const char kDuplicatedContentScriptNamesError[] = |
+ "The given content script name already exists."; |
uint32 MaskForKey(const char* key) { |
if (strcmp(key, kAppCacheKey) == 0) |
@@ -56,6 +69,169 @@ uint32 MaskForKey(const char* key) { |
return 0; |
} |
+HostID GenerateHostIDFromEmbedder(const extensions::Extension* extension, |
+ const content::WebContents* web_contents) { |
+ if (extension) |
+ return HostID(HostID::EXTENSIONS, extension->id()); |
+ |
+ if (web_contents && web_contents->GetWebUI()) { |
+ const GURL& url = web_contents->GetSiteInstance()->GetSiteURL(); |
+ return HostID(HostID::WEBUI, url.spec()); |
+ } |
+ NOTREACHED(); |
+ return HostID(); |
+} |
+ |
+// Parses the values stored in ContentScriptDetails, and constructs a |
+// UserScript. |
+bool ParseContentScript(const ContentScriptDetails& script_value, |
+ const extensions::Extension* extension, |
+ const GURL& owner_base_url, |
+ UserScript* script, |
+ std::string* error) { |
+ // matches (required): |
+ if (script_value.matches.empty()) |
+ return false; |
+ |
+ // The default for WebUI is not having special access, but we can change that |
+ // if needed. |
+ bool allowed_everywhere = false; |
+ if (extension && |
+ extensions::PermissionsData::CanExecuteScriptEverywhere(extension)) |
+ allowed_everywhere = true; |
+ |
+ for (const std::string& match : script_value.matches) { |
+ URLPattern pattern(UserScript::ValidUserScriptSchemes(allowed_everywhere)); |
+ if (pattern.Parse(match) != URLPattern::PARSE_SUCCESS) { |
+ *error = errors::kInvalidMatches; |
+ return false; |
+ } |
+ script->add_url_pattern(pattern); |
+ } |
+ |
+ // exclude_matches: |
+ if (script_value.exclude_matches) { |
+ const std::vector<std::string>& exclude_matches = |
+ *(script_value.exclude_matches.get()); |
+ for (const std::string& exclude_match : exclude_matches) { |
+ URLPattern pattern( |
+ UserScript::ValidUserScriptSchemes(allowed_everywhere)); |
+ |
+ if (pattern.Parse(exclude_match) != URLPattern::PARSE_SUCCESS) { |
+ *error = errors::kInvalidExcludeMatches; |
+ return false; |
+ } |
+ script->add_exclude_url_pattern(pattern); |
+ } |
+ } |
+ // run_at: |
+ if (script_value.run_at) { |
+ UserScript::RunLocation run_at = UserScript::UNDEFINED; |
+ switch (script_value.run_at) { |
+ case extensions::core_api::extension_types::RUN_AT_NONE: |
+ case extensions::core_api::extension_types::RUN_AT_DOCUMENT_IDLE: |
+ run_at = UserScript::DOCUMENT_IDLE; |
+ break; |
+ case extensions::core_api::extension_types::RUN_AT_DOCUMENT_START: |
+ run_at = UserScript::DOCUMENT_START; |
+ break; |
+ case extensions::core_api::extension_types::RUN_AT_DOCUMENT_END: |
+ run_at = UserScript::DOCUMENT_END; |
+ break; |
+ } |
+ // The default for run_at is RUN_AT_DOCUMENT_IDLE. |
+ script->set_run_location(run_at); |
+ } |
+ |
+ // match_about_blank: |
+ if (script_value.match_about_blank) |
+ script->set_match_about_blank(*script_value.match_about_blank); |
+ |
+ // css: |
+ if (script_value.css) { |
+ for (const std::string& relative : *(script_value.css.get())) { |
+ GURL url = owner_base_url.Resolve(relative); |
+ if (extension) { |
+ ExtensionResource resource = extension->GetResource(relative); |
+ script->css_scripts().push_back(UserScript::File( |
+ resource.extension_root(), resource.relative_path(), url)); |
+ } else { |
+ script->css_scripts().push_back(extensions::UserScript::File( |
+ base::FilePath(), base::FilePath(), url)); |
+ } |
+ } |
+ } |
+ |
+ // js: |
+ if (script_value.js) { |
+ for (const std::string& relative : *(script_value.js.get())) { |
+ GURL url = owner_base_url.Resolve(relative); |
+ if (extension) { |
+ ExtensionResource resource = extension->GetResource(relative); |
+ script->js_scripts().push_back(UserScript::File( |
+ resource.extension_root(), resource.relative_path(), url)); |
+ } else { |
+ script->js_scripts().push_back(extensions::UserScript::File( |
+ base::FilePath(), base::FilePath(), url)); |
+ } |
+ } |
+ } |
+ |
+ // all_frames: |
+ if (script_value.all_frames) |
+ script->set_match_all_frames(*(script_value.all_frames)); |
+ |
+ // include_globs: |
+ if (script_value.include_globs) { |
+ for (const std::string& glob : *(script_value.include_globs.get())) |
+ script->add_glob(glob); |
+ } |
+ |
+ // exclude_globs: |
+ if (script_value.exclude_globs) { |
+ for (const std::string& glob : *(script_value.exclude_globs.get())) |
+ script->add_exclude_glob(glob); |
+ } |
+ |
+ return true; |
+} |
+ |
+bool ParseContentScripts( |
+ std::vector<linked_ptr<ContentScriptDetails>> content_script_list, |
+ const extensions::Extension* extension, |
+ const HostID& host_id, |
+ bool incognito_enabled, |
+ const GURL& owner_base_url, |
+ std::set<UserScript>* result, |
+ std::string* error) { |
+ if (content_script_list.empty()) |
+ return false; |
+ |
+ std::set<std::string> names; |
+ for (const linked_ptr<ContentScriptDetails> script_value : |
+ content_script_list) { |
+ const std::string& name = script_value->name; |
+ if (!names.insert(name).second) { |
+ // The name was already in the list. |
+ *error = kDuplicatedContentScriptNamesError; |
+ return false; |
+ } |
+ |
+ UserScript script; |
+ if (!ParseContentScript(*script_value, extension, owner_base_url, &script, |
+ error)) |
+ return false; |
+ |
+ script.set_id(UserScript::GenerateUserScriptID()); |
+ script.set_name(name); |
+ script.set_incognito_enabled(incognito_enabled); |
+ script.set_host_id(host_id); |
+ script.set_consumer_instance_type(UserScript::WEBVIEW); |
+ result->insert(script); |
+ } |
+ return true; |
+} |
+ |
} // namespace |
namespace extensions { |
@@ -256,6 +432,77 @@ bool WebViewInternalInsertCSSFunction::ShouldInsertCSS() const { |
return true; |
} |
+WebViewInternalAddContentScriptsFunction:: |
+ WebViewInternalAddContentScriptsFunction() { |
+} |
+ |
+WebViewInternalAddContentScriptsFunction:: |
+ ~WebViewInternalAddContentScriptsFunction() { |
+} |
+ |
+ExecuteCodeFunction::ResponseAction |
+WebViewInternalAddContentScriptsFunction::Run() { |
+ scoped_ptr<web_view_internal::AddContentScripts::Params> params( |
+ web_view_internal::AddContentScripts::Params::Create(*args_)); |
+ EXTENSION_FUNCTION_VALIDATE(params.get()); |
+ |
+ if (!params->instance_id) |
+ return RespondNow(Error(kViewInstanceIdError)); |
+ |
+ GURL owner_base_url( |
+ render_view_host()->GetSiteInstance()->GetSiteURL().GetWithEmptyPath()); |
+ std::set<UserScript> result; |
+ |
+ content::WebContents* sender_web_contents = GetSenderWebContents(); |
+ HostID host_id = GenerateHostIDFromEmbedder(extension(), sender_web_contents); |
+ bool incognito_enabled = browser_context()->IsOffTheRecord(); |
+ |
+ if (!ParseContentScripts(params->content_script_list, extension(), host_id, |
+ incognito_enabled, owner_base_url, &result, &error_)) |
+ return RespondNow(Error(error_)); |
+ |
+ WebViewContentScriptManager* manager = |
+ WebViewContentScriptManager::Get(browser_context()); |
+ DCHECK(manager); |
+ |
+ manager->AddContentScripts(sender_web_contents, params->instance_id, host_id, |
+ result); |
+ |
+ return RespondNow(NoArguments()); |
+} |
+ |
+WebViewInternalRemoveContentScriptsFunction:: |
+ WebViewInternalRemoveContentScriptsFunction() { |
+} |
+ |
+WebViewInternalRemoveContentScriptsFunction:: |
+ ~WebViewInternalRemoveContentScriptsFunction() { |
+} |
+ |
+ExecuteCodeFunction::ResponseAction |
+WebViewInternalRemoveContentScriptsFunction::Run() { |
+ scoped_ptr<web_view_internal::RemoveContentScripts::Params> params( |
+ web_view_internal::RemoveContentScripts::Params::Create(*args_)); |
+ EXTENSION_FUNCTION_VALIDATE(params.get()); |
+ |
+ if (!params->instance_id) |
+ return RespondNow(Error(kViewInstanceIdError)); |
+ |
+ WebViewContentScriptManager* manager = |
+ WebViewContentScriptManager::Get(browser_context()); |
+ DCHECK(manager); |
+ |
+ content::WebContents* sender_web_contents = GetSenderWebContents(); |
+ HostID host_id = GenerateHostIDFromEmbedder(extension(), sender_web_contents); |
+ |
+ std::vector<std::string> script_name_list; |
+ if (params->script_name_list) |
+ script_name_list.swap(*params->script_name_list); |
+ manager->RemoveContentScripts(GetSenderWebContents(), params->instance_id, |
+ host_id, script_name_list); |
+ return RespondNow(NoArguments()); |
+} |
+ |
WebViewInternalSetNameFunction::WebViewInternalSetNameFunction() { |
} |