OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. | 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 11 matching lines...) Expand all Loading... | |
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 * | 24 * |
25 */ | 25 */ |
26 | 26 |
27 #include "config.h" | 27 #include "config.h" |
28 #include "core/fetch/CrossOriginAccessControl.h" | 28 #include "core/fetch/CrossOriginAccessControl.h" |
29 | 29 |
30 #include "core/fetch/Resource.h" | 30 #include "core/fetch/Resource.h" |
31 #include "core/fetch/ResourceLoaderOptions.h" | 31 #include "core/fetch/ResourceLoaderOptions.h" |
32 #include "platform/RuntimeEnabledFeatures.h" | |
32 #include "platform/network/HTTPParsers.h" | 33 #include "platform/network/HTTPParsers.h" |
33 #include "platform/network/ResourceRequest.h" | 34 #include "platform/network/ResourceRequest.h" |
34 #include "platform/network/ResourceResponse.h" | 35 #include "platform/network/ResourceResponse.h" |
35 #include "platform/weborigin/SchemeRegistry.h" | 36 #include "platform/weborigin/SchemeRegistry.h" |
36 #include "platform/weborigin/SecurityOrigin.h" | 37 #include "platform/weborigin/SecurityOrigin.h" |
37 #include "wtf/Threading.h" | 38 #include "wtf/Threading.h" |
38 #include "wtf/text/AtomicString.h" | 39 #include "wtf/text/AtomicString.h" |
39 #include "wtf/text/StringBuilder.h" | 40 #include "wtf/text/StringBuilder.h" |
40 | 41 |
41 namespace blink { | 42 namespace blink { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 } | 98 } |
98 | 99 |
99 return preflightRequest; | 100 return preflightRequest; |
100 } | 101 } |
101 | 102 |
102 static bool isOriginSeparator(UChar ch) | 103 static bool isOriginSeparator(UChar ch) |
103 { | 104 { |
104 return isASCIISpace(ch) || ch == ','; | 105 return isASCIISpace(ch) || ch == ','; |
105 } | 106 } |
106 | 107 |
108 static bool experimentalContentSecurityPolicyFeaturesEnabled() | |
109 { | |
110 return RuntimeEnabledFeatures::experimentalContentSecurityPolicyFeaturesEnab led(); | |
Mike West
2014/10/23 12:59:19
For clarity, I'd suggest adding a RuntimeEnabledFe
jww
2015/03/20 22:50:02
Done.
| |
111 } | |
112 | |
107 static bool isInterestingStatusCode(int statusCode) | 113 static bool isInterestingStatusCode(int statusCode) |
108 { | 114 { |
109 // Predicate that gates what status codes should be included in | 115 // Predicate that gates what status codes should be included in |
110 // console error messages for responses containing no access | 116 // console error messages for responses containing no access |
111 // control headers. | 117 // control headers. |
112 return statusCode >= 400; | 118 return statusCode >= 400; |
113 } | 119 } |
114 | 120 |
115 bool passesAccessControlCheck(const ResourceResponse& response, StoredCredential s includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription) | 121 bool passesAccessControlCheck(const ResourceResponse& response, StoredCredential s includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription) |
116 { | 122 { |
117 AtomicallyInitializedStatic(AtomicString&, accessControlAllowOrigin = *new A tomicString("access-control-allow-origin", AtomicString::ConstructFromLiteral)); | 123 AtomicallyInitializedStatic(AtomicString&, accessControlAllowOrigin = *new A tomicString("access-control-allow-origin", AtomicString::ConstructFromLiteral)); |
118 AtomicallyInitializedStatic(AtomicString&, accessControlAllowCredentials = * new AtomicString("access-control-allow-credentials", AtomicString::ConstructFrom Literal)); | 124 AtomicallyInitializedStatic(AtomicString&, accessControlAllowCredentials = * new AtomicString("access-control-allow-credentials", AtomicString::ConstructFrom Literal)); |
125 AtomicallyInitializedStatic(AtomicString&, accessControlAllowFinerOrigin = * new AtomicString("access-control-allow-finer-origin", AtomicString::ConstructFro mLiteral)); | |
Mike West
2014/10/23 12:59:18
"finer-origin"? Why not "suborigin"?
This is a sp
jww
2015/03/20 22:50:02
I'll leave this for now since it's what I've said
| |
119 | 126 |
120 if (!response.httpStatusCode()) { | 127 if (!response.httpStatusCode()) { |
121 errorDescription = "Received an invalid response. Origin '" + securityOr igin->toString() + "' is therefore not allowed access."; | 128 errorDescription = "Received an invalid response. Origin '" + securityOr igin->toString() + "' is therefore not allowed access."; |
122 return false; | 129 return false; |
123 } | 130 } |
124 | 131 |
125 const AtomicString& accessControlOriginString = response.httpHeaderField(acc essControlAllowOrigin); | 132 const AtomicString& accessControlOriginString = response.httpHeaderField(acc essControlAllowOrigin); |
126 if (accessControlOriginString == starAtom) { | 133 const AtomicString& accessControlFinerOriginString = response.httpHeaderFiel d(accessControlAllowFinerOrigin); |
134 if (accessControlOriginString == starAtom || accessControlAllowFinerOrigin = = starAtom) { | |
Mike West
2014/10/23 12:59:18
This seems wrong: as written, either `a-c-allow-or
jww
2015/03/20 22:50:02
This is on purpose, and I've tried to explain in t
| |
127 // A wildcard Access-Control-Allow-Origin can not be used if credentials are to be sent, | 135 // A wildcard Access-Control-Allow-Origin can not be used if credentials are to be sent, |
128 // even with Access-Control-Allow-Credentials set to true. | 136 // even with Access-Control-Allow-Credentials set to true. |
129 if (includeCredentials == DoNotAllowStoredCredentials) | 137 if (includeCredentials == DoNotAllowStoredCredentials) |
130 return true; | 138 return true; |
131 if (response.isHTTP()) { | 139 if (response.isHTTP()) { |
132 errorDescription = "A wildcard '*' cannot be used in the 'Access-Con trol-Allow-Origin' header when the credentials flag is true. Origin '" + securit yOrigin->toString() + "' is therefore not allowed access."; | 140 if (!experimentalContentSecurityPolicyFeaturesEnabled()) |
133 return false; | 141 errorDescription = "A wildcard '*' cannot be used in the 'Access -Control-Allow-Origin' header when the credentials flag is true. Origin '" + sec urityOrigin->toString() + "' is therefore not allowed access."; |
142 else | |
143 errorDescription = "A wildcard '*' cannot be used in the 'Access -Control-Allow-Origin' or 'Access-Control-Allow-Finer-Origin' header when the cr edentials flag is true. Origin '" + securityOrigin->toString() + "' is therefore not allowed access."; | |
134 } | 144 } |
135 } else if (accessControlOriginString != securityOrigin->toAtomicString()) { | 145 } else if (accessControlOriginString != securityOrigin->toAtomicString() && accessControlFinerOriginString != securityOrigin->toRawAtomicString()) { |
136 if (accessControlOriginString.isEmpty()) { | 146 if (accessControlOriginString.isEmpty() && accessControlFinerOriginStrin g.isEmpty()) { |
137 errorDescription = "No 'Access-Control-Allow-Origin' header is prese nt on the requested resource. Origin '" + securityOrigin->toString() + "' is the refore not allowed access."; | 147 if (!experimentalContentSecurityPolicyFeaturesEnabled()) |
138 | 148 errorDescription = "No 'Access-Control-Allow-Origin' header is p resent on the requested resource. Origin '" + securityOrigin->toString() + "' is therefore not allowed access."; |
149 else | |
150 errorDescription = "No 'Access-Control-Allow-Origin' or 'Access- Control-Allow-accessControlFinerOriginString' header is present on the requested resource. Origin '" + securityOrigin->toString() + "' is therefore not allowed access."; | |
139 if (isInterestingStatusCode(response.httpStatusCode())) | 151 if (isInterestingStatusCode(response.httpStatusCode())) |
140 errorDescription.append(" The response had HTTP status code " + String::number(response.httpStatusCode()) + "."); | 152 errorDescription.append(" The response had HTTP status code " + String::number(response.httpStatusCode()) + "."); |
141 } else if (accessControlOriginString.string().find(isOriginSeparator, 0) != kNotFound) { | 153 } else if (accessControlOriginString.string().find(isOriginSeparator, 0) != kNotFound || accessControlFinerOriginString.string().find(isOriginSeparator, 0) != kNotFound) { |
142 errorDescription = "The 'Access-Control-Allow-Origin' header contain s multiple values '" + accessControlOriginString + "', but only one is allowed. Origin '" + securityOrigin->toString() + "' is therefore not allowed access."; | 154 if (!experimentalContentSecurityPolicyFeaturesEnabled()) |
155 errorDescription = "The 'Access-Control-Allow-Origin' header con tains multiple values '" + accessControlOriginString + "', but only one is allow ed. Origin '" + securityOrigin->toString() + "' is therefore not allowed access. "; | |
156 else | |
157 errorDescription = "The 'Access-Control-Allow-Origin' or 'Access -Control-Allow-Finer-Origin' header contains multiple values '" + accessControlO riginString + "', but only one is allowed. Origin '" + securityOrigin->toString( ) + "' is therefore not allowed access."; | |
143 } else { | 158 } else { |
144 KURL headerOrigin(KURL(), accessControlOriginString); | 159 KURL headerOrigin(KURL(), accessControlOriginString); |
145 if (!headerOrigin.isValid()) | 160 KURL headerFinerOrigin(KURL(), accessControlFinerOriginString); |
161 if (!headerOrigin.isValid()) { | |
146 errorDescription = "The 'Access-Control-Allow-Origin' header con tains the invalid value '" + accessControlOriginString + "'. Origin '" + securit yOrigin->toString() + "' is therefore not allowed access."; | 162 errorDescription = "The 'Access-Control-Allow-Origin' header con tains the invalid value '" + accessControlOriginString + "'. Origin '" + securit yOrigin->toString() + "' is therefore not allowed access."; |
147 else | 163 } else if (experimentalContentSecurityPolicyFeaturesEnabled() && !he aderFinerOrigin.isValid()) { |
148 errorDescription = "The 'Access-Control-Allow-Origin' header has a value '" + accessControlOriginString + "' that is not equal to the supplied o rigin. Origin '" + securityOrigin->toString() + "' is therefore not allowed acce ss."; | 164 errorDescription = "The 'Access-Control-Allow-Finer-Origin' head er contains the invalid value '" + accessControlOriginString + "'. Origin '" + s ecurityOrigin->toString() + "' is therefore not allowed access."; |
165 } else { | |
166 if (!experimentalContentSecurityPolicyFeaturesEnabled()) | |
167 errorDescription = "The 'Access-Control-Allow-Origin' header has a value '" + accessControlOriginString + "' that is not equal to the suppli ed origin. Origin '" + securityOrigin->toString() + "' is therefore not allowed access."; | |
168 else | |
169 errorDescription = "The 'Access-Control-Allow-Origin' or 'Ac cess-Control-Allow-Finer-Origin' header has a value '" + accessControlOriginStri ng + "' that is not equal to the supplied origin. Origin '" + securityOrigin->to String() + "' is therefore not allowed access."; | |
Mike West
2014/10/23 12:59:19
I'd suggest moving all the occurrences of these er
jww
2015/03/20 22:50:02
Done. It's still a bit ugly, though, so any other
| |
170 } | |
149 } | 171 } |
150 return false; | 172 return false; |
151 } | 173 } |
152 | 174 |
153 if (includeCredentials == AllowStoredCredentials) { | 175 if (includeCredentials == AllowStoredCredentials) { |
154 const AtomicString& accessControlCredentialsString = response.httpHeader Field(accessControlAllowCredentials); | 176 const AtomicString& accessControlCredentialsString = response.httpHeader Field(accessControlAllowCredentials); |
155 if (accessControlCredentialsString != "true") { | 177 if (accessControlCredentialsString != "true") { |
156 errorDescription = "Credentials flag is 'true', but the 'Access-Cont rol-Allow-Credentials' header is '" + accessControlCredentialsString + "'. It mu st be 'true' to allow credentials."; | 178 errorDescription = "Credentials flag is 'true', but the 'Access-Cont rol-Allow-Credentials' header is '" + accessControlCredentialsString + "'. It mu st be 'true' to allow credentials."; |
157 return false; | 179 return false; |
158 } | 180 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
239 request.setHTTPOrigin(securityOrigin->toAtomicString()); | 261 request.setHTTPOrigin(securityOrigin->toAtomicString()); |
240 // If the user didn't request credentials in the first place, update our | 262 // If the user didn't request credentials in the first place, update our |
241 // state so we neither request them nor expect they must be allowed. | 263 // state so we neither request them nor expect they must be allowed. |
242 if (options.credentialsRequested == ClientDidNotRequestCredentials) | 264 if (options.credentialsRequested == ClientDidNotRequestCredentials) |
243 options.allowCredentials = DoNotAllowStoredCredentials; | 265 options.allowCredentials = DoNotAllowStoredCredentials; |
244 } | 266 } |
245 return true; | 267 return true; |
246 } | 268 } |
247 | 269 |
248 } // namespace blink | 270 } // namespace blink |
OLD | NEW |