GCC Code Coverage Report


Directory: libs/http_proto/
File: src/field.cpp
Date: 2025-09-21 18:08:15
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 // 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
2/2
✓ Branch 0 taken 52530 times.
✓ Branch 1 taken 17799 times.
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
2/2
✓ Branch 0 taken 27039 times.
✓ Branch 1 taken 17799 times.
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
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 11115 times.
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
2/2
✓ Branch 0 taken 35098 times.
✓ Branch 1 taken 11115 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35098 times.
35098 if((v1 ^ v2) & Mask)
98 return false;
99 }
100
2/2
✓ Branch 0 taken 17601 times.
✓ Branch 1 taken 11115 times.
28716 for(; n; ++p1, ++p2, --n)
101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17601 times.
17601 if(( *p1 ^ *p2) & 0xDF)
102 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
2/2
✓ Branch 0 taken 4080 times.
✓ Branch 1 taken 16 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4080 times.
4080 BOOST_ASSERT(map_[j][0] == 0);
484 4080 map_[j][0] = static_cast<unsigned char>(i);
485 }
486
487
2/2
✓ Branch 0 taken 1616 times.
✓ Branch 1 taken 16 times.
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
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1616 times.
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
6/6
✓ Branch 0 taken 5510 times.
✓ Branch 1 taken 6593 times.
✓ Branch 3 taken 5505 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 5505 times.
✓ Branch 6 taken 6598 times.
12103 if(i != 0 && equals(s, s2))
506 5505 return static_cast<field>(i);
507 6598 i = map_[j][1];
508
2/2
✓ Branch 0 taken 988 times.
✓ Branch 1 taken 5610 times.
6598 if(i == 0)
509 988 return boost::none;
510 5610 i += 255;
511 5610 s2 = by_name_[i];
512
513
1/2
✓ Branch 1 taken 5610 times.
✗ Branch 2 not taken.
5610 if(equals(s, s2))
514 5610 return static_cast<field>(i);
515 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
3/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 12680 times.
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
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
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 593 times.
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 operator<<(std::ostream& os, field f)
571 {
572 return os << to_string(f);
573 }
574
575 } // http_proto
576 } // boost
577