Commit 0b1539fc authored by David Van Cleve's avatar David Van Cleve Committed by Chromium LUCI CQ

css: Make fetches from inline CSS use the document's URL as referrer

Right now, fetches from inline CSS use the inline CSS's base URL
instead of the URL from the context that embeds the inline CSS: for
instance, loading a source-site.com page with the following code
  <base href="https://other-site.com">
  <style type=text/css> @import('best-sheet.com') </style>
should lead to the best-sheet.com sheet getting fetched with a
source-site.com referrer, but it will currently provide an
other-site.com referrer. However, if the imported sheet from
best-sheet.com makes more nested fetches, those nested requests should
use best-sheet.com as the basis for their referrers (as they do
currently).

This CL updates CSSParserContext's referrer setting logic to roughly do
the following:
- inline CSS: use the embedding document's URL as the referrer, or, for
srcdoc iframes, walk up the frame tree until hitting a non-srcdoc frame
- requests from fetched stylesheets: just as currently, use the fetched
sheet's URL as the basis for constructing the referrer

This seemed like it required refactoring CSSParserContext slightly
because there are constructors that take both a Document and a base URL,
and it's not obvious from the constructor signature whether the
Document or the base URL should be the one that provides the referrer.
To resolve this ambiguity, the refactor updates these CSSParserContext
constructors to take caller-provided Referrer objects.

