Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(515)

Side by Side Diff: third_party/WebKit/Source/platform/feature_policy/FeaturePolicy.cpp

Issue 2254533002: [FeaturePolicy] Initial implementation of Feature Policy (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@fp-flag
Patch Set: Conform to JFV spec for header format Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "platform/feature_policy/FeaturePolicy.h"
6
7 #include "platform/json/JSONValues.h"
8 #include "platform/network/HTTPParsers.h"
9 #include "platform/weborigin/KURL.h"
10 #include "platform/weborigin/SecurityOrigin.h"
11 #include "wtf/text/StringBuilder.h"
12
13 namespace blink {
14
15 namespace {
16
17 // Given a string name, return the matching feature struct, or nullptr if it is
18 // not the name of a policy-controlled feature.
19 const FeaturePolicyFeature* featureForName(const String& featureName) {
20 for (const FeaturePolicyFeature* feature :
21 FeaturePolicy::getFeatureRegistry()) {
22 if (featureName == feature->featureName)
23 return feature;
24 }
25 return nullptr;
26 }
27
28 // Parses a feature policy string into a mapping of features to whitelists. The
29 // parse algorithm is deliberately very lenient, and will return as much as it
30 // can recognize. Unrecognized features are simply ignored, as are invalid
31 // policy items and invalid origins inside of whitelists.
32 HeapHashMap<const FeaturePolicyFeature*, Member<FeaturePolicy::Whitelist>>
33 parseFeaturePolicyString(std::unique_ptr<JSONArray> policyJSON,
34 RefPtr<SecurityOrigin> origin) {
35 HeapHashMap<const FeaturePolicyFeature*, Member<FeaturePolicy::Whitelist>>
36 whitelists;
37
38 if (!policyJSON)
39 return whitelists; // Policy string is not valid JSON
40
41 std::unique_ptr<JSONArray> items = JSONArray::cast(std::move(policyJSON));
dcheng 2016/10/20 17:41:44 The input is already a JSONArray, so this cast is
iclelland 2016/10/21 13:38:25 Done.
42 if (!items)
43 return whitelists; // Policy string is not an array
44
45 for (size_t i = 0; i < items->size(); ++i) {
46 JSONObject* item = JSONObject::cast(items->at(i));
47 if (!item)
48 continue; // Array element is not an object; skip
49
50 for (size_t j = 0; j < item->size(); ++j) {
51 JSONObject::Entry entry = item->at(j);
52 String featureName = entry.first;
53 const FeaturePolicyFeature* feature = featureForName(featureName);
54 if (!feature)
55 continue; // Feature is not recognized; skip
56
57 JSONArray* targets = JSONArray::cast(entry.second);
58 if (!targets)
59 continue; // Whitelist is not an array; skip
60
61 FeaturePolicy::Whitelist* whitelist = new FeaturePolicy::Whitelist;
62 String targetString;
63 for (size_t j = 0; j < targets->size(); ++j) {
64 if (targets->at(j)->asString(&targetString)) {
65 if (equalIgnoringCase(targetString, "self")) {
66 whitelist->add(origin);
67 } else if (targetString == "*") {
68 whitelist->addAll();
69 } else {
70 KURL originUrl = KURL(KURL(), targetString);
71 if (originUrl.isValid()) {
72 whitelist->add(SecurityOrigin::create(originUrl));
73 }
74 }
75 }
76 }
77 whitelists.set(feature, whitelist);
78 }
79 }
80 return whitelists;
81 }
82
83 } // namespace
84
85 // Definitions of all features controlled by Feature Policy should appear here.
86 const FeaturePolicyFeature kDocumentCookie{"cookie",
87 kEnableFeatureForAllOrigins};
88 const FeaturePolicyFeature kDocumentDomain{"domain",
89 kEnableFeatureForAllOrigins};
90 const FeaturePolicyFeature kDocumentWrite{"docwrite",
91 kEnableFeatureForAllOrigins};
92 const FeaturePolicyFeature kGeolocationFeature{"geolocation",
93 kEnableFeatureForSelf};
94 const FeaturePolicyFeature kMidiFeature{"midi", kEnableFeatureForAllOrigins};
95 const FeaturePolicyFeature kNotificationsFeature{"notifications",
96 kEnableFeatureForAllOrigins};
97 const FeaturePolicyFeature kPaymentFeature{"payment", kEnableFeatureForSelf};
98 const FeaturePolicyFeature kPushFeature{"push", kEnableFeatureForAllOrigins};
99 const FeaturePolicyFeature kSyncScript{"sync-script",
100 kEnableFeatureForAllOrigins};
101 const FeaturePolicyFeature kSyncXHR{"sync-xhr", kEnableFeatureForAllOrigins};
102 const FeaturePolicyFeature kUsermedia{"usermedia", kEnableFeatureForAllOrigins};
103 const FeaturePolicyFeature kVibrateFeature{"vibrate", kEnableFeatureForSelf};
104 const FeaturePolicyFeature kWebRTC{"webrtc", kEnableFeatureForAllOrigins};
105
106 FeaturePolicy::Whitelist::Whitelist() : m_matchesAllOrigins(false) {}
107
108 void FeaturePolicy::Whitelist::addAll() {
109 m_matchesAllOrigins = true;
110 }
111
112 void FeaturePolicy::Whitelist::add(RefPtr<SecurityOrigin> origin) {
113 m_origins.append(std::move(origin));
114 }
115
116 bool FeaturePolicy::Whitelist::contains(const SecurityOrigin& origin) const {
117 if (m_matchesAllOrigins)
118 return true;
119 for (const auto& targetOrigin : m_origins) {
120 if (targetOrigin->isSameSchemeHostPortAndSuborigin(&origin))
121 return true;
122 }
123 return false;
124 }
125
126 String FeaturePolicy::Whitelist::toString() {
127 StringBuilder sb;
128 sb.append("[");
129 if (m_matchesAllOrigins) {
130 sb.append("*");
131 } else {
132 for (size_t i = 0; i < m_origins.size(); ++i) {
133 if (i > 0) {
134 sb.append(", ");
135 }
136 sb.append(m_origins[i]->toString());
137 }
138 }
139 sb.append("]");
140 return sb.toString();
141 }
142
143 // static
144 Vector<const FeaturePolicyFeature*>& FeaturePolicy::getFeatureRegistry() {
145 DEFINE_STATIC_LOCAL(
146 Vector<const FeaturePolicyFeature*>, featureRegistry,
147 ({&kDocumentCookie, &kDocumentDomain, &kDocumentWrite,
148 &kGeolocationFeature, &kMidiFeature, &kNotificationsFeature,
149 &kPaymentFeature, &kPushFeature, &kSyncScript, &kSyncXHR, &kUsermedia,
150 &kVibrateFeature, &kWebRTC}));
151 return featureRegistry;
152 }
153
154 // static
155 FeaturePolicy* FeaturePolicy::createFromParentPolicy(
156 const FeaturePolicy* parent,
157 RefPtr<SecurityOrigin> currentOrigin) {
158 DCHECK(currentOrigin);
159 FeaturePolicy* newPolicy = new FeaturePolicy(currentOrigin);
160 for (const FeaturePolicyFeature* feature : getFeatureRegistry()) {
161 if (!parent || parent->isFeatureEnabledForOrigin(feature, *currentOrigin)) {
162 newPolicy->m_inheritedFeatures.set(feature, true);
163 } else {
164 newPolicy->m_inheritedFeatures.set(feature, false);
165 }
166 }
167 return newPolicy;
168 }
169
170 void FeaturePolicy::setHeaderPolicy(const String& policy) {
171 DCHECK(m_headerWhitelists.isEmpty());
172 std::unique_ptr<JSONArray> policyJSON = parseJSONHeader(policy);
173 if (!policyJSON)
174 return;
175 for (const auto& whitelist :
176 parseFeaturePolicyString(std::move(policyJSON), m_origin)) {
177 m_headerWhitelists.set(whitelist.key, whitelist.value);
raymes 2016/10/19 23:47:36 Could we just set m_headerWhitelists = parseFeatu
iclelland 2016/10/21 13:38:25 I think we can -- this used to be guarded, feature
178 }
179 }
180
181 bool FeaturePolicy::isFeatureEnabledForOrigin(
182 const FeaturePolicyFeature* feature,
183 const SecurityOrigin& origin) const {
184 if (m_inheritedFeatures.contains(feature)) {
raymes 2016/10/19 23:47:36 Can we remove this now (or make it a DCHECK?)
iclelland 2016/10/21 13:38:25 I'll make it a dcheck -- it'll just guard against
185 if (!m_inheritedFeatures.get(feature)) {
186 return false;
187 }
188 }
189 if (m_headerWhitelists.contains(feature)) {
190 return m_headerWhitelists.get(feature)->contains(origin);
191 }
192 if (feature->defaultPolicy == kEnableFeatureForAllOrigins) {
193 return true;
194 }
195 if (feature->defaultPolicy == kEnableFeatureForSelf) {
196 return m_origin->isSameSchemeHostPortAndSuborigin(&origin);
197 }
198 return false;
199 }
200
201 bool FeaturePolicy::isFeatureEnabled(
202 const FeaturePolicyFeature* feature) const {
203 DCHECK(m_origin);
204 return isFeatureEnabledForOrigin(feature, *m_origin);
205 }
206
207 FeaturePolicy::FeaturePolicy(RefPtr<SecurityOrigin> currentOrigin)
208 : m_origin(std::move(currentOrigin)) {}
209
210 String FeaturePolicy::toString() {
211 StringBuilder sb;
212 sb.append("Feature Policy for frame in origin: ");
213 sb.append(m_origin->toString());
214 sb.append("\n");
215 sb.append("Inherited features:\n");
216 for (const auto& inheritedFeature : m_inheritedFeatures) {
217 sb.append(" ");
218 sb.append(inheritedFeature.key->featureName);
219 sb.append(": ");
220 sb.append(inheritedFeature.value ? "true" : "false");
221 sb.append("\n");
222 }
223 sb.append("Header whitelists:\n");
224 for (const auto& whitelist : m_headerWhitelists) {
225 sb.append(" ");
226 sb.append(whitelist.key->featureName);
227 sb.append(": ");
228 sb.append(whitelist.value->toString());
229 sb.append("\n");
230 }
231 return sb.toString();
232 }
233
234 DEFINE_TRACE(FeaturePolicy) {
235 visitor->trace(m_headerWhitelists);
236 }
237
238 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698