LCOV - code coverage report
Current view: top level - http_proto/impl - field.ipp (source / functions) Hit Total Coverage
Test: coverage_filtered.info Lines: 78 83 94.0 %
Date: 2023-03-01 04:48:12 Functions: 10 11 90.9 %

          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       78498 :     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       78498 :              p[0] |
      39       78498 :             (p[1] <<  8) |
      40       78498 :             (p[2] << 16) |
      41       78498 :             (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       15405 :     digest(core::string_view s)
      51             :     {
      52       15405 :         std::uint32_t r = 0;
      53       15405 :         std::size_t n = s.size();
      54             :         auto p = reinterpret_cast<
      55       15405 :             unsigned char const*>(s.data());
      56             :         // consume N characters at a time
      57             :         // VFALCO Can we do 8 on 64-bit systems?
      58       49467 :         while(n >= 4)
      59             :         {
      60       34062 :             auto const v = get_chars(p);
      61       34062 :             r = (r * 5 + (
      62       34062 :                 v | 0x20202020 )); // convert to lower
      63       34062 :             p += 4;
      64       34062 :             n -= 4;
      65             :         }
      66             :         // handle remaining characters
      67       43151 :         while( n > 0 )
      68             :         {
      69       27746 :             r = r * 5 + ( *p | 0x20 );
      70       27746 :             ++p;
      71       27746 :             --n;
      72             :         }
      73       15405 :         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       10772 :     equals(
      81             :         core::string_view lhs,
      82             :         core::string_view rhs)
      83             :     {
      84             :         using Int = std::uint32_t; // VFALCO std::size_t?
      85       10772 :         auto n = lhs.size();
      86       10772 :         if(n != rhs.size())
      87           3 :             return false;
      88             :         auto p1 = reinterpret_cast<
      89       10769 :             unsigned char const*>(lhs.data());
      90             :         auto p2 = reinterpret_cast<
      91       10769 :             unsigned char const*>(rhs.data());
      92       10769 :         auto constexpr S = sizeof(Int);
      93       10769 :         auto constexpr Mask = static_cast<Int>(
      94             :             0xDFDFDFDFDFDFDFDF & ~Int{0});
      95       32987 :         for(; n >= S; p1 += S, p2 += S, n -= S)
      96             :         {
      97       22218 :             Int const v1 = get_chars(p1);
      98       22218 :             Int const v2 = get_chars(p2);
      99       22218 :             if((v1 ^ v2) & Mask)
     100           0 :                 return false;
     101             :         }
     102       31991 :         for(; n; ++p1, ++p2, --n)
     103       21222 :             if(( *p1 ^ *p2) & 0xDF)
     104           0 :                 return false;
     105       10769 :         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       11489 :     string_to_field(
     501             :         core::string_view s) const noexcept
     502             :     {
     503       11489 :         auto h = digest(s);
     504       11489 :         auto j = h % N;
     505       11489 :         int i = map_[j][0];
     506       11489 :         core::string_view s2 = by_name_[i];
     507       11489 :         if(i != 0 && equals(s, s2))
     508        4326 :             return static_cast<field>(i);
     509        7163 :         i = map_[j][1];
     510        7163 :         if(i == 0)
     511         720 :             return field::unknown;
     512        6443 :         i += 255;
     513        6443 :         s2 = by_name_[i];
     514             : 
     515        6443 :         if(equals(s, s2))
     516        6443 :             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       11892 : get_field_table() noexcept
     549             : {
     550       11892 :     static field_table const tab;
     551       11892 :     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       11489 : string_to_field(
     566             :     core::string_view s) noexcept
     567             : {
     568       11489 :     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

Generated by: LCOV version 1.15