boost/beast/http/impl/field.ipp
//
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/beast
//
#ifndef BOOST_BEAST_HTTP_IMPL_FIELD_IPP
#define BOOST_BEAST_HTTP_IMPL_FIELD_IPP
#include <boost/beast/http/field.hpp>
#include <boost/assert.hpp>
#include <algorithm>
#include <array>
#include <cstdint>
#include <cstring>
#include <ostream>
namespace boost {
namespace beast {
namespace http {
namespace detail {
struct field_table
{
static
std::uint32_t
get_chars(
unsigned char const* p) noexcept
{
// VFALCO memcpy is endian-dependent
//std::memcpy(&v, p, 4);
// Compiler should be smart enough to
// optimize this down to one instruction.
return
p[0] |
(p[1] << 8) |
(p[2] << 16) |
(p[3] << 24);
}
using array_type =
std::array<string_view, 357>;
// Strings are converted to lowercase
static
std::uint32_t
digest(string_view s)
{
std::uint32_t r = 0;
std::size_t n = s.size();
auto p = reinterpret_cast<
unsigned char const*>(s.data());
// consume N characters at a time
// VFALCO Can we do 8 on 64-bit systems?
while(n >= 4)
{
auto const v = get_chars(p);
r = (r * 5 + (
v | 0x20202020 )); // convert to lower
p += 4;
n -= 4;
}
// handle remaining characters
while( n > 0 )
{
r = r * 5 + ( *p | 0x20 );
++p;
--n;
}
return r;
}
// This comparison is case-insensitive, and the
// strings must contain only valid http field characters.
static
bool
equals(string_view lhs, string_view rhs)
{
using Int = std::uint32_t; // VFALCO std::size_t?
auto n = lhs.size();
if(n != rhs.size())
return false;
auto p1 = reinterpret_cast<
unsigned char const*>(lhs.data());
auto p2 = reinterpret_cast<
unsigned char const*>(rhs.data());
auto constexpr S = sizeof(Int);
auto constexpr Mask = static_cast<Int>(
0xDFDFDFDFDFDFDFDF & ~Int{0});
for(; n >= S; p1 += S, p2 += S, n -= S)
{
Int const v1 = get_chars(p1);
Int const v2 = get_chars(p2);
if((v1 ^ v2) & Mask)
return false;
}
for(; n; ++p1, ++p2, --n)
if(( *p1 ^ *p2) & 0xDF)
return false;
return true;
}
array_type by_name_;
enum { N = 5155 };
unsigned char map_[ N ][ 2 ] = {};
/*
From:
https://www.iana.org/assignments/message-headers/message-headers.xhtml
*/
field_table()
: by_name_({{
// string constants
"<unknown-field>",
"A-IM",
"Accept",
"Accept-Additions",
"Accept-Charset",
"Accept-Datetime",
"Accept-Encoding",
"Accept-Features",
"Accept-Language",
"Accept-Patch",
"Accept-Post",
"Accept-Ranges",
"Access-Control",
"Access-Control-Allow-Credentials",
"Access-Control-Allow-Headers",
"Access-Control-Allow-Methods",
"Access-Control-Allow-Origin",
"Access-Control-Expose-Headers",
"Access-Control-Max-Age",
"Access-Control-Request-Headers",
"Access-Control-Request-Method",
"Age",
"Allow",
"ALPN",
"Also-Control",
"Alt-Svc",
"Alt-Used",
"Alternate-Recipient",
"Alternates",
"Apparently-To",
"Apply-To-Redirect-Ref",
"Approved",
"Archive",
"Archived-At",
"Article-Names",
"Article-Updates",
"Authentication-Control",
"Authentication-Info",
"Authentication-Results",
"Authorization",
"Auto-Submitted",
"Autoforwarded",
"Autosubmitted",
"Base",
"Bcc",
"Body",
"C-Ext",
"C-Man",
"C-Opt",
"C-PEP",
"C-PEP-Info",
"Cache-Control",
"CalDAV-Timezones",
"Cancel-Key",
"Cancel-Lock",
"Cc",
"Close",
"Comments",
"Compliance",
"Connection",
"Content-Alternative",
"Content-Base",
"Content-Description",
"Content-Disposition",
"Content-Duration",
"Content-Encoding",
"Content-features",
"Content-ID",
"Content-Identifier",
"Content-Language",
"Content-Length",
"Content-Location",
"Content-MD5",
"Content-Range",
"Content-Return",
"Content-Script-Type",
"Content-Style-Type",
"Content-Transfer-Encoding",
"Content-Type",
"Content-Version",
"Control",
"Conversion",
"Conversion-With-Loss",
"Cookie",
"Cookie2",
"Cost",
"DASL",
"Date",
"Date-Received",
"DAV",
"Default-Style",
"Deferred-Delivery",
"Delivery-Date",
"Delta-Base",
"Depth",
"Derived-From",
"Destination",
"Differential-ID",
"Digest",
"Discarded-X400-IPMS-Extensions",
"Discarded-X400-MTS-Extensions",
"Disclose-Recipients",
"Disposition-Notification-Options",
"Disposition-Notification-To",
"Distribution",
"DKIM-Signature",
"DL-Expansion-History",
"Downgraded-Bcc",
"Downgraded-Cc",
"Downgraded-Disposition-Notification-To",
"Downgraded-Final-Recipient",
"Downgraded-From",
"Downgraded-In-Reply-To",
"Downgraded-Mail-From",
"Downgraded-Message-Id",
"Downgraded-Original-Recipient",
"Downgraded-Rcpt-To",
"Downgraded-References",
"Downgraded-Reply-To",
"Downgraded-Resent-Bcc",
"Downgraded-Resent-Cc",
"Downgraded-Resent-From",
"Downgraded-Resent-Reply-To",
"Downgraded-Resent-Sender",
"Downgraded-Resent-To",
"Downgraded-Return-Path",
"Downgraded-Sender",
"Downgraded-To",
"EDIINT-Features",
"Eesst-Version",
"Encoding",
"Encrypted",
"Errors-To",
"ETag",
"Expect",
"Expires",
"Expiry-Date",
"Ext",
"Followup-To",
"Forwarded",
"From",
"Generate-Delivery-Report",
"GetProfile",
"Hobareg",
"Host",
"HTTP2-Settings",
"If",
"If-Match",
"If-Modified-Since",
"If-None-Match",
"If-Range",
"If-Schedule-Tag-Match",
"If-Unmodified-Since",
"IM",
"Importance",
"In-Reply-To",
"Incomplete-Copy",
"Injection-Date",
"Injection-Info",
"Jabber-ID",
"Keep-Alive",
"Keywords",
"Label",
"Language",
"Last-Modified",
"Latest-Delivery-Time",
"Lines",
"Link",
"List-Archive",
"List-Help",
"List-ID",
"List-Owner",
"List-Post",
"List-Subscribe",
"List-Unsubscribe",
"List-Unsubscribe-Post",
"Location",
"Lock-Token",
"Man",
"Max-Forwards",
"Memento-Datetime",
"Message-Context",
"Message-ID",
"Message-Type",
"Meter",
"Method-Check",
"Method-Check-Expires",
"MIME-Version",
"MMHS-Acp127-Message-Identifier",
"MMHS-Authorizing-Users",
"MMHS-Codress-Message-Indicator",
"MMHS-Copy-Precedence",
"MMHS-Exempted-Address",
"MMHS-Extended-Authorisation-Info",
"MMHS-Handling-Instructions",
"MMHS-Message-Instructions",
"MMHS-Message-Type",
"MMHS-Originator-PLAD",
"MMHS-Originator-Reference",
"MMHS-Other-Recipients-Indicator-CC",
"MMHS-Other-Recipients-Indicator-To",
"MMHS-Primary-Precedence",
"MMHS-Subject-Indicator-Codes",
"MT-Priority",
"Negotiate",
"Newsgroups",
"NNTP-Posting-Date",
"NNTP-Posting-Host",
"Non-Compliance",
"Obsoletes",
"Opt",
"Optional",
"Optional-WWW-Authenticate",
"Ordering-Type",
"Organization",
"Origin",
"Original-Encoded-Information-Types",
"Original-From",
"Original-Message-ID",
"Original-Recipient",
"Original-Sender",
"Original-Subject",
"Originator-Return-Address",
"Overwrite",
"P3P",
"Path",
"PEP",
"Pep-Info",
"PICS-Label",
"Position",
"Posting-Version",
"Pragma",
"Prefer",
"Preference-Applied",
"Prevent-NonDelivery-Report",
"Priority",
"Privicon",
"ProfileObject",
"Protocol",
"Protocol-Info",
"Protocol-Query",
"Protocol-Request",
"Proxy-Authenticate",
"Proxy-Authentication-Info",
"Proxy-Authorization",
"Proxy-Connection",
"Proxy-Features",
"Proxy-Instruction",
"Public",
"Public-Key-Pins",
"Public-Key-Pins-Report-Only",
"Range",
"Received",
"Received-SPF",
"Redirect-Ref",
"References",
"Referer",
"Referer-Root",
"Relay-Version",
"Reply-By",
"Reply-To",
"Require-Recipient-Valid-Since",
"Resent-Bcc",
"Resent-Cc",
"Resent-Date",
"Resent-From",
"Resent-Message-ID",
"Resent-Reply-To",
"Resent-Sender",
"Resent-To",
"Resolution-Hint",
"Resolver-Location",
"Retry-After",
"Return-Path",
"Safe",
"Schedule-Reply",
"Schedule-Tag",
"Sec-Fetch-Dest",
"Sec-Fetch-Mode",
"Sec-Fetch-Site",
"Sec-Fetch-User",
"Sec-WebSocket-Accept",
"Sec-WebSocket-Extensions",
"Sec-WebSocket-Key",
"Sec-WebSocket-Protocol",
"Sec-WebSocket-Version",
"Security-Scheme",
"See-Also",
"Sender",
"Sensitivity",
"Server",
"Set-Cookie",
"Set-Cookie2",
"SetProfile",
"SIO-Label",
"SIO-Label-History",
"SLUG",
"SoapAction",
"Solicitation",
"Status-URI",
"Strict-Transport-Security",
"Subject",
"SubOK",
"Subst",
"Summary",
"Supersedes",
"Surrogate-Capability",
"Surrogate-Control",
"TCN",
"TE",
"Timeout",
"Title",
"To",
"Topic",
"Trailer",
"Transfer-Encoding",
"TTL",
"UA-Color",
"UA-Media",
"UA-Pixels",
"UA-Resolution",
"UA-Windowpixels",
"Upgrade",
"Urgency",
"URI",
"User-Agent",
"Variant-Vary",
"Vary",
"VBR-Info",
"Version",
"Via",
"Want-Digest",
"Warning",
"WWW-Authenticate",
"X-Archived-At",
"X-Device-Accept",
"X-Device-Accept-Charset",
"X-Device-Accept-Encoding",
"X-Device-Accept-Language",
"X-Device-User-Agent",
"X-Frame-Options",
"X-Mittente",
"X-PGP-Sig",
"X-Ricevuta",
"X-Riferimento-Message-ID",
"X-TipoRicevuta",
"X-Trasporto",
"X-VerificaSicurezza",
"X400-Content-Identifier",
"X400-Content-Return",
"X400-Content-Type",
"X400-MTS-Identifier",
"X400-Originator",
"X400-Received",
"X400-Recipients",
"X400-Trace",
"Xref"
}})
{
for(std::size_t i = 1, n = 256; i < n; ++i)
{
auto sv = by_name_[ i ];
auto h = digest(sv);
auto j = h % N;
BOOST_ASSERT(map_[j][0] == 0);
map_[j][0] = static_cast<unsigned char>(i);
}
for(std::size_t i = 256, n = by_name_.size(); i < n; ++i)
{
auto sv = by_name_[i];
auto h = digest(sv);
auto j = h % N;
BOOST_ASSERT(map_[j][1] == 0);
map_[j][1] = static_cast<unsigned char>(i - 255);
}
}
field
string_to_field(string_view s) const
{
auto h = digest(s);
auto j = h % N;
int i = map_[j][0];
string_view s2 = by_name_[i];
if(i != 0 && equals(s, s2))
return static_cast<field>(i);
i = map_[j][1];
if(i == 0)
return field::unknown;
i += 255;
s2 = by_name_[i];
if(equals(s, s2))
return static_cast<field>(i);
return field::unknown;
}
//
// Deprecated
//
using const_iterator =
array_type::const_iterator;
std::size_t
size() const
{
return by_name_.size();
}
const_iterator
begin() const
{
return by_name_.begin();
}
const_iterator
end() const
{
return by_name_.end();
}
};
BOOST_BEAST_DECL
field_table const&
get_field_table()
{
static field_table const tab;
return tab;
}
BOOST_BEAST_DECL
string_view
to_string(field f)
{
auto const& v = get_field_table();
BOOST_ASSERT(static_cast<unsigned>(f) < v.size());
return v.begin()[static_cast<unsigned>(f)];
}
} // detail
string_view
to_string(field f)
{
return detail::to_string(f);
}
field
string_to_field(string_view s)
{
return detail::get_field_table().string_to_field(s);
}
std::ostream&
operator<<(std::ostream& os, field f)
{
return os << to_string(f);
}
} // http
} // beast
} // boost
#endif