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(" Either change the header or use the 'no-co rs' mode with fetch to get an opaque response."); | |
tyoshino (SeeGerritForStatus)
2015/09/07 08:41:07
Please update the text after "or" here as well. Fo
jeremyarcher
2015/09/07 08:47:28
Good eyes! I've made the patch.
| |
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 |