| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- //
- // 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 <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, 129>;
- // 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 = 1367 };
- unsigned char map_[ N ] = {};
- /*
- From:
- https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers
- https://www.iana.org/assignments/http-fields/http-fields.xhtml
- */
- field_table()
- : by_name_({{
- "<unknown-field>",
- "Accept",
- "Accept-CH",
- "Accept-Charset",
- "Accept-Encoding",
- "Accept-Language",
- "Accept-Patch",
- "Accept-Post",
- "Accept-Ranges",
- "Accept-Signature",
- "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",
- "Alt-Svc",
- "Alt-Used",
- "Authorization",
- "Cache-Control",
- "Clear-Site-Data",
- "Connection",
- "Content-Digest",
- "Content-Disposition",
- "Content-DPR",
- "Content-Encoding",
- "Content-Language",
- "Content-Length",
- "Content-Location",
- "Content-Range",
- "Content-Security-Policy",
- "Content-Security-Policy-Report-Only",
- "Content-Type",
- "Cookie",
- "Cross-Origin-Embedder-Policy",
- "Cross-Origin-Opener-Policy",
- "Cross-Origin-Resource-Policy",
- "Date",
- "Deprecation",
- "Device-Memory",
- "Digest",
- "DNT",
- "DPR",
- "ETag",
- "Expect",
- "Expect-CT",
- "Expires",
- "Forwarded",
- "From",
- "Host",
- "If-Match",
- "If-Modified-Since",
- "If-None-Match",
- "If-Range",
- "If-Unmodified-Since",
- "Keep-Alive",
- "Last-Modified",
- "Link",
- "Location",
- "Max-Forwards",
- "Origin",
- "Origin-Agent-Cluster",
- "Pragma",
- "Prefer",
- "Preference-Applied",
- "Priority",
- "Proxy-Authenticate",
- "Proxy-Authorization",
- "Proxy-Connection",
- "Range",
- "Referer",
- "Referrer-Policy",
- "Refresh",
- "Report-To",
- "Reporting-Endpoints",
- "Repr-Digest",
- "Retry-After",
- "Sec-CH-UA-Full-Version",
- "Sec-Fetch-Dest",
- "Sec-Fetch-Mode",
- "Sec-Fetch-Site",
- "Sec-Fetch-User",
- "Sec-Purpose",
- "Sec-WebSocket-Accept",
- "Sec-WebSocket-Extensions",
- "Sec-WebSocket-Key",
- "Sec-WebSocket-Protocol",
- "Sec-WebSocket-Version",
- "Server",
- "Server-Timing",
- "Service-Worker",
- "Service-Worker-Allowed",
- "Service-Worker-Navigation-Preload",
- "Set-Cookie",
- "Set-Login",
- "Signature",
- "Signature-Input",
- "SourceMap",
- "Strict-Transport-Security",
- "TE",
- "Timing-Allow-Origin",
- "Tk",
- "Trailer",
- "Transfer-Encoding",
- "Upgrade",
- "Upgrade-Insecure-Requests",
- "User-Agent",
- "Vary",
- "Via",
- "Viewport-Width",
- "Want-Content-Digest",
- "Want-Repr-Digest",
- "Warning",
- "Width",
- "WWW-Authenticate",
- "X-Content-Type-Options",
- "X-DNS-Prefetch-Control",
- "X-Forwarded-For",
- "X-Forwarded-Host",
- "X-Forwarded-Proto",
- "X-Frame-Options",
- "X-Permitted-Cross-Domain-Policies",
- "X-Powered-By",
- "X-Robots-Tag",
- "X-XSS-Protection"
- }})
- {
- for(std::size_t i = 1; i < by_name_.size(); ++i)
- {
- auto sv = by_name_[ i ];
- auto h = digest(sv);
- auto j = h % N;
- BOOST_ASSERT(map_[j] == 0);
- map_[j] = static_cast<unsigned char>(i);
- }
- }
- field
- string_to_field(string_view s) const
- {
- auto h = digest(s);
- auto j = h % N;
- int i = map_[j];
- if(i != 0 && equals(s, by_name_[i]))
- 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
|