field.ipp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. //
  2. // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot 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/boostorg/beast
  8. //
  9. #ifndef BOOST_BEAST_HTTP_IMPL_FIELD_IPP
  10. #define BOOST_BEAST_HTTP_IMPL_FIELD_IPP
  11. #include <boost/beast/http/field.hpp>
  12. #include <boost/assert.hpp>
  13. #include <array>
  14. #include <cstdint>
  15. #include <cstring>
  16. #include <ostream>
  17. namespace boost {
  18. namespace beast {
  19. namespace http {
  20. namespace detail {
  21. struct field_table
  22. {
  23. static
  24. std::uint32_t
  25. get_chars(
  26. unsigned char const* p) noexcept
  27. {
  28. // VFALCO memcpy is endian-dependent
  29. //std::memcpy(&v, p, 4);
  30. // Compiler should be smart enough to
  31. // optimize this down to one instruction.
  32. return
  33. p[0] |
  34. (p[1] << 8) |
  35. (p[2] << 16) |
  36. (p[3] << 24);
  37. }
  38. using array_type =
  39. std::array<string_view, 129>;
  40. // Strings are converted to lowercase
  41. static
  42. std::uint32_t
  43. digest(string_view s)
  44. {
  45. std::uint32_t r = 0;
  46. std::size_t n = s.size();
  47. auto p = reinterpret_cast<
  48. unsigned char const*>(s.data());
  49. // consume N characters at a time
  50. // VFALCO Can we do 8 on 64-bit systems?
  51. while(n >= 4)
  52. {
  53. auto const v = get_chars(p);
  54. r = (r * 5 + (
  55. v | 0x20202020 )); // convert to lower
  56. p += 4;
  57. n -= 4;
  58. }
  59. // handle remaining characters
  60. while( n > 0 )
  61. {
  62. r = r * 5 + ( *p | 0x20 );
  63. ++p;
  64. --n;
  65. }
  66. return r;
  67. }
  68. // This comparison is case-insensitive, and the
  69. // strings must contain only valid http field characters.
  70. static
  71. bool
  72. equals(string_view lhs, string_view rhs)
  73. {
  74. using Int = std::uint32_t; // VFALCO std::size_t?
  75. auto n = lhs.size();
  76. if(n != rhs.size())
  77. return false;
  78. auto p1 = reinterpret_cast<
  79. unsigned char const*>(lhs.data());
  80. auto p2 = reinterpret_cast<
  81. unsigned char const*>(rhs.data());
  82. auto constexpr S = sizeof(Int);
  83. auto constexpr Mask = static_cast<Int>(
  84. 0xDFDFDFDFDFDFDFDF & ~Int{0});
  85. for(; n >= S; p1 += S, p2 += S, n -= S)
  86. {
  87. Int const v1 = get_chars(p1);
  88. Int const v2 = get_chars(p2);
  89. if((v1 ^ v2) & Mask)
  90. return false;
  91. }
  92. for(; n; ++p1, ++p2, --n)
  93. if(( *p1 ^ *p2) & 0xDF)
  94. return false;
  95. return true;
  96. }
  97. array_type by_name_;
  98. enum { N = 1367 };
  99. unsigned char map_[ N ] = {};
  100. /*
  101. From:
  102. https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers
  103. https://www.iana.org/assignments/http-fields/http-fields.xhtml
  104. */
  105. field_table()
  106. : by_name_({{
  107. "<unknown-field>",
  108. "Accept",
  109. "Accept-CH",
  110. "Accept-Charset",
  111. "Accept-Encoding",
  112. "Accept-Language",
  113. "Accept-Patch",
  114. "Accept-Post",
  115. "Accept-Ranges",
  116. "Accept-Signature",
  117. "Access-Control-Allow-Credentials",
  118. "Access-Control-Allow-Headers",
  119. "Access-Control-Allow-Methods",
  120. "Access-Control-Allow-Origin",
  121. "Access-Control-Expose-Headers",
  122. "Access-Control-Max-Age",
  123. "Access-Control-Request-Headers",
  124. "Access-Control-Request-Method",
  125. "Age",
  126. "Allow",
  127. "Alt-Svc",
  128. "Alt-Used",
  129. "Authorization",
  130. "Cache-Control",
  131. "Clear-Site-Data",
  132. "Connection",
  133. "Content-Digest",
  134. "Content-Disposition",
  135. "Content-DPR",
  136. "Content-Encoding",
  137. "Content-Language",
  138. "Content-Length",
  139. "Content-Location",
  140. "Content-Range",
  141. "Content-Security-Policy",
  142. "Content-Security-Policy-Report-Only",
  143. "Content-Type",
  144. "Cookie",
  145. "Cross-Origin-Embedder-Policy",
  146. "Cross-Origin-Opener-Policy",
  147. "Cross-Origin-Resource-Policy",
  148. "Date",
  149. "Deprecation",
  150. "Device-Memory",
  151. "Digest",
  152. "DNT",
  153. "DPR",
  154. "ETag",
  155. "Expect",
  156. "Expect-CT",
  157. "Expires",
  158. "Forwarded",
  159. "From",
  160. "Host",
  161. "If-Match",
  162. "If-Modified-Since",
  163. "If-None-Match",
  164. "If-Range",
  165. "If-Unmodified-Since",
  166. "Keep-Alive",
  167. "Last-Modified",
  168. "Link",
  169. "Location",
  170. "Max-Forwards",
  171. "Origin",
  172. "Origin-Agent-Cluster",
  173. "Pragma",
  174. "Prefer",
  175. "Preference-Applied",
  176. "Priority",
  177. "Proxy-Authenticate",
  178. "Proxy-Authorization",
  179. "Proxy-Connection",
  180. "Range",
  181. "Referer",
  182. "Referrer-Policy",
  183. "Refresh",
  184. "Report-To",
  185. "Reporting-Endpoints",
  186. "Repr-Digest",
  187. "Retry-After",
  188. "Sec-CH-UA-Full-Version",
  189. "Sec-Fetch-Dest",
  190. "Sec-Fetch-Mode",
  191. "Sec-Fetch-Site",
  192. "Sec-Fetch-User",
  193. "Sec-Purpose",
  194. "Sec-WebSocket-Accept",
  195. "Sec-WebSocket-Extensions",
  196. "Sec-WebSocket-Key",
  197. "Sec-WebSocket-Protocol",
  198. "Sec-WebSocket-Version",
  199. "Server",
  200. "Server-Timing",
  201. "Service-Worker",
  202. "Service-Worker-Allowed",
  203. "Service-Worker-Navigation-Preload",
  204. "Set-Cookie",
  205. "Set-Login",
  206. "Signature",
  207. "Signature-Input",
  208. "SourceMap",
  209. "Strict-Transport-Security",
  210. "TE",
  211. "Timing-Allow-Origin",
  212. "Tk",
  213. "Trailer",
  214. "Transfer-Encoding",
  215. "Upgrade",
  216. "Upgrade-Insecure-Requests",
  217. "User-Agent",
  218. "Vary",
  219. "Via",
  220. "Viewport-Width",
  221. "Want-Content-Digest",
  222. "Want-Repr-Digest",
  223. "Warning",
  224. "Width",
  225. "WWW-Authenticate",
  226. "X-Content-Type-Options",
  227. "X-DNS-Prefetch-Control",
  228. "X-Forwarded-For",
  229. "X-Forwarded-Host",
  230. "X-Forwarded-Proto",
  231. "X-Frame-Options",
  232. "X-Permitted-Cross-Domain-Policies",
  233. "X-Powered-By",
  234. "X-Robots-Tag",
  235. "X-XSS-Protection"
  236. }})
  237. {
  238. for(std::size_t i = 1; i < by_name_.size(); ++i)
  239. {
  240. auto sv = by_name_[ i ];
  241. auto h = digest(sv);
  242. auto j = h % N;
  243. BOOST_ASSERT(map_[j] == 0);
  244. map_[j] = static_cast<unsigned char>(i);
  245. }
  246. }
  247. field
  248. string_to_field(string_view s) const
  249. {
  250. auto h = digest(s);
  251. auto j = h % N;
  252. int i = map_[j];
  253. if(i != 0 && equals(s, by_name_[i]))
  254. return static_cast<field>(i);
  255. return field::unknown;
  256. }
  257. //
  258. // Deprecated
  259. //
  260. using const_iterator =
  261. array_type::const_iterator;
  262. std::size_t
  263. size() const
  264. {
  265. return by_name_.size();
  266. }
  267. const_iterator
  268. begin() const
  269. {
  270. return by_name_.begin();
  271. }
  272. const_iterator
  273. end() const
  274. {
  275. return by_name_.end();
  276. }
  277. };
  278. BOOST_BEAST_DECL
  279. field_table const&
  280. get_field_table()
  281. {
  282. static field_table const tab;
  283. return tab;
  284. }
  285. BOOST_BEAST_DECL
  286. string_view
  287. to_string(field f)
  288. {
  289. auto const& v = get_field_table();
  290. BOOST_ASSERT(static_cast<unsigned>(f) < v.size());
  291. return v.begin()[static_cast<unsigned>(f)];
  292. }
  293. } // detail
  294. string_view
  295. to_string(field f)
  296. {
  297. return detail::to_string(f);
  298. }
  299. field
  300. string_to_field(string_view s)
  301. {
  302. return detail::get_field_table().string_to_field(s);
  303. }
  304. std::ostream&
  305. operator<<(std::ostream& os, field f)
  306. {
  307. return os << to_string(f);
  308. }
  309. } // http
  310. } // beast
  311. } // boost
  312. #endif