blob: 91f68634c907e7f663877db7eeea7689ace93b51 [file] [log] [blame]
/*
* Copyright (C) 2008 Apple Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* 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
* 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
* 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
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "third_party/blink/public/platform/web_cors.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "net/http/http_util.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_url_response.h"
#include "third_party/blink/renderer/platform/loader/cors/cors.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_utils.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
#include "third_party/blink/renderer/platform/network/http_names.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "url/gurl.h"
#include "url/url_util.h"
using network::mojom::CORSError;
namespace blink {
namespace WebCORS {
namespace {
// A parser for the value of the Access-Control-Expose-Headers header.
class HTTPHeaderNameListParser {
STACK_ALLOCATED();
public:
explicit HTTPHeaderNameListParser(const String& value)
: value_(value), pos_(0) {}
// Tries parsing |value_| expecting it to be conforming to the #field-name
// ABNF rule defined in RFC 7230. Returns with the field-name entries stored
// in |output| when successful. Otherwise, returns with |output| kept empty.
//
// |output| must be empty.
void Parse(WebHTTPHeaderSet& output) {
DCHECK(output.empty());
while (true) {
ConsumeSpaces();
size_t token_start = pos_;
ConsumeTokenChars();
size_t token_size = pos_ - token_start;
if (token_size == 0) {
output.clear();
return;
}
const CString& name = value_.Substring(token_start, token_size).Ascii();
output.emplace(name.data(), name.length());
ConsumeSpaces();
if (pos_ == value_.length())
return;
if (value_[pos_] == ',') {
++pos_;
} else {
output.clear();
return;
}
}
}
private:
// Consumes zero or more spaces (SP and HTAB) from value_.
void ConsumeSpaces() {
while (true) {
if (pos_ == value_.length())
return;
UChar c = value_[pos_];
if (c != ' ' && c != '\t')
return;
++pos_;
}
}
// Consumes zero or more tchars from value_.
void ConsumeTokenChars() {
while (true) {
if (pos_ == value_.length())
return;
UChar c = value_[pos_];
if (c > 0x7F || !net::HttpUtil::IsTokenChar(c))
return;
++pos_;
}
}
const String value_;
size_t pos_;
};
} // namespace
WebHTTPHeaderSet ExtractCorsExposedHeaderNamesList(
network::mojom::FetchCredentialsMode credentials_mode,
const WebURLResponse& response) {
// If a response was fetched via a service worker, it will always have
// CorsExposedHeaderNames set from the Access-Control-Expose-Headers header.
// For requests that didn't come from a service worker, just parse the CORS
// header.
if (response.WasFetchedViaServiceWorker()) {
WebHTTPHeaderSet header_set;
for (const auto& header : response.CorsExposedHeaderNames())
header_set.emplace(header.Ascii().data(), header.Ascii().length());
return header_set;
}
WebHTTPHeaderSet header_set;
HTTPHeaderNameListParser parser(response.HttpHeaderField(
WebString(HTTPNames::Access_Control_Expose_Headers)));
parser.Parse(header_set);
if (credentials_mode != network::mojom::FetchCredentialsMode::kInclude &&
header_set.find("*") != header_set.end()) {
header_set.clear();
for (const auto& header :
response.ToResourceResponse().HttpHeaderFields()) {
CString name = header.key.Ascii();
header_set.emplace(name.data(), name.length());
}
}
return header_set;
}
bool IsOnAccessControlResponseHeaderWhitelist(const WebString& name) {
DEFINE_THREAD_SAFE_STATIC_LOCAL(
WebHTTPHeaderSet, allowed_cross_origin_response_headers,
({
"cache-control", "content-language", "content-type", "expires",
"last-modified", "pragma",
}));
return allowed_cross_origin_response_headers.find(name.Ascii().data()) !=
allowed_cross_origin_response_headers.end();
}
// In the spec, https://fetch.spec.whatwg.org/#ref-for-concept-request-mode,
// No-CORS mode is highly discouraged from using it for new features. Only
// legacy usages for backward compatibility are allowed except for well-designed
// usages over the fetch API.
bool IsNoCORSAllowedContext(mojom::RequestContextType context) {
switch (context) {
case mojom::RequestContextType::AUDIO:
case mojom::RequestContextType::FAVICON:
case mojom::RequestContextType::FETCH:
case mojom::RequestContextType::IMAGE:
case mojom::RequestContextType::OBJECT:
case mojom::RequestContextType::PLUGIN:
case mojom::RequestContextType::SCRIPT:
case mojom::RequestContextType::SHARED_WORKER:
case mojom::RequestContextType::VIDEO:
case mojom::RequestContextType::WORKER:
return true;
default:
return false;
}
}
} // namespace WebCORS
} // namespace blink