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