GCC Code Coverage Report


Directory: libs/http_proto/include/boost/http_proto/
File: boost/http_proto/impl/field.ipp
Date: 2023-12-11 14:11:20
Exec Total Coverage
Lines: 78 83 94.0%
Functions: 10 11 90.9%
Branches: 31 38 81.6%

Line Branch Exec Source
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
2/2
✓ Branch 0 taken 16487 times.
✓ Branch 1 taken 6794 times.
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
2/2
✓ Branch 0 taken 10524 times.
✓ Branch 1 taken 6794 times.
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
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2158 times.
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
2/2
✓ Branch 0 taken 4643 times.
✓ Branch 1 taken 2158 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4643 times.
4643 if((v1 ^ v2) & Mask)
100 return false;
101 }
102
2/2
✓ Branch 0 taken 4000 times.
✓ Branch 1 taken 2158 times.
6158 for(; n; ++p1, ++p2, --n)
103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4000 times.
4000 if(( *p1 ^ *p2) & 0xDF)
104 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
2/2
✓ Branch 0 taken 2805 times.
✓ Branch 1 taken 11 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2805 times.
2805 BOOST_ASSERT(map_[j][0] == 0);
486 2805 map_[j][0] = static_cast<unsigned char>(i);
487 }
488
489
2/2
✓ Branch 1 taken 1111 times.
✓ Branch 2 taken 11 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1111 times.
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
6/6
✓ Branch 0 taken 1096 times.
✓ Branch 1 taken 1782 times.
✓ Branch 3 taken 1093 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1093 times.
✓ Branch 6 taken 1785 times.
2878 if(i != 0 && equals(s, s2))
508 1093 return static_cast<field>(i);
509 1785 i = map_[j][1];
510
2/2
✓ Branch 0 taken 720 times.
✓ Branch 1 taken 1065 times.
1785 if(i == 0)
511 720 return field::unknown;
512 1065 i += 255;
513 1065 s2 = by_name_[i];
514
515
1/2
✓ Branch 1 taken 1065 times.
✗ Branch 2 not taken.
1065 if(equals(s, s2))
516 1065 return static_cast<field>(i);
517 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
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 3270 times.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 403 times.
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 operator<<(std::ostream& os, field f)
573 {
574 return os << to_string(f);
575 }
576
577 } // http_proto
578 } // boost
579
580 #endif
581