TLA Line data Source code
1 : //
2 : // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2025 Mohammad Nejati
4 : //
5 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 : //
8 : // Official repository: https://github.com/cppalliance/http
9 : //
10 :
11 : #include <boost/http/field.hpp>
12 : #include <boost/assert.hpp>
13 : #include <boost/core/detail/string_view.hpp>
14 : #include <array>
15 : #include <cstdint>
16 : #include <cstring>
17 : #include <ostream>
18 :
19 : namespace boost {
20 : namespace http {
21 :
22 : namespace detail {
23 :
24 : struct field_table
25 : {
26 : static
27 : std::uint32_t
28 HIT 105131 : get_chars(
29 : unsigned char const* p) noexcept
30 : {
31 : // VFALCO memcpy is endian-dependent
32 : //std::memcpy(&v, p, 4);
33 : // Compiler should be smart enough to
34 : // optimize this down to one instruction.
35 : return
36 105131 : p[0] |
37 105131 : (p[1] << 8) |
38 105131 : (p[2] << 16) |
39 105131 : (p[3] << 24);
40 : }
41 :
42 : using array_type = std::array<
43 : core::string_view, 130>;
44 :
45 : // Strings are converted to lowercase
46 : static
47 : std::uint32_t
48 13013 : digest(core::string_view s)
49 : {
50 13013 : std::uint32_t r = 0;
51 13013 : std::size_t n = s.size();
52 : auto p = reinterpret_cast<
53 13013 : unsigned char const*>(s.data());
54 : // consume N characters at a time
55 : // VFALCO Can we do 8 on 64-bit systems?
56 52510 : while(n >= 4)
57 : {
58 39497 : auto const v = get_chars(p);
59 39497 : r = (r * 5 + (
60 39497 : v | 0x20202020 )); // convert to lower
61 39497 : p += 4;
62 39497 : n -= 4;
63 : }
64 : // handle remaining characters
65 32523 : while( n > 0 )
66 : {
67 19510 : r = r * 5 + ( *p | 0x20 );
68 19510 : ++p;
69 19510 : --n;
70 : }
71 13013 : return r;
72 : }
73 :
74 : // This comparison is case-insensitive, and the
75 : // strings must contain only valid http field characters.
76 : static
77 : bool
78 9970 : equals(
79 : core::string_view lhs,
80 : core::string_view rhs)
81 : {
82 : using Int = std::uint32_t; // VFALCO std::size_t?
83 9970 : auto n = lhs.size();
84 9970 : if(n != rhs.size())
85 MIS 0 : return false;
86 : auto p1 = reinterpret_cast<
87 HIT 9970 : unsigned char const*>(lhs.data());
88 : auto p2 = reinterpret_cast<
89 9970 : unsigned char const*>(rhs.data());
90 9970 : auto constexpr S = sizeof(Int);
91 9970 : auto constexpr Mask = static_cast<Int>(
92 : 0xDFDFDFDFDFDFDFDF & ~Int{0});
93 42787 : for(; n >= S; p1 += S, p2 += S, n -= S)
94 : {
95 32817 : Int const v1 = get_chars(p1);
96 32817 : Int const v2 = get_chars(p2);
97 32817 : if((v1 ^ v2) & Mask)
98 MIS 0 : return false;
99 : }
100 HIT 25363 : for(; n; ++p1, ++p2, --n)
101 15393 : if(( *p1 ^ *p2) & 0xDF)
102 MIS 0 : return false;
103 HIT 9970 : return true;
104 : }
105 :
106 : array_type by_name_;
107 :
108 : enum { N = 1367 };
109 : unsigned char map_[ N ] = {};
110 :
111 : /*
112 : From:
113 : https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers
114 : https://www.iana.org/assignments/http-fields/http-fields.xhtml
115 : */
116 16 : field_table()
117 16 : : by_name_({{
118 : "<unknown-field>",
119 : "Accept",
120 : "Accept-CH",
121 : "Accept-Charset",
122 : "Accept-Encoding",
123 : "Accept-Language",
124 : "Accept-Patch",
125 : "Accept-Post",
126 : "Accept-Ranges",
127 : "Accept-Signature",
128 : "Access-Control-Allow-Credentials",
129 : "Access-Control-Allow-Headers",
130 : "Access-Control-Allow-Methods",
131 : "Access-Control-Allow-Origin",
132 : "Access-Control-Expose-Headers",
133 : "Access-Control-Max-Age",
134 : "Access-Control-Request-Headers",
135 : "Access-Control-Request-Method",
136 : "Age",
137 : "Allow",
138 : "Alt-Svc",
139 : "Alt-Used",
140 : "Authorization",
141 : "Cache-Control",
142 : "Clear-Site-Data",
143 : "Connection",
144 : "Content-Digest",
145 : "Content-Disposition",
146 : "Content-DPR",
147 : "Content-Encoding",
148 : "Content-Language",
149 : "Content-Length",
150 : "Content-Location",
151 : "Content-Range",
152 : "Content-Security-Policy",
153 : "Content-Security-Policy-Report-Only",
154 : "Content-Type",
155 : "Cookie",
156 : "Cross-Origin-Embedder-Policy",
157 : "Cross-Origin-Opener-Policy",
158 : "Cross-Origin-Resource-Policy",
159 : "Date",
160 : "Deprecation",
161 : "Device-Memory",
162 : "Digest",
163 : "DNT",
164 : "DPR",
165 : "ETag",
166 : "Expect",
167 : "Expect-CT",
168 : "Expires",
169 : "Forwarded",
170 : "From",
171 : "Host",
172 : "HTTP2-Settings",
173 : "If-Match",
174 : "If-Modified-Since",
175 : "If-None-Match",
176 : "If-Range",
177 : "If-Unmodified-Since",
178 : "Keep-Alive",
179 : "Last-Modified",
180 : "Link",
181 : "Location",
182 : "Max-Forwards",
183 : "Origin",
184 : "Origin-Agent-Cluster",
185 : "Pragma",
186 : "Prefer",
187 : "Preference-Applied",
188 : "Priority",
189 : "Proxy-Authenticate",
190 : "Proxy-Authorization",
191 : "Proxy-Connection",
192 : "Range",
193 : "Referer",
194 : "Referrer-Policy",
195 : "Refresh",
196 : "Report-To",
197 : "Reporting-Endpoints",
198 : "Repr-Digest",
199 : "Retry-After",
200 : "Sec-CH-UA-Full-Version",
201 : "Sec-Fetch-Dest",
202 : "Sec-Fetch-Mode",
203 : "Sec-Fetch-Site",
204 : "Sec-Fetch-User",
205 : "Sec-Purpose",
206 : "Sec-WebSocket-Accept",
207 : "Sec-WebSocket-Extensions",
208 : "Sec-WebSocket-Key",
209 : "Sec-WebSocket-Protocol",
210 : "Sec-WebSocket-Version",
211 : "Server",
212 : "Server-Timing",
213 : "Service-Worker",
214 : "Service-Worker-Allowed",
215 : "Service-Worker-Navigation-Preload",
216 : "Set-Cookie",
217 : "Set-Login",
218 : "Signature",
219 : "Signature-Input",
220 : "SourceMap",
221 : "Strict-Transport-Security",
222 : "TE",
223 : "Timing-Allow-Origin",
224 : "Tk",
225 : "Trailer",
226 : "Transfer-Encoding",
227 : "Upgrade",
228 : "Upgrade-Insecure-Requests",
229 : "User-Agent",
230 : "Vary",
231 : "Via",
232 : "Viewport-Width",
233 : "Want-Content-Digest",
234 : "Want-Repr-Digest",
235 : "Warning",
236 : "Width",
237 : "WWW-Authenticate",
238 : "X-Content-Type-Options",
239 : "X-DNS-Prefetch-Control",
240 : "X-Forwarded-For",
241 : "X-Forwarded-Host",
242 : "X-Forwarded-Proto",
243 : "X-Frame-Options",
244 : "X-Permitted-Cross-Domain-Policies",
245 : "X-Powered-By",
246 : "X-Robots-Tag",
247 : "X-XSS-Protection"
248 16 : }})
249 : {
250 4160 : for(std::size_t i = 1; i < by_name_.size(); ++i)
251 : {
252 2064 : auto sv = by_name_[ i ];
253 2064 : auto h = digest(sv);
254 2064 : auto j = h % N;
255 2064 : BOOST_ASSERT(map_[j] == 0);
256 2064 : map_[j] = static_cast<unsigned char>(i);
257 : }
258 16 : }
259 :
260 : optional<field>
261 10949 : string_to_field(
262 : core::string_view s) const noexcept
263 : {
264 10949 : auto h = digest(s);
265 10949 : auto j = h % N;
266 10949 : int i = map_[j];
267 10949 : if(i != 0 && equals(s, by_name_[i]))
268 9970 : return static_cast<field>(i);
269 979 : return boost::none;
270 : }
271 :
272 : //
273 : // Deprecated
274 : //
275 :
276 : using const_iterator =
277 : array_type::const_iterator;
278 :
279 : std::size_t
280 369 : size() const
281 : {
282 738 : return by_name_.size();
283 : }
284 :
285 : const_iterator
286 369 : begin() const
287 : {
288 369 : return by_name_.begin();
289 : }
290 :
291 : const_iterator
292 : end() const
293 : {
294 : return by_name_.end();
295 : }
296 : };
297 :
298 : static
299 : field_table const&
300 11318 : get_field_table() noexcept
301 : {
302 11318 : static field_table const tab;
303 11318 : return tab;
304 : }
305 :
306 : } // detail
307 :
308 : core::string_view
309 369 : to_string(field f)
310 : {
311 369 : auto const& v = detail::get_field_table();
312 369 : BOOST_ASSERT(static_cast<unsigned>(f) < v.size());
313 369 : return v.begin()[static_cast<unsigned>(f)];
314 : }
315 :
316 : boost::optional<field>
317 10949 : string_to_field(
318 : core::string_view s) noexcept
319 : {
320 10949 : return detail::get_field_table().string_to_field(s);
321 : }
322 :
323 : std::ostream&
324 MIS 0 : operator<<(std::ostream& os, field f)
325 : {
326 0 : return os << to_string(f);
327 : }
328 :
329 : } // http
330 : } // boost
|