92.67% Lines (569/614) 82.46% Functions (47/57)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // 1   //
2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) 2   // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3   // Copyright (c) 2024 Mohammad Nejati 3   // Copyright (c) 2024 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 "src/rfc/detail/rules.hpp" 11   #include "src/rfc/detail/rules.hpp"
12   #include "src/rfc/detail/transfer_coding_rule.hpp" 12   #include "src/rfc/detail/transfer_coding_rule.hpp"
13   13  
14   #include <boost/http/detail/header.hpp> 14   #include <boost/http/detail/header.hpp>
15   #include <boost/http/field.hpp> 15   #include <boost/http/field.hpp>
16   #include <boost/http/header_limits.hpp> 16   #include <boost/http/header_limits.hpp>
17   #include <boost/http/rfc/list_rule.hpp> 17   #include <boost/http/rfc/list_rule.hpp>
18   #include <boost/http/rfc/token_rule.hpp> 18   #include <boost/http/rfc/token_rule.hpp>
19   #include <boost/http/rfc/upgrade_rule.hpp> 19   #include <boost/http/rfc/upgrade_rule.hpp>
20   #include <boost/assert.hpp> 20   #include <boost/assert.hpp>
21   #include <boost/assert/source_location.hpp> 21   #include <boost/assert/source_location.hpp>
22   #include <boost/static_assert.hpp> 22   #include <boost/static_assert.hpp>
23   #include <boost/url/grammar/ci_string.hpp> 23   #include <boost/url/grammar/ci_string.hpp>
24   #include <boost/url/grammar/parse.hpp> 24   #include <boost/url/grammar/parse.hpp>
25   #include <boost/url/grammar/range_rule.hpp> 25   #include <boost/url/grammar/range_rule.hpp>
26   #include <boost/url/grammar/recycled.hpp> 26   #include <boost/url/grammar/recycled.hpp>
27   #include <boost/url/grammar/unsigned_rule.hpp> 27   #include <boost/url/grammar/unsigned_rule.hpp>
28   28  
29   #include <utility> 29   #include <utility>
30   30  
31   namespace boost { 31   namespace boost {
32   namespace http { 32   namespace http {
33   namespace detail { 33   namespace detail {
34   34  
35   //------------------------------------------------ 35   //------------------------------------------------
36   36  
37   auto 37   auto
HITCBC 38   87 header:: 38   87 header::
39   entry:: 39   entry::
40   operator+( 40   operator+(
41   std::size_t dv) const noexcept -> 41   std::size_t dv) const noexcept ->
42   entry 42   entry
43   { 43   {
44   return { 44   return {
45   static_cast< 45   static_cast<
HITCBC 46   87 offset_type>(np + dv), 46   87 offset_type>(np + dv),
HITCBC 47   87 nn, 47   87 nn,
48   static_cast< 48   static_cast<
HITCBC 49   87 offset_type>(vp + dv), 49   87 offset_type>(vp + dv),
HITCBC 50   87 vn, 50   87 vn,
HITCBC 51   87 id }; 51   87 id };
52   } 52   }
53   53  
54   auto 54   auto
HITCBC 55   101 header:: 55   101 header::
56   entry:: 56   entry::
57   operator-( 57   operator-(
58   std::size_t dv) const noexcept -> 58   std::size_t dv) const noexcept ->
59   entry 59   entry
60   { 60   {
61   return { 61   return {
62   static_cast< 62   static_cast<
HITCBC 63   101 offset_type>(np - dv), 63   101 offset_type>(np - dv),
HITCBC 64   101 nn, 64   101 nn,
65   static_cast< 65   static_cast<
HITCBC 66   101 offset_type>(vp - dv), 66   101 offset_type>(vp - dv),
HITCBC 67   101 vn, 67   101 vn,
HITCBC 68   101 id }; 68   101 id };
69   } 69   }
70   70  
71   //------------------------------------------------ 71   //------------------------------------------------
72   72  
73   constexpr field header::unknown_field; 73   constexpr field header::unknown_field;
74   74  
75   //------------------------------------------------ 75   //------------------------------------------------
76   76  
77   constexpr 77   constexpr
78   header:: 78   header::
79   header(fields_tag) noexcept 79   header(fields_tag) noexcept
80   : kind(detail::kind::fields) 80   : kind(detail::kind::fields)
81   , cbuf("\r\n") 81   , cbuf("\r\n")
82   , size(2) 82   , size(2)
83   , fld{} 83   , fld{}
84   { 84   {
85   } 85   }
86   86  
87   constexpr 87   constexpr
88   header:: 88   header::
89   header(request_tag) noexcept 89   header(request_tag) noexcept
90   : kind(detail::kind::request) 90   : kind(detail::kind::request)
91   , cbuf("GET / HTTP/1.1\r\n\r\n") 91   , cbuf("GET / HTTP/1.1\r\n\r\n")
92   , size(18) 92   , size(18)
93   , prefix(16) 93   , prefix(16)
94   , req{ 3, 1, 94   , req{ 3, 1,
95   http::method::get } 95   http::method::get }
96   { 96   {
97   } 97   }
98   98  
99   constexpr 99   constexpr
100   header:: 100   header::
101   header(response_tag) noexcept 101   header(response_tag) noexcept
102   : kind(detail::kind::response) 102   : kind(detail::kind::response)
103   , cbuf("HTTP/1.1 200 OK\r\n\r\n") 103   , cbuf("HTTP/1.1 200 OK\r\n\r\n")
104   , size(19) 104   , size(19)
105   , prefix(17) 105   , prefix(17)
106   , res{ 200, 106   , res{ 200,
107   http::status::ok } 107   http::status::ok }
108   { 108   {
109   } 109   }
110   110  
111   //------------------------------------------------ 111   //------------------------------------------------
112   112  
113   header const* 113   header const*
HITCBC 114   4656 header:: 114   4872 header::
115   get_default(detail::kind k) noexcept 115   get_default(detail::kind k) noexcept
116   { 116   {
117   static constexpr header h[3] = { 117   static constexpr header h[3] = {
118   fields_tag{}, 118   fields_tag{},
119   request_tag{}, 119   request_tag{},
120   response_tag{}}; 120   response_tag{}};
HITCBC 121   4656 return &h[k]; 121   4872 return &h[k];
122   } 122   }
123   123  
HITCBC 124   13154 header:: 124   13370 header::
HITCBC 125   13154 header(empty v) noexcept 125   13370 header(empty v) noexcept
HITCBC 126   13154 : kind(v.param) 126   13370 : kind(v.param)
127   { 127   {
HITCBC 128   13154 } 128   13370 }
129   129  
HITCBC 130   2571 header:: 130   2679 header::
HITCBC 131   2571 header(detail::kind k) noexcept 131   2679 header(detail::kind k) noexcept
HITCBC 132   2571 : header(*get_default(k)) 132   2679 : header(*get_default(k))
133   { 133   {
HITCBC 134   2571 } 134   2679 }
135   135  
136   void 136   void
HITCBC 137   79 header:: 137   79 header::
138   swap(header& h) noexcept 138   swap(header& h) noexcept
139   { 139   {
HITCBC 140   79 std::swap(cbuf, h.cbuf); 140   79 std::swap(cbuf, h.cbuf);
HITCBC 141   79 std::swap(buf, h.buf); 141   79 std::swap(buf, h.buf);
HITCBC 142   79 std::swap(cap, h.cap); 142   79 std::swap(cap, h.cap);
HITCBC 143   79 std::swap(size, h.size); 143   79 std::swap(size, h.size);
HITCBC 144   79 std::swap(count, h.count); 144   79 std::swap(count, h.count);
HITCBC 145   79 std::swap(prefix, h.prefix); 145   79 std::swap(prefix, h.prefix);
HITCBC 146   79 std::swap(version, h.version); 146   79 std::swap(version, h.version);
HITCBC 147   79 std::swap(md, h.md); 147   79 std::swap(md, h.md);
HITCBC 148   79 switch(kind) 148   79 switch(kind)
149   { 149   {
HITCBC 150   15 default: 150   15 default:
151   case detail::kind::fields: 151   case detail::kind::fields:
HITCBC 152   15 break; 152   15 break;
HITCBC 153   56 case detail::kind::request: 153   56 case detail::kind::request:
HITCBC 154   56 std::swap( 154   56 std::swap(
HITCBC 155   56 req.method_len, h.req.method_len); 155   56 req.method_len, h.req.method_len);
HITCBC 156   56 std::swap( 156   56 std::swap(
HITCBC 157   56 req.target_len, h.req.target_len); 157   56 req.target_len, h.req.target_len);
HITCBC 158   56 std::swap(req.method, h.req.method); 158   56 std::swap(req.method, h.req.method);
HITCBC 159   56 break; 159   56 break;
HITCBC 160   8 case detail::kind::response: 160   8 case detail::kind::response:
HITCBC 161   8 std::swap( 161   8 std::swap(
HITCBC 162   8 res.status_int, h.res.status_int); 162   8 res.status_int, h.res.status_int);
HITCBC 163   8 std::swap(res.status, h.res.status); 163   8 std::swap(res.status, h.res.status);
HITCBC 164   8 break; 164   8 break;
165   } 165   }
HITCBC 166   79 } 166   79 }
167   167  
168   /* References: 168   /* References:
169   169  
170   6.3. Persistence 170   6.3. Persistence
171   https://datatracker.ietf.org/doc/html/rfc7230#section-6.3 171   https://datatracker.ietf.org/doc/html/rfc7230#section-6.3
172   */ 172   */
173   bool 173   bool
HITCBC 174   24 header:: 174   24 header::
175   keep_alive() const noexcept 175   keep_alive() const noexcept
176   { 176   {
HITCBC 177   24 if(md.payload == payload::error) 177   24 if(md.payload == payload::error)
HITCBC 178   1 return false; 178   1 return false;
HITCBC 179   23 if( version == 179   23 if( version ==
180   http::version::http_1_1) 180   http::version::http_1_1)
181   { 181   {
HITCBC 182   15 if(md.connection.close) 182   15 if(md.connection.close)
HITCBC 183   5 return false; 183   5 return false;
184   } 184   }
185   else 185   else
186   { 186   {
HITCBC 187   8 if(! md.connection.keep_alive) 187   8 if(! md.connection.keep_alive)
HITCBC 188   4 return false; 188   4 return false;
189   } 189   }
190   // can't use to_eof in requests 190   // can't use to_eof in requests
HITCBC 191   14 BOOST_ASSERT( 191   14 BOOST_ASSERT(
192   kind != detail::kind::request || 192   kind != detail::kind::request ||
193   md.payload != payload::to_eof); 193   md.payload != payload::to_eof);
HITCBC 194   14 if(md.payload == payload::to_eof) 194   14 if(md.payload == payload::to_eof)
HITCBC 195   3 return false; 195   3 return false;
HITCBC 196   11 return true; 196   11 return true;
197   } 197   }
198   198  
199   //------------------------------------------------ 199   //------------------------------------------------
200   200  
201   // return total bytes needed 201   // return total bytes needed
202   // to store message of `size` 202   // to store message of `size`
203   // bytes and `count` fields. 203   // bytes and `count` fields.
204   std::size_t 204   std::size_t
HITCBC 205   3048 header:: 205   3156 header::
206   bytes_needed( 206   bytes_needed(
207   std::size_t size, 207   std::size_t size,
208   std::size_t count) noexcept 208   std::size_t count) noexcept
209   { 209   {
210   // make sure `size` is big enough 210   // make sure `size` is big enough
211   // to hold the largest default buffer: 211   // to hold the largest default buffer:
212   // "HTTP/1.1 200 OK\r\n\r\n" 212   // "HTTP/1.1 200 OK\r\n\r\n"
HITCBC 213   3048 if(size < 19) 213   3156 if(size < 19)
HITCBC 214   2280 size = 19; 214   2388 size = 19;
215   215  
216   // align size up to alignof(entry) 216   // align size up to alignof(entry)
HITCBC 217   3048 size = (size + alignof(entry) - 1) & ~(alignof(entry) - 1); 217   3156 size = (size + alignof(entry) - 1) & ~(alignof(entry) - 1);
218   218  
HITCBC 219   3048 return size + count * sizeof(entry); 219   3156 return size + count * sizeof(entry);
220   } 220   }
221   221  
222   std::size_t 222   std::size_t
HITCBC 223   9557 header:: 223   9585 header::
224   table_space( 224   table_space(
225   std::size_t count) noexcept 225   std::size_t count) noexcept
226   { 226   {
227   return count * 227   return count *
HITCBC 228   9557 sizeof(header::entry); 228   9585 sizeof(header::entry);
229   } 229   }
230   230  
231   std::size_t 231   std::size_t
HITCBC 232   9557 header:: 232   9585 header::
233   table_space() const noexcept 233   table_space() const noexcept
234   { 234   {
HITCBC 235   9557 return table_space(count); 235   9585 return table_space(count);
236   } 236   }
237   237  
238   auto 238   auto
HITCBC 239   2669 header:: 239   2669 header::
240   tab() const noexcept -> 240   tab() const noexcept ->
241   table 241   table
242   { 242   {
HITCBC 243   2669 BOOST_ASSERT(cap > 0); 243   2669 BOOST_ASSERT(cap > 0);
HITCBC 244   2669 BOOST_ASSERT(buf != nullptr); 244   2669 BOOST_ASSERT(buf != nullptr);
HITCBC 245   2669 return table(buf + cap); 245   2669 return table(buf + cap);
246   } 246   }
247   247  
248   auto 248   auto
HITCBC 249   680 header:: 249   680 header::
250   tab_() const noexcept -> 250   tab_() const noexcept ->
251   entry* 251   entry*
252   { 252   {
253   return reinterpret_cast< 253   return reinterpret_cast<
HITCBC 254   680 entry*>(buf + cap); 254   680 entry*>(buf + cap);
255   } 255   }
256   256  
257   // return true if header cbuf is a default 257   // return true if header cbuf is a default
258   bool 258   bool
HITCBC 259   45 header:: 259   45 header::
260   is_default() const noexcept 260   is_default() const noexcept
261   { 261   {
HITCBC 262   45 return buf == nullptr; 262   45 return buf == nullptr;
263   } 263   }
264   264  
265   std::size_t 265   std::size_t
HITCBC 266   135 header:: 266   135 header::
267   find( 267   find(
268   field id) const noexcept 268   field id) const noexcept
269   { 269   {
HITCBC 270   135 if(count == 0) 270   135 if(count == 0)
HITCBC 271   64 return 0; 271   64 return 0;
HITCBC 272   71 std::size_t i = 0; 272   71 std::size_t i = 0;
HITCBC 273   71 auto const* p = &tab()[0]; 273   71 auto const* p = &tab()[0];
HITCBC 274   118 while(i < count) 274   118 while(i < count)
275   { 275   {
HITCBC 276   95 if(p->id == id) 276   95 if(p->id == id)
HITCBC 277   48 break; 277   48 break;
HITCBC 278   47 ++i; 278   47 ++i;
HITCBC 279   47 --p; 279   47 --p;
280   } 280   }
HITCBC 281   71 return i; 281   71 return i;
282   } 282   }
283   283  
284   std::size_t 284   std::size_t
HITCBC 285   42 header:: 285   42 header::
286   find( 286   find(
287   core::string_view name) const noexcept 287   core::string_view name) const noexcept
288   { 288   {
HITCBC 289   42 if(count == 0) 289   42 if(count == 0)
HITCBC 290   6 return 0; 290   6 return 0;
HITCBC 291   36 std::size_t i = 0; 291   36 std::size_t i = 0;
HITCBC 292   36 auto const* p = &tab()[0]; 292   36 auto const* p = &tab()[0];
HITCBC 293   57 while(i < count) 293   57 while(i < count)
294   { 294   {
295   core::string_view s( 295   core::string_view s(
HITCBC 296   54 cbuf + prefix + p->np, 296   54 cbuf + prefix + p->np,
HITCBC 297   54 p->nn); 297   54 p->nn);
HITCBC 298   54 if(grammar::ci_is_equal(s, name)) 298   54 if(grammar::ci_is_equal(s, name))
HITCBC 299   33 break; 299   33 break;
HITCBC 300   21 ++i; 300   21 ++i;
HITCBC 301   21 --p; 301   21 --p;
302   } 302   }
HITCBC 303   36 return i; 303   36 return i;
304   } 304   }
305   305  
306   void 306   void
HITCBC 307   2159 header:: 307   2267 header::
308   copy_table( 308   copy_table(
309   void* dest, 309   void* dest,
310   std::size_t n) const noexcept 310   std::size_t n) const noexcept
311   { 311   {
312   // When `n == 0`, cbuf + cap may have incorrect 312   // When `n == 0`, cbuf + cap may have incorrect
313   // alignment, which can trigger UB sanitizer. 313   // alignment, which can trigger UB sanitizer.
HITCBC 314   2159 if(n == 0) 314   2267 if(n == 0)
HITCBC 315   2138 return; 315   2246 return;
316   316  
HITCBC 317   21 std::memcpy( 317   21 std::memcpy(
318   reinterpret_cast< 318   reinterpret_cast<
HITCBC 319   21 entry*>(dest) - n, 319   21 entry*>(dest) - n,
320   reinterpret_cast< 320   reinterpret_cast<
321   entry const*>( 321   entry const*>(
HITCBC 322   21 cbuf + cap) - n, 322   21 cbuf + cap) - n,
323   n * sizeof(entry)); 323   n * sizeof(entry));
324   } 324   }
325   325  
326   void 326   void
HITCBC 327   2159 header:: 327   2267 header::
328   copy_table( 328   copy_table(
329   void* dest) const noexcept 329   void* dest) const noexcept
330   { 330   {
HITCBC 331   2159 copy_table(dest, count); 331   2267 copy_table(dest, count);
HITCBC 332   2159 } 332   2267 }
333   333  
334   // assign all the members but 334   // assign all the members but
335   // preserve the allocated memory 335   // preserve the allocated memory
336   void 336   void
HITCBC 337   2109 header:: 337   2217 header::
338   assign_to( 338   assign_to(
339   header& dest) const noexcept 339   header& dest) const noexcept
340   { 340   {
HITCBC 341   2109 auto const buf_ = dest.buf; 341   2217 auto const buf_ = dest.buf;
HITCBC 342   2109 auto const cbuf_ = dest.cbuf; 342   2217 auto const cbuf_ = dest.cbuf;
HITCBC 343   2109 auto const cap_ = dest.cap; 343   2217 auto const cap_ = dest.cap;
HITCBC 344   2109 dest = *this; 344   2217 dest = *this;
HITCBC 345   2109 dest.buf = buf_; 345   2217 dest.buf = buf_;
HITCBC 346   2109 dest.cbuf = cbuf_; 346   2217 dest.cbuf = cbuf_;
HITCBC 347   2109 dest.cap = cap_; 347   2217 dest.cap = cap_;
HITCBC 348   2109 } 348   2217 }
349   349  
350   //------------------------------------------------ 350   //------------------------------------------------
351   // 351   //
352   // Metadata 352   // Metadata
353   // 353   //
354   //------------------------------------------------ 354   //------------------------------------------------
355   355  
356   std::size_t 356   std::size_t
MISUBC 357   header:: 357   header::
358   maybe_count( 358   maybe_count(
359   field id) const noexcept 359   field id) const noexcept
360   { 360   {
MISUBC 361   if(kind == detail::kind::fields) 361   if(kind == detail::kind::fields)
MISUBC 362   return std::size_t(-1); 362   return std::size_t(-1);
MISUBC 363   switch(id) 363   switch(id)
364   { 364   {
MISUBC 365   case field::connection: 365   case field::connection:
MISUBC 366   return md.connection.count; 366   return md.connection.count;
MISUBC 367   case field::content_encoding: 367   case field::content_encoding:
MISUBC 368   return md.content_encoding.count; 368   return md.content_encoding.count;
MISUBC 369   case field::content_length: 369   case field::content_length:
MISUBC 370   return md.content_length.count; 370   return md.content_length.count;
MISUBC 371   case field::expect: 371   case field::expect:
MISUBC 372   return md.expect.count; 372   return md.expect.count;
MISUBC 373   case field::transfer_encoding: 373   case field::transfer_encoding:
MISUBC 374   return md.transfer_encoding.count; 374   return md.transfer_encoding.count;
MISUBC 375   case field::upgrade: 375   case field::upgrade:
MISUBC 376   return md.upgrade.count; 376   return md.upgrade.count;
MISUBC 377   default: 377   default:
MISUBC 378   break; 378   break;
379   } 379   }
MISUBC 380   return std::size_t(-1); 380   return std::size_t(-1);
381   } 381   }
382   382  
383   bool 383   bool
HITCBC 384   24 header:: 384   24 header::
385   is_special( 385   is_special(
386   field id) const noexcept 386   field id) const noexcept
387   { 387   {
HITCBC 388   24 if(kind == detail::kind::fields) 388   24 if(kind == detail::kind::fields)
HITCBC 389   5 return false; 389   5 return false;
HITCBC 390   19 switch(id) 390   19 switch(id)
391   { 391   {
HITCBC 392   9 case field::connection: 392   9 case field::connection:
393   case field::content_encoding: 393   case field::content_encoding:
394   case field::content_length: 394   case field::content_length:
395   case field::expect: 395   case field::expect:
396   case field::transfer_encoding: 396   case field::transfer_encoding:
397   case field::upgrade: 397   case field::upgrade:
HITCBC 398   9 return true; 398   9 return true;
HITCBC 399   10 default: 399   10 default:
HITCBC 400   10 break; 400   10 break;
401   } 401   }
HITCBC 402   10 return false; 402   10 return false;
403   } 403   }
404   404  
405   //------------------------------------------------ 405   //------------------------------------------------
406   406  
407   // called when the start-line changes 407   // called when the start-line changes
408   void 408   void
HITCBC 409   10596 header:: 409   10668 header::
410   on_start_line() 410   on_start_line()
411   { 411   {
412   // items in both the request-line 412   // items in both the request-line
413   // and the status-line can affect 413   // and the status-line can affect
414   // the payload, for example whether 414   // the payload, for example whether
415   // or not EOF marks the end of the 415   // or not EOF marks the end of the
416   // payload. 416   // payload.
417   417  
HITCBC 418   10596 update_payload(); 418   10668 update_payload();
HITCBC 419   10596 } 419   10668 }
420   420  
421   // called after a field is inserted 421   // called after a field is inserted
422   void 422   void
HITCBC 423   11001 header:: 423   11031 header::
424   on_insert( 424   on_insert(
425   field id, 425   field id,
426   core::string_view v) 426   core::string_view v)
427   { 427   {
HITCBC 428   11001 if(kind == detail::kind::fields) 428   11031 if(kind == detail::kind::fields)
HITCBC 429   482 return; 429   482 return;
HITCBC 430   10519 switch(id) 430   10549 switch(id)
431   { 431   {
HITCBC 432   7 case field::content_encoding: 432   7 case field::content_encoding:
HITCBC 433   7 return on_insert_content_encoding(v); 433   7 return on_insert_content_encoding(v);
HITCBC 434   4527 case field::content_length: 434   4557 case field::content_length:
HITCBC 435   4527 return on_insert_content_length(v); 435   4557 return on_insert_content_length(v);
HITCBC 436   141 case field::connection: 436   141 case field::connection:
HITCBC 437   141 return on_insert_connection(v); 437   141 return on_insert_connection(v);
HITCBC 438   47 case field::expect: 438   47 case field::expect:
HITCBC 439   47 return on_insert_expect(v); 439   47 return on_insert_expect(v);
HITCBC 440   4413 case field::transfer_encoding: 440   4413 case field::transfer_encoding:
HITCBC 441   4413 return on_insert_transfer_encoding(v); 441   4413 return on_insert_transfer_encoding(v);
HITCBC 442   24 case field::upgrade: 442   24 case field::upgrade:
HITCBC 443   24 return on_insert_upgrade(v); 443   24 return on_insert_upgrade(v);
HITCBC 444   1360 default: 444   1360 default:
HITCBC 445   1360 break; 445   1360 break;
446   } 446   }
447   } 447   }
448   448  
449   // called when one field is erased 449   // called when one field is erased
450   void 450   void
HITCBC 451   39 header:: 451   39 header::
452   on_erase(field id) 452   on_erase(field id)
453   { 453   {
HITCBC 454   39 if(kind == detail::kind::fields) 454   39 if(kind == detail::kind::fields)
HITCBC 455   3 return; 455   3 return;
HITCBC 456   36 switch(id) 456   36 switch(id)
457   { 457   {
HITCBC 458   9 case field::connection: 458   9 case field::connection:
HITCBC 459   9 return on_erase_connection(); 459   9 return on_erase_connection();
MISUBC 460   case field::content_encoding: 460   case field::content_encoding:
MISUBC 461   return on_erase_content_encoding(); 461   return on_erase_content_encoding();
HITCBC 462   4 case field::content_length: 462   4 case field::content_length:
HITCBC 463   4 return on_erase_content_length(); 463   4 return on_erase_content_length();
HITCBC 464   10 case field::expect: 464   10 case field::expect:
HITCBC 465   10 return on_erase_expect(); 465   10 return on_erase_expect();
HITCBC 466   4 case field::transfer_encoding: 466   4 case field::transfer_encoding:
HITCBC 467   4 return on_erase_transfer_encoding(); 467   4 return on_erase_transfer_encoding();
HITCBC 468   4 case field::upgrade: 468   4 case field::upgrade:
HITCBC 469   4 return on_erase_upgrade(); 469   4 return on_erase_upgrade();
HITCBC 470   5 default: 470   5 default:
HITCBC 471   5 break; 471   5 break;
472   } 472   }
473   } 473   }
474   474  
475   //------------------------------------------------ 475   //------------------------------------------------
476   476  
477   /* 477   /*
478   https://datatracker.ietf.org/doc/html/rfc7230#section-6.1 478   https://datatracker.ietf.org/doc/html/rfc7230#section-6.1
479   */ 479   */
480   void 480   void
HITCBC 481   148 header:: 481   148 header::
482   on_insert_connection( 482   on_insert_connection(
483   core::string_view v) 483   core::string_view v)
484   { 484   {
HITCBC 485   148 ++md.connection.count; 485   148 ++md.connection.count;
HITCBC 486   148 if(md.connection.ec) 486   148 if(md.connection.ec)
HITCBC 487   5 return; 487   5 return;
488   auto rv = grammar::parse( 488   auto rv = grammar::parse(
HITCBC 489   147 v, list_rule(token_rule, 1)); 489   147 v, list_rule(token_rule, 1));
HITCBC 490   147 if(! rv) 490   147 if(! rv)
491   { 491   {
HITCBC 492   4 md.connection.ec = 492   4 md.connection.ec =
HITCBC 493   8 BOOST_HTTP_ERR( 493   8 BOOST_HTTP_ERR(
494   error::bad_connection); 494   error::bad_connection);
HITCBC 495   4 return; 495   4 return;
496   } 496   }
HITCBC 497   143 md.connection.ec = {}; 497   143 md.connection.ec = {};
HITCBC 498   297 for(auto t : *rv) 498   297 for(auto t : *rv)
499   { 499   {
HITCBC 500   154 if(grammar::ci_is_equal( 500   154 if(grammar::ci_is_equal(
501   t, "close")) 501   t, "close"))
HITCBC 502   99 md.connection.close = true; 502   99 md.connection.close = true;
HITCBC 503   55 else if(grammar::ci_is_equal( 503   55 else if(grammar::ci_is_equal(
504   t, "keep-alive")) 504   t, "keep-alive"))
HITCBC 505   28 md.connection.keep_alive = true; 505   28 md.connection.keep_alive = true;
HITCBC 506   27 else if(grammar::ci_is_equal( 506   27 else if(grammar::ci_is_equal(
507   t, "upgrade")) 507   t, "upgrade"))
HITCBC 508   20 md.connection.upgrade = true; 508   20 md.connection.upgrade = true;
509   } 509   }
HITCBC 510   147 } 510   147 }
511   511  
512   void 512   void
HITCBC 513   4528 header:: 513   4558 header::
514   on_insert_content_length( 514   on_insert_content_length(
515   core::string_view v) 515   core::string_view v)
516   { 516   {
517   static 517   static
518   constexpr 518   constexpr
519   grammar::unsigned_rule< 519   grammar::unsigned_rule<
520   std::uint64_t> num_rule{}; 520   std::uint64_t> num_rule{};
521   521  
HITCBC 522   4528 ++md.content_length.count; 522   4558 ++md.content_length.count;
HITCBC 523   4528 if(md.content_length.ec) 523   4558 if(md.content_length.ec)
HITCBC 524   4465 return; 524   4495 return;
525   auto rv = 525   auto rv =
HITCBC 526   4526 grammar::parse(v, num_rule); 526   4556 grammar::parse(v, num_rule);
HITCBC 527   4526 if(! rv) 527   4556 if(! rv)
528   { 528   {
529   // parse failure 529   // parse failure
HITCBC 530   5 md.content_length.ec = 530   5 md.content_length.ec =
HITCBC 531   10 BOOST_HTTP_ERR( 531   10 BOOST_HTTP_ERR(
532   error::bad_content_length); 532   error::bad_content_length);
HITCBC 533   5 md.content_length.value = 0; 533   5 md.content_length.value = 0;
HITCBC 534   5 update_payload(); 534   5 update_payload();
HITCBC 535   5 return; 535   5 return;
536   } 536   }
HITCBC 537   4521 if(md.content_length.count == 1) 537   4551 if(md.content_length.count == 1)
538   { 538   {
539   // one value 539   // one value
HITCBC 540   4451 md.content_length.ec = {}; 540   4481 md.content_length.ec = {};
HITCBC 541   4451 md.content_length.value = *rv; 541   4481 md.content_length.value = *rv;
HITCBC 542   4451 update_payload(); 542   4481 update_payload();
HITCBC 543   4451 return; 543   4481 return;
544   } 544   }
HITCBC 545   70 if(*rv == md.content_length.value) 545   70 if(*rv == md.content_length.value)
546   { 546   {
547   // ok: duplicate value 547   // ok: duplicate value
HITCBC 548   7 return; 548   7 return;
549   } 549   }
550   // bad: different values 550   // bad: different values
HITCBC 551   63 md.content_length.ec = 551   63 md.content_length.ec =
HITCBC 552   126 BOOST_HTTP_ERR( 552   126 BOOST_HTTP_ERR(
553   error::multiple_content_length); 553   error::multiple_content_length);
HITCBC 554   63 md.content_length.value = 0; 554   63 md.content_length.value = 0;
HITCBC 555   63 update_payload(); 555   63 update_payload();
556   } 556   }
557   557  
558   void 558   void
HITCBC 559   53 header:: 559   53 header::
560   on_insert_expect( 560   on_insert_expect(
561   core::string_view v) 561   core::string_view v)
562   { 562   {
HITCBC 563   53 ++md.expect.count; 563   53 ++md.expect.count;
HITCBC 564   53 if(kind != detail::kind::request) 564   53 if(kind != detail::kind::request)
HITCBC 565   8 return; 565   8 return;
HITCBC 566   45 if(md.expect.ec) 566   45 if(md.expect.ec)
HITCBC 567   4 return; 567   4 return;
568   // VFALCO Should we allow duplicate 568   // VFALCO Should we allow duplicate
569   // Expect fields that have 100-continue? 569   // Expect fields that have 100-continue?
HITCBC 570   73 if( md.expect.count > 1 || 570   73 if( md.expect.count > 1 ||
HITCBC 571   73 ! grammar::ci_is_equal(v, 571   73 ! grammar::ci_is_equal(v,
572   "100-continue")) 572   "100-continue"))
573   { 573   {
HITCBC 574   19 md.expect.ec = 574   19 md.expect.ec =
HITCBC 575   38 BOOST_HTTP_ERR( 575   38 BOOST_HTTP_ERR(
576   error::bad_expect); 576   error::bad_expect);
HITCBC 577   19 md.expect.is_100_continue = false; 577   19 md.expect.is_100_continue = false;
HITCBC 578   19 return; 578   19 return;
579   } 579   }
HITCBC 580   22 md.expect.is_100_continue = true; 580   22 md.expect.is_100_continue = true;
581   } 581   }
582   582  
583   void 583   void
HITCBC 584   4415 header:: 584   4415 header::
585   on_insert_transfer_encoding( 585   on_insert_transfer_encoding(
586   core::string_view v) 586   core::string_view v)
587   { 587   {
HITCBC 588   4415 ++md.transfer_encoding.count; 588   4415 ++md.transfer_encoding.count;
HITCBC 589   4415 if(md.transfer_encoding.ec) 589   4415 if(md.transfer_encoding.ec)
HITCBC 590   4407 return; 590   4407 return;
591   591  
592   auto rv = grammar::parse( 592   auto rv = grammar::parse(
HITCBC 593   4414 v, list_rule(transfer_coding_rule, 1)); 593   4414 v, list_rule(transfer_coding_rule, 1));
HITCBC 594   4414 if(! rv) 594   4414 if(! rv)
595   { 595   {
596   // parse error 596   // parse error
HITCBC 597   4 goto error; 597   4 goto error;
598   } 598   }
HITCBC 599   8823 for(auto t : *rv) 599   8823 for(auto t : *rv)
600   { 600   {
HITCBC 601   4417 if(! md.transfer_encoding.is_chunked) 601   4417 if(! md.transfer_encoding.is_chunked)
602   { 602   {
HITCBC 603   4413 if(t.id == transfer_coding_rule_t::chunked) 603   4413 if(t.id == transfer_coding_rule_t::chunked)
HITCBC 604   4394 md.transfer_encoding.is_chunked = true; 604   4394 md.transfer_encoding.is_chunked = true;
HITCBC 605   4413 continue; 605   4413 continue;
606   } 606   }
HITCBC 607   4 if(t.id == transfer_coding_rule_t::chunked) 607   4 if(t.id == transfer_coding_rule_t::chunked)
608   { 608   {
609   // chunked appears twice 609   // chunked appears twice
HITCBC 610   2 goto error; 610   2 goto error;
611   } 611   }
612   // chunked must be last 612   // chunked must be last
HITCBC 613   2 goto error; 613   2 goto error;
HITCBC 614   8831 } 614   8831 }
HITCBC 615   4406 update_payload(); 615   4406 update_payload();
HITCBC 616   4406 return; 616   4406 return;
617   617  
HITCBC 618   8 error: 618   8 error:
HITCBC 619   8 md.transfer_encoding.ec = 619   8 md.transfer_encoding.ec =
HITCBC 620   16 BOOST_HTTP_ERR( 620   16 BOOST_HTTP_ERR(
621   error::bad_transfer_encoding); 621   error::bad_transfer_encoding);
HITCBC 622   8 md.transfer_encoding.is_chunked = false; 622   8 md.transfer_encoding.is_chunked = false;
HITCBC 623   8 update_payload(); 623   8 update_payload();
HITCBC 624   4414 } 624   4414 }
625   625  
626   void 626   void
HITCBC 627   7 header:: 627   7 header::
628   on_insert_content_encoding( 628   on_insert_content_encoding(
629   core::string_view v) 629   core::string_view v)
630   { 630   {
HITCBC 631   7 ++md.content_encoding.count; 631   7 ++md.content_encoding.count;
HITCBC 632   7 if(md.content_encoding.ec) 632   7 if(md.content_encoding.ec)
HITCBC 633   3 return; 633   3 return;
634   634  
635   auto rv = grammar::parse( 635   auto rv = grammar::parse(
HITCBC 636   7 v, list_rule(token_rule, 1)); 636   7 v, list_rule(token_rule, 1));
HITCBC 637   7 if(!rv) 637   7 if(!rv)
638   { 638   {
HITCBC 639   1 md.content_encoding.ec = 639   1 md.content_encoding.ec =
HITCBC 640   2 BOOST_HTTP_ERR( 640   2 BOOST_HTTP_ERR(
641   error::bad_content_encoding); 641   error::bad_content_encoding);
HITCBC 642   1 md.content_encoding.coding = 642   1 md.content_encoding.coding =
643   content_coding::unknown; 643   content_coding::unknown;
HITCBC 644   1 return; 644   1 return;
645   } 645   }
646   646  
HITCBC 647   6 if(rv->size() > 1 || md.content_encoding.count > 1) 647   6 if(rv->size() > 1 || md.content_encoding.count > 1)
648   { 648   {
HITCBC 649   2 md.content_encoding.coding = 649   2 md.content_encoding.coding =
650   content_coding::unknown; 650   content_coding::unknown;
HITCBC 651   2 return; 651   2 return;
652   } 652   }
653   653  
HITCBC 654   8 if(grammar::ci_is_equal( 654   8 if(grammar::ci_is_equal(
HITCBC 655   8 *rv->begin(), "deflate")) 655   8 *rv->begin(), "deflate"))
656   { 656   {
MISUBC 657   md.content_encoding.coding = 657   md.content_encoding.coding =
658   content_coding::deflate; 658   content_coding::deflate;
659   } 659   }
HITCBC 660   8 else if(grammar::ci_is_equal( 660   8 else if(grammar::ci_is_equal(
HITCBC 661   8 *rv->begin(), "gzip")) 661   8 *rv->begin(), "gzip"))
662   { 662   {
HITCBC 663   2 md.content_encoding.coding = 663   2 md.content_encoding.coding =
664   content_coding::gzip; 664   content_coding::gzip;
665   } 665   }
HITCBC 666   4 else if(grammar::ci_is_equal( 666   4 else if(grammar::ci_is_equal(
HITCBC 667   4 *rv->begin(), "br")) 667   4 *rv->begin(), "br"))
668   { 668   {
HITCBC 669   1 md.content_encoding.coding = 669   1 md.content_encoding.coding =
670   content_coding::br; 670   content_coding::br;
671   } 671   }
HITCBC 672   2 else if(grammar::ci_is_equal( 672   2 else if(grammar::ci_is_equal(
HITCBC 673   2 *rv->begin(), "zstd")) 673   2 *rv->begin(), "zstd"))
674   { 674   {
HITCBC 675   1 md.content_encoding.coding = 675   1 md.content_encoding.coding =
676   content_coding::zstd; 676   content_coding::zstd;
677   } 677   }
678   else 678   else
679   { 679   {
MISUBC 680   md.content_encoding.coding = 680   md.content_encoding.coding =
681   content_coding::unknown; 681   content_coding::unknown;
682   } 682   }
HITCBC 683   7 } 683   7 }
684   684  
685   void 685   void
HITCBC 686   26 header:: 686   26 header::
687   on_insert_upgrade( 687   on_insert_upgrade(
688   core::string_view v) 688   core::string_view v)
689   { 689   {
HITCBC 690   26 ++md.upgrade.count; 690   26 ++md.upgrade.count;
HITCBC 691   26 if(md.upgrade.ec) 691   26 if(md.upgrade.ec)
HITCBC 692   5 return; 692   5 return;
HITCBC 693   25 if( version != 693   25 if( version !=
694   http::version::http_1_1) 694   http::version::http_1_1)
695   { 695   {
HITCBC 696   1 md.upgrade.ec = 696   1 md.upgrade.ec =
HITCBC 697   2 BOOST_HTTP_ERR( 697   2 BOOST_HTTP_ERR(
698   error::bad_upgrade); 698   error::bad_upgrade);
HITCBC 699   1 md.upgrade.websocket = false; 699   1 md.upgrade.websocket = false;
HITCBC 700   1 return; 700   1 return;
701   } 701   }
702   auto rv = grammar::parse( 702   auto rv = grammar::parse(
HITCBC 703   24 v, upgrade_rule); 703   24 v, upgrade_rule);
HITCBC 704   24 if(! rv) 704   24 if(! rv)
705   { 705   {
HITCBC 706   3 md.upgrade.ec = 706   3 md.upgrade.ec =
HITCBC 707   6 BOOST_HTTP_ERR( 707   6 BOOST_HTTP_ERR(
708   error::bad_upgrade); 708   error::bad_upgrade);
HITCBC 709   3 md.upgrade.websocket = false; 709   3 md.upgrade.websocket = false;
HITCBC 710   3 return; 710   3 return;
711   } 711   }
HITCBC 712   21 if(! md.upgrade.websocket) 712   21 if(! md.upgrade.websocket)
713   { 713   {
HITCBC 714   23 for(auto t : *rv) 714   23 for(auto t : *rv)
715   { 715   {
HITCBC 716   16 if( grammar::ci_is_equal( 716   16 if( grammar::ci_is_equal(
HITCBC 717   26 t.name, "websocket") && 717   26 t.name, "websocket") &&
HITCBC 718   10 t.version.empty()) 718   10 t.version.empty())
719   { 719   {
HITCBC 720   9 md.upgrade.websocket = true; 720   9 md.upgrade.websocket = true;
HITCBC 721   9 break; 721   9 break;
722   } 722   }
723   } 723   }
724   } 724   }
HITCBC 725   24 } 725   24 }
726   726  
727   //------------------------------------------------ 727   //------------------------------------------------
728   728  
729   void 729   void
HITCBC 730   9 header:: 730   9 header::
731   on_erase_connection() 731   on_erase_connection()
732   { 732   {
HITCBC 733   9 BOOST_ASSERT( 733   9 BOOST_ASSERT(
734   md.connection.count > 0); 734   md.connection.count > 0);
735   // reset and re-insert 735   // reset and re-insert
HITCBC 736   9 auto n = md.connection.count - 1; 736   9 auto n = md.connection.count - 1;
HITCBC 737   9 auto const p = cbuf + prefix; 737   9 auto const p = cbuf + prefix;
HITCBC 738   9 auto const* e = &tab()[0]; 738   9 auto const* e = &tab()[0];
HITCBC 739   9 md.connection = {}; 739   9 md.connection = {};
HITCBC 740   17 while(n > 0) 740   17 while(n > 0)
741   { 741   {
HITCBC 742   8 if(e->id == field::connection) 742   8 if(e->id == field::connection)
743   { 743   {
HITCBC 744   7 on_insert_connection( 744   7 on_insert_connection(
745   core::string_view( 745   core::string_view(
HITCBC 746   7 p + e->vp, e->vn)); 746   7 p + e->vp, e->vn));
HITCBC 747   7 --n; 747   7 --n;
748   } 748   }
HITCBC 749   8 --e; 749   8 --e;
750   } 750   }
HITCBC 751   9 } 751   9 }
752   752  
753   void 753   void
HITCBC 754   4 header:: 754   4 header::
755   on_erase_content_length() 755   on_erase_content_length()
756   { 756   {
HITCBC 757   4 BOOST_ASSERT( 757   4 BOOST_ASSERT(
758   md.content_length.count > 0); 758   md.content_length.count > 0);
HITCBC 759   4 --md.content_length.count; 759   4 --md.content_length.count;
HITCBC 760   4 if(md.content_length.count == 0) 760   4 if(md.content_length.count == 0)
761   { 761   {
762   // no Content-Length 762   // no Content-Length
HITCBC 763   1 md.content_length = {}; 763   1 md.content_length = {};
HITCBC 764   1 update_payload(); 764   1 update_payload();
HITCBC 765   1 return; 765   1 return;
766   } 766   }
HITCBC 767   3 if(! md.content_length.ec) 767   3 if(! md.content_length.ec)
768   { 768   {
769   // removing a duplicate value 769   // removing a duplicate value
HITCBC 770   2 return; 770   2 return;
771   } 771   }
772   // reset and re-insert 772   // reset and re-insert
HITCBC 773   1 auto n = md.content_length.count; 773   1 auto n = md.content_length.count;
HITCBC 774   1 auto const p = cbuf + prefix; 774   1 auto const p = cbuf + prefix;
HITCBC 775   1 auto const* e = &tab()[0]; 775   1 auto const* e = &tab()[0];
HITCBC 776   1 md.content_length = {}; 776   1 md.content_length = {};
HITCBC 777   2 while(n > 0) 777   2 while(n > 0)
778   { 778   {
HITCBC 779   1 if(e->id == field::content_length) 779   1 if(e->id == field::content_length)
780   { 780   {
HITCBC 781   1 on_insert_content_length( 781   1 on_insert_content_length(
782   core::string_view( 782   core::string_view(
HITCBC 783   1 p + e->vp, e->vn)); 783   1 p + e->vp, e->vn));
HITCBC 784   1 --n; 784   1 --n;
785   } 785   }
HITCBC 786   1 --e; 786   1 --e;
787   } 787   }
HITCBC 788   1 update_payload(); 788   1 update_payload();
789   } 789   }
790   790  
791   void 791   void
HITCBC 792   10 header:: 792   10 header::
793   on_erase_expect() 793   on_erase_expect()
794   { 794   {
HITCBC 795   10 BOOST_ASSERT( 795   10 BOOST_ASSERT(
796   md.expect.count > 0); 796   md.expect.count > 0);
HITCBC 797   10 --md.expect.count; 797   10 --md.expect.count;
HITCBC 798   10 if(kind != detail::kind::request) 798   10 if(kind != detail::kind::request)
HITCBC 799   1 return; 799   1 return;
HITCBC 800   9 if(md.expect.count == 0) 800   9 if(md.expect.count == 0)
801   { 801   {
802   // no Expect 802   // no Expect
HITCBC 803   3 md.expect = {}; 803   3 md.expect = {};
HITCBC 804   3 return; 804   3 return;
805   } 805   }
806   // VFALCO This should be uncommented 806   // VFALCO This should be uncommented
807   // if we want to allow multiple Expect 807   // if we want to allow multiple Expect
808   // fields with the value 100-continue 808   // fields with the value 100-continue
809   /* 809   /*
810   if(! md.expect.ec) 810   if(! md.expect.ec)
811   return; 811   return;
812   */ 812   */
813   // reset and re-insert 813   // reset and re-insert
HITCBC 814   6 auto n = md.expect.count; 814   6 auto n = md.expect.count;
HITCBC 815   6 auto const p = cbuf + prefix; 815   6 auto const p = cbuf + prefix;
HITCBC 816   6 auto const* e = &tab()[0]; 816   6 auto const* e = &tab()[0];
HITCBC 817   6 md.expect = {}; 817   6 md.expect = {};
HITCBC 818   18 while(n > 0) 818   18 while(n > 0)
819   { 819   {
HITCBC 820   12 if(e->id == field::expect) 820   12 if(e->id == field::expect)
821   { 821   {
HITCBC 822   6 on_insert_expect( 822   6 on_insert_expect(
823   core::string_view( 823   core::string_view(
HITCBC 824   6 p + e->vp, e->vn)); 824   6 p + e->vp, e->vn));
HITCBC 825   6 --n; 825   6 --n;
826   } 826   }
HITCBC 827   12 --e; 827   12 --e;
828   } 828   }
829   } 829   }
830   830  
831   void 831   void
HITCBC 832   4 header:: 832   4 header::
833   on_erase_transfer_encoding() 833   on_erase_transfer_encoding()
834   { 834   {
HITCBC 835   4 BOOST_ASSERT( 835   4 BOOST_ASSERT(
836   md.transfer_encoding.count > 0); 836   md.transfer_encoding.count > 0);
837   // reset and re-insert 837   // reset and re-insert
HITCBC 838   4 auto n = md.transfer_encoding.count - 1; 838   4 auto n = md.transfer_encoding.count - 1;
HITCBC 839   4 auto const p = cbuf + prefix; 839   4 auto const p = cbuf + prefix;
HITCBC 840   4 auto const* e = &tab()[0]; 840   4 auto const* e = &tab()[0];
HITCBC 841   4 md.transfer_encoding = {}; 841   4 md.transfer_encoding = {};
HITCBC 842   7 while(n > 0) 842   7 while(n > 0)
843   { 843   {
HITCBC 844   3 if(e->id == field::transfer_encoding) 844   3 if(e->id == field::transfer_encoding)
845   { 845   {
HITCBC 846   2 on_insert_transfer_encoding( 846   2 on_insert_transfer_encoding(
847   core::string_view( 847   core::string_view(
HITCBC 848   2 p + e->vp, e->vn)); 848   2 p + e->vp, e->vn));
HITCBC 849   2 --n; 849   2 --n;
850   } 850   }
HITCBC 851   3 --e; 851   3 --e;
852   } 852   }
HITCBC 853   4 } 853   4 }
854   854  
855   void 855   void
MISUBC 856   header:: 856   header::
857   on_erase_content_encoding() 857   on_erase_content_encoding()
858   { 858   {
MISUBC 859   BOOST_ASSERT( 859   BOOST_ASSERT(
860   md.content_encoding.count > 0); 860   md.content_encoding.count > 0);
MISUBC 861   --md.content_encoding.count; 861   --md.content_encoding.count;
MISUBC 862   if(md.content_encoding.count == 0) 862   if(md.content_encoding.count == 0)
863   { 863   {
864   // no Content-Encoding 864   // no Content-Encoding
MISUBC 865   md.content_encoding = {}; 865   md.content_encoding = {};
MISUBC 866   return; 866   return;
867   } 867   }
868   // re-insert everything 868   // re-insert everything
MISUBC 869   --md.content_encoding.count; 869   --md.content_encoding.count;
870   // TODO 870   // TODO
871   // on_insert_content_encoding(); 871   // on_insert_content_encoding();
872   } 872   }
873   873  
874   // called when Upgrade is erased 874   // called when Upgrade is erased
875   void 875   void
HITCBC 876   4 header:: 876   4 header::
877   on_erase_upgrade() 877   on_erase_upgrade()
878   { 878   {
HITCBC 879   4 BOOST_ASSERT( 879   4 BOOST_ASSERT(
880   md.upgrade.count > 0); 880   md.upgrade.count > 0);
HITCBC 881   4 --md.upgrade.count; 881   4 --md.upgrade.count;
HITCBC 882   4 if(md.upgrade.count == 0) 882   4 if(md.upgrade.count == 0)
883   { 883   {
884   // no Upgrade 884   // no Upgrade
HITCBC 885   2 md.upgrade = {}; 885   2 md.upgrade = {};
HITCBC 886   2 return; 886   2 return;
887   } 887   }
888   // reset and re-insert 888   // reset and re-insert
HITCBC 889   2 auto n = md.upgrade.count; 889   2 auto n = md.upgrade.count;
HITCBC 890   2 auto const p = cbuf + prefix; 890   2 auto const p = cbuf + prefix;
HITCBC 891   2 auto const* e = &tab()[0]; 891   2 auto const* e = &tab()[0];
HITCBC 892   2 md.upgrade = {}; 892   2 md.upgrade = {};
HITCBC 893   4 while(n > 0) 893   4 while(n > 0)
894   { 894   {
HITCBC 895   2 if(e->id == field::upgrade) 895   2 if(e->id == field::upgrade)
HITCBC 896   2 on_insert_upgrade( 896   2 on_insert_upgrade(
897   core::string_view( 897   core::string_view(
HITCBC 898   2 p + e->vp, e->vn)); 898   2 p + e->vp, e->vn));
HITCBC 899   2 --n; 899   2 --n;
HITCBC 900   2 --e; 900   2 --e;
901   } 901   }
902   } 902   }
903   903  
904   //------------------------------------------------ 904   //------------------------------------------------
905   905  
906   // called when all fields with id are removed 906   // called when all fields with id are removed
907   void 907   void
HITCBC 908   72 header:: 908   72 header::
909   on_erase_all( 909   on_erase_all(
910   field id) 910   field id)
911   { 911   {
HITCBC 912   72 if(kind == detail::kind::fields) 912   72 if(kind == detail::kind::fields)
HITCBC 913   21 return; 913   21 return;
HITCBC 914   51 switch(id) 914   51 switch(id)
915   { 915   {
HITCBC 916   3 case field::connection: 916   3 case field::connection:
HITCBC 917   3 md.connection = {}; 917   3 md.connection = {};
HITCBC 918   3 return; 918   3 return;
919   919  
HITCBC 920   2 case field::content_length: 920   2 case field::content_length:
HITCBC 921   2 md.content_length = {}; 921   2 md.content_length = {};
HITCBC 922   2 update_payload(); 922   2 update_payload();
HITCBC 923   2 return; 923   2 return;
924   924  
HITCBC 925   5 case field::expect: 925   5 case field::expect:
HITCBC 926   5 md.expect = {}; 926   5 md.expect = {};
HITCBC 927   5 update_payload(); 927   5 update_payload();
HITCBC 928   5 return; 928   5 return;
929   929  
HITCBC 930   1 case field::transfer_encoding: 930   1 case field::transfer_encoding:
HITCBC 931   1 md.transfer_encoding = {}; 931   1 md.transfer_encoding = {};
HITCBC 932   1 update_payload(); 932   1 update_payload();
HITCBC 933   1 return; 933   1 return;
934   934  
HITCBC 935   1 case field::upgrade: 935   1 case field::upgrade:
HITCBC 936   1 md.upgrade = {}; 936   1 md.upgrade = {};
HITCBC 937   1 return; 937   1 return;
938   938  
HITCBC 939   39 default: 939   39 default:
HITCBC 940   39 break; 940   39 break;
941   } 941   }
942   } 942   }
943   943  
944   //------------------------------------------------ 944   //------------------------------------------------
945   945  
946   /* References: 946   /* References:
947   947  
948   3.3. Message Body 948   3.3. Message Body
949   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3 949   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3
950   950  
951   3.3.1. Transfer-Encoding 951   3.3.1. Transfer-Encoding
952   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1 952   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
953   953  
954   3.3.2. Content-Length 954   3.3.2. Content-Length
955   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2 955   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
956   */ 956   */
957   void 957   void
HITCBC 958   19539 header:: 958   19641 header::
959   update_payload() noexcept 959   update_payload() noexcept
960   { 960   {
HITCBC 961   19539 BOOST_ASSERT(kind != 961   19641 BOOST_ASSERT(kind !=
962   detail::kind::fields); 962   detail::kind::fields);
HITCBC 963   19539 if(md.payload_override) 963   19641 if(md.payload_override)
964   { 964   {
965   // e.g. response to 965   // e.g. response to
966   // a HEAD request 966   // a HEAD request
MISUBC 967   return; 967   return;
968   } 968   }
969   969  
970   /* If there is an error in either Content-Length 970   /* If there is an error in either Content-Length
971   or Transfer-Encoding, then the payload is 971   or Transfer-Encoding, then the payload is
972   undefined. Clients should probably close the 972   undefined. Clients should probably close the
973   connection. Servers can send a Bad Request 973   connection. Servers can send a Bad Request
974   and avoid reading any payload bytes. 974   and avoid reading any payload bytes.
975   */ 975   */
HITCBC 976   19539 if(md.content_length.ec) 976   19641 if(md.content_length.ec)
977   { 977   {
978   // invalid Content-Length 978   // invalid Content-Length
HITCBC 979   68 md.payload = payload::error; 979   68 md.payload = payload::error;
HITCBC 980   68 md.payload_size = 0; 980   68 md.payload_size = 0;
HITCBC 981   68 return; 981   68 return;
982   } 982   }
HITCBC 983   19471 if(md.transfer_encoding.ec) 983   19573 if(md.transfer_encoding.ec)
984   { 984   {
985   // invalid Transfer-Encoding 985   // invalid Transfer-Encoding
HITCBC 986   8 md.payload = payload::error; 986   8 md.payload = payload::error;
HITCBC 987   8 md.payload_size = 0; 987   8 md.payload_size = 0;
HITCBC 988   8 return; 988   8 return;
989   } 989   }
990   990  
991   /* A sender MUST NOT send a Content-Length 991   /* A sender MUST NOT send a Content-Length
992   header field in any message that contains 992   header field in any message that contains
993   a Transfer-Encoding header field. 993   a Transfer-Encoding header field.
994   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2 994   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
995   */ 995   */
HITCBC 996   19463 if( md.content_length.count > 0 && 996   19565 if( md.content_length.count > 0 &&
HITCBC 997   4455 md.transfer_encoding.count > 0) 997   4485 md.transfer_encoding.count > 0)
998   { 998   {
HITCBC 999   3 md.payload = payload::error; 999   3 md.payload = payload::error;
HITCBC 1000   3 md.payload_size = 0; 1000   3 md.payload_size = 0;
HITCBC 1001   3 return; 1001   3 return;
1002   } 1002   }
1003   1003  
HITCBC 1004   19460 if(kind == detail::kind::response) 1004   19562 if(kind == detail::kind::response)
HITCBC 1005   1822 goto do_response; 1005   1924 goto do_response;
1006   1006  
1007   //-------------------------------------------- 1007   //--------------------------------------------
1008   1008  
1009   /* The presence of a message body in a 1009   /* The presence of a message body in a
1010   request is signaled by a Content-Length 1010   request is signaled by a Content-Length
1011   or Transfer-Encoding header field. Request 1011   or Transfer-Encoding header field. Request
1012   message framing is independent of method 1012   message framing is independent of method
1013   semantics, even if the method does not 1013   semantics, even if the method does not
1014   define any use for a message body. 1014   define any use for a message body.
1015   */ 1015   */
HITCBC 1016   17638 if(md.content_length.count > 0) 1016   17638 if(md.content_length.count > 0)
1017   { 1017   {
HITCBC 1018   4177 if(md.content_length.value > 0) 1018   4177 if(md.content_length.value > 0)
1019   { 1019   {
1020   // non-zero Content-Length 1020   // non-zero Content-Length
HITCBC 1021   4150 md.payload = payload::size; 1021   4150 md.payload = payload::size;
HITCBC 1022   4150 md.payload_size = md.content_length.value; 1022   4150 md.payload_size = md.content_length.value;
HITCBC 1023   4150 return; 1023   4150 return;
1024   } 1024   }
1025   // Content-Length: 0 1025   // Content-Length: 0
HITCBC 1026   27 md.payload = payload::none; 1026   27 md.payload = payload::none;
HITCBC 1027   27 md.payload_size = 0; 1027   27 md.payload_size = 0;
HITCBC 1028   27 return; 1028   27 return;
1029   } 1029   }
HITCBC 1030   13461 if(md.transfer_encoding.is_chunked) 1030   13461 if(md.transfer_encoding.is_chunked)
1031   { 1031   {
1032   // chunked 1032   // chunked
HITCBC 1033   4012 md.payload = payload::chunked; 1033   4012 md.payload = payload::chunked;
HITCBC 1034   4012 md.payload_size = 0; 1034   4012 md.payload_size = 0;
HITCBC 1035   4012 return; 1035   4012 return;
1036   } 1036   }
1037   // no payload 1037   // no payload
HITCBC 1038   9449 md.payload = payload::none; 1038   9449 md.payload = payload::none;
HITCBC 1039   9449 md.payload_size = 0; 1039   9449 md.payload_size = 0;
HITCBC 1040   9449 return; 1040   9449 return;
1041   1041  
1042   //-------------------------------------------- 1042   //--------------------------------------------
HITCBC 1043   1822 do_response: 1043   1924 do_response:
1044   1044  
HITCBC 1045   1822 if( res.status_int / 100 == 1 || // 1xx e.g. Continue 1045   1924 if( res.status_int / 100 == 1 || // 1xx e.g. Continue
HITCBC 1046   1811 res.status_int == 204 || // No Content 1046   1913 res.status_int == 204 || // No Content
HITCBC 1047   1808 res.status_int == 304) // Not Modified 1047   1910 res.status_int == 304) // Not Modified
1048   { 1048   {
1049   /* The correctness of any Content-Length 1049   /* The correctness of any Content-Length
1050   here is defined by the particular 1050   here is defined by the particular
1051   resource, and cannot be determined 1051   resource, and cannot be determined
1052   here. In any case there is no payload. 1052   here. In any case there is no payload.
1053   */ 1053   */
HITCBC 1054   16 md.payload = payload::none; 1054   16 md.payload = payload::none;
HITCBC 1055   16 md.payload_size = 0; 1055   16 md.payload_size = 0;
HITCBC 1056   16 return; 1056   16 return;
1057   } 1057   }
HITCBC 1058   1806 if(md.content_length.count > 0) 1058   1908 if(md.content_length.count > 0)
1059   { 1059   {
HITCBC 1060   272 if(md.content_length.value > 0) 1060   302 if(md.content_length.value > 0)
1061   { 1061   {
1062   // Content-Length > 0 1062   // Content-Length > 0
HITCBC 1063   253 md.payload = payload::size; 1063   283 md.payload = payload::size;
HITCBC 1064   253 md.payload_size = md.content_length.value; 1064   283 md.payload_size = md.content_length.value;
HITCBC 1065   253 return; 1065   283 return;
1066   } 1066   }
1067   // Content-Length: 0 1067   // Content-Length: 0
HITCBC 1068   19 md.payload = payload::none; 1068   19 md.payload = payload::none;
HITCBC 1069   19 md.payload_size = 0; 1069   19 md.payload_size = 0;
HITCBC 1070   19 return; 1070   19 return;
1071   } 1071   }
HITCBC 1072   1534 if(md.transfer_encoding.is_chunked) 1072   1606 if(md.transfer_encoding.is_chunked)
1073   { 1073   {
1074   // chunked 1074   // chunked
HITCBC 1075   377 md.payload = payload::chunked; 1075   377 md.payload = payload::chunked;
HITCBC 1076   377 md.payload_size = 0; 1076   377 md.payload_size = 0;
HITCBC 1077   377 return; 1077   377 return;
1078   } 1078   }
1079   1079  
1080   // eof needed 1080   // eof needed
HITCBC 1081   1157 md.payload = payload::to_eof; 1081   1229 md.payload = payload::to_eof;
HITCBC 1082   1157 md.payload_size = 0; 1082   1229 md.payload_size = 0;
1083   } 1083   }
1084   1084  
1085   //------------------------------------------------ 1085   //------------------------------------------------
1086   1086  
1087   std::size_t 1087   std::size_t
HITCBC 1088   549 header:: 1088   549 header::
1089   count_crlf( 1089   count_crlf(
1090   core::string_view s) noexcept 1090   core::string_view s) noexcept
1091   { 1091   {
HITCBC 1092   549 auto it = s.data(); 1092   549 auto it = s.data();
HITCBC 1093   549 auto len = s.size(); 1093   549 auto len = s.size();
HITCBC 1094   549 std::size_t n = 0; 1094   549 std::size_t n = 0;
HITCBC 1095   19120 while(len >= 2) 1095   19120 while(len >= 2)
1096   { 1096   {
HITCBC 1097   18571 if( it[0] == '\r' && 1097   18571 if( it[0] == '\r' &&
HITCBC 1098   1749 it[1] != '\r') 1098   1749 it[1] != '\r')
1099   { 1099   {
HITCBC 1100   1749 if(it[1] == '\n') 1100   1749 if(it[1] == '\n')
HITCBC 1101   1749 n++; 1101   1749 n++;
HITCBC 1102   1749 it += 2; 1102   1749 it += 2;
HITCBC 1103   1749 len -= 2; 1103   1749 len -= 2;
1104   } 1104   }
1105   else 1105   else
1106   { 1106   {
HITCBC 1107   16822 it++; 1107   16822 it++;
HITCBC 1108   16822 len--; 1108   16822 len--;
1109   } 1109   }
1110   } 1110   }
HITCBC 1111   549 return n; 1111   549 return n;
1112   } 1112   }
1113   1113  
1114   static 1114   static
1115   void 1115   void
HITCBC 1116   27541 parse_start_line( 1116   29145 parse_start_line(
1117   header& h, 1117   header& h,
1118   header_limits const& lim, 1118   header_limits const& lim,
1119   std::size_t new_size, 1119   std::size_t new_size,
1120   system::error_code& ec) noexcept 1120   system::error_code& ec) noexcept
1121   { 1121   {
HITCBC 1122   27541 BOOST_ASSERT(h.size == 0); 1122   29145 BOOST_ASSERT(h.size == 0);
HITCBC 1123   27541 BOOST_ASSERT(h.prefix == 0); 1123   29145 BOOST_ASSERT(h.prefix == 0);
HITCBC 1124   27541 BOOST_ASSERT(h.cbuf != nullptr); 1124   29145 BOOST_ASSERT(h.cbuf != nullptr);
HITCBC 1125   27541 BOOST_ASSERT( 1125   29145 BOOST_ASSERT(
1126   h.kind != detail::kind::fields); 1126   h.kind != detail::kind::fields);
1127   1127  
HITCBC 1128   27541 auto const it0 = h.cbuf; 1128   29145 auto const it0 = h.cbuf;
HITCBC 1129   27541 auto const end = it0 + new_size; 1129   29145 auto const end = it0 + new_size;
HITCBC 1130   27541 char const* it = it0; 1130   29145 char const* it = it0;
HITCBC 1131   27541 if( new_size > lim.max_start_line) 1131   29145 if( new_size > lim.max_start_line)
HITCBC 1132   10 new_size = lim.max_start_line; 1132   10 new_size = lim.max_start_line;
HITCBC 1133   27541 if(h.kind == detail::kind::request) 1133   29145 if(h.kind == detail::kind::request)
1134   { 1134   {
1135   auto rv = grammar::parse( 1135   auto rv = grammar::parse(
HITCBC 1136   11375 it, end, request_line_rule); 1136   11375 it, end, request_line_rule);
HITCBC 1137   11375 if(! rv) 1137   11375 if(! rv)
1138   { 1138   {
HITCBC 1139   1991 ec = rv.error(); 1139   1991 ec = rv.error();
HITCBC 1140   3982 if( ec == grammar::error::need_more && 1140   3982 if( ec == grammar::error::need_more &&
HITCBC 1141   1991 new_size == lim.max_start_line) 1141   1991 new_size == lim.max_start_line)
MISUBC 1142   ec = BOOST_HTTP_ERR( 1142   ec = BOOST_HTTP_ERR(
1143   error::start_line_limit); 1143   error::start_line_limit);
HITCBC 1144   1991 return; 1144   1991 return;
1145   } 1145   }
1146   // method 1146   // method
HITCBC 1147   9384 auto sm = std::get<0>(*rv); 1147   9384 auto sm = std::get<0>(*rv);
HITCBC 1148   9384 h.req.method = string_to_method(sm); 1148   9384 h.req.method = string_to_method(sm);
HITCBC 1149   9384 h.req.method_len = 1149   9384 h.req.method_len =
HITCBC 1150   9384 static_cast<header::offset_type>(sm.size()); 1150   9384 static_cast<header::offset_type>(sm.size());
1151   // target 1151   // target
HITCBC 1152   9384 auto st = std::get<1>(*rv); 1152   9384 auto st = std::get<1>(*rv);
HITCBC 1153   9384 h.req.target_len = 1153   9384 h.req.target_len =
HITCBC 1154   9384 static_cast<header::offset_type>(st.size()); 1154   9384 static_cast<header::offset_type>(st.size());
1155   // version 1155   // version
HITCBC 1156   9384 switch(std::get<2>(*rv)) 1156   9384 switch(std::get<2>(*rv))
1157   { 1157   {
HITCBC 1158   25 case 10: 1158   25 case 10:
HITCBC 1159   25 h.version = 1159   25 h.version =
1160   http::version::http_1_0; 1160   http::version::http_1_0;
HITCBC 1161   25 break; 1161   25 break;
HITCBC 1162   9359 case 11: 1162   9359 case 11:
HITCBC 1163   9359 h.version = 1163   9359 h.version =
1164   http::version::http_1_1; 1164   http::version::http_1_1;
HITCBC 1165   9359 break; 1165   9359 break;
MISUBC 1166   default: 1166   default:
1167   { 1167   {
MISUBC 1168   ec = BOOST_HTTP_ERR( 1168   ec = BOOST_HTTP_ERR(
1169   error::bad_version); 1169   error::bad_version);
MISUBC 1170   return; 1170   return;
1171   } 1171   }
1172   } 1172   }
1173   } 1173   }
1174   else 1174   else
1175   { 1175   {
1176   auto rv = grammar::parse( 1176   auto rv = grammar::parse(
HITCBC 1177   16166 it, end, status_line_rule); 1177   17770 it, end, status_line_rule);
HITCBC 1178   16166 if(! rv) 1178   17770 if(! rv)
1179   { 1179   {
HITCBC 1180   15022 ec = rv.error(); 1180   16554 ec = rv.error();
HITCBC 1181   30044 if( ec == grammar::error::need_more && 1181   33108 if( ec == grammar::error::need_more &&
HITCBC 1182   15022 new_size == lim.max_start_line) 1182   16554 new_size == lim.max_start_line)
MISUBC 1183   ec = BOOST_HTTP_ERR( 1183   ec = BOOST_HTTP_ERR(
1184   error::start_line_limit); 1184   error::start_line_limit);
HITCBC 1185   15022 return; 1185   16554 return;
1186   } 1186   }
1187   // version 1187   // version
HITCBC 1188   1144 switch(std::get<0>(*rv)) 1188   1216 switch(std::get<0>(*rv))
1189   { 1189   {
HITCBC 1190   4 case 10: 1190   4 case 10:
HITCBC 1191   4 h.version = 1191   4 h.version =
1192   http::version::http_1_0; 1192   http::version::http_1_0;
HITCBC 1193   4 break; 1193   4 break;
HITCBC 1194   1140 case 11: 1194   1212 case 11:
HITCBC 1195   1140 h.version = 1195   1212 h.version =
1196   http::version::http_1_1; 1196   http::version::http_1_1;
HITCBC 1197   1140 break; 1197   1212 break;
MISUBC 1198   default: 1198   default:
1199   { 1199   {
MISUBC 1200   ec = BOOST_HTTP_ERR( 1200   ec = BOOST_HTTP_ERR(
1201   error::bad_version); 1201   error::bad_version);
MISUBC 1202   return; 1202   return;
1203   } 1203   }
1204   } 1204   }
1205   // status-code 1205   // status-code
HITCBC 1206   1144 h.res.status_int = 1206   1216 h.res.status_int =
1207   static_cast<unsigned short>( 1207   static_cast<unsigned short>(
HITCBC 1208   1144 std::get<1>(*rv).v); 1208   1216 std::get<1>(*rv).v);
HITCBC 1209   1144 h.res.status = std::get<1>(*rv).st; 1209   1216 h.res.status = std::get<1>(*rv).st;
1210   } 1210   }
HITCBC 1211   10528 h.prefix = static_cast<header::offset_type>(it - it0); 1211   10600 h.prefix = static_cast<header::offset_type>(it - it0);
HITCBC 1212   10528 h.size = h.prefix; 1212   10600 h.size = h.prefix;
HITCBC 1213   10528 h.on_start_line(); 1213   10600 h.on_start_line();
1214   } 1214   }
1215   1215  
1216   // returns: true if we added a field 1216   // returns: true if we added a field
1217   static 1217   static
1218   void 1218   void
HITCBC 1219   36564 parse_field( 1219   37744 parse_field(
1220   header& h, 1220   header& h,
1221   header_limits const& lim, 1221   header_limits const& lim,
1222   std::size_t new_size, 1222   std::size_t new_size,
1223   system::error_code& ec) noexcept 1223   system::error_code& ec) noexcept
1224   { 1224   {
HITCBC 1225   36564 if( new_size > lim.max_field) 1225   37744 if( new_size > lim.max_field)
HITCBC 1226   20 new_size = lim.max_field; 1226   20 new_size = lim.max_field;
HITCBC 1227   36564 auto const it0 = h.cbuf + h.size; 1227   37744 auto const it0 = h.cbuf + h.size;
HITCBC 1228   36564 auto const end = h.cbuf + new_size; 1228   37744 auto const end = h.cbuf + new_size;
HITCBC 1229   36564 char const* it = it0; 1229   37744 char const* it = it0;
HITCBC 1230   36564 auto rv = grammar::parse( 1230   37744 auto rv = grammar::parse(
1231   it, end, field_rule); 1231   it, end, field_rule);
HITCBC 1232   36564 if(rv.has_error()) 1232   37744 if(rv.has_error())
1233   { 1233   {
HITCBC 1234   25880 ec = rv.error(); 1234   27030 ec = rv.error();
HITCBC 1235   25880 if(ec == grammar::error::end_of_range) 1235   27030 if(ec == grammar::error::end_of_range)
1236   { 1236   {
1237   // final CRLF 1237   // final CRLF
HITCBC 1238   10103 h.size = static_cast< 1238   10131 h.size = static_cast<
HITCBC 1239   10103 header::offset_type>(it - h.cbuf); 1239   10131 header::offset_type>(it - h.cbuf);
HITCBC 1240   25880 return; 1240   27030 return;
1241   } 1241   }
HITCBC 1242   31295 if( ec == grammar::error::need_more && 1242   33539 if( ec == grammar::error::need_more &&
HITCBC 1243   15518 new_size == lim.max_field) 1243   16640 new_size == lim.max_field)
1244   { 1244   {
MISUBC 1245   ec = BOOST_HTTP_ERR( 1245   ec = BOOST_HTTP_ERR(
1246   error::field_size_limit); 1246   error::field_size_limit);
1247   } 1247   }
HITCBC 1248   15777 return; 1248   16899 return;
1249   } 1249   }
HITCBC 1250   10684 if(h.count >= lim.max_fields) 1250   10714 if(h.count >= lim.max_fields)
1251   { 1251   {
MISUBC 1252   ec = BOOST_HTTP_ERR( 1252   ec = BOOST_HTTP_ERR(
1253   error::fields_limit); 1253   error::fields_limit);
MISUBC 1254   return; 1254   return;
1255   } 1255   }
HITCBC 1256   10684 if(rv->has_obs_fold) 1256   10714 if(rv->has_obs_fold)
1257   { 1257   {
1258   // obs fold not allowed in test views 1258   // obs fold not allowed in test views
HITCBC 1259   210 BOOST_ASSERT(h.buf != nullptr); 1259   210 BOOST_ASSERT(h.buf != nullptr);
HITCBC 1260   210 remove_obs_fold(h.buf + h.size, it); 1260   210 remove_obs_fold(h.buf + h.size, it);
1261   } 1261   }
HITCBC 1262   10684 auto id = string_to_field(rv->name) 1262   10714 auto id = string_to_field(rv->name)
HITCBC 1263   10684 .value_or(header::unknown_field); 1263   10714 .value_or(header::unknown_field);
HITCBC 1264   10684 h.size = static_cast<header::offset_type>(it - h.cbuf); 1264   10714 h.size = static_cast<header::offset_type>(it - h.cbuf);
1265   1265  
1266   // add field table entry 1266   // add field table entry
HITCBC 1267   10684 if(h.buf != nullptr) 1267   10714 if(h.buf != nullptr)
1268   { 1268   {
HITCBC 1269   21368 auto& e = header::table( 1269   21428 auto& e = header::table(
HITCBC 1270   10684 h.buf + h.cap)[h.count]; 1270   10714 h.buf + h.cap)[h.count];
HITCBC 1271   10684 auto const base = 1271   10714 auto const base =
HITCBC 1272   10684 h.buf + h.prefix; 1272   10714 h.buf + h.prefix;
HITCBC 1273   10684 e.np = static_cast<header::offset_type>( 1273   10714 e.np = static_cast<header::offset_type>(
HITCBC 1274   10684 rv->name.data() - base); 1274   10714 rv->name.data() - base);
HITCBC 1275   10684 e.nn = static_cast<header::offset_type>( 1275   10714 e.nn = static_cast<header::offset_type>(
HITCBC 1276   10684 rv->name.size()); 1276   10714 rv->name.size());
HITCBC 1277   10684 e.vp = static_cast<header::offset_type>( 1277   10714 e.vp = static_cast<header::offset_type>(
HITCBC 1278   10684 rv->value.data() - base); 1278   10714 rv->value.data() - base);
HITCBC 1279   10684 e.vn = static_cast<header::offset_type>( 1279   10714 e.vn = static_cast<header::offset_type>(
HITCBC 1280   10684 rv->value.size()); 1280   10714 rv->value.size());
HITCBC 1281   10684 e.id = id; 1281   10714 e.id = id;
1282   } 1282   }
HITCBC 1283   10684 ++h.count; 1283   10714 ++h.count;
HITCBC 1284   10684 h.on_insert(id, rv->value); 1284   10714 h.on_insert(id, rv->value);
HITCBC 1285   10684 ec = {}; 1285   10714 ec = {};
1286   } 1286   }
1287   1287  
1288   void 1288   void
HITCBC 1289   42893 header:: 1289   45575 header::
1290   parse( 1290   parse(
1291   std::size_t new_size, 1291   std::size_t new_size,
1292   header_limits const& lim, 1292   header_limits const& lim,
1293   system::error_code& ec) noexcept 1293   system::error_code& ec) noexcept
1294   { 1294   {
HITCBC 1295   42893 if( new_size > lim.max_size) 1295   45575 if( new_size > lim.max_size)
HITCBC 1296   10 new_size = lim.max_size; 1296   10 new_size = lim.max_size;
HITCBC 1297   42893 if( this->prefix == 0 && 1297   45575 if( this->prefix == 0 &&
HITCBC 1298   27775 this->kind != 1298   29379 this->kind !=
1299   detail::kind::fields) 1299   detail::kind::fields)
1300   { 1300   {
HITCBC 1301   27541 parse_start_line( 1301   29145 parse_start_line(
1302   *this, lim, new_size, ec); 1302   *this, lim, new_size, ec);
HITCBC 1303   27541 if(ec) 1303   29145 if(ec)
1304   { 1304   {
HITCBC 1305   34026 if( ec == grammar::error::need_more && 1305   37090 if( ec == grammar::error::need_more &&
HITCBC 1306   17013 new_size == lim.max_fields) 1306   18545 new_size == lim.max_fields)
1307   { 1307   {
MISUBC 1308   ec = BOOST_HTTP_ERR( 1308   ec = BOOST_HTTP_ERR(
1309   error::headers_limit); 1309   error::headers_limit);
1310   } 1310   }
HITCBC 1311   17013 return; 1311   18545 return;
1312   } 1312   }
1313   } 1313   }
1314   for(;;) 1314   for(;;)
1315   { 1315   {
HITCBC 1316   36564 parse_field( 1316   37744 parse_field(
1317   *this, lim, new_size, ec); 1317   *this, lim, new_size, ec);
HITCBC 1318   36564 if(ec) 1318   37744 if(ec)
1319   { 1319   {
HITCBC 1320   41398 if( ec == grammar::error::need_more && 1320   43670 if( ec == grammar::error::need_more &&
HITCBC 1321   15518 new_size == lim.max_size) 1321   16640 new_size == lim.max_size)
1322   { 1322   {
MISUBC 1323   ec = BOOST_HTTP_ERR( 1323   ec = BOOST_HTTP_ERR(
1324   error::headers_limit); 1324   error::headers_limit);
MISUBC 1325   return; 1325   return;
1326   } 1326   }
HITCBC 1327   25880 break; 1327   27030 break;
1328   } 1328   }
HITCBC 1329   10684 } 1329   10714 }
HITCBC 1330   25880 if(ec == grammar::error::end_of_range) 1330   27030 if(ec == grammar::error::end_of_range)
HITCBC 1331   10103 ec = {}; 1331   10131 ec = {};
1332   } 1332   }
1333   1333  
1334   } // detail 1334   } // detail
1335   } // http 1335   } // http
1336   } // boost 1336   } // boost