1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
6 #include "core/fetch/FetchUtils.h"
8 #include "platform/network/HTTPHeaderMap.h"
9 #include "platform/network/HTTPParsers.h"
10 #include "wtf/HashSet.h"
11 #include "wtf/Threading.h"
12 #include "wtf/text/AtomicString.h"
13 #include "wtf/text/WTFString.h"
19 class ForbiddenHeaderNames
{
20 WTF_MAKE_NONCOPYABLE(ForbiddenHeaderNames
); WTF_MAKE_FAST_ALLOCATED(ForbiddenHeaderNames
);
22 bool has(const String
& name
) const
24 return m_fixedNames
.contains(name
)
25 || name
.startsWith(m_proxyHeaderPrefix
, TextCaseInsensitive
)
26 || name
.startsWith(m_secHeaderPrefix
, TextCaseInsensitive
);
29 static const ForbiddenHeaderNames
& get();
32 ForbiddenHeaderNames();
34 String m_proxyHeaderPrefix
;
35 String m_secHeaderPrefix
;
36 HashSet
<String
, CaseFoldingHash
> m_fixedNames
;
39 ForbiddenHeaderNames::ForbiddenHeaderNames()
40 : m_proxyHeaderPrefix("proxy-")
41 , m_secHeaderPrefix("sec-")
43 m_fixedNames
.add("accept-charset");
44 m_fixedNames
.add("accept-encoding");
45 m_fixedNames
.add("access-control-request-headers");
46 m_fixedNames
.add("access-control-request-method");
47 m_fixedNames
.add("connection");
48 m_fixedNames
.add("content-length");
49 m_fixedNames
.add("cookie");
50 m_fixedNames
.add("cookie2");
51 m_fixedNames
.add("date");
52 m_fixedNames
.add("dnt");
53 m_fixedNames
.add("expect");
54 m_fixedNames
.add("host");
55 m_fixedNames
.add("keep-alive");
56 m_fixedNames
.add("origin");
57 m_fixedNames
.add("referer");
58 m_fixedNames
.add("te");
59 m_fixedNames
.add("trailer");
60 m_fixedNames
.add("transfer-encoding");
61 m_fixedNames
.add("upgrade");
62 m_fixedNames
.add("user-agent");
63 m_fixedNames
.add("via");
66 const ForbiddenHeaderNames
& ForbiddenHeaderNames::get()
68 AtomicallyInitializedStaticReference(const ForbiddenHeaderNames
, instance
, new ForbiddenHeaderNames
);
74 bool FetchUtils::isSimpleMethod(const String
& method
)
76 // http://fetch.spec.whatwg.org/#simple-method
77 // "A simple method is a method that is `GET`, `HEAD`, or `POST`."
78 return method
== "GET" || method
== "HEAD" || method
== "POST";
81 bool FetchUtils::isSimpleHeader(const AtomicString
& name
, const AtomicString
& value
)
83 // http://fetch.spec.whatwg.org/#simple-header
84 // "A simple header is a header whose name is either one of `Accept`,
85 // `Accept-Language`, and `Content-Language`, or whose name is
86 // `Content-Type` and value, once parsed, is one of
87 // `application/x-www-form-urlencoded`, `multipart/form-data`, and
90 if (equalIgnoringCase(name
, "accept")
91 || equalIgnoringCase(name
, "accept-language")
92 || equalIgnoringCase(name
, "content-language"))
95 if (equalIgnoringCase(name
, "content-type")) {
96 AtomicString mimeType
= extractMIMETypeFromMediaType(value
);
97 return equalIgnoringCase(mimeType
, "application/x-www-form-urlencoded")
98 || equalIgnoringCase(mimeType
, "multipart/form-data")
99 || equalIgnoringCase(mimeType
, "text/plain");
105 bool FetchUtils::isSimpleRequest(const String
& method
, const HTTPHeaderMap
& headerMap
)
107 if (!isSimpleMethod(method
))
110 for (const auto& header
: headerMap
) {
111 // Preflight is required for MIME types that can not be sent via form
113 if (!isSimpleHeader(header
.key
, header
.value
))
120 bool FetchUtils::isForbiddenMethod(const String
& method
)
122 // http://fetch.spec.whatwg.org/#forbidden-method
123 // "A forbidden method is a method that is a byte case-insensitive match"
124 // for one of `CONNECT`, `TRACE`, and `TRACK`."
125 return equalIgnoringCase(method
, "TRACE")
126 || equalIgnoringCase(method
, "TRACK")
127 || equalIgnoringCase(method
, "CONNECT");
130 bool FetchUtils::isForbiddenHeaderName(const String
& name
)
132 // http://fetch.spec.whatwg.org/#forbidden-header-name
133 // "A forbidden header name is a header names that is one of:
134 // `Accept-Charset`, `Accept-Encoding`, `Access-Control-Request-Headers`,
135 // `Access-Control-Request-Method`, `Connection`,
136 // `Content-Length, Cookie`, `Cookie2`, `Date`, `DNT`, `Expect`, `Host`,
137 // `Keep-Alive`, `Origin`, `Referer`, `TE`, `Trailer`,
138 // `Transfer-Encoding`, `Upgrade`, `User-Agent`, `Via`
139 // or starts with `Proxy-` or `Sec-` (including when it is just `Proxy-` or
142 return ForbiddenHeaderNames::get().has(name
);
145 bool FetchUtils::isForbiddenResponseHeaderName(const String
& name
)
147 // http://fetch.spec.whatwg.org/#forbidden-response-header-name
148 // "A forbidden response header name is a header name that is one of:
149 // `Set-Cookie`, `Set-Cookie2`"
151 return equalIgnoringCase(name
, "set-cookie") || equalIgnoringCase(name
, "set-cookie2");
154 bool FetchUtils::isSimpleOrForbiddenRequest(const String
& method
, const HTTPHeaderMap
& headerMap
)
156 if (!isSimpleMethod(method
))
159 for (const auto& header
: headerMap
) {
160 if (!isSimpleHeader(header
.key
, header
.value
) && !isForbiddenHeaderName(header
.key
))
167 AtomicString
FetchUtils::normalizeMethod(const AtomicString
& method
)
169 // https://fetch.spec.whatwg.org/#concept-method-normalize
171 // We place GET and POST first because they are more commonly used than
173 const char* const methods
[] = {
182 for (const auto& known
: methods
) {
183 if (equalIgnoringCase(method
, known
)) {
184 // Don't bother allocating a new string if it's already all
186 return method
== known
? method
: known
;