Change-Id: If5a99d8057dff5e771e821d0e1f605566e28ff1d
Fixed: 1158645, 1158010
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2592447Reviewed-by: default avatarRune Lillesveen <futhark@chromium.org>
Reviewed-by: default avatarMatt Falkenhagen <falken@chromium.org>
Commit-Queue: David Van Cleve <davidvc@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841509}
parent 597bf82a
......@@ -37,6 +37,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/frame/deprecation.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/html/html_link_element.h"
#include "third_party/blink/renderer/core/html/html_style_element.h"
#include "third_party/blink/renderer/core/html_names.h"
......@@ -137,9 +138,15 @@ CSSStyleSheet* CSSStyleSheet::CreateInline(Node& owner_node,
const KURL& base_url,
const TextPosition& start_position,
const WTF::TextEncoding& encoding) {
Document& owner_node_document = owner_node.GetDocument();
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
owner_node.GetDocument(), owner_node.GetDocument().BaseURL(),
true /* origin_clean */, owner_node.GetDocument().GetReferrerPolicy(),
owner_node_document, owner_node_document.BaseURL(),
true /* origin_clean */,
Referrer(
owner_node_document.GetExecutionContext()
? owner_node_document.GetExecutionContext()->OutgoingReferrer()
: String(), // GetExecutionContext() only returns null in tests.
owner_node.GetDocument().GetReferrerPolicy()),
encoding);
if (AdTracker::IsAdScriptExecutingInDocument(&owner_node.GetDocument()))
parser_context->SetIsAdRelated();
......
......@@ -53,27 +53,25 @@ CSSParserContext::CSSParserContext(const CSSParserContext* other,
is_ad_related_ = other->is_ad_related_;
}
CSSParserContext::CSSParserContext(
const CSSParserContext* other,
const KURL& base_url,
bool origin_clean,
network::mojom::ReferrerPolicy referrer_policy,
const WTF::TextEncoding& charset,
const Document* use_counter_document)
: CSSParserContext(
base_url,
origin_clean,
charset,
other->mode_,
other->match_mode_,
other->profile_,
Referrer(base_url.StrippedForUseAsReferrer(), referrer_policy),
other->is_html_document_,
other->use_legacy_background_size_shorthand_behavior_,
other->secure_context_mode_,
other->world_,
use_counter_document,
other->resource_fetch_restriction_) {
CSSParserContext::CSSParserContext(const CSSParserContext* other,
const KURL& base_url,
bool origin_clean,
const Referrer& referrer,
const WTF::TextEncoding& charset,
const Document* use_counter_document)
: CSSParserContext(base_url,
origin_clean,
charset,
other->mode_,
other->match_mode_,
other->profile_,
referrer,
other->is_html_document_,
other->use_legacy_background_size_shorthand_behavior_,
other->secure_context_mode_,
other->world_,
use_counter_document,
other->resource_fetch_restriction_) {
is_ad_related_ = other->is_ad_related_;
}
......@@ -96,18 +94,23 @@ CSSParserContext::CSSParserContext(CSSParserMode mode,
ResourceFetchRestriction::kNone) {}
CSSParserContext::CSSParserContext(const Document& document)
: CSSParserContext(document,
document.BaseURL(),
true /* origin_clean */,
document.GetReferrerPolicy(),
WTF::TextEncoding(),
kLiveProfile) {}
: CSSParserContext(
document,
document.BaseURL(),
true /* origin_clean */,
Referrer(document.GetExecutionContext()
? document.GetExecutionContext()->OutgoingReferrer()
: String(), // GetExecutionContext() only returns null
// in tests.
document.GetReferrerPolicy()),
WTF::TextEncoding(),
kLiveProfile) {}
CSSParserContext::CSSParserContext(
const Document& document,
const KURL& base_url_override,
bool origin_clean,
network::mojom::ReferrerPolicy referrer_policy_override,
const Referrer& referrer,
const WTF::TextEncoding& charset,
SelectorProfile profile,
enum ResourceFetchRestriction resource_fetch_restriction)
......@@ -122,8 +125,7 @@ CSSParserContext::CSSParserContext(
: kHTMLStandardMode)
: document.InQuirksMode() ? kHTMLQuirksMode : kHTMLStandardMode,
profile,
Referrer(base_url_override.StrippedForUseAsReferrer(),
referrer_policy_override),
referrer,
IsA<HTMLDocument>(document),
document.GetSettings()
? document.GetSettings()
......
......@@ -42,10 +42,15 @@ class CORE_EXPORT CSSParserContext final
explicit CSSParserContext(const CSSParserContext* other,
const Document* use_counter_document = nullptr);
// Creates a context with most of its constructor attributes provided by
// copying from |other|, except that the remaining constructor arguments take
// precedence over the corresponding characteristics of |other|. This is
// useful for initializing @imported sheets' contexts, which inherit most of
// their characteristics from their parents.
CSSParserContext(const CSSParserContext* other,
const KURL& base_url_override,
bool origin_clean,
network::mojom::ReferrerPolicy referrer_policy_override,
const Referrer& referrer,
const WTF::TextEncoding& charset_override,
const Document* use_counter_document);
CSSParserContext(CSSParserMode,
......@@ -56,7 +61,7 @@ class CORE_EXPORT CSSParserContext final
CSSParserContext(const Document&,
const KURL& base_url_override,
bool origin_clean,
network::mojom::ReferrerPolicy referrer_policy_override,
const Referrer& referrer,
const WTF::TextEncoding& charset = WTF::TextEncoding(),
SelectorProfile = kLiveProfile,
ResourceFetchRestriction resource_fetch_restriction =
......@@ -71,7 +76,7 @@ class CORE_EXPORT CSSParserContext final
CSSParserMode,
CSSParserMode match_mode,
SelectorProfile,
const Referrer&,
const Referrer& referrer,
bool is_html_document,
bool use_legacy_background_size_shorthand_behavior,
SecureContextMode,
......
......@@ -466,9 +466,8 @@ SelectorQuery* SelectorQueryCache::Add(const AtomicString& selectors,
CSSSelectorList selector_list = CSSParser::ParseSelector(
MakeGarbageCollected<CSSParserContext>(
document, document.BaseURL(), true /* origin_clean */,
document.GetReferrerPolicy(), WTF::TextEncoding(),
CSSParserContext::kSnapshotProfile),
document, document.BaseURL(), true /* origin_clean */, Referrer(),
WTF::TextEncoding(), CSSParserContext::kSnapshotProfile),
nullptr, selectors);
if (!selector_list.First()) {
......
......@@ -72,9 +72,8 @@ TEST(SelectorQueryTest, NotMatchingPseudoElement) {
CSSSelectorList selector_list = CSSParser::ParseSelector(
MakeGarbageCollected<CSSParserContext>(
*document, NullURL(), true /* origin_clean */,
network::mojom::ReferrerPolicy::kDefault, WTF::TextEncoding(),
CSSParserContext::kSnapshotProfile),
*document, NullURL(), true /* origin_clean */, Referrer(),
WTF::TextEncoding(), CSSParserContext::kSnapshotProfile),
nullptr, "span::before");
std::unique_ptr<SelectorQuery> query =
SelectorQuery::Adopt(std::move(selector_list));
......@@ -83,9 +82,8 @@ TEST(SelectorQueryTest, NotMatchingPseudoElement) {
selector_list = CSSParser::ParseSelector(
MakeGarbageCollected<CSSParserContext>(
*document, NullURL(), true /* origin_clean */,
network::mojom::ReferrerPolicy::kDefault, WTF::TextEncoding(),
CSSParserContext::kSnapshotProfile),
*document, NullURL(), true /* origin_clean */, Referrer(),
WTF::TextEncoding(), CSSParserContext::kSnapshotProfile),
nullptr, "span");
query = SelectorQuery::Adopt(std::move(selector_list));
elm = query->QueryFirst(*document);
......@@ -103,9 +101,8 @@ TEST(SelectorQueryTest, LastOfTypeNotFinishedParsing) {
CSSSelectorList selector_list = CSSParser::ParseSelector(
MakeGarbageCollected<CSSParserContext>(
*document, NullURL(), true /* origin_clean */,
network::mojom::ReferrerPolicy::kDefault, WTF::TextEncoding(),
CSSParserContext::kSnapshotProfile),
*document, NullURL(), true /* origin_clean */, Referrer(),
WTF::TextEncoding(), CSSParserContext::kSnapshotProfile),
nullptr, "p:last-of-type");
std::unique_ptr<SelectorQuery> query =
SelectorQuery::Adopt(std::move(selector_list));
......
......@@ -83,8 +83,9 @@ void StyleRuleImport::NotifyFinished(Resource* resource) {
CSSParserContext* context = MakeGarbageCollected<CSSParserContext>(
parent_context, cached_style_sheet->GetResponse().ResponseUrl(),
cached_style_sheet->GetResponse().IsCorsSameOrigin(),
cached_style_sheet->GetReferrerPolicy(), cached_style_sheet->Encoding(),
document);
Referrer(cached_style_sheet->GetResponse().ResponseUrl(),
cached_style_sheet->GetReferrerPolicy()),
cached_style_sheet->Encoding(), document);
if (cached_style_sheet->GetResourceRequest().IsAdResource())
context->SetIsAdRelated();
......
......@@ -206,7 +206,9 @@ void ProcessingInstruction::NotifyFinished(Resource* resource) {
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
GetDocument(), style_resource->GetResponse().ResponseUrl(),
style_resource->GetResponse().IsCorsSameOrigin(),
style_resource->GetReferrerPolicy(), style_resource->Encoding());
Referrer(style_resource->GetResponse().ResponseUrl(),
style_resource->GetReferrerPolicy()),
style_resource->Encoding());
if (style_resource->GetResourceRequest().IsAdResource())
parser_context->SetIsAdRelated();
......
......@@ -88,7 +88,9 @@ void LinkStyle::NotifyFinished(Resource* resource) {
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
GetDocument(), cached_style_sheet->GetResponse().ResponseUrl(),
cached_style_sheet->GetResponse().IsCorsSameOrigin(),
cached_style_sheet->GetReferrerPolicy(), cached_style_sheet->Encoding());
Referrer(cached_style_sheet->GetResponse().ResponseUrl(),
cached_style_sheet->GetReferrerPolicy()),
cached_style_sheet->Encoding());
if (cached_style_sheet->GetResourceRequest().IsAdResource()) {
parser_context->SetIsAdRelated();
}
......
......@@ -244,9 +244,8 @@ VTTParser::ParseState VTTParser::CollectRegionSettings(const String& line) {
VTTParser::ParseState VTTParser::CollectStyleSheet(const String& line) {
if (line.IsEmpty() || line.Contains("-->")) {
auto* parser_context = MakeGarbageCollected<CSSParserContext>(
*document_, NullURL(), true /* origin_clean */,
document_->GetReferrerPolicy(), UTF8Encoding(),
CSSParserContext::kLiveProfile,
*document_, NullURL(), true /* origin_clean */, Referrer(),
UTF8Encoding(), CSSParserContext::kLiveProfile,
ResourceFetchRestriction::kOnlyDataUrls);
auto* style_sheet_contents =
MakeGarbageCollected<StyleSheetContents>(parser_context);
......
......@@ -2826,6 +2826,7 @@ crbug.com/1131471 external/wpt/web-locks/clientids.tentative.https.html [ Failur
# See also crbug.com/920100 (sheriff 2019-01-09).
crbug.com/626703 external/wpt/referrer-policy/css-integration/svg/external-stylesheet.html [ Timeout Failure ]
crbug.com/626703 external/wpt/referrer-policy/css-integration/svg/inline-style.html [ Timeout Failure ]
crbug.com/626703 external/wpt/referrer-policy/css-integration/svg/inline-style-with-differentorigin-base-tag.tentative.html [ Timeout Failure ]
crbug.com/626703 external/wpt/referrer-policy/css-integration/svg/internal-stylesheet.html [ Timeout Failure ]
crbug.com/626703 external/wpt/referrer-policy/css-integration/svg/presentation-attribute.html [ Timeout Failure ]
crbug.com/626703 external/wpt/referrer-policy/css-integration/svg/processing-instruction.html [ Timeout Failure ]
......
<!DOCTYPE html>
<title>CSS integration - image from inline style from document with base tag</title>
<link rel="help" href="https://crbug.com/1158645" />
<head>
<meta name="referrer" content="origin">
</head>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<!-- Common global functions for referrer-policy tests. -->
<script src="/common/security-features/resources/common.sub.js"></script>
<!-- This has to follow the <script> tags, or it will make the js files fail to load. -->
<base href="http://other-site.example" />
<p>Check that resources from inline styles are loaded with
the referrer and referrer policy from the document and, in
particular, not with the different base URL set in the base tag.</p>
<div class="styled"></div>
<script>
'use strict';
promise_test(function(css_test) {
var id = token();
var css_url = location.protocol + "//www1." + location.hostname + ":" + location.port + "/common/security-features/subresource/image.py" + "?id=" + id;
var img_url = css_url + "&report-headers";
var div = document.querySelector("div.styled");
div.style = "content:url(" + css_url + ")";
return timeoutPromise(css_test, 1000)
.then(() => requestViaXhr(img_url))
.then(function(message) {
assert_own_property(message, "headers");
assert_own_property(message, "referrer");
assert_equals(message.referrer, location.origin + "/");
});
}, "Image from inline styles.");
</script>
<div id="log"></div>
</html>
<!DOCTYPE html>
<html>
<head>
<title>CSS integration - styling SVG from inline style on page with different-origin base tag</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/utils.js"></script>
<!-- Common global functions for referrer-policy tests. -->
<script src="/common/security-features/resources/common.sub.js"></script>
<!-- Helper functions for referrer-policy css tests. -->
<script src="/referrer-policy/css-integration/css-test-helper.js"></script>
<meta name="referrer" content="origin">
</head>
<base href="http://other-page.example/" />
<body>
<p>Check that resources from inline styles are loaded with
the referrer and referrer policy from the document and, in
particular, not from the document's overridden base URL.</p>
<script>
function setInlineStyle(test) {
test.expected = location.origin + "/";
let svg = createSvg();
document.body.appendChild(svg);
let element = svg.getElementsByTagName('path')[0];
element.style = test.property + ": url(" + url_prefix + "svg.py?id=" +
test.id + "#invalidFragment);";
}
runSvgTests(svg_test_properties,
"Styling SVG from inline styles",
setInlineStyle);
</script>
<div id="log"></div>
</body>
</html>
......@@ -31,7 +31,7 @@ $expectedReferrerPaths = array(
"document" => "/css/css-resources-referrer.html",
"sheet" => "/css/resources/css-resources-referrer.css",
"importedSheet" => "/css/resources/css-resources-referrer-import.css",
"iframe" => "/from/iframe.html"
"iframe" => "/css/css-resources-referrer-srcdoc.html"
);
$from = $_GET["from"];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment