8f9c4531eaa29e6ccd265b312fc1087eb34c8edf
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / fetch / FetchUtils.cpp
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.
4
5 #include "config.h"
6 #include "core/fetch/FetchUtils.h"
7
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"
14
15 namespace blink {
16
17 namespace {
18
19 class ForbiddenHeaderNames {
20     WTF_MAKE_NONCOPYABLE(ForbiddenHeaderNames); WTF_MAKE_FAST_ALLOCATED;
21 public:
22     bool has(const String& name) const
23     {
24         return m_fixedNames.contains(name)
25             || name.startsWith(m_proxyHeaderPrefix, false)
26             || name.startsWith(m_secHeaderPrefix, false);
27     }
28
29     static const ForbiddenHeaderNames* get();
30
31 private:
32     ForbiddenHeaderNames();
33
34     String m_proxyHeaderPrefix;
35     String m_secHeaderPrefix;
36     HashSet<String, CaseFoldingHash> m_fixedNames;
37 };
38
39 ForbiddenHeaderNames::ForbiddenHeaderNames()
40     : m_proxyHeaderPrefix("proxy-")
41     , m_secHeaderPrefix("sec-")
42 {
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");
64 }
65
66 const ForbiddenHeaderNames* ForbiddenHeaderNames::get()
67 {
68     AtomicallyInitializedStatic(const ForbiddenHeaderNames*, instance = new ForbiddenHeaderNames);
69     return instance;
70 }
71
72 } // namespace
73
74 bool FetchUtils::isSimpleMethod(const String& method)
75 {
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";
79 }
80
81 bool FetchUtils::isSimpleHeader(const AtomicString& name, const AtomicString& value)
82 {
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
88     // `text/plain`."
89
90     if (equalIgnoringCase(name, "accept")
91         || equalIgnoringCase(name, "accept-language")
92         || equalIgnoringCase(name, "content-language"))
93         return true;
94
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");
100     }
101
102     return false;
103 }
104
105 bool FetchUtils::isSimpleRequest(const String& method, const HTTPHeaderMap& headerMap)
106 {
107     if (!isSimpleMethod(method))
108         return false;
109
110     for (const auto& header : headerMap) {
111         // Preflight is required for MIME types that can not be sent via form
112         // submission.
113         if (!isSimpleHeader(header.key, header.value))
114             return false;
115     }
116
117     return true;
118 }
119
120 bool FetchUtils::isForbiddenMethod(const String& method)
121 {
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");
128 }
129
130 bool FetchUtils::isForbiddenHeaderName(const String& name)
131 {
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
140     // `Sec-`)."
141
142     return ForbiddenHeaderNames::get()->has(name);
143 }
144
145 bool FetchUtils::isForbiddenResponseHeaderName(const String& name)
146 {
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`"
150
151     return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set-cookie2");
152 }
153
154 bool FetchUtils::isSimpleOrForbiddenRequest(const String& method, const HTTPHeaderMap& headerMap)
155 {
156     if (!isSimpleMethod(method))
157         return false;
158
159     for (const auto& header : headerMap) {
160         if (!isSimpleHeader(header.key, header.value) && !isForbiddenHeaderName(header.key))
161             return false;
162     }
163
164     return true;
165 }
166
167 AtomicString FetchUtils::normalizeMethod(const AtomicString& method)
168 {
169     // https://fetch.spec.whatwg.org/#concept-method-normalize
170
171     // We place GET and POST first because they are more commonly used than
172     // others.
173     const char* const methods[] = {
174         "GET",
175         "POST",
176         "DELETE",
177         "HEAD",
178         "OPTIONS",
179         "PUT",
180     };
181
182     for (const auto& known : methods) {
183         if (equalIgnoringCase(method, known)) {
184             // Don't bother allocating a new string if it's already all
185             // uppercase.
186             return method == known ? method : known;
187         }
188     }
189     return method;
190 }
191
192 } // namespace blink