field.ipp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  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 <algorithm>
  14. #include <array>
  15. #include <cstdint>
  16. #include <cstring>
  17. #include <ostream>
  18. namespace boost {
  19. namespace beast {
  20. namespace http {
  21. namespace detail {
  22. struct field_table
  23. {
  24. static
  25. std::uint32_t
  26. get_chars(
  27. unsigned char const* p) noexcept
  28. {
  29. // VFALCO memcpy is endian-dependent
  30. //std::memcpy(&v, p, 4);
  31. // Compiler should be smart enough to
  32. // optimize this down to one instruction.
  33. return
  34. p[0] |
  35. (p[1] << 8) |
  36. (p[2] << 16) |
  37. (p[3] << 24);
  38. }
  39. using array_type =
  40. std::array<string_view, 357>;
  41. // Strings are converted to lowercase
  42. static
  43. std::uint32_t
  44. digest(string_view s)
  45. {
  46. std::uint32_t r = 0;
  47. std::size_t n = s.size();
  48. auto p = reinterpret_cast<
  49. unsigned char const*>(s.data());
  50. // consume N characters at a time
  51. // VFALCO Can we do 8 on 64-bit systems?
  52. while(n >= 4)
  53. {
  54. auto const v = get_chars(p);
  55. r = (r * 5 + (
  56. v | 0x20202020 )); // convert to lower
  57. p += 4;
  58. n -= 4;
  59. }
  60. // handle remaining characters
  61. while( n > 0 )
  62. {
  63. r = r * 5 + ( *p | 0x20 );
  64. ++p;
  65. --n;
  66. }
  67. return r;
  68. }
  69. // This comparison is case-insensitive, and the
  70. // strings must contain only valid http field characters.
  71. static
  72. bool
  73. equals(string_view lhs, string_view rhs)
  74. {
  75. using Int = std::uint32_t; // VFALCO std::size_t?
  76. auto n = lhs.size();
  77. if(n != rhs.size())
  78. return false;
  79. auto p1 = reinterpret_cast<
  80. unsigned char const*>(lhs.data());
  81. auto p2 = reinterpret_cast<
  82. unsigned char const*>(rhs.data());
  83. auto constexpr S = sizeof(Int);
  84. auto constexpr Mask = static_cast<Int>(
  85. 0xDFDFDFDFDFDFDFDF & ~Int{0});
  86. for(; n >= S; p1 += S, p2 += S, n -= S)
  87. {
  88. Int const v1 = get_chars(p1);
  89. Int const v2 = get_chars(p2);
  90. if((v1 ^ v2) & Mask)
  91. return false;
  92. }
  93. for(; n; ++p1, ++p2, --n)
  94. if(( *p1 ^ *p2) & 0xDF)
  95. return false;
  96. return true;
  97. }
  98. array_type by_name_;
  99. enum { N = 5155 };
  100. unsigned char map_[ N ][ 2 ] = {};
  101. /*
  102. From:
  103. https://www.iana.org/assignments/message-headers/message-headers.xhtml
  104. */
  105. field_table()
  106. : by_name_({{
  107. // string constants
  108. "<unknown-field>",
  109. "A-IM",
  110. "Accept",
  111. "Accept-Additions",
  112. "Accept-Charset",
  113. "Accept-Datetime",
  114. "Accept-Encoding",
  115. "Accept-Features",
  116. "Accept-Language",
  117. "Accept-Patch",
  118. "Accept-Post",
  119. "Accept-Ranges",
  120. "Access-Control",
  121. "Access-Control-Allow-Credentials",
  122. "Access-Control-Allow-Headers",
  123. "Access-Control-Allow-Methods",
  124. "Access-Control-Allow-Origin",
  125. "Access-Control-Expose-Headers",
  126. "Access-Control-Max-Age",
  127. "Access-Control-Request-Headers",
  128. "Access-Control-Request-Method",
  129. "Age",
  130. "Allow",
  131. "ALPN",
  132. "Also-Control",
  133. "Alt-Svc",
  134. "Alt-Used",
  135. "Alternate-Recipient",
  136. "Alternates",
  137. "Apparently-To",
  138. "Apply-To-Redirect-Ref",
  139. "Approved",
  140. "Archive",
  141. "Archived-At",
  142. "Article-Names",
  143. "Article-Updates",
  144. "Authentication-Control",
  145. "Authentication-Info",
  146. "Authentication-Results",
  147. "Authorization",
  148. "Auto-Submitted",
  149. "Autoforwarded",
  150. "Autosubmitted",
  151. "Base",
  152. "Bcc",
  153. "Body",
  154. "C-Ext",
  155. "C-Man",
  156. "C-Opt",
  157. "C-PEP",
  158. "C-PEP-Info",
  159. "Cache-Control",
  160. "CalDAV-Timezones",
  161. "Cancel-Key",
  162. "Cancel-Lock",
  163. "Cc",
  164. "Close",
  165. "Comments",
  166. "Compliance",
  167. "Connection",
  168. "Content-Alternative",
  169. "Content-Base",
  170. "Content-Description",
  171. "Content-Disposition",
  172. "Content-Duration",
  173. "Content-Encoding",
  174. "Content-features",
  175. "Content-ID",
  176. "Content-Identifier",
  177. "Content-Language",
  178. "Content-Length",
  179. "Content-Location",
  180. "Content-MD5",
  181. "Content-Range",
  182. "Content-Return",
  183. "Content-Script-Type",
  184. "Content-Style-Type",
  185. "Content-Transfer-Encoding",
  186. "Content-Type",
  187. "Content-Version",
  188. "Control",
  189. "Conversion",
  190. "Conversion-With-Loss",
  191. "Cookie",
  192. "Cookie2",
  193. "Cost",
  194. "DASL",
  195. "Date",
  196. "Date-Received",
  197. "DAV",
  198. "Default-Style",
  199. "Deferred-Delivery",
  200. "Delivery-Date",
  201. "Delta-Base",
  202. "Depth",
  203. "Derived-From",
  204. "Destination",
  205. "Differential-ID",
  206. "Digest",
  207. "Discarded-X400-IPMS-Extensions",
  208. "Discarded-X400-MTS-Extensions",
  209. "Disclose-Recipients",
  210. "Disposition-Notification-Options",
  211. "Disposition-Notification-To",
  212. "Distribution",
  213. "DKIM-Signature",
  214. "DL-Expansion-History",
  215. "Downgraded-Bcc",
  216. "Downgraded-Cc",
  217. "Downgraded-Disposition-Notification-To",
  218. "Downgraded-Final-Recipient",
  219. "Downgraded-From",
  220. "Downgraded-In-Reply-To",
  221. "Downgraded-Mail-From",
  222. "Downgraded-Message-Id",
  223. "Downgraded-Original-Recipient",
  224. "Downgraded-Rcpt-To",
  225. "Downgraded-References",
  226. "Downgraded-Reply-To",
  227. "Downgraded-Resent-Bcc",
  228. "Downgraded-Resent-Cc",
  229. "Downgraded-Resent-From",
  230. "Downgraded-Resent-Reply-To",
  231. "Downgraded-Resent-Sender",
  232. "Downgraded-Resent-To",
  233. "Downgraded-Return-Path",
  234. "Downgraded-Sender",
  235. "Downgraded-To",
  236. "EDIINT-Features",
  237. "Eesst-Version",
  238. "Encoding",
  239. "Encrypted",
  240. "Errors-To",
  241. "ETag",
  242. "Expect",
  243. "Expires",
  244. "Expiry-Date",
  245. "Ext",
  246. "Followup-To",
  247. "Forwarded",
  248. "From",
  249. "Generate-Delivery-Report",
  250. "GetProfile",
  251. "Hobareg",
  252. "Host",
  253. "HTTP2-Settings",
  254. "If",
  255. "If-Match",
  256. "If-Modified-Since",
  257. "If-None-Match",
  258. "If-Range",
  259. "If-Schedule-Tag-Match",
  260. "If-Unmodified-Since",
  261. "IM",
  262. "Importance",
  263. "In-Reply-To",
  264. "Incomplete-Copy",
  265. "Injection-Date",
  266. "Injection-Info",
  267. "Jabber-ID",
  268. "Keep-Alive",
  269. "Keywords",
  270. "Label",
  271. "Language",
  272. "Last-Modified",
  273. "Latest-Delivery-Time",
  274. "Lines",
  275. "Link",
  276. "List-Archive",
  277. "List-Help",
  278. "List-ID",
  279. "List-Owner",
  280. "List-Post",
  281. "List-Subscribe",
  282. "List-Unsubscribe",
  283. "List-Unsubscribe-Post",
  284. "Location",
  285. "Lock-Token",
  286. "Man",
  287. "Max-Forwards",
  288. "Memento-Datetime",
  289. "Message-Context",
  290. "Message-ID",
  291. "Message-Type",
  292. "Meter",
  293. "Method-Check",
  294. "Method-Check-Expires",
  295. "MIME-Version",
  296. "MMHS-Acp127-Message-Identifier",
  297. "MMHS-Authorizing-Users",
  298. "MMHS-Codress-Message-Indicator",
  299. "MMHS-Copy-Precedence",
  300. "MMHS-Exempted-Address",
  301. "MMHS-Extended-Authorisation-Info",
  302. "MMHS-Handling-Instructions",
  303. "MMHS-Message-Instructions",
  304. "MMHS-Message-Type",
  305. "MMHS-Originator-PLAD",
  306. "MMHS-Originator-Reference",
  307. "MMHS-Other-Recipients-Indicator-CC",
  308. "MMHS-Other-Recipients-Indicator-To",
  309. "MMHS-Primary-Precedence",
  310. "MMHS-Subject-Indicator-Codes",
  311. "MT-Priority",
  312. "Negotiate",
  313. "Newsgroups",
  314. "NNTP-Posting-Date",
  315. "NNTP-Posting-Host",
  316. "Non-Compliance",
  317. "Obsoletes",
  318. "Opt",
  319. "Optional",
  320. "Optional-WWW-Authenticate",
  321. "Ordering-Type",
  322. "Organization",
  323. "Origin",
  324. "Original-Encoded-Information-Types",
  325. "Original-From",
  326. "Original-Message-ID",
  327. "Original-Recipient",
  328. "Original-Sender",
  329. "Original-Subject",
  330. "Originator-Return-Address",
  331. "Overwrite",
  332. "P3P",
  333. "Path",
  334. "PEP",
  335. "Pep-Info",
  336. "PICS-Label",
  337. "Position",
  338. "Posting-Version",
  339. "Pragma",
  340. "Prefer",
  341. "Preference-Applied",
  342. "Prevent-NonDelivery-Report",
  343. "Priority",
  344. "Privicon",
  345. "ProfileObject",
  346. "Protocol",
  347. "Protocol-Info",
  348. "Protocol-Query",
  349. "Protocol-Request",
  350. "Proxy-Authenticate",
  351. "Proxy-Authentication-Info",
  352. "Proxy-Authorization",
  353. "Proxy-Connection",
  354. "Proxy-Features",
  355. "Proxy-Instruction",
  356. "Public",
  357. "Public-Key-Pins",
  358. "Public-Key-Pins-Report-Only",
  359. "Range",
  360. "Received",
  361. "Received-SPF",
  362. "Redirect-Ref",
  363. "References",
  364. "Referer",
  365. "Referer-Root",
  366. "Relay-Version",
  367. "Reply-By",
  368. "Reply-To",
  369. "Require-Recipient-Valid-Since",
  370. "Resent-Bcc",
  371. "Resent-Cc",
  372. "Resent-Date",
  373. "Resent-From",
  374. "Resent-Message-ID",
  375. "Resent-Reply-To",
  376. "Resent-Sender",
  377. "Resent-To",
  378. "Resolution-Hint",
  379. "Resolver-Location",
  380. "Retry-After",
  381. "Return-Path",
  382. "Safe",
  383. "Schedule-Reply",
  384. "Schedule-Tag",
  385. "Sec-Fetch-Dest",
  386. "Sec-Fetch-Mode",
  387. "Sec-Fetch-Site",
  388. "Sec-Fetch-User",
  389. "Sec-WebSocket-Accept",
  390. "Sec-WebSocket-Extensions",
  391. "Sec-WebSocket-Key",
  392. "Sec-WebSocket-Protocol",
  393. "Sec-WebSocket-Version",
  394. "Security-Scheme",
  395. "See-Also",
  396. "Sender",
  397. "Sensitivity",
  398. "Server",
  399. "Set-Cookie",
  400. "Set-Cookie2",
  401. "SetProfile",
  402. "SIO-Label",
  403. "SIO-Label-History",
  404. "SLUG",
  405. "SoapAction",
  406. "Solicitation",
  407. "Status-URI",
  408. "Strict-Transport-Security",
  409. "Subject",
  410. "SubOK",
  411. "Subst",
  412. "Summary",
  413. "Supersedes",
  414. "Surrogate-Capability",
  415. "Surrogate-Control",
  416. "TCN",
  417. "TE",
  418. "Timeout",
  419. "Title",
  420. "To",
  421. "Topic",
  422. "Trailer",
  423. "Transfer-Encoding",
  424. "TTL",
  425. "UA-Color",
  426. "UA-Media",
  427. "UA-Pixels",
  428. "UA-Resolution",
  429. "UA-Windowpixels",
  430. "Upgrade",
  431. "Urgency",
  432. "URI",
  433. "User-Agent",
  434. "Variant-Vary",
  435. "Vary",
  436. "VBR-Info",
  437. "Version",
  438. "Via",
  439. "Want-Digest",
  440. "Warning",
  441. "WWW-Authenticate",
  442. "X-Archived-At",
  443. "X-Device-Accept",
  444. "X-Device-Accept-Charset",
  445. "X-Device-Accept-Encoding",
  446. "X-Device-Accept-Language",
  447. "X-Device-User-Agent",
  448. "X-Frame-Options",
  449. "X-Mittente",
  450. "X-PGP-Sig",
  451. "X-Ricevuta",
  452. "X-Riferimento-Message-ID",
  453. "X-TipoRicevuta",
  454. "X-Trasporto",
  455. "X-VerificaSicurezza",
  456. "X400-Content-Identifier",
  457. "X400-Content-Return",
  458. "X400-Content-Type",
  459. "X400-MTS-Identifier",
  460. "X400-Originator",
  461. "X400-Received",
  462. "X400-Recipients",
  463. "X400-Trace",
  464. "Xref"
  465. }})
  466. {
  467. for(std::size_t i = 1, n = 256; i < n; ++i)
  468. {
  469. auto sv = by_name_[ i ];
  470. auto h = digest(sv);
  471. auto j = h % N;
  472. BOOST_ASSERT(map_[j][0] == 0);
  473. map_[j][0] = static_cast<unsigned char>(i);
  474. }
  475. for(std::size_t i = 256, n = by_name_.size(); i < n; ++i)
  476. {
  477. auto sv = by_name_[i];
  478. auto h = digest(sv);
  479. auto j = h % N;
  480. BOOST_ASSERT(map_[j][1] == 0);
  481. map_[j][1] = static_cast<unsigned char>(i - 255);
  482. }
  483. }
  484. field
  485. string_to_field(string_view s) const
  486. {
  487. auto h = digest(s);
  488. auto j = h % N;
  489. int i = map_[j][0];
  490. string_view s2 = by_name_[i];
  491. if(i != 0 && equals(s, s2))
  492. return static_cast<field>(i);
  493. i = map_[j][1];
  494. if(i == 0)
  495. return field::unknown;
  496. i += 255;
  497. s2 = by_name_[i];
  498. if(equals(s, s2))
  499. return static_cast<field>(i);
  500. return field::unknown;
  501. }
  502. //
  503. // Deprecated
  504. //
  505. using const_iterator =
  506. array_type::const_iterator;
  507. std::size_t
  508. size() const
  509. {
  510. return by_name_.size();
  511. }
  512. const_iterator
  513. begin() const
  514. {
  515. return by_name_.begin();
  516. }
  517. const_iterator
  518. end() const
  519. {
  520. return by_name_.end();
  521. }
  522. };
  523. BOOST_BEAST_DECL
  524. field_table const&
  525. get_field_table()
  526. {
  527. static field_table const tab;
  528. return tab;
  529. }
  530. BOOST_BEAST_DECL
  531. string_view
  532. to_string(field f)
  533. {
  534. auto const& v = get_field_table();
  535. BOOST_ASSERT(static_cast<unsigned>(f) < v.size());
  536. return v.begin()[static_cast<unsigned>(f)];
  537. }
  538. } // detail
  539. string_view
  540. to_string(field f)
  541. {
  542. return detail::to_string(f);
  543. }
  544. field
  545. string_to_field(string_view s)
  546. {
  547. return detail::get_field_table().string_to_field(s);
  548. }
  549. std::ostream&
  550. operator<<(std::ostream& os, field f)
  551. {
  552. return os << to_string(f);
  553. }
  554. } // http
  555. } // beast
  556. } // boost
  557. #endif