Commit 8fb68e33 authored by Charlie Hu's avatar Charlie Hu Committed by Chromium LUCI CQ

[Document Policy] Fix Document Policy lost issue in XSLT documents

This CL fixes the missing Document Policy issue for XSLT document.
The fix is similar to the previous fix on Permissions Policy.
See https://chromium-review.googlesource.com/c/chromium/src/+/2561144.

Bug: 1151954
Change-Id: Ie080c360ddc70ac46a63d5166b3830752ecdd94e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2563440
Commit-Queue: Charlie Hu <chenleihu@google.com>
Reviewed-by: default avatarIan Clelland <iclelland@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833361}
parent b8b242f8
...@@ -21,6 +21,21 @@ std::unique_ptr<DocumentPolicy> DocumentPolicy::CreateWithHeaderPolicy( ...@@ -21,6 +21,21 @@ std::unique_ptr<DocumentPolicy> DocumentPolicy::CreateWithHeaderPolicy(
header_policy.endpoint_map, feature_defaults); header_policy.endpoint_map, feature_defaults);
} }
// static
std::unique_ptr<DocumentPolicy> DocumentPolicy::CopyStateFrom(
const DocumentPolicy* source) {
if (!source)
return nullptr;
std::unique_ptr<DocumentPolicy> new_policy =
DocumentPolicy::CreateWithHeaderPolicy(
{/* header_policy */ {}, /* endpoint_map */ {}});
new_policy->internal_feature_state_ = source->internal_feature_state_;
new_policy->endpoint_map_ = source->endpoint_map_;
return new_policy;
}
namespace { namespace {
net::structured_headers::Item PolicyValueToItem(const PolicyValue& value) { net::structured_headers::Item PolicyValueToItem(const PolicyValue& value) {
switch (value.Type()) { switch (value.Type()) {
......
...@@ -76,6 +76,8 @@ class BLINK_COMMON_EXPORT DocumentPolicy { ...@@ -76,6 +76,8 @@ class BLINK_COMMON_EXPORT DocumentPolicy {
static std::unique_ptr<DocumentPolicy> CreateWithHeaderPolicy( static std::unique_ptr<DocumentPolicy> CreateWithHeaderPolicy(
const ParsedDocumentPolicy& header_policy); const ParsedDocumentPolicy& header_policy);
static std::unique_ptr<DocumentPolicy> CopyStateFrom(const DocumentPolicy*);
// Returns true if the feature is unrestricted (has its default value for the // Returns true if the feature is unrestricted (has its default value for the
// platform) // platform)
bool IsFeatureEnabled(mojom::DocumentPolicyFeature feature) const; bool IsFeatureEnabled(mojom::DocumentPolicyFeature feature) const;
...@@ -131,9 +133,10 @@ class BLINK_COMMON_EXPORT DocumentPolicy { ...@@ -131,9 +133,10 @@ class BLINK_COMMON_EXPORT DocumentPolicy {
void UpdateFeatureState(const DocumentPolicyFeatureState& feature_state); void UpdateFeatureState(const DocumentPolicyFeatureState& feature_state);
// Internal feature state is represented as an array to avoid overhead // Internal feature state is represented as an array to avoid overhead
// in using container classes. // of indexing into map like structure.
PolicyValue internal_feature_state_ std::array<PolicyValue,
[static_cast<size_t>(mojom::DocumentPolicyFeature::kMaxValue) + 1]; static_cast<size_t>(mojom::DocumentPolicyFeature::kMaxValue) + 1>
internal_feature_state_;
FeatureEndpointMap endpoint_map_; FeatureEndpointMap endpoint_map_;
......
...@@ -273,4 +273,12 @@ void SecurityContextInit::InitFeaturePolicyFrom(const SecurityContext& other) { ...@@ -273,4 +273,12 @@ void SecurityContextInit::InitFeaturePolicyFrom(const SecurityContext& other) {
security_context.SetReportOnlyFeaturePolicy( security_context.SetReportOnlyFeaturePolicy(
FeaturePolicy::CopyStateFrom(other.GetReportOnlyFeaturePolicy())); FeaturePolicy::CopyStateFrom(other.GetReportOnlyFeaturePolicy()));
} }
void SecurityContextInit::InitDocumentPolicyFrom(const SecurityContext& other) {
auto& security_context = execution_context_->GetSecurityContext();
security_context.SetDocumentPolicy(
DocumentPolicy::CopyStateFrom(other.GetDocumentPolicy()));
security_context.SetReportOnlyDocumentPolicy(
DocumentPolicy::CopyStateFrom(other.GetReportOnlyDocumentPolicy()));
}
} // namespace blink } // namespace blink
...@@ -36,6 +36,13 @@ class CORE_EXPORT SecurityContextInit { ...@@ -36,6 +36,13 @@ class CORE_EXPORT SecurityContextInit {
// does not have header information available. // does not have header information available.
void InitFeaturePolicyFrom(const SecurityContext& other); void InitFeaturePolicyFrom(const SecurityContext& other);
// Init |document_policy_| and |report_only_document_policy_| by copying
// state from another security context instance.
// Used to carry document policy information from previous document
// to current document during XSLT navigation, because XSLT navigation
// does not have header information available.
void InitDocumentPolicyFrom(const SecurityContext& other);
void ApplyFeaturePolicy(LocalFrame* frame, void ApplyFeaturePolicy(LocalFrame* frame,
const ResourceResponse& response, const ResourceResponse& response,
const base::Optional<WebOriginPolicy>& origin_policy, const base::Optional<WebOriginPolicy>& origin_policy,
......
...@@ -1688,34 +1688,35 @@ void DocumentLoader::CommitNavigation() { ...@@ -1688,34 +1688,35 @@ void DocumentLoader::CommitNavigation() {
SecurityContextInit security_init(frame_->DomWindow()); SecurityContextInit security_init(frame_->DomWindow());
// The document constructed by XSLTProcessor should inherit Feature Policy // The document constructed by XSLTProcessor should inherit Feature Policy and
// from the previous Document. Note: In XSLT commit, |response_| no longer // Document Policy from the previous Document. Note: In XSLT commit,
// holds header fields. Going through regular initialization will cause empty // |response_| no longer holds header fields. Going through regular
// policy even if there is header on xml document. // initialization will cause empty policy even if there is header on xml
// TODO(crbug.com/1151954): Fix the problem for Document Policy as well. // document.
if (commit_reason_ == CommitReason::kXSLT) { if (commit_reason_ == CommitReason::kXSLT) {
DCHECK(response_.HttpHeaderField(http_names::kFeaturePolicy).IsEmpty()); DCHECK(response_.HttpHeaderField(http_names::kFeaturePolicy).IsEmpty());
DCHECK(response_.HttpHeaderField(http_names::kPermissionsPolicy).IsEmpty()); DCHECK(response_.HttpHeaderField(http_names::kPermissionsPolicy).IsEmpty());
DCHECK(response_.HttpHeaderField(http_names::kDocumentPolicy).IsEmpty());
security_init.InitFeaturePolicyFrom(previous_window->GetSecurityContext()); security_init.InitFeaturePolicyFrom(previous_window->GetSecurityContext());
security_init.InitDocumentPolicyFrom(previous_window->GetSecurityContext());
} else { } else {
// FeaturePolicy and DocumentPolicy require SecurityOrigin and origin trials // FeaturePolicy and DocumentPolicy require SecurityOrigin and origin trials
// to be initialized. // to be initialized.
// TODO(iclelland): Add Feature-Policy-Report-Only to Origin Policy. // TODO(iclelland): Add Feature-Policy-Report-Only to Origin Policy.
security_init.ApplyFeaturePolicy(frame_.Get(), response_, origin_policy_, security_init.ApplyFeaturePolicy(frame_.Get(), response_, origin_policy_,
frame_policy_); frame_policy_);
// |document_policy_| is parsed in document loader because it is
// compared with |frame_policy.required_document_policy| to decide
// whether to block the document load or not.
// |report_only_document_policy| does not block the page load. Its
// initialization is delayed to
// SecurityContextInit::InitializeDocumentPolicy(), similar to
// |report_only_feature_policy|.
security_init.ApplyDocumentPolicy(
document_policy_,
response_.HttpHeaderField(http_names::kDocumentPolicyReportOnly));
} }
// |document_policy_| is parsed in document loader because it is
// compared with |frame_policy.required_document_policy| to decide
// whether to block the document load or not.
// |report_only_document_policy| does not block the page load. Its
// initialization is delayed to
// SecurityContextInit::InitializeDocumentPolicy(), similar to
// |report_only_feature_policy|.
security_init.ApplyDocumentPolicy(
document_policy_,
response_.HttpHeaderField(http_names::kDocumentPolicyReportOnly));
navigation_scroll_allowed_ = !frame_->DomWindow()->IsFeatureEnabled( navigation_scroll_allowed_ = !frame_->DomWindow()->IsFeatureEnabled(
mojom::blink::DocumentPolicyFeature::kForceLoadAtTop); mojom::blink::DocumentPolicyFeature::kForceLoadAtTop);
......
<?php
header("Document-Policy: oversized-images=2.0");
header("Content-Type: application/xml");
echo '<?xml version="1.0"?>
<?xml-stylesheet href="resources/document-policy-in-xsl.xslt" type="text/xsl"?>
<page>
</page>';
?>
<?php
header("Document-Policy-Report-Only: oversized-images=2.0");
header("Content-Type: application/xml");
echo '<?xml version="1.0"?>
<?xml-stylesheet href="resources/document-policy-report-only-in-xsl.xslt" type="text/xsl"?>
<page>
</page>';
?>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="page">
<html>
<head>
<title> Test XSLT </title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
// The page is expected to have 'oversized-images' threshold
// set to 2.0, i.e. images with actual_size / display_size ratio
// > 2.0 should be replaced with placeholder images. A violation
// report is also expected to be generated.
async_test(t => {
new ReportingObserver(t.step_func_done((reports, _) => {
assert_equals(reports.length, 1);
const report = reports[0];
assert_equals(report.type, 'document-policy-violation');
assert_equals(report.body.featureId, 'oversized-images');
assert_equals(report.body.disposition, 'enforce');
}), {types: ['document-policy-violation']}).observe();
});
</script>
</head>
<body bgcolor="#ffffff">
<img src="resources/green-256x256.jpg" width="100"></img>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
\ No newline at end of file
<?xml version="1.0"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="page">
<html>
<head>
<title> Test XSLT </title>
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script>
// The page is expected to have 'oversized-images' threshold
// set to 2.0 in report only mode, i.e. images with
// actual_size / display_size ratio > 2.0 should generate
// violation reports.
async_test(t => {
new ReportingObserver(t.step_func_done((reports, _) => {
assert_equals(reports.length, 1);
const report = reports[0];
assert_equals(report.type, 'document-policy-violation');
assert_equals(report.body.featureId, 'oversized-images');
assert_equals(report.body.disposition, 'report');
}), {types: ['document-policy-violation']}).observe();
});
</script>
</head>
<body bgcolor="#ffffff">
<img src="resources/green-256x256.jpg" width="100"></img>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
\ No newline at end of file
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