| Index: third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
|
| diff --git a/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp b/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
|
| index 74dd919175f7a509e0e07367683c25ba5a06d0cc..3c70a9865bc370ffd61a479af39e0e8335de2be7 100644
|
| --- a/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
|
| +++ b/third_party/WebKit/Source/core/fetch/CrossOriginAccessControl.cpp
|
| @@ -56,7 +56,7 @@ bool isOnAccessControlResponseHeaderWhitelist(const String& name)
|
| return allowedCrossOriginResponseHeaders.contains(name);
|
| }
|
|
|
| -void updateRequestForAccessControl(ResourceRequest& request, SecurityOrigin* securityOrigin, StoredCredentials allowCredentials)
|
| +void updateRequestForAccessControl(ResourceRequest& request, const SecurityOrigin* securityOrigin, StoredCredentials allowCredentials)
|
| {
|
| request.removeCredentials();
|
| request.setAllowStoredCredentials(allowCredentials == AllowStoredCredentials);
|
| @@ -65,7 +65,7 @@ void updateRequestForAccessControl(ResourceRequest& request, SecurityOrigin* sec
|
| request.setHTTPOrigin(securityOrigin);
|
| }
|
|
|
| -ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& request, SecurityOrigin* securityOrigin)
|
| +ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& request, const SecurityOrigin* securityOrigin)
|
| {
|
| ResourceRequest preflightRequest(request.url());
|
| updateRequestForAccessControl(preflightRequest, securityOrigin, DoNotAllowStoredCredentials);
|
| @@ -124,12 +124,12 @@ static bool isInterestingStatusCode(int statusCode)
|
| return statusCode >= 400;
|
| }
|
|
|
| -static String buildAccessControlFailureMessage(const String& detail, SecurityOrigin* securityOrigin)
|
| +static String buildAccessControlFailureMessage(const String& detail, const SecurityOrigin* securityOrigin)
|
| {
|
| return detail + " Origin '" + securityOrigin->toString() + "' is therefore not allowed access.";
|
| }
|
|
|
| -bool passesAccessControlCheck(const ResourceResponse& response, StoredCredentials includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription, WebURLRequest::RequestContext context)
|
| +bool passesAccessControlCheck(const ResourceResponse& response, StoredCredentials includeCredentials, const SecurityOrigin* securityOrigin, String& errorDescription, WebURLRequest::RequestContext context)
|
| {
|
| DEFINE_THREAD_SAFE_STATIC_LOCAL(AtomicString, allowOriginHeaderName, (new AtomicString("access-control-allow-origin")));
|
| DEFINE_THREAD_SAFE_STATIC_LOCAL(AtomicString, allowCredentialsHeaderName, (new AtomicString("access-control-allow-credentials")));
|
| @@ -272,12 +272,22 @@ void extractCorsExposedHeaderNamesList(const ResourceResponse& response, 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.)
|
| + // Block non HTTP(S) schemes as specified in the step 4 in
|
| + // https://fetch.spec.whatwg.org/#http-redirect-fetch. Chromium also allows
|
| + // the data scheme.
|
| + //
|
| + // TODO(tyoshino): This check should be performed regardless of the CORS
|
| + // flag and request's mode.
|
| if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(requestURL.protocol())) {
|
| errorDescription = "Redirect location '" + requestURL.getString() + "' has a disallowed scheme for cross-origin requests.";
|
| return false;
|
| }
|
|
|
| + // Block URLs including credentials as specified in the step 9 in
|
| + // https://fetch.spec.whatwg.org/#http-redirect-fetch.
|
| + //
|
| + // TODO(tyoshino): This check should be performed also when request's
|
| + // origin is not same origin with the redirect destination's origin.
|
| if (!(requestURL.user().isEmpty() && requestURL.pass().isEmpty())) {
|
| errorDescription = "Redirect location '" + requestURL.getString() + "' contains userinfo, which is disallowed for cross-origin requests.";
|
| return false;
|
| @@ -286,45 +296,49 @@ bool CrossOriginAccessControl::isLegalRedirectLocation(const KURL& requestURL, S
|
| return true;
|
| }
|
|
|
| -bool CrossOriginAccessControl::handleRedirect(SecurityOrigin* securityOrigin, ResourceRequest& newRequest, const ResourceResponse& redirectResponse, StoredCredentials withCredentials, ResourceLoaderOptions& options, String& errorMessage)
|
| +bool CrossOriginAccessControl::handleRedirect(const SecurityOrigin* securityOrigin, ResourceRequest& newRequest, const ResourceResponse& redirectResponse, StoredCredentials withCredentials, ResourceLoaderOptions& options, String& errorMessage)
|
| {
|
| // http://www.w3.org/TR/cors/#redirect-steps terminology:
|
| - const KURL& originalURL = redirectResponse.url();
|
| + const KURL& lastURL = redirectResponse.url();
|
| const KURL& newURL = newRequest.url();
|
|
|
| - bool redirectCrossOrigin = !securityOrigin->canRequest(newURL);
|
| + const SecurityOrigin* securityOriginForHeader = securityOrigin;
|
|
|
| - // Same-origin request URLs that redirect are allowed without checking access.
|
| - if (!securityOrigin->canRequest(originalURL)) {
|
| + // TODO(tyoshino): This should be fixed to check not only the last one but
|
| + // all redirect responses.
|
| + if (!securityOrigin->canRequest(lastURL)) {
|
| // Follow http://www.w3.org/TR/cors/#redirect-steps
|
| String errorDescription;
|
|
|
| - // Steps 3 & 4 - check if scheme and other URL restrictions hold.
|
| if (!isLegalRedirectLocation(newURL, errorDescription)) {
|
| - errorMessage = "Redirect from '" + originalURL.getString() + "' has been blocked by CORS policy: " + errorDescription;
|
| + errorMessage = "Redirect from '" + lastURL.getString() + "' has been blocked by CORS policy: " + errorDescription;
|
| return false;
|
| }
|
|
|
| // Step 5: perform resource sharing access check.
|
| if (!passesAccessControlCheck(redirectResponse, withCredentials, securityOrigin, errorDescription, newRequest.requestContext())) {
|
| - errorMessage = "Redirect from '" + originalURL.getString() + "' has been blocked by CORS policy: " + errorDescription;
|
| + errorMessage = "Redirect from '" + lastURL.getString() + "' has been blocked by CORS policy: " + errorDescription;
|
| return false;
|
| }
|
|
|
| - 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(newURL)) {
|
| + RefPtr<SecurityOrigin> lastOrigin = SecurityOrigin::create(lastURL);
|
| + // Set request's origin to a globally unique identifier as specified in
|
| + // the step 10 in https://fetch.spec.whatwg.org/#http-redirect-fetch.
|
| + if (!lastOrigin->canRequest(newURL)) {
|
| options.securityOrigin = SecurityOrigin::createUnique();
|
| - securityOrigin = options.securityOrigin.get();
|
| + securityOriginForHeader = options.securityOrigin.get();
|
| }
|
| }
|
| - if (redirectCrossOrigin) {
|
| - // If now to a different origin, update/set Origin:.
|
| +
|
| + if (!securityOrigin->canRequest(newURL)) {
|
| newRequest.clearHTTPOrigin();
|
| - newRequest.setHTTPOrigin(securityOrigin);
|
| - // 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.
|
| + newRequest.setHTTPOrigin(securityOriginForHeader);
|
| +
|
| + // Unset credentials flag if request's credentials mode is
|
| + // "same-origin" as request's response tainting becomes "cors".
|
| + //
|
| + // This is equivalent to the step 2 in
|
| + // https://fetch.spec.whatwg.org/#http-network-or-cache-fetch
|
| if (options.credentialsRequested == ClientDidNotRequestCredentials)
|
| options.allowCredentials = DoNotAllowStoredCredentials;
|
| }
|
|
|