summaryrefslogtreecommitdiffstats
path: root/chromium/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp')
-rw-r--r--chromium/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp96
1 files changed, 85 insertions, 11 deletions
diff --git a/chromium/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp b/chromium/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
index f35116c73f8..ddcb29c4064 100644
--- a/chromium/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
+++ b/chromium/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
@@ -27,8 +27,12 @@
#include "config.h"
#include "core/fetch/CrossOriginAccessControl.h"
+#include "core/fetch/Resource.h"
+#include "core/fetch/ResourceLoaderOptions.h"
#include "platform/network/HTTPParsers.h"
+#include "platform/network/ResourceRequest.h"
#include "platform/network/ResourceResponse.h"
+#include "platform/weborigin/SchemeRegistry.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "wtf/Threading.h"
#include "wtf/text/AtomicString.h"
@@ -99,10 +103,10 @@ bool isOnAccessControlResponseHeaderWhitelist(const String& name)
void updateRequestForAccessControl(ResourceRequest& request, SecurityOrigin* securityOrigin, StoredCredentials allowCredentials)
{
request.removeCredentials();
- request.setAllowCookies(allowCredentials == AllowStoredCredentials);
+ request.setAllowStoredCredentials(allowCredentials == AllowStoredCredentials);
if (securityOrigin)
- request.setHTTPOrigin(securityOrigin->toString());
+ request.setHTTPOrigin(securityOrigin->toAtomicString());
}
ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& request, SecurityOrigin* securityOrigin)
@@ -127,7 +131,7 @@ ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& reque
headerBuffer.append(it->key);
}
- preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", headerBuffer.toString().lower());
+ preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", AtomicString(headerBuffer.toString().lower()));
}
return preflightRequest;
@@ -143,16 +147,23 @@ bool passesAccessControlCheck(const ResourceResponse& response, StoredCredential
AtomicallyInitializedStatic(AtomicString&, accessControlAllowOrigin = *new AtomicString("access-control-allow-origin", AtomicString::ConstructFromLiteral));
AtomicallyInitializedStatic(AtomicString&, accessControlAllowCredentials = *new AtomicString("access-control-allow-credentials", AtomicString::ConstructFromLiteral));
- // A wildcard Access-Control-Allow-Origin can not be used if credentials are to be sent,
- // even with Access-Control-Allow-Credentials set to true.
- const AtomicString& accessControlOriginString = response.httpHeaderField(accessControlAllowOrigin);
- if (accessControlOriginString == starAtom && includeCredentials == DoNotAllowStoredCredentials)
- return true;
+ if (!response.httpStatusCode()) {
+ errorDescription = "Received an invalid response. Origin '" + securityOrigin->toString() + "' is therefore not allowed access.";
+ return false;
+ }
- if (accessControlOriginString != securityOrigin->toString()) {
- if (accessControlOriginString == starAtom) {
+ const AtomicString& accessControlOriginString = response.httpHeaderField(accessControlAllowOrigin);
+ if (accessControlOriginString == starAtom) {
+ // A wildcard Access-Control-Allow-Origin can not be used if credentials are to be sent,
+ // even with Access-Control-Allow-Credentials set to true.
+ if (includeCredentials == DoNotAllowStoredCredentials)
+ return true;
+ if (response.isHTTP()) {
errorDescription = "A wildcard '*' cannot be used in the 'Access-Control-Allow-Origin' header when the credentials flag is true. Origin '" + securityOrigin->toString() + "' is therefore not allowed access.";
- } else if (accessControlOriginString.isEmpty()) {
+ return false;
+ }
+ } else if (accessControlOriginString != securityOrigin->toAtomicString()) {
+ if (accessControlOriginString.isEmpty()) {
errorDescription = "No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin '" + securityOrigin->toString() + "' is therefore not allowed access.";
} else if (accessControlOriginString.string().find(isOriginSeparator, 0) != kNotFound) {
errorDescription = "The 'Access-Control-Allow-Origin' header contains multiple values '" + accessControlOriginString + "', but only one is allowed. Origin '" + securityOrigin->toString() + "' is therefore not allowed access.";
@@ -198,4 +209,67 @@ void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHea
}
}
+bool CrossOriginAccessControl::isLegalRedirectLocation(const KURL& requestURL, String& errorDescription)
+{
+ // CORS restrictions imposed on Location: URL -- http://www.w3.org/TR/cors/#redirect-steps (steps 2 + 3.)
+ if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(requestURL.protocol())) {
+ errorDescription = "The request was redirected to a URL ('" + requestURL.string() + "') which has a disallowed scheme for cross-origin requests.";
+ return false;
+ }
+
+ if (!(requestURL.user().isEmpty() && requestURL.pass().isEmpty())) {
+ errorDescription = "The request was redirected to a URL ('" + requestURL.string() + "') containing userinfo, which is disallowed for cross-origin requests.";
+ return false;
+ }
+
+ return true;
+}
+
+bool CrossOriginAccessControl::handleRedirect(Resource* resource, SecurityOrigin* securityOrigin, ResourceRequest& request, const ResourceResponse& redirectResponse, ResourceLoaderOptions& options, String& errorMessage)
+{
+ // http://www.w3.org/TR/cors/#redirect-steps terminology:
+ const KURL& originalURL = redirectResponse.url();
+ const KURL& requestURL = request.url();
+
+ bool redirectCrossOrigin = !securityOrigin->canRequest(requestURL);
+
+ // Same-origin request URLs that redirect are allowed without checking access.
+ if (!securityOrigin->canRequest(originalURL)) {
+ // Follow http://www.w3.org/TR/cors/#redirect-steps
+ String errorDescription;
+
+ // Steps 3 & 4 - check if scheme and other URL restrictions hold.
+ bool allowRedirect = isLegalRedirectLocation(requestURL, errorDescription);
+ if (allowRedirect) {
+ // Step 5: perform resource sharing access check.
+ StoredCredentials withCredentials = resource->lastResourceRequest().allowStoredCredentials() ? AllowStoredCredentials : DoNotAllowStoredCredentials;
+ allowRedirect = passesAccessControlCheck(redirectResponse, withCredentials, securityOrigin, errorDescription);
+ if (allowRedirect) {
+ RefPtr<SecurityOrigin> originalOrigin = SecurityOrigin::create(originalURL);
+ // Step 6: if the request URL origin is not same origin as the original URL's,
+ // set the source origin to a globally unique identifier.
+ if (!originalOrigin->canRequest(requestURL)) {
+ options.securityOrigin = SecurityOrigin::createUnique();
+ securityOrigin = options.securityOrigin.get();
+ }
+ }
+ }
+ if (!allowRedirect) {
+ const String& originalOrigin = SecurityOrigin::create(originalURL)->toString();
+ errorMessage = "Redirect at origin '" + originalOrigin + "' has been blocked from loading by Cross-Origin Resource Sharing policy: " + errorDescription;
+ return false;
+ }
+ }
+ if (redirectCrossOrigin) {
+ // If now to a different origin, update/set Origin:.
+ request.clearHTTPOrigin();
+ request.setHTTPOrigin(securityOrigin->toAtomicString());
+ // If the user didn't request credentials in the first place, update our
+ // state so we neither request them nor expect they must be allowed.
+ if (options.credentialsRequested == ClientDidNotRequestCredentials)
+ options.allowCredentials = DoNotAllowStoredCredentials;
+ }
+ return true;
+}
+
} // namespace WebCore