summaryrefslogtreecommitdiff
path: root/Source/WebCore/loader/CrossOriginAccessControl.cpp
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/loader/CrossOriginAccessControl.cpp
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/WebCore/loader/CrossOriginAccessControl.cpp')
-rw-r--r--Source/WebCore/loader/CrossOriginAccessControl.cpp136
1 files changed, 68 insertions, 68 deletions
diff --git a/Source/WebCore/loader/CrossOriginAccessControl.cpp b/Source/WebCore/loader/CrossOriginAccessControl.cpp
index 257b43ed8..36b55a12d 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 <mutex>
+#include <wtf/NeverDestroyed.h>
#include <wtf/text/AtomicString.h>
#include <wtf/text/StringBuilder.h>
@@ -42,34 +45,13 @@ bool isOnAccessControlSimpleRequestMethodWhitelist(const String& method)
return method == "GET" || method == "HEAD" || method == "POST";
}
-bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name, const String& value)
-{
- if (equalIgnoringCase(name, "accept")
- || equalIgnoringCase(name, "accept-language")
- || equalIgnoringCase(name, "content-language")
- || equalIgnoringCase(name, "origin")
- || equalIgnoringCase(name, "referer"))
- return true;
-
- // Preflight is required for MIME types that can not be sent via form submission.
- if (equalIgnoringCase(name, "content-type")) {
- String mimeType = extractMIMETypeFromMediaType(value);
- return equalIgnoringCase(mimeType, "application/x-www-form-urlencoded")
- || equalIgnoringCase(mimeType, "multipart/form-data")
- || equalIgnoringCase(mimeType, "text/plain");
- }
-
- return false;
-}
-
bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap& headerMap)
{
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 || !isCrossOriginSafeRequestHeader(header.keyAsHTTPHeaderName.value(), header.value))
return false;
}
@@ -79,82 +61,111 @@ bool isSimpleCrossOriginAccessRequest(const String& method, const HTTPHeaderMap&
bool isOnAccessControlResponseHeaderWhitelist(const String& name)
{
static std::once_flag onceFlag;
- static HTTPHeaderSet* allowedCrossOriginResponseHeaders;
+ static LazyNeverDestroyed<HTTPHeaderSet> allowedCrossOriginResponseHeaders;
std::call_once(onceFlag, []{
- allowedCrossOriginResponseHeaders = std::make_unique<HTTPHeaderSet, std::initializer_list<String>>({
+ allowedCrossOriginResponseHeaders.construct<std::initializer_list<String>>({
"cache-control",
"content-language",
"content-type",
"expires",
"last-modified",
"pragma"
- }).release();
+ });
});
- return allowedCrossOriginResponseHeaders->contains(name);
+ return allowedCrossOriginResponseHeaders.get().contains(name);
}
-void updateRequestForAccessControl(ResourceRequest& request, SecurityOrigin* securityOrigin, StoredCredentials allowCredentials)
+void updateRequestForAccessControl(ResourceRequest& request, SecurityOrigin& securityOrigin, StoredCredentials allowCredentials)
{
request.removeCredentials();
request.setAllowCookies(allowCredentials == AllowStoredCredentials);
- request.setHTTPOrigin(securityOrigin->toString());
+ request.setHTTPOrigin(securityOrigin.toString());
}
-ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& request, SecurityOrigin* securityOrigin)
+ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& request, SecurityOrigin& securityOrigin, const String& referrer)
{
ResourceRequest preflightRequest(request.url());
+ static const double platformDefaultTimeout = 0;
+ preflightRequest.setTimeoutInterval(platformDefaultTimeout);
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());
+ if (!referrer.isNull())
+ preflightRequest.setHTTPReferrer(referrer);
const HTTPHeaderMap& requestHeaderFields = request.httpHeaderFields();
- if (requestHeaderFields.size() > 0) {
- 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);
+ if (!requestHeaderFields.isEmpty()) {
+ Vector<String> unsafeHeaders;
+ for (const auto& headerField : requestHeaderFields.commonHeaders()) {
+ if (!isCrossOriginSafeRequestHeader(headerField.key, headerField.value))
+ unsafeHeaders.append(httpHeaderNameString(headerField.key).toStringWithoutCopying().convertToASCIILowercase());
}
+ for (const auto& headerField : requestHeaderFields.uncommonHeaders())
+ unsafeHeaders.append(headerField.key.convertToASCIILowercase());
+
+ std::sort(unsafeHeaders.begin(), unsafeHeaders.end(), WTF::codePointCompareLessThan);
+
+ StringBuilder headerBuffer;
+
+ bool appendComma = false;
+ for (const auto& headerField : unsafeHeaders) {
+ if (appendComma)
+ headerBuffer.append(',');
+ else
+ appendComma = true;
- preflightRequest.setHTTPHeaderField("Access-Control-Request-Headers", headerBuffer.toString().lower());
+ headerBuffer.append(headerField);
+ }
+ if (!headerBuffer.isEmpty())
+ preflightRequest.setHTTPHeaderField(HTTPHeaderName::AccessControlRequestHeaders, headerBuffer.toString());
}
return preflightRequest;
}
-bool passesAccessControlCheck(const ResourceResponse& response, StoredCredentials includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription)
+bool isValidCrossOriginRedirectionURL(const URL& redirectURL)
+{
+ return SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(redirectURL.protocol().toStringWithoutCopying())
+ && redirectURL.user().isEmpty()
+ && redirectURL.pass().isEmpty();
+}
+
+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("access-control-allow-origin");
+ 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()) {
+ String securityOriginString = securityOrigin.toString();
+ if (accessControlOriginString != securityOriginString) {
if (accessControlOriginString == "*")
- errorDescription = "Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.";
+ errorDescription = ASCIILiteral("Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.");
+ else if (accessControlOriginString.find(',') != notFound)
+ errorDescription = ASCIILiteral("Access-Control-Allow-Origin cannot contain more than one origin.");
else
- errorDescription = "Origin " + securityOrigin->toString() + " is not allowed by Access-Control-Allow-Origin.";
+ errorDescription = makeString("Origin ", securityOriginString, " is not allowed by Access-Control-Allow-Origin.");
return false;
}
if (includeCredentials == AllowStoredCredentials) {
- const String& accessControlCredentialsString = response.httpHeaderField("access-control-allow-credentials");
+ 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;
@@ -164,15 +175,4 @@ bool passesAccessControlCheck(const ResourceResponse& response, StoredCredential
return true;
}
-void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHeaderSet& headerSet)
-{
- Vector<String> headers;
- headerValue.split(',', false, headers);
- for (unsigned headerCount = 0; headerCount < headers.size(); headerCount++) {
- String strippedHeader = headers[headerCount].stripWhiteSpace();
- if (!strippedHeader.isEmpty())
- headerSet.add(strippedHeader);
- }
-}
-
} // namespace WebCore