[Extensions] Allow mojom::CodeInjections to specify a list of sources
Allow mojom::CodeInjections to specify a list of sources to support injecting multiple code files at once. To accomplish this, pull out a struct for a JSSource and a CSSSource, which each represent a single source for the given type of injection (including the code and other necessary bits, like the script URL for JS or the injection key for CSS). Update all callers to provide a list of sources, as well as the handling on the renderer side. Add a test to exercise injecting multiple files through ScriptExecutor. This CL should have no behavior change, as currently, all production callers only provide a single source. Bug: 1219788 Change-Id: Id6e3db840c122a13ca510cf182a1c480bff2fadf Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2960077 Reviewed-by: David Bertoni <dbertoni@chromium.org> Reviewed-by: Ken Rockot <rockot@google.com> Reviewed-by: Alex Gough <ajgo@chromium.org> Commit-Queue: Devlin <rdevlin.cronin@chromium.org> Cr-Commit-Position: refs/heads/master@{#894013}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
f27b80887f
commit
59fc378914
chrome/browser/extensions
extensions
@ -322,11 +322,14 @@ bool ScriptingExecuteScriptFunction::Execute(std::string code_to_execute,
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<mojom::JSSourcePtr> sources;
|
||||
sources.push_back(
|
||||
mojom::JSSource::New(std::move(code_to_execute), std::move(script_url)));
|
||||
script_executor->ExecuteScript(
|
||||
mojom::HostID(mojom::HostID::HostType::kExtensions, extension()->id()),
|
||||
mojom::CodeInjection::NewJs(mojom::JSInjection::New(
|
||||
std::move(code_to_execute), std::move(script_url),
|
||||
/*wants_result=*/true, user_gesture())),
|
||||
mojom::CodeInjection::NewJs(mojom::JSInjection::New(std::move(sources),
|
||||
/*wants_result=*/true,
|
||||
user_gesture())),
|
||||
frame_scope, frame_ids, ScriptExecutor::MATCH_ABOUT_BLANK,
|
||||
mojom::RunLocation::kDocumentIdle, ScriptExecutor::DEFAULT_PROCESS,
|
||||
/* webview_src */ GURL(),
|
||||
@ -442,11 +445,14 @@ bool ScriptingInsertCSSFunction::Execute(std::string code_to_execute,
|
||||
extension()->id());
|
||||
std::string injection_key = ScriptExecutor::GenerateInjectionKey(
|
||||
host_id, script_url, code_to_execute);
|
||||
|
||||
std::vector<mojom::CSSSourcePtr> sources;
|
||||
sources.push_back(mojom::CSSSource::New(std::move(code_to_execute),
|
||||
std::move(injection_key)));
|
||||
script_executor->ExecuteScript(
|
||||
std::move(host_id),
|
||||
mojom::CodeInjection::NewCss(mojom::CSSInjection::New(
|
||||
std::move(code_to_execute), std::move(injection_key),
|
||||
ConvertStyleOriginToCSSOrigin(injection_.origin),
|
||||
std::move(sources), ConvertStyleOriginToCSSOrigin(injection_.origin),
|
||||
mojom::CSSInjection::Operation::kAdd)),
|
||||
frame_scope, frame_ids, ScriptExecutor::MATCH_ABOUT_BLANK,
|
||||
kCSSRunLocation, ScriptExecutor::DEFAULT_PROCESS,
|
||||
@ -515,11 +521,14 @@ ExtensionFunction::ResponseAction ScriptingRemoveCSSFunction::Run() {
|
||||
extension()->id());
|
||||
std::string injection_key =
|
||||
ScriptExecutor::GenerateInjectionKey(host_id, script_url, code);
|
||||
|
||||
std::vector<mojom::CSSSourcePtr> sources;
|
||||
sources.push_back(
|
||||
mojom::CSSSource::New(std::move(code), std::move(injection_key)));
|
||||
script_executor->ExecuteScript(
|
||||
std::move(host_id),
|
||||
mojom::CodeInjection::NewCss(mojom::CSSInjection::New(
|
||||
std::move(code), std::move(injection_key),
|
||||
ConvertStyleOriginToCSSOrigin(injection.origin),
|
||||
std::move(sources), ConvertStyleOriginToCSSOrigin(injection.origin),
|
||||
mojom::CSSInjection::Operation::kRemove)),
|
||||
frame_scope, frame_ids, ScriptExecutor::MATCH_ABOUT_BLANK,
|
||||
kCSSRunLocation, ScriptExecutor::DEFAULT_PROCESS,
|
||||
|
@ -126,10 +126,13 @@ IN_PROC_BROWSER_TEST_F(ScriptExecutorBrowserTest, MainFrameExecution) {
|
||||
)";
|
||||
|
||||
ScriptExecutorHelper helper;
|
||||
std::vector<mojom::JSSourcePtr> sources;
|
||||
sources.push_back(mojom::JSSource::New(kCode, GURL()));
|
||||
script_executor.ExecuteScript(
|
||||
mojom::HostID(mojom::HostID::HostType::kExtensions, extension->id()),
|
||||
mojom::CodeInjection::NewJs(mojom::JSInjection::New(
|
||||
kCode, GURL(), true /* wants_result */, false /* user_gesture */)),
|
||||
mojom::CodeInjection::NewJs(
|
||||
mojom::JSInjection::New(std::move(sources), true /* wants_result */,
|
||||
false /* user_gesture */)),
|
||||
ScriptExecutor::SPECIFIED_FRAMES, {ExtensionApiFrameIdMap::kTopFrameId},
|
||||
ScriptExecutor::DONT_MATCH_ABOUT_BLANK, mojom::RunLocation::kDocumentIdle,
|
||||
ScriptExecutor::DEFAULT_PROCESS, GURL() /* webview_src */,
|
||||
@ -144,6 +147,60 @@ IN_PROC_BROWSER_TEST_F(ScriptExecutorBrowserTest, MainFrameExecution) {
|
||||
EXPECT_EQ("", helper.results()[0].error);
|
||||
}
|
||||
|
||||
// Tests injecting multiple JS sources into a frame.
|
||||
IN_PROC_BROWSER_TEST_F(ScriptExecutorBrowserTest, MultipleSourceExecution) {
|
||||
const Extension* extension =
|
||||
LoadExtensionWithHostPermission("http://example.com/*");
|
||||
|
||||
GURL example_com =
|
||||
embedded_test_server()->GetURL("example.com", "/simple.html");
|
||||
content::WebContents* web_contents =
|
||||
browser()->tab_strip_model()->GetActiveWebContents();
|
||||
ASSERT_TRUE(web_contents);
|
||||
|
||||
{
|
||||
content::TestNavigationObserver nav_observer(web_contents);
|
||||
ui_test_utils::NavigateToURL(browser(), example_com);
|
||||
nav_observer.Wait();
|
||||
EXPECT_TRUE(nav_observer.last_navigation_succeeded());
|
||||
}
|
||||
|
||||
EXPECT_EQ("OK", base::UTF16ToUTF8(web_contents->GetTitle()));
|
||||
|
||||
// Inject two pieces of code. Note that the second references a variable set
|
||||
// by the first, which thus also exercises injection order (in addition to
|
||||
// that they both run).
|
||||
ScriptExecutor script_executor(web_contents);
|
||||
constexpr char kCode1[] =
|
||||
R"(window.newTitle = 'New Title';
|
||||
'First Result';)";
|
||||
constexpr char kCode2[] =
|
||||
R"(document.title = window.newTitle;
|
||||
'Second Result';)";
|
||||
|
||||
ScriptExecutorHelper helper;
|
||||
std::vector<mojom::JSSourcePtr> sources;
|
||||
sources.push_back(mojom::JSSource::New(kCode1, GURL()));
|
||||
sources.push_back(mojom::JSSource::New(kCode2, GURL()));
|
||||
script_executor.ExecuteScript(
|
||||
mojom::HostID(mojom::HostID::HostType::kExtensions, extension->id()),
|
||||
mojom::CodeInjection::NewJs(
|
||||
mojom::JSInjection::New(std::move(sources), true /* wants_result */,
|
||||
false /* user_gesture */)),
|
||||
ScriptExecutor::SPECIFIED_FRAMES, {ExtensionApiFrameIdMap::kTopFrameId},
|
||||
ScriptExecutor::DONT_MATCH_ABOUT_BLANK, mojom::RunLocation::kDocumentIdle,
|
||||
ScriptExecutor::DEFAULT_PROCESS, GURL() /* webview_src */,
|
||||
helper.GetCallback());
|
||||
helper.Wait();
|
||||
EXPECT_EQ("New Title", base::UTF16ToUTF8(web_contents->GetTitle()));
|
||||
|
||||
ASSERT_EQ(1u, helper.results().size());
|
||||
EXPECT_EQ(web_contents->GetLastCommittedURL(), helper.results()[0].url);
|
||||
EXPECT_EQ(base::Value("Second Result"), helper.results()[0].value);
|
||||
EXPECT_EQ(0, helper.results()[0].frame_id);
|
||||
EXPECT_EQ("", helper.results()[0].error);
|
||||
}
|
||||
|
||||
// Tests script execution into a specified set of frames.
|
||||
IN_PROC_BROWSER_TEST_F(ScriptExecutorBrowserTest, SpecifiedFrames) {
|
||||
const Extension* extension =
|
||||
@ -207,10 +264,13 @@ IN_PROC_BROWSER_TEST_F(ScriptExecutorBrowserTest, SpecifiedFrames) {
|
||||
// Execute in frames 1 and 2. These are the only frames for which we should
|
||||
// get a result.
|
||||
ScriptExecutorHelper helper;
|
||||
std::vector<mojom::JSSourcePtr> sources;
|
||||
sources.push_back(mojom::JSSource::New(kCode, GURL()));
|
||||
script_executor.ExecuteScript(
|
||||
mojom::HostID(mojom::HostID::HostType::kExtensions, extension->id()),
|
||||
mojom::CodeInjection::NewJs(mojom::JSInjection::New(
|
||||
kCode, GURL(), true /* wants_result */, false /* user_gesture */)),
|
||||
mojom::CodeInjection::NewJs(
|
||||
mojom::JSInjection::New(std::move(sources), true /* wants_result */,
|
||||
false /* user_gesture */)),
|
||||
ScriptExecutor::SPECIFIED_FRAMES, {frame1_id, frame2_id},
|
||||
ScriptExecutor::DONT_MATCH_ABOUT_BLANK,
|
||||
mojom::RunLocation::kDocumentIdle, ScriptExecutor::DEFAULT_PROCESS,
|
||||
@ -227,10 +287,13 @@ IN_PROC_BROWSER_TEST_F(ScriptExecutorBrowserTest, SpecifiedFrames) {
|
||||
// Repeat the execution in frames 1 and 2, but include subframes. This
|
||||
// should result in frame2_child being added to the results.
|
||||
ScriptExecutorHelper helper;
|
||||
std::vector<mojom::JSSourcePtr> sources;
|
||||
sources.push_back(mojom::JSSource::New(kCode, GURL()));
|
||||
script_executor.ExecuteScript(
|
||||
mojom::HostID(mojom::HostID::HostType::kExtensions, extension->id()),
|
||||
mojom::CodeInjection::NewJs(mojom::JSInjection::New(
|
||||
kCode, GURL(), true /* wants_result */, false /* user_gesture */)),
|
||||
mojom::CodeInjection::NewJs(
|
||||
mojom::JSInjection::New(std::move(sources), true /* wants_result */,
|
||||
false /* user_gesture */)),
|
||||
ScriptExecutor::INCLUDE_SUB_FRAMES, {frame1_id, frame2_id},
|
||||
ScriptExecutor::DONT_MATCH_ABOUT_BLANK,
|
||||
mojom::RunLocation::kDocumentIdle, ScriptExecutor::DEFAULT_PROCESS,
|
||||
@ -256,10 +319,13 @@ IN_PROC_BROWSER_TEST_F(ScriptExecutorBrowserTest, SpecifiedFrames) {
|
||||
// Try injecting into multiple frames when one of the specified frames
|
||||
// doesn't exist.
|
||||
ScriptExecutorHelper helper;
|
||||
std::vector<mojom::JSSourcePtr> sources;
|
||||
sources.push_back(mojom::JSSource::New(kCode, GURL()));
|
||||
script_executor.ExecuteScript(
|
||||
mojom::HostID(mojom::HostID::HostType::kExtensions, extension->id()),
|
||||
mojom::CodeInjection::NewJs(mojom::JSInjection::New(
|
||||
kCode, GURL(), true /* wants_result */, false /* user_gesture */)),
|
||||
mojom::CodeInjection::NewJs(
|
||||
mojom::JSInjection::New(std::move(sources), true /* wants_result */,
|
||||
false /* user_gesture */)),
|
||||
ScriptExecutor::SPECIFIED_FRAMES,
|
||||
{frame1_id, frame2_id, kNonExistentFrameId},
|
||||
ScriptExecutor::DONT_MATCH_ABOUT_BLANK,
|
||||
@ -280,10 +346,13 @@ IN_PROC_BROWSER_TEST_F(ScriptExecutorBrowserTest, SpecifiedFrames) {
|
||||
{
|
||||
// Try injecting into a single non-existent frame.
|
||||
ScriptExecutorHelper helper;
|
||||
std::vector<mojom::JSSourcePtr> sources;
|
||||
sources.push_back(mojom::JSSource::New(kCode, GURL()));
|
||||
script_executor.ExecuteScript(
|
||||
mojom::HostID(mojom::HostID::HostType::kExtensions, extension->id()),
|
||||
mojom::CodeInjection::NewJs(mojom::JSInjection::New(
|
||||
kCode, GURL(), true /* wants_result */, false /* user_gesture */)),
|
||||
mojom::CodeInjection::NewJs(
|
||||
mojom::JSInjection::New(std::move(sources), true /* wants_result */,
|
||||
false /* user_gesture */)),
|
||||
ScriptExecutor::SPECIFIED_FRAMES, {kNonExistentFrameId},
|
||||
ScriptExecutor::DONT_MATCH_ABOUT_BLANK,
|
||||
mojom::RunLocation::kDocumentIdle, ScriptExecutor::DEFAULT_PROCESS,
|
||||
|
@ -132,12 +132,17 @@ bool ExecuteCodeFunction::Execute(const std::string& code_string,
|
||||
mojom::CSSInjection::Operation operation =
|
||||
ShouldInsertCSS() ? mojom::CSSInjection::Operation::kAdd
|
||||
: mojom::CSSInjection::Operation::kRemove;
|
||||
injection = mojom::CodeInjection::NewCss(mojom::CSSInjection::New(
|
||||
code_string, std::move(injection_key), css_origin, operation));
|
||||
std::vector<mojom::CSSSourcePtr> sources;
|
||||
sources.push_back(
|
||||
mojom::CSSSource::New(code_string, std::move(injection_key)));
|
||||
injection = mojom::CodeInjection::NewCss(
|
||||
mojom::CSSInjection::New(std::move(sources), css_origin, operation));
|
||||
} else {
|
||||
bool wants_result = has_callback();
|
||||
std::vector<mojom::JSSourcePtr> sources;
|
||||
sources.push_back(mojom::JSSource::New(code_string, script_url_));
|
||||
injection = mojom::CodeInjection::NewJs(mojom::JSInjection::New(
|
||||
code_string, script_url_, wants_result, user_gesture()));
|
||||
std::move(sources), wants_result, user_gesture()));
|
||||
}
|
||||
|
||||
executor->ExecuteScript(
|
||||
|
@ -10,9 +10,11 @@
|
||||
#include "base/bind.h"
|
||||
#include "base/check_op.h"
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/dcheck_is_on.h"
|
||||
#include "base/hash/hash.h"
|
||||
#include "base/memory/weak_ptr.h"
|
||||
#include "base/pickle.h"
|
||||
#include "base/ranges/algorithm.h"
|
||||
#include "base/strings/stringprintf.h"
|
||||
#include "base/types/pass_key.h"
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
@ -302,11 +304,22 @@ void ScriptExecutor::ExecuteScript(const mojom::HostID& host_id,
|
||||
CHECK(process_type == WEB_VIEW_PROCESS);
|
||||
}
|
||||
|
||||
#if DCHECK_IS_ON()
|
||||
if (injection->is_css()) {
|
||||
bool expect_injection_key =
|
||||
host_id.type == mojom::HostID::HostType::kExtensions;
|
||||
DCHECK_EQ(expect_injection_key, injection->get_css()->key.has_value());
|
||||
if (injection->get_css()->operation ==
|
||||
mojom::CSSInjection::Operation::kRemove) {
|
||||
DCHECK(expect_injection_key)
|
||||
<< "Only extensions (with injection keys supplied) can remove CSS.";
|
||||
}
|
||||
DCHECK(base::ranges::all_of(
|
||||
injection->get_css()->sources,
|
||||
[expect_injection_key](const mojom::CSSSourcePtr& source) {
|
||||
return expect_injection_key == source->key.has_value();
|
||||
}));
|
||||
}
|
||||
#endif
|
||||
|
||||
auto params = mojom::ExecuteCodeParams::New();
|
||||
params->host_id = host_id.Clone();
|
||||
|
@ -7,13 +7,29 @@ module extensions.mojom;
|
||||
import "extensions/common/mojom/css_origin.mojom";
|
||||
import "url/mojom/url.mojom";
|
||||
|
||||
// A struct representing a single piece of code to inject in the renderer.
|
||||
struct JSInjection {
|
||||
// A single JS source to execute in the renderer.
|
||||
struct JSSource {
|
||||
// The Javascript code to execute.
|
||||
string code;
|
||||
|
||||
// The URL of the script that was injected, if any.
|
||||
url.mojom.Url script_url;
|
||||
};
|
||||
|
||||
// A single CSS source to execute in the renderer.
|
||||
struct CSSSource {
|
||||
// The CSS code to insert.
|
||||
string code;
|
||||
|
||||
// A generated injection key for the CSS, which can be used to remove it
|
||||
// later.
|
||||
string? key;
|
||||
};
|
||||
|
||||
// A struct representing a collection of JS code to inject in the renderer.
|
||||
struct JSInjection {
|
||||
// The JS sources to execute.
|
||||
array<JSSource> sources;
|
||||
|
||||
// Whether the caller is interested in the result value. Manifest-declared
|
||||
// content scripts and executeScript() calls without a response callback
|
||||
@ -24,18 +40,15 @@ struct JSInjection {
|
||||
bool user_gesture;
|
||||
};
|
||||
|
||||
// A struct representing a collection of CSS code to insert in the renderer.
|
||||
struct CSSInjection {
|
||||
enum Operation {
|
||||
kAdd,
|
||||
kRemove,
|
||||
};
|
||||
|
||||
// The CSS code to insert.
|
||||
string code;
|
||||
|
||||
// A generated injection key for the CSS, which can be used to remove it
|
||||
// later.
|
||||
string? key;
|
||||
// The CSS sources to insert.
|
||||
array<CSSSource> sources;
|
||||
|
||||
// The origin of the CSS.
|
||||
CSSOrigin css_origin;
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <set>
|
||||
|
||||
#include "base/metrics/histogram_macros.h"
|
||||
#include "base/ranges/algorithm.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "base/timer/elapsed_timer.h"
|
||||
#include "content/public/renderer/render_frame.h"
|
||||
@ -471,6 +472,31 @@ void ExtensionFrameHelper::MessageInvoke(const std::string& extension_id,
|
||||
|
||||
void ExtensionFrameHelper::ExecuteCode(mojom::ExecuteCodeParamsPtr param,
|
||||
ExecuteCodeCallback callback) {
|
||||
// Sanity checks.
|
||||
if (param->injection->is_css()) {
|
||||
if (param->injection->get_css()->sources.empty()) {
|
||||
mojo::ReportBadMessage("At least one CSS source must be specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (param->injection->get_css()->operation ==
|
||||
mojom::CSSInjection::Operation::kRemove &&
|
||||
!base::ranges::all_of(param->injection->get_css()->sources,
|
||||
[](const mojom::CSSSourcePtr& source) {
|
||||
return source->key.has_value();
|
||||
})) {
|
||||
mojo::ReportBadMessage(
|
||||
"An injection key must be specified for CSS removal.");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
DCHECK(param->injection->is_js()); // Enforced by mojo.
|
||||
if (param->injection->get_js()->sources.empty()) {
|
||||
mojo::ReportBadMessage("At least one JS source must be specified.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
extension_dispatcher_->ExecuteCode(std::move(param), std::move(callback),
|
||||
render_frame());
|
||||
}
|
||||
|
@ -55,12 +55,6 @@ ProgrammaticScriptInjector::GetCSSInjectionOperation() const {
|
||||
return params_->injection->get_css()->operation;
|
||||
}
|
||||
|
||||
const absl::optional<std::string> ProgrammaticScriptInjector::GetInjectionKey()
|
||||
const {
|
||||
DCHECK(params_->injection->is_css());
|
||||
return params_->injection->get_css()->key;
|
||||
}
|
||||
|
||||
bool ProgrammaticScriptInjector::ExpectsResults() const {
|
||||
DCHECK(params_->injection->is_js());
|
||||
return params_->injection->get_js()->wants_result;
|
||||
@ -123,20 +117,36 @@ std::vector<blink::WebScriptSource> ProgrammaticScriptInjector::GetJsSources(
|
||||
DCHECK(params_->injection->is_js());
|
||||
|
||||
auto& js_injection = params_->injection->get_js();
|
||||
return std::vector<blink::WebScriptSource>(
|
||||
1, blink::WebScriptSource(blink::WebString::FromUTF8(js_injection->code),
|
||||
js_injection->script_url));
|
||||
std::vector<blink::WebScriptSource> sources;
|
||||
sources.reserve(js_injection->sources.size());
|
||||
for (const auto& source : js_injection->sources) {
|
||||
sources.emplace_back(blink::WebString::FromUTF8(source->code),
|
||||
source->script_url);
|
||||
}
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
std::vector<blink::WebString> ProgrammaticScriptInjector::GetCssSources(
|
||||
std::vector<ScriptInjector::CSSSource>
|
||||
ProgrammaticScriptInjector::GetCssSources(
|
||||
mojom::RunLocation run_location,
|
||||
std::set<std::string>* injected_stylesheets,
|
||||
size_t* num_injected_stylesheets) const {
|
||||
DCHECK_EQ(params_->run_at, run_location);
|
||||
DCHECK(params_->injection->is_css());
|
||||
|
||||
return std::vector<blink::WebString>(
|
||||
1, blink::WebString::FromUTF8(params_->injection->get_css()->code));
|
||||
auto& css_injection = params_->injection->get_css();
|
||||
std::vector<CSSSource> sources;
|
||||
sources.reserve(css_injection->sources.size());
|
||||
for (const auto& source : css_injection->sources) {
|
||||
blink::WebStyleSheetKey style_sheet_key;
|
||||
if (source->key)
|
||||
style_sheet_key = blink::WebString::FromASCII(*source->key);
|
||||
sources.push_back(
|
||||
CSSSource{blink::WebString::FromUTF8(source->code), style_sheet_key});
|
||||
}
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
void ProgrammaticScriptInjector::OnInjectionComplete(
|
||||
|
@ -33,7 +33,6 @@ class ProgrammaticScriptInjector : public ScriptInjector {
|
||||
bool IsUserGesture() const override;
|
||||
mojom::CSSOrigin GetCssOrigin() const override;
|
||||
mojom::CSSInjection::Operation GetCSSInjectionOperation() const override;
|
||||
const absl::optional<std::string> GetInjectionKey() const override;
|
||||
bool ExpectsResults() const override;
|
||||
bool ShouldInjectJs(
|
||||
mojom::RunLocation run_location,
|
||||
@ -49,7 +48,7 @@ class ProgrammaticScriptInjector : public ScriptInjector {
|
||||
mojom::RunLocation run_location,
|
||||
std::set<std::string>* executing_scripts,
|
||||
size_t* num_injected_js_scripts) const override;
|
||||
std::vector<blink::WebString> GetCssSources(
|
||||
std::vector<CSSSource> GetCssSources(
|
||||
mojom::RunLocation run_location,
|
||||
std::set<std::string>* injected_stylesheets,
|
||||
size_t* num_injected_stylesheets) const override;
|
||||
|
@ -368,7 +368,7 @@ void ScriptInjection::OnJsInjectionCompleted(
|
||||
|
||||
bool expects_results = injector_->ExpectsResults();
|
||||
if (expects_results) {
|
||||
if (!results.empty() && !results[0].IsEmpty()) {
|
||||
if (!results.empty() && !results.back().IsEmpty()) {
|
||||
// Right now, we only support returning single results (per frame).
|
||||
// It's safe to always use the main world context when converting
|
||||
// here. V8ValueConverterImpl shouldn't actually care about the
|
||||
@ -376,8 +376,12 @@ void ScriptInjection::OnJsInjectionCompleted(
|
||||
// when encountered.
|
||||
v8::Local<v8::Context> context =
|
||||
render_frame_->GetWebFrame()->MainWorldScriptContext();
|
||||
execution_result_ =
|
||||
content::V8ValueConverter::Create()->FromV8Value(results[0], context);
|
||||
// We use the final result, since it is the most meaningful (the result
|
||||
// after running all scripts). Additionally, the final script can
|
||||
// reference values from the previous scripts, so could return them if
|
||||
// desired.
|
||||
execution_result_ = content::V8ValueConverter::Create()->FromV8Value(
|
||||
results.back(), context);
|
||||
}
|
||||
if (!execution_result_.get())
|
||||
execution_result_ = std::make_unique<base::Value>();
|
||||
@ -399,7 +403,7 @@ void ScriptInjection::OnJsInjectionCompleted(
|
||||
void ScriptInjection::InjectOrRemoveCss(
|
||||
std::set<std::string>* injected_stylesheets,
|
||||
size_t* num_injected_stylesheets) {
|
||||
std::vector<blink::WebString> css_sources = injector_->GetCssSources(
|
||||
std::vector<ScriptInjector::CSSSource> css_sources = injector_->GetCssSources(
|
||||
run_location_, injected_stylesheets, num_injected_stylesheets);
|
||||
blink::WebLocalFrame* web_frame = render_frame_->GetWebFrame();
|
||||
|
||||
@ -414,31 +418,27 @@ void ScriptInjection::InjectOrRemoveCss(
|
||||
break;
|
||||
}
|
||||
|
||||
blink::WebStyleSheetKey style_sheet_key;
|
||||
if (const absl::optional<std::string>& injection_key =
|
||||
injector_->GetInjectionKey())
|
||||
style_sheet_key = blink::WebString::FromASCII(*injection_key);
|
||||
// CSS deletion can be thought of as the inverse of CSS injection
|
||||
// (i.e. x - y = x + -y and x | y = ~(~x & ~y)), so it is handled here in the
|
||||
// injection function.
|
||||
//
|
||||
// TODO(https://crbug.com/1116061): Extend this API's capabilities to also
|
||||
// remove CSS added by content scripts?
|
||||
mojom::CSSInjection::Operation injection_type =
|
||||
mojom::CSSInjection::Operation operation =
|
||||
injector_->GetCSSInjectionOperation();
|
||||
|
||||
switch (injection_type) {
|
||||
case mojom::CSSInjection::Operation::kRemove:
|
||||
web_frame->GetDocument().RemoveInsertedStyleSheet(style_sheet_key,
|
||||
blink_css_origin);
|
||||
break;
|
||||
case mojom::CSSInjection::Operation::kAdd: {
|
||||
for (const blink::WebString& css : css_sources) {
|
||||
for (const auto& source : css_sources) {
|
||||
switch (operation) {
|
||||
case mojom::CSSInjection::Operation::kRemove:
|
||||
DCHECK(!source.key.IsEmpty())
|
||||
<< "An injection key is required to remove CSS.";
|
||||
// CSS deletion can be thought of as the inverse of CSS injection
|
||||
// (i.e. x - y = x + -y and x | y = ~(~x & ~y)), so it is handled here
|
||||
// in the injection function.
|
||||
//
|
||||
// TODO(https://crbug.com/1116061): Extend this API's capabilities to
|
||||
// also remove CSS added by content scripts?
|
||||
web_frame->GetDocument().RemoveInsertedStyleSheet(source.key,
|
||||
blink_css_origin);
|
||||
break;
|
||||
case mojom::CSSInjection::Operation::kAdd:
|
||||
web_frame->GetDocument().InsertStyleSheet(
|
||||
css, &style_sheet_key, blink_css_origin,
|
||||
source.code, &source.key, blink_css_origin,
|
||||
blink::BackForwardCacheAware::kPossiblyDisallow);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include "extensions/common/mojom/run_location.mojom-shared.h"
|
||||
#include "extensions/common/permissions/permissions_data.h"
|
||||
#include "extensions/common/user_script.h"
|
||||
#include "third_party/abseil-cpp/absl/types/optional.h"
|
||||
#include "third_party/blink/public/web/web_document.h"
|
||||
#include "third_party/blink/public/web/web_script_source.h"
|
||||
|
||||
class InjectionHost;
|
||||
@ -39,6 +39,11 @@ class ScriptInjector {
|
||||
// (or just did not accept) the injection.
|
||||
};
|
||||
|
||||
struct CSSSource {
|
||||
blink::WebString code;
|
||||
blink::WebStyleSheetKey key;
|
||||
};
|
||||
|
||||
virtual ~ScriptInjector() {}
|
||||
|
||||
// Returns the script type of this particular injection.
|
||||
@ -54,9 +59,6 @@ class ScriptInjector {
|
||||
// performed.
|
||||
virtual mojom::CSSInjection::Operation GetCSSInjectionOperation() const = 0;
|
||||
|
||||
// Returns the key for this injection, if it's a CSS injection.
|
||||
virtual const absl::optional<std::string> GetInjectionKey() const = 0;
|
||||
|
||||
// Returns true if the script expects results.
|
||||
virtual bool ExpectsResults() const = 0;
|
||||
|
||||
@ -87,7 +89,7 @@ class ScriptInjector {
|
||||
|
||||
// Returns the css to inject at the given |run_location|.
|
||||
// Only called if ShouldInjectOrRemoveCss() is true.
|
||||
virtual std::vector<blink::WebString> GetCssSources(
|
||||
virtual std::vector<CSSSource> GetCssSources(
|
||||
mojom::RunLocation run_location,
|
||||
std::set<std::string>* injected_stylesheets,
|
||||
size_t* num_injected_stylesheets) const = 0;
|
||||
|
@ -143,10 +143,6 @@ mojom::CSSInjection::Operation UserScriptInjector::GetCSSInjectionOperation()
|
||||
return mojom::CSSInjection::Operation::kAdd;
|
||||
}
|
||||
|
||||
const absl::optional<std::string> UserScriptInjector::GetInjectionKey() const {
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
bool UserScriptInjector::ShouldInjectJs(
|
||||
mojom::RunLocation run_location,
|
||||
const std::set<std::string>& executing_scripts) const {
|
||||
@ -238,21 +234,21 @@ std::vector<blink::WebScriptSource> UserScriptInjector::GetJsSources(
|
||||
user_script_set_->GetJsSource(*file, script_->emulate_greasemonkey()),
|
||||
script_url));
|
||||
|
||||
(*num_injected_js_scripts) += 1;
|
||||
++*num_injected_js_scripts;
|
||||
executing_scripts->insert(script_url.path());
|
||||
}
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
std::vector<blink::WebString> UserScriptInjector::GetCssSources(
|
||||
std::vector<ScriptInjector::CSSSource> UserScriptInjector::GetCssSources(
|
||||
mojom::RunLocation run_location,
|
||||
std::set<std::string>* injected_stylesheets,
|
||||
size_t* num_injected_stylesheets) const {
|
||||
DCHECK(script_);
|
||||
DCHECK_EQ(mojom::RunLocation::kDocumentStart, run_location);
|
||||
|
||||
std::vector<blink::WebString> sources;
|
||||
std::vector<CSSSource> sources;
|
||||
|
||||
const UserScript::FileList& css_scripts = script_->css_scripts();
|
||||
sources.reserve(css_scripts.size());
|
||||
@ -262,10 +258,11 @@ std::vector<blink::WebString> UserScriptInjector::GetCssSources(
|
||||
if (injected_stylesheets->count(stylesheet_path) != 0)
|
||||
continue;
|
||||
|
||||
sources.push_back(user_script_set_->GetCssSource(*file));
|
||||
(*num_injected_stylesheets) += 1;
|
||||
sources.push_back(CSSSource{user_script_set_->GetCssSource(*file),
|
||||
blink::WebStyleSheetKey()});
|
||||
injected_stylesheets->insert(stylesheet_path);
|
||||
}
|
||||
*num_injected_stylesheets += sources.size();
|
||||
return sources;
|
||||
}
|
||||
|
||||
|
@ -45,7 +45,6 @@ class UserScriptInjector : public ScriptInjector,
|
||||
bool IsUserGesture() const override;
|
||||
mojom::CSSOrigin GetCssOrigin() const override;
|
||||
mojom::CSSInjection::Operation GetCSSInjectionOperation() const override;
|
||||
const absl::optional<std::string> GetInjectionKey() const override;
|
||||
bool ExpectsResults() const override;
|
||||
bool ShouldInjectJs(
|
||||
mojom::RunLocation run_location,
|
||||
@ -61,7 +60,7 @@ class UserScriptInjector : public ScriptInjector,
|
||||
mojom::RunLocation run_location,
|
||||
std::set<std::string>* executing_scripts,
|
||||
size_t* num_injected_js_scripts) const override;
|
||||
std::vector<blink::WebString> GetCssSources(
|
||||
std::vector<CSSSource> GetCssSources(
|
||||
mojom::RunLocation run_location,
|
||||
std::set<std::string>* injected_stylesheets,
|
||||
size_t* num_injected_stylesheets) const override;
|
||||
|
Reference in New Issue
Block a user