diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/WebCore/loader/CrossOriginAccessControl.cpp | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/WebCore/loader/CrossOriginAccessControl.cpp')
-rw-r--r-- | Source/WebCore/loader/CrossOriginAccessControl.cpp | 136 |
1 files changed, 71 insertions, 65 deletions
diff --git a/Source/WebCore/loader/CrossOriginAccessControl.cpp b/Source/WebCore/loader/CrossOriginAccessControl.cpp index 7d011906e..ad0cf1db7 100644 --- a/Source/WebCore/loader/CrossOriginAccessControl.cpp +++ b/Source/WebCore/loader/CrossOriginAccessControl.cpp @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,11 +27,14 @@ #include "config.h" #include "CrossOriginAccessControl.h" +#include "HTTPHeaderNames.h" #include "HTTPParsers.h" #include "ResourceRequest.h" #include "ResourceResponse.h" +#include "SchemeRegistry.h" #include "SecurityOrigin.h" -#include <wtf/Threading.h> +#include <mutex> +#include <wtf/NeverDestroyed.h> #include <wtf/text/AtomicString.h> #include <wtf/text/StringBuilder.h> @@ -42,24 +45,25 @@ bool isOnAccessControlSimpleRequestMethodWhitelist(const String& method) return method == "GET" || method == "HEAD" || method == "POST"; } -bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name, const String& value) +bool isOnAccessControlSimpleRequestHeaderWhitelist(HTTPHeaderName name, const String& value) { - if (equalIgnoringCase(name, "accept") - || equalIgnoringCase(name, "accept-language") - || equalIgnoringCase(name, "content-language") - || equalIgnoringCase(name, "origin") - || equalIgnoringCase(name, "referer")) + switch (name) { + case HTTPHeaderName::Accept: + case HTTPHeaderName::AcceptLanguage: + case HTTPHeaderName::ContentLanguage: + case HTTPHeaderName::Origin: + case HTTPHeaderName::Referer: return true; - - // Preflight is required for MIME types that can not be sent via form submission. - if (equalIgnoringCase(name, "content-type")) { + case HTTPHeaderName::ContentType: { + // Preflight is required for MIME types that can not be sent via form submission. String mimeType = extractMIMETypeFromMediaType(value); - return equalIgnoringCase(mimeType, "application/x-www-form-urlencoded") - || equalIgnoringCase(mimeType, "multipart/form-data") - || equalIgnoringCase(mimeType, "text/plain"); + return equalIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded") + || equalIgnoringASCIICase(mimeType, "multipart/form-data") + || equalIgnoringASCIICase(mimeType, "text/plain"); + } + default: + return false; } - - return false; } bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap& headerMap) @@ -67,34 +71,31 @@ bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap& if (!isOnAccessControlSimpleRequestMethodWhitelist(method)) return false; - HTTPHeaderMap::const_iterator end = headerMap.end(); - for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it) { - if (!isOnAccessControlSimpleRequestHeaderWhitelist(it->key, it->value)) + for (const auto& header : headerMap) { + if (!header.keyAsHTTPHeaderName || !isOnAccessControlSimpleRequestHeaderWhitelist(header.keyAsHTTPHeaderName.value(), header.value)) return false; } return true; } -static PassOwnPtr<HTTPHeaderSet> createAllowedCrossOriginResponseHeadersSet() -{ - OwnPtr<HTTPHeaderSet> headerSet = adoptPtr(new HashSet<String, CaseFoldingHash>); - - headerSet->add("cache-control"); - headerSet->add("content-language"); - headerSet->add("content-type"); - headerSet->add("expires"); - headerSet->add("last-modified"); - headerSet->add("pragma"); - - return headerSet.release(); -} - bool isOnAccessControlResponseHeaderWhitelist(const String& name) { - AtomicallyInitializedStatic(HTTPHeaderSet*, allowedCrossOriginResponseHeaders = createAllowedCrossOriginResponseHeadersSet().leakPtr()); - - return allowedCrossOriginResponseHeaders->contains(name); + static std::once_flag onceFlag; + static LazyNeverDestroyed<HTTPHeaderSet> allowedCrossOriginResponseHeaders; + + std::call_once(onceFlag, []{ + allowedCrossOriginResponseHeaders.construct<std::initializer_list<String>>({ + "cache-control", + "content-language", + "content-type", + "expires", + "last-modified", + "pragma" + }); + }); + + return allowedCrossOriginResponseHeaders.get().contains(name); } void updateRequestForAccessControl(ResourceRequest& request, SecurityOrigin* securityOrigin, StoredCredentials allowCredentials) @@ -109,51 +110,56 @@ ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& reque ResourceRequest preflightRequest(request.url()); updateRequestForAccessControl(preflightRequest, securityOrigin, DoNotAllowStoredCredentials); preflightRequest.setHTTPMethod("OPTIONS"); - preflightRequest.setHTTPHeaderField("Access-Control-Request-Method", request.httpMethod()); + preflightRequest.setHTTPHeaderField(HTTPHeaderName::AccessControlRequestMethod, request.httpMethod()); preflightRequest.setPriority(request.priority()); const HTTPHeaderMap& requestHeaderFields = request.httpHeaderFields(); - if (requestHeaderFields.size() > 0) { + if (!requestHeaderFields.isEmpty()) { StringBuilder headerBuffer; - HTTPHeaderMap::const_iterator it = requestHeaderFields.begin(); - headerBuffer.append(it->key); - ++it; - - HTTPHeaderMap::const_iterator end = requestHeaderFields.end(); - for (; it != end; ++it) { - headerBuffer.append(','); - headerBuffer.append(' '); - headerBuffer.append(it->key); + + bool appendComma = false; + for (const auto& headerField : requestHeaderFields) { + if (appendComma) + headerBuffer.appendLiteral(", "); + else + appendComma = true; + + headerBuffer.append(headerField.key); } - preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", headerBuffer.toString().lower()); + preflightRequest.setHTTPHeaderField(HTTPHeaderName::AccessControlRequestHeaders, headerBuffer.toString().convertToASCIILowercase()); } return preflightRequest; } -bool passesAccessControlCheck(const ResourceResponse& response, StoredCredentials includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription) +bool isValidCrossOriginRedirectionURL(const URL& redirectURL) { - AtomicallyInitializedStatic(AtomicString&, accessControlAllowOrigin = *new AtomicString("access-control-allow-origin", AtomicString::ConstructFromLiteral)); - AtomicallyInitializedStatic(AtomicString&, accessControlAllowCredentials = *new AtomicString("access-control-allow-credentials", AtomicString::ConstructFromLiteral)); + return SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(redirectURL.protocol()) + && redirectURL.user().isEmpty() + && redirectURL.pass().isEmpty(); +} - if (!securityOrigin->allowsCrossOriginRequests()) { - errorDescription = "Cannot make any cross origin requests from " + securityOrigin->toString() + "."; - return false; - } +void cleanRedirectedRequestForAccessControl(ResourceRequest& request) +{ + // Remove headers that may have been added by the network layer that cause access control to fail. + request.clearHTTPContentType(); + request.clearHTTPReferrer(); + request.clearHTTPOrigin(); + request.clearHTTPUserAgent(); + request.clearHTTPAccept(); + request.clearHTTPAcceptEncoding(); +} +bool passesAccessControlCheck(const ResourceResponse& response, StoredCredentials includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription) +{ // 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 String& accessControlOriginString = response.httpHeaderField(accessControlAllowOrigin); + const String& accessControlOriginString = response.httpHeaderField(HTTPHeaderName::AccessControlAllowOrigin); if (accessControlOriginString == "*" && includeCredentials == DoNotAllowStoredCredentials) return true; - if (securityOrigin->isUnique()) { - errorDescription = "Cannot make any requests from " + securityOrigin->toString() + "."; - return false; - } - // FIXME: Access-Control-Allow-Origin can contain a list of origins. if (accessControlOriginString != securityOrigin->toString()) { if (accessControlOriginString == "*") @@ -164,7 +170,7 @@ bool passesAccessControlCheck(const ResourceResponse& response, StoredCredential } if (includeCredentials == AllowStoredCredentials) { - const String& accessControlCredentialsString = response.httpHeaderField(accessControlAllowCredentials); + const String& accessControlCredentialsString = response.httpHeaderField(HTTPHeaderName::AccessControlAllowCredentials); if (accessControlCredentialsString != "true") { errorDescription = "Credentials flag is true, but Access-Control-Allow-Credentials is not \"true\"."; return false; @@ -178,8 +184,8 @@ void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHea { Vector<String> headers; headerValue.split(',', false, headers); - for (unsigned headerCount = 0; headerCount < headers.size(); headerCount++) { - String strippedHeader = headers[headerCount].stripWhiteSpace(); + for (auto& header : headers) { + String strippedHeader = header.stripWhiteSpace(); if (!strippedHeader.isEmpty()) headerSet.add(strippedHeader); } |