LCOV - code coverage report
Current view: top level - libs/http_proto/src/field.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 94.0 % 83 78
Test Date: 2025-09-21 18:08:14 Functions: 90.9 % 11 10

            Line data    Source code
       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        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        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        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        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        35098 :             if((v1 ^ v2) & Mask)
      98            0 :                 return false;
      99              :         }
     100        28716 :         for(; n; ++p1, ++p2, --n)
     101        17601 :             if(( *p1 ^ *p2) & 0xDF)
     102            0 :                 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         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         4080 :             BOOST_ASSERT(map_[j][0] == 0);
     484         4080 :             map_[j][0] = static_cast<unsigned char>(i);
     485              :         }
     486              : 
     487         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         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        12103 :         if(i != 0 && equals(s, s2))
     506         5505 :             return static_cast<field>(i);
     507         6598 :         i = map_[j][1];
     508         6598 :         if(i == 0)
     509          988 :             return boost::none;
     510         5610 :         i += 255;
     511         5610 :         s2 = by_name_[i];
     512              : 
     513         5610 :         if(equals(s, s2))
     514         5610 :             return static_cast<field>(i);
     515            0 :         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        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          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            0 : operator<<(std::ostream& os, field f)
     571              : {
     572            0 :     return os << to_string(f);
     573              : }
     574              : 
     575              : } // http_proto
     576              : } // boost
        

Generated by: LCOV version 2.1