blob: 3650b260cec4686786ece2fff31456e086cfcc75 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "platform/loader/fetch/FetchUtils.h"
#include "platform/loader/cors/CORS.h"
#include "platform/network/HTTPHeaderMap.h"
#include "platform/network/HTTPParsers.h"
#include "platform/network/http_names.h"
#include "platform/wtf/HashSet.h"
#include "platform/wtf/Threading.h"
#include "platform/wtf/text/AtomicString.h"
#include "platform/wtf/text/WTFString.h"
#include "services/network/public/cpp/cors/cors.h"
namespace blink {
namespace {
bool IsHTTPWhitespace(UChar chr) {
return chr == ' ' || chr == '\n' || chr == '\t' || chr == '\r';
}
} // namespace
bool FetchUtils::IsForbiddenMethod(const String& method) {
// http://fetch.spec.whatwg.org/#forbidden-method
// "A forbidden method is a method that is a byte case-insensitive match"
// for one of `CONNECT`, `TRACE`, and `TRACK`."
return EqualIgnoringASCIICase(method, "TRACE") ||
EqualIgnoringASCIICase(method, "TRACK") ||
EqualIgnoringASCIICase(method, "CONNECT");
}
bool FetchUtils::IsForbiddenHeaderName(const String& name) {
const CString utf8_name = name.Utf8();
return network::cors::IsForbiddenHeader(
std::string(utf8_name.data(), utf8_name.length()));
}
bool FetchUtils::IsForbiddenResponseHeaderName(const String& name) {
// http://fetch.spec.whatwg.org/#forbidden-response-header-name
// "A forbidden response header name is a header name that is one of:
// `Set-Cookie`, `Set-Cookie2`"
return EqualIgnoringASCIICase(name, "set-cookie") ||
EqualIgnoringASCIICase(name, "set-cookie2");
}
AtomicString FetchUtils::NormalizeMethod(const AtomicString& method) {
// https://fetch.spec.whatwg.org/#concept-method-normalize
// We place GET and POST first because they are more commonly used than
// others.
const char* const kMethods[] = {
"GET", "POST", "DELETE", "HEAD", "OPTIONS", "PUT",
};
for (auto* const known : kMethods) {
if (EqualIgnoringASCIICase(method, known)) {
// Don't bother allocating a new string if it's already all
// uppercase.
return method == known ? method : known;
}
}
return method;
}
String FetchUtils::NormalizeHeaderValue(const String& value) {
// https://fetch.spec.whatwg.org/#concept-header-value-normalize
// Strip leading and trailing whitespace from header value.
// HTTP whitespace bytes are 0x09, 0x0A, 0x0D, and 0x20.
return value.StripWhiteSpace(IsHTTPWhitespace);
}
bool FetchUtils::ContainsOnlyCORSSafelistedHeaders(
const HTTPHeaderMap& header_map) {
for (const auto& header : header_map) {
if (!CORS::IsCORSSafelistedHeader(header.key, header.value))
return false;
}
return true;
}
bool FetchUtils::ContainsOnlyCORSSafelistedOrForbiddenHeaders(
const HTTPHeaderMap& header_map) {
for (const auto& header : header_map) {
if (!CORS::IsCORSSafelistedHeader(header.key, header.value) &&
!IsForbiddenHeaderName(header.key))
return false;
}
return true;
}
} // namespace blink