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 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
122 // console error messages for responses containing no access | 122 // console error messages for responses containing no access |
123 // control headers. | 123 // control headers. |
124 return statusCode >= 400; | 124 return statusCode >= 400; |
125 } | 125 } |
126 | 126 |
127 static String buildAccessControlFailureMessage(const String& detail, SecurityOri
gin* securityOrigin) | 127 static String buildAccessControlFailureMessage(const String& detail, SecurityOri
gin* securityOrigin) |
128 { | 128 { |
129 return detail + " Origin '" + securityOrigin->toString() + "' is therefore n
ot allowed access."; | 129 return detail + " Origin '" + securityOrigin->toString() + "' is therefore n
ot allowed access."; |
130 } | 130 } |
131 | 131 |
132 bool passesAccessControlCheck(const ResourceResponse& response, StoredCredential
s includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription) | 132 bool passesAccessControlCheck(const ResourceResponse& response, StoredCredential
s includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription,
WebURLRequest::RequestContext context) |
133 { | 133 { |
134 AtomicallyInitializedStaticReference(AtomicString, allowOriginHeaderName, (n
ew AtomicString("access-control-allow-origin", AtomicString::ConstructFromLitera
l))); | 134 AtomicallyInitializedStaticReference(AtomicString, allowOriginHeaderName, (n
ew AtomicString("access-control-allow-origin", AtomicString::ConstructFromLitera
l))); |
135 AtomicallyInitializedStaticReference(AtomicString, allowCredentialsHeaderNam
e, (new AtomicString("access-control-allow-credentials", AtomicString::Construct
FromLiteral))); | 135 AtomicallyInitializedStaticReference(AtomicString, allowCredentialsHeaderNam
e, (new AtomicString("access-control-allow-credentials", AtomicString::Construct
FromLiteral))); |
136 | 136 |
137 int statusCode = response.httpStatusCode(); | 137 int statusCode = response.httpStatusCode(); |
138 | 138 |
139 if (!statusCode) { | 139 if (!statusCode) { |
140 errorDescription = buildAccessControlFailureMessage("Invalid response.",
securityOrigin); | 140 errorDescription = buildAccessControlFailureMessage("Invalid response.",
securityOrigin); |
141 return false; | 141 return false; |
142 } | 142 } |
143 | 143 |
144 const AtomicString& allowOriginHeaderValue = response.httpHeaderField(allowO
riginHeaderName); | 144 const AtomicString& allowOriginHeaderValue = response.httpHeaderField(allowO
riginHeaderName); |
145 if (allowOriginHeaderValue == starAtom) { | 145 if (allowOriginHeaderValue == starAtom) { |
146 // A wildcard Access-Control-Allow-Origin can not be used if credentials
are to be sent, | 146 // A wildcard Access-Control-Allow-Origin can not be used if credentials
are to be sent, |
147 // even with Access-Control-Allow-Credentials set to true. | 147 // even with Access-Control-Allow-Credentials set to true. |
148 if (includeCredentials == DoNotAllowStoredCredentials) | 148 if (includeCredentials == DoNotAllowStoredCredentials) |
149 return true; | 149 return true; |
150 if (response.isHTTP()) { | 150 if (response.isHTTP()) { |
151 errorDescription = buildAccessControlFailureMessage("A wildcard '*'
cannot be used in the 'Access-Control-Allow-Origin' header when the credentials
flag is true.", securityOrigin); | 151 errorDescription = buildAccessControlFailureMessage("A wildcard '*'
cannot be used in the 'Access-Control-Allow-Origin' header when the credentials
flag is true.", securityOrigin); |
152 return false; | 152 return false; |
153 } | 153 } |
154 } else if (allowOriginHeaderValue != securityOrigin->toAtomicString()) { | 154 } else if (allowOriginHeaderValue != securityOrigin->toAtomicString()) { |
155 if (allowOriginHeaderValue.isNull()) { | 155 if (allowOriginHeaderValue.isNull()) { |
156 errorDescription = buildAccessControlFailureMessage("No 'Access-Cont
rol-Allow-Origin' header is present on the requested resource.", securityOrigin)
; | 156 errorDescription = buildAccessControlFailureMessage("No 'Access-Cont
rol-Allow-Origin' header is present on the requested resource.", securityOrigin)
; |
157 | 157 |
158 if (isInterestingStatusCode(statusCode)) | 158 if (isInterestingStatusCode(statusCode)) |
159 errorDescription.append(" The response had HTTP status code " +
String::number(statusCode) + "."); | 159 errorDescription.append(" The response had HTTP status code " +
String::number(statusCode) + "."); |
160 | 160 |
| 161 if (context == WebURLRequest::RequestContextFetch) |
| 162 errorDescription.append(" If an opaque response serves your need
s, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
"); |
| 163 |
161 return false; | 164 return false; |
162 } | 165 } |
163 | 166 |
164 String detail; | 167 String detail; |
165 if (allowOriginHeaderValue.string().find(isOriginSeparator, 0) != kNotFo
und) { | 168 if (allowOriginHeaderValue.string().find(isOriginSeparator, 0) != kNotFo
und) { |
166 detail = "The 'Access-Control-Allow-Origin' header contains multiple
values '" + allowOriginHeaderValue + "', but only one is allowed."; | 169 detail = "The 'Access-Control-Allow-Origin' header contains multiple
values '" + allowOriginHeaderValue + "', but only one is allowed."; |
167 } else { | 170 } else { |
168 KURL headerOrigin(KURL(), allowOriginHeaderValue); | 171 KURL headerOrigin(KURL(), allowOriginHeaderValue); |
169 if (!headerOrigin.isValid()) | 172 if (!headerOrigin.isValid()) |
170 detail = "The 'Access-Control-Allow-Origin' header contains the
invalid value '" + allowOriginHeaderValue + "'."; | 173 detail = "The 'Access-Control-Allow-Origin' header contains the
invalid value '" + allowOriginHeaderValue + "'."; |
171 else | 174 else |
172 detail = "The 'Access-Control-Allow-Origin' header has a value '
" + allowOriginHeaderValue + "' that is not equal to the supplied origin."; | 175 detail = "The 'Access-Control-Allow-Origin' header has a value '
" + allowOriginHeaderValue + "' that is not equal to the supplied origin."; |
173 } | 176 } |
174 errorDescription = buildAccessControlFailureMessage(detail, securityOrig
in); | 177 errorDescription = buildAccessControlFailureMessage(detail, securityOrig
in); |
| 178 if (context == WebURLRequest::RequestContextFetch) |
| 179 errorDescription.append(" Have the server send the header with a val
id value, or, if an opaque response serves your needs, set the request's mode to
'no-cors' to fetch the resource with CORS disabled."); |
175 return false; | 180 return false; |
176 } | 181 } |
177 | 182 |
178 if (includeCredentials == AllowStoredCredentials) { | 183 if (includeCredentials == AllowStoredCredentials) { |
179 const AtomicString& allowCredentialsHeaderValue = response.httpHeaderFie
ld(allowCredentialsHeaderName); | 184 const AtomicString& allowCredentialsHeaderValue = response.httpHeaderFie
ld(allowCredentialsHeaderName); |
180 if (allowCredentialsHeaderValue != "true") { | 185 if (allowCredentialsHeaderValue != "true") { |
181 errorDescription = buildAccessControlFailureMessage("Credentials fla
g is 'true', but the 'Access-Control-Allow-Credentials' header is '" + allowCred
entialsHeaderValue + "'. It must be 'true' to allow credentials.", securityOrigi
n); | 186 errorDescription = buildAccessControlFailureMessage("Credentials fla
g is 'true', but the 'Access-Control-Allow-Credentials' header is '" + allowCred
entialsHeaderValue + "'. It must be 'true' to allow credentials.", securityOrigi
n); |
182 return false; | 187 return false; |
183 } | 188 } |
184 } | 189 } |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 | 244 |
240 // Same-origin request URLs that redirect are allowed without checking acces
s. | 245 // Same-origin request URLs that redirect are allowed without checking acces
s. |
241 if (!securityOrigin->canRequest(originalURL)) { | 246 if (!securityOrigin->canRequest(originalURL)) { |
242 // Follow http://www.w3.org/TR/cors/#redirect-steps | 247 // Follow http://www.w3.org/TR/cors/#redirect-steps |
243 String errorDescription; | 248 String errorDescription; |
244 | 249 |
245 // Steps 3 & 4 - check if scheme and other URL restrictions hold. | 250 // Steps 3 & 4 - check if scheme and other URL restrictions hold. |
246 bool allowRedirect = isLegalRedirectLocation(newURL, errorDescription); | 251 bool allowRedirect = isLegalRedirectLocation(newURL, errorDescription); |
247 if (allowRedirect) { | 252 if (allowRedirect) { |
248 // Step 5: perform resource sharing access check. | 253 // Step 5: perform resource sharing access check. |
249 allowRedirect = passesAccessControlCheck(redirectResponse, withCrede
ntials, securityOrigin, errorDescription); | 254 allowRedirect = passesAccessControlCheck(redirectResponse, withCrede
ntials, securityOrigin, errorDescription, newRequest.requestContext()); |
250 if (allowRedirect) { | 255 if (allowRedirect) { |
251 RefPtr<SecurityOrigin> originalOrigin = SecurityOrigin::create(o
riginalURL); | 256 RefPtr<SecurityOrigin> originalOrigin = SecurityOrigin::create(o
riginalURL); |
252 // Step 6: if the request URL origin is not same origin as the o
riginal URL's, | 257 // Step 6: if the request URL origin is not same origin as the o
riginal URL's, |
253 // set the source origin to a globally unique identifier. | 258 // set the source origin to a globally unique identifier. |
254 if (!originalOrigin->canRequest(newURL)) { | 259 if (!originalOrigin->canRequest(newURL)) { |
255 options.securityOrigin = SecurityOrigin::createUnique(); | 260 options.securityOrigin = SecurityOrigin::createUnique(); |
256 securityOrigin = options.securityOrigin.get(); | 261 securityOrigin = options.securityOrigin.get(); |
257 } | 262 } |
258 } | 263 } |
259 } | 264 } |
260 if (!allowRedirect) { | 265 if (!allowRedirect) { |
261 const String& originalOrigin = SecurityOrigin::create(originalURL)->
toString(); | 266 const String& originalOrigin = SecurityOrigin::create(originalURL)->
toString(); |
262 errorMessage = "Redirect at origin '" + originalOrigin + "' has been
blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescript
ion; | 267 errorMessage = "Redirect at origin '" + originalOrigin + "' has been
blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescript
ion; |
263 return false; | 268 return false; |
264 } | 269 } |
265 } | 270 } |
266 if (redirectCrossOrigin) { | 271 if (redirectCrossOrigin) { |
267 // If now to a different origin, update/set Origin:. | 272 // If now to a different origin, update/set Origin:. |
268 newRequest.clearHTTPOrigin(); | 273 newRequest.clearHTTPOrigin(); |
269 newRequest.setHTTPOrigin(securityOrigin->toAtomicString()); | 274 newRequest.setHTTPOrigin(securityOrigin->toAtomicString()); |
270 // If the user didn't request credentials in the first place, update our | 275 // If the user didn't request credentials in the first place, update our |
271 // state so we neither request them nor expect they must be allowed. | 276 // state so we neither request them nor expect they must be allowed. |
272 if (options.credentialsRequested == ClientDidNotRequestCredentials) | 277 if (options.credentialsRequested == ClientDidNotRequestCredentials) |
273 options.allowCredentials = DoNotAllowStoredCredentials; | 278 options.allowCredentials = DoNotAllowStoredCredentials; |
274 } | 279 } |
275 return true; | 280 return true; |
276 } | 281 } |
277 | 282 |
278 } // namespace blink | 283 } // namespace blink |
OLD | NEW |