src/field.cpp

92.8% Lines (64/69) 90.9% List of functions (10/11)
field.cpp
f(x) Functions (11)
Line TLA Hits 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 105131x 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 105131x p[0] |
37 105131x (p[1] << 8) |
38 105131x (p[2] << 16) |
39 105131x (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 13013x digest(core::string_view s)
49 {
50 13013x std::uint32_t r = 0;
51 13013x std::size_t n = s.size();
52 auto p = reinterpret_cast<
53 13013x unsigned char const*>(s.data());
54 // consume N characters at a time
55 // VFALCO Can we do 8 on 64-bit systems?
56 52510x while(n >= 4)
57 {
58 39497x auto const v = get_chars(p);
59 39497x r = (r * 5 + (
60 39497x v | 0x20202020 )); // convert to lower
61 39497x p += 4;
62 39497x n -= 4;
63 }
64 // handle remaining characters
65 32523x while( n > 0 )
66 {
67 19510x r = r * 5 + ( *p | 0x20 );
68 19510x ++p;
69 19510x --n;
70 }
71 13013x 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 9970x equals(
79 core::string_view lhs,
80 core::string_view rhs)
81 {
82 using Int = std::uint32_t; // VFALCO std::size_t?
83 9970x auto n = lhs.size();
84 9970x if(n != rhs.size())
85 return false;
86 auto p1 = reinterpret_cast<
87 9970x unsigned char const*>(lhs.data());
88 auto p2 = reinterpret_cast<
89 9970x unsigned char const*>(rhs.data());
90 9970x auto constexpr S = sizeof(Int);
91 9970x auto constexpr Mask = static_cast<Int>(
92 0xDFDFDFDFDFDFDFDF & ~Int{0});
93 42787x for(; n >= S; p1 += S, p2 += S, n -= S)
94 {
95 32817x Int const v1 = get_chars(p1);
96 32817x Int const v2 = get_chars(p2);
97 32817x if((v1 ^ v2) & Mask)
98 return false;
99 }
100 25363x for(; n; ++p1, ++p2, --n)
101 15393x if(( *p1 ^ *p2) & 0xDF)
102 return false;
103 9970x 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 16x field_table()
117 16x : 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 16x }})
249 {
250 4160x for(std::size_t i = 1; i < by_name_.size(); ++i)
251 {
252 2064x auto sv = by_name_[ i ];
253 2064x auto h = digest(sv);
254 2064x auto j = h % N;
255 2064x BOOST_ASSERT(map_[j] == 0);
256 2064x map_[j] = static_cast<unsigned char>(i);
257 }
258 16x }
259
260 optional<field>
261 10949x string_to_field(
262 core::string_view s) const noexcept
263 {
264 10949x auto h = digest(s);
265 10949x auto j = h % N;
266 10949x int i = map_[j];
267 10949x if(i != 0 && equals(s, by_name_[i]))
268 9970x return static_cast<field>(i);
269 979x 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 369x size() const
281 {
282 738x return by_name_.size();
283 }
284
285 const_iterator
286 369x begin() const
287 {
288 369x 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 11318x get_field_table() noexcept
301 {
302 11318x static field_table const tab;
303 11318x return tab;
304 }
305
306 } // detail
307
308 core::string_view
309 369x to_string(field f)
310 {
311 369x auto const& v = detail::get_field_table();
312 369x BOOST_ASSERT(static_cast<unsigned>(f) < v.size());
313 369x return v.begin()[static_cast<unsigned>(f)];
314 }
315
316 boost::optional<field>
317 10949x string_to_field(
318 core::string_view s) noexcept
319 {
320 10949x return detail::get_field_table().string_to_field(s);
321 }
322
323 std::ostream&
324 operator<<(std::ostream& os, field f)
325 {
326 return os << to_string(f);
327 }
328
329 } // http
330 } // boost
331