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_proto
9 : //
10 :
11 : #include <boost/http_proto/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_proto {
21 :
22 : namespace detail {
23 :
24 : struct field_table
25 : {
26 : static
27 : std::uint32_t
28 122726 : 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 122726 : p[0] |
37 122726 : (p[1] << 8) |
38 122726 : (p[2] << 16) |
39 122726 : (p[3] << 24);
40 : }
41 :
42 : using array_type = std::array<
43 : core::string_view, 357>;
44 :
45 : // Strings are converted to lowercase
46 : static
47 : std::uint32_t
48 17799 : digest(core::string_view s)
49 : {
50 17799 : std::uint32_t r = 0;
51 17799 : std::size_t n = s.size();
52 : auto p = reinterpret_cast<
53 17799 : unsigned char const*>(s.data());
54 : // consume N characters at a time
55 : // VFALCO Can we do 8 on 64-bit systems?
56 70329 : while(n >= 4)
57 : {
58 52530 : auto const v = get_chars(p);
59 52530 : r = (r * 5 + (
60 52530 : v | 0x20202020 )); // convert to lower
61 52530 : p += 4;
62 52530 : n -= 4;
63 : }
64 : // handle remaining characters
65 44838 : while( n > 0 )
66 : {
67 27039 : r = r * 5 + ( *p | 0x20 );
68 27039 : ++p;
69 27039 : --n;
70 : }
71 17799 : 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 11120 : equals(
79 : core::string_view lhs,
80 : core::string_view rhs)
81 : {
82 : using Int = std::uint32_t; // VFALCO std::size_t?
83 11120 : auto n = lhs.size();
84 11120 : if(n != rhs.size())
85 5 : return false;
86 : auto p1 = reinterpret_cast<
87 11115 : unsigned char const*>(lhs.data());
88 : auto p2 = reinterpret_cast<
89 11115 : unsigned char const*>(rhs.data());
90 11115 : auto constexpr S = sizeof(Int);
91 11115 : auto constexpr Mask = static_cast<Int>(
92 : 0xDFDFDFDFDFDFDFDF & ~Int{0});
93 46213 : for(; n >= S; p1 += S, p2 += S, n -= S)
94 : {
95 35098 : Int const v1 = get_chars(p1);
96 35098 : Int const v2 = get_chars(p2);
97 35098 : if((v1 ^ v2) & Mask)
98 0 : return false;
99 : }
100 28716 : for(; n; ++p1, ++p2, --n)
101 17601 : if(( *p1 ^ *p2) & 0xDF)
102 0 : return false;
103 11115 : return true;
104 : }
105 :
106 : array_type by_name_;
107 :
108 : enum { N = 5155 };
109 : unsigned char map_[ N ][ 2 ] = {};
110 :
111 : /*
112 : From:
113 :
114 : https://www.iana.org/assignments/message-headers/message-headers.xhtml
115 : */
116 16 : field_table()
117 16 : : by_name_({{
118 : // string constants
119 : "<unknown-field>",
120 : "A-IM",
121 : "Accept",
122 : "Accept-Additions",
123 : "Accept-Charset",
124 : "Accept-Datetime",
125 : "Accept-Encoding",
126 : "Accept-Features",
127 : "Accept-Language",
128 : "Accept-Patch",
129 : "Accept-Post",
130 : "Accept-Ranges",
131 : "Access-Control",
132 : "Access-Control-Allow-Credentials",
133 : "Access-Control-Allow-Headers",
134 : "Access-Control-Allow-Methods",
135 : "Access-Control-Allow-Origin",
136 : "Access-Control-Expose-Headers",
137 : "Access-Control-Max-Age",
138 : "Access-Control-Request-Headers",
139 : "Access-Control-Request-Method",
140 : "Age",
141 : "Allow",
142 : "ALPN",
143 : "Also-Control",
144 : "Alt-Svc",
145 : "Alt-Used",
146 : "Alternate-Recipient",
147 : "Alternates",
148 : "Apparently-To",
149 : "Apply-To-Redirect-Ref",
150 : "Approved",
151 : "Archive",
152 : "Archived-At",
153 : "Article-Names",
154 : "Article-Updates",
155 : "Authentication-Control",
156 : "Authentication-Info",
157 : "Authentication-Results",
158 : "Authorization",
159 : "Auto-Submitted",
160 : "Autoforwarded",
161 : "Autosubmitted",
162 : "Base",
163 : "Bcc",
164 : "Body",
165 : "C-Ext",
166 : "C-Man",
167 : "C-Opt",
168 : "C-PEP",
169 : "C-PEP-Info",
170 : "Cache-Control",
171 : "CalDAV-Timezones",
172 : "Cancel-Key",
173 : "Cancel-Lock",
174 : "Cc",
175 : "Close",
176 : "Comments",
177 : "Compliance",
178 : "Connection",
179 : "Content-Alternative",
180 : "Content-Base",
181 : "Content-Description",
182 : "Content-Disposition",
183 : "Content-Duration",
184 : "Content-Encoding",
185 : "Content-features",
186 : "Content-ID",
187 : "Content-Identifier",
188 : "Content-Language",
189 : "Content-Length",
190 : "Content-Location",
191 : "Content-MD5",
192 : "Content-Range",
193 : "Content-Return",
194 : "Content-Script-Type",
195 : "Content-Style-Type",
196 : "Content-Transfer-Encoding",
197 : "Content-Type",
198 : "Content-Version",
199 : "Control",
200 : "Conversion",
201 : "Conversion-With-Loss",
202 : "Cookie",
203 : "Cookie2",
204 : "Cost",
205 : "DASL",
206 : "Date",
207 : "Date-Received",
208 : "DAV",
209 : "Default-Style",
210 : "Deferred-Delivery",
211 : "Delivery-Date",
212 : "Delta-Base",
213 : "Depth",
214 : "Derived-From",
215 : "Destination",
216 : "Differential-ID",
217 : "Digest",
218 : "Discarded-X400-IPMS-Extensions",
219 : "Discarded-X400-MTS-Extensions",
220 : "Disclose-Recipients",
221 : "Disposition-Notification-Options",
222 : "Disposition-Notification-To",
223 : "Distribution",
224 : "DKIM-Signature",
225 : "DL-Expansion-History",
226 : "Downgraded-Bcc",
227 : "Downgraded-Cc",
228 : "Downgraded-Disposition-Notification-To",
229 : "Downgraded-Final-Recipient",
230 : "Downgraded-From",
231 : "Downgraded-In-Reply-To",
232 : "Downgraded-Mail-From",
233 : "Downgraded-Message-Id",
234 : "Downgraded-Original-Recipient",
235 : "Downgraded-Rcpt-To",
236 : "Downgraded-References",
237 : "Downgraded-Reply-To",
238 : "Downgraded-Resent-Bcc",
239 : "Downgraded-Resent-Cc",
240 : "Downgraded-Resent-From",
241 : "Downgraded-Resent-Reply-To",
242 : "Downgraded-Resent-Sender",
243 : "Downgraded-Resent-To",
244 : "Downgraded-Return-Path",
245 : "Downgraded-Sender",
246 : "Downgraded-To",
247 : "EDIINT-Features",
248 : "Eesst-Version",
249 : "Encoding",
250 : "Encrypted",
251 : "Errors-To",
252 : "ETag",
253 : "Expect",
254 : "Expires",
255 : "Expiry-Date",
256 : "Ext",
257 : "Followup-To",
258 : "Forwarded",
259 : "From",
260 : "Generate-Delivery-Report",
261 : "GetProfile",
262 : "Hobareg",
263 : "Host",
264 : "HTTP2-Settings",
265 : "If",
266 : "If-Match",
267 : "If-Modified-Since",
268 : "If-None-Match",
269 : "If-Range",
270 : "If-Schedule-Tag-Match",
271 : "If-Unmodified-Since",
272 : "IM",
273 : "Importance",
274 : "In-Reply-To",
275 : "Incomplete-Copy",
276 : "Injection-Date",
277 : "Injection-Info",
278 : "Jabber-ID",
279 : "Keep-Alive",
280 : "Keywords",
281 : "Label",
282 : "Language",
283 : "Last-Modified",
284 : "Latest-Delivery-Time",
285 : "Lines",
286 : "Link",
287 : "List-Archive",
288 : "List-Help",
289 : "List-ID",
290 : "List-Owner",
291 : "List-Post",
292 : "List-Subscribe",
293 : "List-Unsubscribe",
294 : "List-Unsubscribe-Post",
295 : "Location",
296 : "Lock-Token",
297 : "Man",
298 : "Max-Forwards",
299 : "Memento-Datetime",
300 : "Message-Context",
301 : "Message-ID",
302 : "Message-Type",
303 : "Meter",
304 : "Method-Check",
305 : "Method-Check-Expires",
306 : "MIME-Version",
307 : "MMHS-Acp127-Message-Identifier",
308 : "MMHS-Authorizing-Users",
309 : "MMHS-Codress-Message-Indicator",
310 : "MMHS-Copy-Precedence",
311 : "MMHS-Exempted-Address",
312 : "MMHS-Extended-Authorisation-Info",
313 : "MMHS-Handling-Instructions",
314 : "MMHS-Message-Instructions",
315 : "MMHS-Message-Type",
316 : "MMHS-Originator-PLAD",
317 : "MMHS-Originator-Reference",
318 : "MMHS-Other-Recipients-Indicator-CC",
319 : "MMHS-Other-Recipients-Indicator-To",
320 : "MMHS-Primary-Precedence",
321 : "MMHS-Subject-Indicator-Codes",
322 : "MT-Priority",
323 : "Negotiate",
324 : "Newsgroups",
325 : "NNTP-Posting-Date",
326 : "NNTP-Posting-Host",
327 : "Non-Compliance",
328 : "Obsoletes",
329 : "Opt",
330 : "Optional",
331 : "Optional-WWW-Authenticate",
332 : "Ordering-Type",
333 : "Organization",
334 : "Origin",
335 : "Original-Encoded-Information-Types",
336 : "Original-From",
337 : "Original-Message-ID",
338 : "Original-Recipient",
339 : "Original-Sender",
340 : "Original-Subject",
341 : "Originator-Return-Address",
342 : "Overwrite",
343 : "P3P",
344 : "Path",
345 : "PEP",
346 : "Pep-Info",
347 : "PICS-Label",
348 : "Position",
349 : "Posting-Version",
350 : "Pragma",
351 : "Prefer",
352 : "Preference-Applied",
353 : "Prevent-NonDelivery-Report",
354 : "Priority",
355 : "Privicon",
356 : "ProfileObject",
357 : "Protocol",
358 : "Protocol-Info",
359 : "Protocol-Query",
360 : "Protocol-Request",
361 : "Proxy-Authenticate",
362 : "Proxy-Authentication-Info",
363 : "Proxy-Authorization",
364 : "Proxy-Connection",
365 : "Proxy-Features",
366 : "Proxy-Instruction",
367 : "Public",
368 : "Public-Key-Pins",
369 : "Public-Key-Pins-Report-Only",
370 : "Range",
371 : "Received",
372 : "Received-SPF",
373 : "Redirect-Ref",
374 : "References",
375 : "Referer",
376 : "Referer-Root",
377 : "Relay-Version",
378 : "Reply-By",
379 : "Reply-To",
380 : "Require-Recipient-Valid-Since",
381 : "Resent-Bcc",
382 : "Resent-Cc",
383 : "Resent-Date",
384 : "Resent-From",
385 : "Resent-Message-ID",
386 : "Resent-Reply-To",
387 : "Resent-Sender",
388 : "Resent-To",
389 : "Resolution-Hint",
390 : "Resolver-Location",
391 : "Retry-After",
392 : "Return-Path",
393 : "Safe",
394 : "Schedule-Reply",
395 : "Schedule-Tag",
396 : "Sec-Fetch-Dest",
397 : "Sec-Fetch-Mode",
398 : "Sec-Fetch-Site",
399 : "Sec-Fetch-User",
400 : "Sec-WebSocket-Accept",
401 : "Sec-WebSocket-Extensions",
402 : "Sec-WebSocket-Key",
403 : "Sec-WebSocket-Protocol",
404 : "Sec-WebSocket-Version",
405 : "Security-Scheme",
406 : "See-Also",
407 : "Sender",
408 : "Sensitivity",
409 : "Server",
410 : "Set-Cookie",
411 : "Set-Cookie2",
412 : "SetProfile",
413 : "SIO-Label",
414 : "SIO-Label-History",
415 : "SLUG",
416 : "SoapAction",
417 : "Solicitation",
418 : "Status-URI",
419 : "Strict-Transport-Security",
420 : "Subject",
421 : "SubOK",
422 : "Subst",
423 : "Summary",
424 : "Supersedes",
425 : "Surrogate-Capability",
426 : "Surrogate-Control",
427 : "TCN",
428 : "TE",
429 : "Timeout",
430 : "Title",
431 : "To",
432 : "Topic",
433 : "Trailer",
434 : "Transfer-Encoding",
435 : "TTL",
436 : "UA-Color",
437 : "UA-Media",
438 : "UA-Pixels",
439 : "UA-Resolution",
440 : "UA-Windowpixels",
441 : "Upgrade",
442 : "Urgency",
443 : "URI",
444 : "User-Agent",
445 : "Variant-Vary",
446 : "Vary",
447 : "VBR-Info",
448 : "Version",
449 : "Via",
450 : "Want-Digest",
451 : "Warning",
452 : "WWW-Authenticate",
453 : "X-Archived-At",
454 : "X-Device-Accept",
455 : "X-Device-Accept-Charset",
456 : "X-Device-Accept-Encoding",
457 : "X-Device-Accept-Language",
458 : "X-Device-User-Agent",
459 : "X-Frame-Options",
460 : "X-Mittente",
461 : "X-PGP-Sig",
462 : "X-Ricevuta",
463 : "X-Riferimento-Message-ID",
464 : "X-TipoRicevuta",
465 : "X-Trasporto",
466 : "X-VerificaSicurezza",
467 : "X400-Content-Identifier",
468 : "X400-Content-Return",
469 : "X400-Content-Type",
470 : "X400-MTS-Identifier",
471 : "X400-Originator",
472 : "X400-Received",
473 : "X400-Recipients",
474 : "X400-Trace",
475 : "Xref"
476 16 : }})
477 : {
478 4096 : for(std::size_t i = 1, n = 256; i < n; ++i)
479 : {
480 4080 : auto sv = by_name_[ i ];
481 4080 : auto h = digest(sv);
482 4080 : auto j = h % N;
483 4080 : BOOST_ASSERT(map_[j][0] == 0);
484 4080 : map_[j][0] = static_cast<unsigned char>(i);
485 : }
486 :
487 1648 : for(std::size_t i = 256, n = by_name_.size(); i < n; ++i)
488 : {
489 1616 : auto sv = by_name_[i];
490 1616 : auto h = digest(sv);
491 1616 : auto j = h % N;
492 1616 : BOOST_ASSERT(map_[j][1] == 0);
493 1616 : map_[j][1] = static_cast<unsigned char>(i - 255);
494 : }
495 16 : }
496 :
497 : optional<field>
498 12103 : string_to_field(
499 : core::string_view s) const noexcept
500 : {
501 12103 : auto h = digest(s);
502 12103 : auto j = h % N;
503 12103 : int i = map_[j][0];
504 12103 : core::string_view s2 = by_name_[i];
505 12103 : if(i != 0 && equals(s, s2))
506 5505 : return static_cast<field>(i);
507 6598 : i = map_[j][1];
508 6598 : if(i == 0)
509 988 : return boost::none;
510 5610 : i += 255;
511 5610 : s2 = by_name_[i];
512 :
513 5610 : if(equals(s, s2))
514 5610 : return static_cast<field>(i);
515 0 : return boost::none;
516 : }
517 :
518 : //
519 : // Deprecated
520 : //
521 :
522 : using const_iterator =
523 : array_type::const_iterator;
524 :
525 : std::size_t
526 593 : size() const
527 : {
528 1186 : return by_name_.size();
529 : }
530 :
531 : const_iterator
532 593 : begin() const
533 : {
534 593 : return by_name_.begin();
535 : }
536 :
537 : const_iterator
538 : end() const
539 : {
540 : return by_name_.end();
541 : }
542 : };
543 :
544 : static
545 : field_table const&
546 12696 : get_field_table() noexcept
547 : {
548 12696 : static field_table const tab;
549 12696 : return tab;
550 : }
551 :
552 : } // detail
553 :
554 : core::string_view
555 593 : to_string(field f)
556 : {
557 593 : auto const& v = detail::get_field_table();
558 593 : BOOST_ASSERT(static_cast<unsigned>(f) < v.size());
559 593 : return v.begin()[static_cast<unsigned>(f)];
560 : }
561 :
562 : boost::optional<field>
563 12103 : string_to_field(
564 : core::string_view s) noexcept
565 : {
566 12103 : return detail::get_field_table().string_to_field(s);
567 : }
568 :
569 : std::ostream&
570 0 : operator<<(std::ostream& os, field f)
571 : {
572 0 : return os << to_string(f);
573 : }
574 :
575 : } // http_proto
576 : } // boost
|