Use default value for incoming policy when required entry not found in incoming policy

This CL let document policy use default value when not specified in header.
This CL also lets static content such as about:blank/about:srcdoc to always fulfill required document policy so that they are not blocked.

Change-Id: I14bf7d114fcd838f92ae91f773bde944f65f2c13
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2039972
Commit-Queue: Charlie Hu <chenleihu@google.com>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Ian Clelland <iclelland@chromium.org>
Cr-Commit-Position: refs/heads/master@{#741485}
diff --git a/third_party/blink/common/feature_policy/document_policy.cc b/third_party/blink/common/feature_policy/document_policy.cc
index 1f1cc19..f1c03bf9 100644
--- a/third_party/blink/common/feature_policy/document_policy.cc
+++ b/third_party/blink/common/feature_policy/document_policy.cc
@@ -172,17 +172,21 @@
 bool DocumentPolicy::IsPolicyCompatible(
     const DocumentPolicy::FeatureState& required_policy,
     const DocumentPolicy::FeatureState& incoming_policy) {
-  for (const auto& incoming_entry : incoming_policy) {
+  for (const auto& required_entry : required_policy) {
     // feature value > threshold => enabled, where feature value is the value in
     // document policy and threshold is the value to test against.
     // The smaller the feature value, the stricter the policy.
     // Incoming policy should be at least as strict as the required one.
-    const auto required_entry =
-        required_policy.find(incoming_entry.first /* feature */);
+    const auto& feature = required_entry.first;
+    const auto& required_value = required_entry.second;
+    // Use default value when incoming policy does not specify a value.
+    const auto incoming_entry = incoming_policy.find(feature);
+    const auto& incoming_value =
+        incoming_entry != incoming_policy.end()
+            ? incoming_entry->second
+            : GetDocumentPolicyFeatureInfoMap().at(feature).default_value;
 
-    if (required_entry != required_policy.end() &&
-        required_entry->second /* required_value */ <
-            incoming_entry.second /* incoming_value */)
+    if (required_value < incoming_value)
       return false;
   }
   return true;
diff --git a/third_party/blink/common/feature_policy/document_policy_unittest.cc b/third_party/blink/common/feature_policy/document_policy_unittest.cc
index e9444f9..5d8a81d3 100644
--- a/third_party/blink/common/feature_policy/document_policy_unittest.cc
+++ b/third_party/blink/common/feature_policy/document_policy_unittest.cc
@@ -5,18 +5,13 @@
 #include "third_party/blink/public/common/feature_policy/document_policy.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/feature_policy/document_policy_features.h"
 #include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom.h"
 
 namespace blink {
 namespace {
 
-class DocumentPolicyTest : public ::testing::Test {
- public:
-  DocumentPolicyTest() = default;
-
- protected:
-  std::unique_ptr<DocumentPolicy> document_policy_;
-};
+using DocumentPolicyTest = ::testing::Test;
 
 // Helper function to convert literal to FeatureState.
 template <class T>
@@ -49,5 +44,24 @@
       FeatureState<double>({{1, 1.0}, {2, 0.5}, {3, 1.0}, {4, 0.5}, {5, 1.0}}));
 }
 
+// IsPolicyCompatible should use default value for incoming policy when required
+// policy specifies a value for a feature and incoming policy is missing value
+// for that feature.
+TEST_F(DocumentPolicyTest, IsPolicyCompatible) {
+  mojom::FeaturePolicyFeature feature =
+      mojom::FeaturePolicyFeature::kUnoptimizedLosslessImages;
+  double default_policy_value =
+      GetDocumentPolicyFeatureInfoMap().at(feature).default_value.DoubleValue();
+  // Cap the default_policy_value, as it can be INF.
+  double strict_policy_value =
+      default_policy_value > 1.0 ? 1.0 : default_policy_value / 2;
+
+  EXPECT_FALSE(DocumentPolicy::IsPolicyCompatible(
+      DocumentPolicy::FeatureState{
+          {feature, PolicyValue(strict_policy_value)}}, /* required policy */
+      DocumentPolicy::FeatureState{}                    /* incoming policy */
+      ));
+}
+
 }  // namespace
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 65c68af..022c9c7 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -822,6 +822,13 @@
   if (!RuntimeEnabledFeatures::DocumentPolicyEnabled())
     return DocumentPolicy::FeatureState{};
 
+  // For URLs referring to local content to parent frame, they have no way to
+  // specify the document policy they use. If the parent frame requires a
+  // document policy on them, use the required policy as effective policy.
+  if (url_.IsEmpty() || url_.ProtocolIsAbout() || url_.ProtocolIsData() ||
+      url_.ProtocolIs("blob") || url_.ProtocolIs("filesystem"))
+    return frame_policy_.required_document_policy;
+
   const DocumentPolicy::FeatureState header_policy =
       DocumentPolicyParser::Parse(
           response_.HttpHeaderField(http_names::kDocumentPolicy))