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