GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/field.cpp
Date: 2024-04-15 15:38:04
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 #include <boost/http_proto/field.hpp>
11 #include <boost/core/detail/string_view.hpp>
12 #include <boost/assert.hpp>
13 #include <algorithm>
14 #include <array>
15 #include <cstring>
16 #include <ostream>
17
18 namespace boost {
19 namespace http_proto {
20
21 namespace detail {
22
23 struct field_table
24 {
25 static
26 std::uint32_t
27 27214 get_chars(
28 unsigned char const* p) noexcept
29 {
30 // VFALCO memcpy is endian-dependent
31 //std::memcpy(&v, p, 4);
32 // Compiler should be smart enough to
33 // optimize this down to one instruction.
34 return
35 27214 p[0] |
36 27214 (p[1] << 8) |
37 27214 (p[2] << 16) |
38 27214 (p[3] << 24);
39 }
40
41 using array_type = std::array<
42 core::string_view, 357>;
43
44 // Strings are converted to lowercase
45 static
46 std::uint32_t
47 7432 digest(core::string_view s)
48 {
49 7432 std::uint32_t r = 0;
50 7432 std::size_t n = s.size();
51 auto p = reinterpret_cast<
52 7432 unsigned char const*>(s.data());
53 // consume N characters at a time
54 // VFALCO Can we do 8 on 64-bit systems?
55
2/2
✓ Branch 0 taken 17718 times.
✓ Branch 1 taken 7432 times.
25150 while(n >= 4)
56 {
57 17718 auto const v = get_chars(p);
58 17718 r = (r * 5 + (
59 17718 v | 0x20202020 )); // convert to lower
60 17718 p += 4;
61 17718 n -= 4;
62 }
63 // handle remaining characters
64
2/2
✓ Branch 0 taken 11395 times.
✓ Branch 1 taken 7432 times.
18827 while( n > 0 )
65 {
66 11395 r = r * 5 + ( *p | 0x20 );
67 11395 ++p;
68 11395 --n;
69 }
70 7432 return r;
71 }
72
73 // This comparison is case-insensitive, and the
74 // strings must contain only valid http field characters.
75 static
76 bool
77 2222 equals(
78 core::string_view lhs,
79 core::string_view rhs)
80 {
81 using Int = std::uint32_t; // VFALCO std::size_t?
82 2222 auto n = lhs.size();
83
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2219 times.
2222 if(n != rhs.size())
84 3 return false;
85 auto p1 = reinterpret_cast<
86 2219 unsigned char const*>(lhs.data());
87 auto p2 = reinterpret_cast<
88 2219 unsigned char const*>(rhs.data());
89 2219 auto constexpr S = sizeof(Int);
90 2219 auto constexpr Mask = static_cast<Int>(
91 0xDFDFDFDFDFDFDFDF & ~Int{0});
92
2/2
✓ Branch 0 taken 4748 times.
✓ Branch 1 taken 2219 times.
6967 for(; n >= S; p1 += S, p2 += S, n -= S)
93 {
94 4748 Int const v1 = get_chars(p1);
95 4748 Int const v2 = get_chars(p2);
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4748 times.
4748 if((v1 ^ v2) & Mask)
97 return false;
98 }
99
2/2
✓ Branch 0 taken 4117 times.
✓ Branch 1 taken 2219 times.
6336 for(; n; ++p1, ++p2, --n)
100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4117 times.
4117 if(( *p1 ^ *p2) & 0xDF)
101 return false;
102 2219 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 12 field_table()
116 12 : 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 12 }})
476 {
477
2/2
✓ Branch 0 taken 3060 times.
✓ Branch 1 taken 12 times.
3072 for(std::size_t i = 1, n = 256; i < n; ++i)
478 {
479 3060 auto sv = by_name_[ i ];
480 3060 auto h = digest(sv);
481 3060 auto j = h % N;
482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3060 times.
3060 BOOST_ASSERT(map_[j][0] == 0);
483 3060 map_[j][0] = static_cast<unsigned char>(i);
484 }
485
486
2/2
✓ Branch 1 taken 1212 times.
✓ Branch 2 taken 12 times.
1224 for(std::size_t i = 256, n = by_name_.size(); i < n; ++i)
487 {
488 1212 auto sv = by_name_[i];
489 1212 auto h = digest(sv);
490 1212 auto j = h % N;
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1212 times.
1212 BOOST_ASSERT(map_[j][1] == 0);
492 1212 map_[j][1] = static_cast<unsigned char>(i - 255);
493 }
494 12 }
495
496 field
497 3160 string_to_field(
498 core::string_view s) const noexcept
499 {
500 3160 auto h = digest(s);
501 3160 auto j = h % N;
502 3160 int i = map_[j][0];
503 3160 core::string_view s2 = by_name_[i];
504
6/6
✓ Branch 0 taken 1122 times.
✓ Branch 1 taken 2038 times.
✓ Branch 3 taken 1119 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1119 times.
✓ Branch 6 taken 2041 times.
3160 if(i != 0 && equals(s, s2))
505 1119 return static_cast<field>(i);
506 2041 i = map_[j][1];
507
2/2
✓ Branch 0 taken 941 times.
✓ Branch 1 taken 1100 times.
2041 if(i == 0)
508 941 return field::unknown;
509 1100 i += 255;
510 1100 s2 = by_name_[i];
511
512
1/2
✓ Branch 1 taken 1100 times.
✗ Branch 2 not taken.
1100 if(equals(s, s2))
513 1100 return static_cast<field>(i);
514 return field::unknown;
515 }
516
517 //
518 // Deprecated
519 //
520
521 using const_iterator =
522 array_type::const_iterator;
523
524 std::size_t
525 519 size() const
526 {
527 519 return by_name_.size();
528 }
529
530 const_iterator
531 519 begin() const
532 {
533 519 return by_name_.begin();
534 }
535
536 const_iterator
537 end() const
538 {
539 return by_name_.end();
540 }
541 };
542
543 static
544 field_table const&
545 3679 get_field_table() noexcept
546 {
547
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3667 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
3679 static field_table const tab;
548 3679 return tab;
549 }
550
551 } // detail
552
553 core::string_view
554 519 to_string(field f)
555 {
556 519 auto const& v = detail::get_field_table();
557
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 519 times.
519 BOOST_ASSERT(static_cast<unsigned>(f) < v.size());
558 519 return v.begin()[static_cast<unsigned>(f)];
559 }
560
561 field
562 3160 string_to_field(
563 core::string_view s) noexcept
564 {
565 3160 return detail::get_field_table().string_to_field(s);
566 }
567
568 std::ostream&
569 operator<<(std::ostream& os, field f)
570 {
571 return os << to_string(f);
572 }
573
574 } // http_proto
575 } // boost
576