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