92.14% Lines (563/611) 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   4638 header:: 114   4656 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   4638 return &h[k]; 121   4656 return &h[k];
122   } 122   }
123   123  
HITCBC 124   13134 header:: 124   13152 header::
HITCBC 125   13134 header(empty v) noexcept 125   13152 header(empty v) noexcept
HITCBC 126   13134 : kind(v.param) 126   13152 : kind(v.param)
127   { 127   {
HITCBC 128   13134 } 128   13152 }
129   129  
HITCBC 130   2562 header:: 130   2571 header::
HITCBC 131   2562 header(detail::kind k) noexcept 131   2571 header(detail::kind k) noexcept
HITCBC 132   2562 : header(*get_default(k)) 132   2571 : header(*get_default(k))
133   { 133   {
HITCBC 134   2562 } 134   2571 }
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   3037 header:: 205   3046 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   3037 if(size < 19) 213   3046 if(size < 19)
HITCBC 214   2271 size = 19; 214   2280 size = 19;
215   215  
216   // align size up to alignof(entry) 216   // align size up to alignof(entry)
HITCBC 217   3037 size = (size + alignof(entry) - 1) & ~(alignof(entry) - 1); 217   3046 size = (size + alignof(entry) - 1) & ~(alignof(entry) - 1);
218   218  
HITCBC 219   3037 return size + count * sizeof(entry); 219   3046 return size + count * sizeof(entry);
220   } 220   }
221   221  
222   std::size_t 222   std::size_t
HITCBC 223   9548 header:: 223   9557 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   9548 sizeof(header::entry); 228   9557 sizeof(header::entry);
229   } 229   }
230   230  
231   std::size_t 231   std::size_t
HITCBC 232   9548 header:: 232   9557 header::
233   table_space() const noexcept 233   table_space() const noexcept
234   { 234   {
HITCBC 235   9548 return table_space(count); 235   9557 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   2150 header:: 307   2159 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   2150 if(n == 0) 314   2159 if(n == 0)
HITCBC 315   2129 return; 315   2138 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   2150 header:: 327   2159 header::
328   copy_table( 328   copy_table(
329   void* dest) const noexcept 329   void* dest) const noexcept
330   { 330   {
HITCBC 331   2150 copy_table(dest, count); 331   2159 copy_table(dest, count);
HITCBC 332   2150 } 332   2159 }
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   2100 header:: 337   2109 header::
338   assign_to( 338   assign_to(
339   header& dest) const noexcept 339   header& dest) const noexcept
340   { 340   {
HITCBC 341   2100 auto const buf_ = dest.buf; 341   2109 auto const buf_ = dest.buf;
HITCBC 342   2100 auto const cbuf_ = dest.cbuf; 342   2109 auto const cbuf_ = dest.cbuf;
HITCBC 343   2100 auto const cap_ = dest.cap; 343   2109 auto const cap_ = dest.cap;
HITCBC 344   2100 dest = *this; 344   2109 dest = *this;
HITCBC 345   2100 dest.buf = buf_; 345   2109 dest.buf = buf_;
HITCBC 346   2100 dest.cbuf = cbuf_; 346   2109 dest.cbuf = cbuf_;
HITCBC 347   2100 dest.cap = cap_; 347   2109 dest.cap = cap_;
HITCBC 348   2100 } 348   2109 }
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   10585 header:: 409   10594 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   10585 update_payload(); 418   10594 update_payload();
HITCBC 419   10585 } 419   10594 }
420   420  
421   // called after a field is inserted 421   // called after a field is inserted
422   void 422   void
HITCBC 423   10991 header:: 423   10999 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   10991 if(kind == detail::kind::fields) 428   10999 if(kind == detail::kind::fields)
HITCBC 429   482 return; 429   482 return;
HITCBC 430   10509 switch(id) 430   10517 switch(id)
431   { 431   {
HITCBC 432   5 case field::content_encoding: 432   5 case field::content_encoding:
HITCBC 433   5 return on_insert_content_encoding(v); 433   5 return on_insert_content_encoding(v);
HITCBC 434   4521 case field::content_length: 434   4527 case field::content_length:
HITCBC 435   4521 return on_insert_content_length(v); 435   4527 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   4411 case field::transfer_encoding: 440   4413 case field::transfer_encoding:
HITCBC 441   4411 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   4522 header:: 513   4528 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   4522 ++md.content_length.count; 522   4528 ++md.content_length.count;
HITCBC 523   4522 if(md.content_length.ec) 523   4528 if(md.content_length.ec)
HITCBC 524   4459 return; 524   4465 return;
525   auto rv = 525   auto rv =
HITCBC 526   4520 grammar::parse(v, num_rule); 526   4526 grammar::parse(v, num_rule);
HITCBC 527   4520 if(! rv) 527   4526 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   4515 if(md.content_length.count == 1) 537   4521 if(md.content_length.count == 1)
538   { 538   {
539   // one value 539   // one value
HITCBC 540   4445 md.content_length.ec = {}; 540   4451 md.content_length.ec = {};
HITCBC 541   4445 md.content_length.value = *rv; 541   4451 md.content_length.value = *rv;
HITCBC 542   4445 update_payload(); 542   4451 update_payload();
HITCBC 543   4445 return; 543   4451 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   4413 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   4413 ++md.transfer_encoding.count; 588   4415 ++md.transfer_encoding.count;
HITCBC 589   4413 if(md.transfer_encoding.ec) 589   4415 if(md.transfer_encoding.ec)
HITCBC 590   4405 return; 590   4407 return;
591   591  
592   auto rv = grammar::parse( 592   auto rv = grammar::parse(
HITCBC 593   4412 v, list_rule(transfer_coding_rule, 1)); 593   4414 v, list_rule(transfer_coding_rule, 1));
HITCBC 594   4412 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   8819 for(auto t : *rv) 599   8823 for(auto t : *rv)
600   { 600   {
HITCBC 601   4415 if(! md.transfer_encoding.is_chunked) 601   4417 if(! md.transfer_encoding.is_chunked)
602   { 602   {
HITCBC 603   4411 if(t.id == transfer_coding_rule_t::chunked) 603   4413 if(t.id == transfer_coding_rule_t::chunked)
HITCBC 604   4392 md.transfer_encoding.is_chunked = true; 604   4394 md.transfer_encoding.is_chunked = true;
HITCBC 605   4411 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   8827 } 614   8831 }
HITCBC 615   4404 update_payload(); 615   4406 update_payload();
HITCBC 616   4404 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   4412 } 624   4414 }
625   625  
626   void 626   void
HITCBC 627   5 header:: 627   5 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   5 ++md.content_encoding.count; 631   5 ++md.content_encoding.count;
HITCBC 632   5 if(md.content_encoding.ec) 632   5 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   5 v, list_rule(token_rule, 1)); 636   5 v, list_rule(token_rule, 1));
HITCBC 637   5 if(!rv) 637   5 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   4 if(rv->size() > 1 || md.content_encoding.count > 1) 647   4 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   4 if(grammar::ci_is_equal( 654   4 if(grammar::ci_is_equal(
HITCBC 655   4 *rv->begin(), "deflate")) 655   4 *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   4 else if(grammar::ci_is_equal( 660   4 else if(grammar::ci_is_equal(
HITCBC 661   4 *rv->begin(), "gzip")) 661   4 *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   }
MISUBC 666   else if(grammar::ci_is_equal( 666   else if(grammar::ci_is_equal(
MISUBC 667   *rv->begin(), "br")) 667   *rv->begin(), "br"))
668   { 668   {
MISUBC 669   md.content_encoding.coding = 669   md.content_encoding.coding =
670   content_coding::br; 670   content_coding::br;
671   } 671   }
672   else 672   else
673   { 673   {
MISUBC 674   md.content_encoding.coding = 674   md.content_encoding.coding =
675   content_coding::unknown; 675   content_coding::unknown;
676   } 676   }
HITCBC 677   5 } 677   5 }
678   678  
679   void 679   void
HITCBC 680   26 header:: 680   26 header::
681   on_insert_upgrade( 681   on_insert_upgrade(
682   core::string_view v) 682   core::string_view v)
683   { 683   {
HITCBC 684   26 ++md.upgrade.count; 684   26 ++md.upgrade.count;
HITCBC 685   26 if(md.upgrade.ec) 685   26 if(md.upgrade.ec)
HITCBC 686   5 return; 686   5 return;
HITCBC 687   25 if( version != 687   25 if( version !=
688   http::version::http_1_1) 688   http::version::http_1_1)
689   { 689   {
HITCBC 690   1 md.upgrade.ec = 690   1 md.upgrade.ec =
HITCBC 691   2 BOOST_HTTP_ERR( 691   2 BOOST_HTTP_ERR(
692   error::bad_upgrade); 692   error::bad_upgrade);
HITCBC 693   1 md.upgrade.websocket = false; 693   1 md.upgrade.websocket = false;
HITCBC 694   1 return; 694   1 return;
695   } 695   }
696   auto rv = grammar::parse( 696   auto rv = grammar::parse(
HITCBC 697   24 v, upgrade_rule); 697   24 v, upgrade_rule);
HITCBC 698   24 if(! rv) 698   24 if(! rv)
699   { 699   {
HITCBC 700   3 md.upgrade.ec = 700   3 md.upgrade.ec =
HITCBC 701   6 BOOST_HTTP_ERR( 701   6 BOOST_HTTP_ERR(
702   error::bad_upgrade); 702   error::bad_upgrade);
HITCBC 703   3 md.upgrade.websocket = false; 703   3 md.upgrade.websocket = false;
HITCBC 704   3 return; 704   3 return;
705   } 705   }
HITCBC 706   21 if(! md.upgrade.websocket) 706   21 if(! md.upgrade.websocket)
707   { 707   {
HITCBC 708   23 for(auto t : *rv) 708   23 for(auto t : *rv)
709   { 709   {
HITCBC 710   16 if( grammar::ci_is_equal( 710   16 if( grammar::ci_is_equal(
HITCBC 711   26 t.name, "websocket") && 711   26 t.name, "websocket") &&
HITCBC 712   10 t.version.empty()) 712   10 t.version.empty())
713   { 713   {
HITCBC 714   9 md.upgrade.websocket = true; 714   9 md.upgrade.websocket = true;
HITCBC 715   9 break; 715   9 break;
716   } 716   }
717   } 717   }
718   } 718   }
HITCBC 719   24 } 719   24 }
720   720  
721   //------------------------------------------------ 721   //------------------------------------------------
722   722  
723   void 723   void
HITCBC 724   9 header:: 724   9 header::
725   on_erase_connection() 725   on_erase_connection()
726   { 726   {
HITCBC 727   9 BOOST_ASSERT( 727   9 BOOST_ASSERT(
728   md.connection.count > 0); 728   md.connection.count > 0);
729   // reset and re-insert 729   // reset and re-insert
HITCBC 730   9 auto n = md.connection.count - 1; 730   9 auto n = md.connection.count - 1;
HITCBC 731   9 auto const p = cbuf + prefix; 731   9 auto const p = cbuf + prefix;
HITCBC 732   9 auto const* e = &tab()[0]; 732   9 auto const* e = &tab()[0];
HITCBC 733   9 md.connection = {}; 733   9 md.connection = {};
HITCBC 734   17 while(n > 0) 734   17 while(n > 0)
735   { 735   {
HITCBC 736   8 if(e->id == field::connection) 736   8 if(e->id == field::connection)
737   { 737   {
HITCBC 738   7 on_insert_connection( 738   7 on_insert_connection(
739   core::string_view( 739   core::string_view(
HITCBC 740   7 p + e->vp, e->vn)); 740   7 p + e->vp, e->vn));
HITCBC 741   7 --n; 741   7 --n;
742   } 742   }
HITCBC 743   8 --e; 743   8 --e;
744   } 744   }
HITCBC 745   9 } 745   9 }
746   746  
747   void 747   void
HITCBC 748   4 header:: 748   4 header::
749   on_erase_content_length() 749   on_erase_content_length()
750   { 750   {
HITCBC 751   4 BOOST_ASSERT( 751   4 BOOST_ASSERT(
752   md.content_length.count > 0); 752   md.content_length.count > 0);
HITCBC 753   4 --md.content_length.count; 753   4 --md.content_length.count;
HITCBC 754   4 if(md.content_length.count == 0) 754   4 if(md.content_length.count == 0)
755   { 755   {
756   // no Content-Length 756   // no Content-Length
HITCBC 757   1 md.content_length = {}; 757   1 md.content_length = {};
HITCBC 758   1 update_payload(); 758   1 update_payload();
HITCBC 759   1 return; 759   1 return;
760   } 760   }
HITCBC 761   3 if(! md.content_length.ec) 761   3 if(! md.content_length.ec)
762   { 762   {
763   // removing a duplicate value 763   // removing a duplicate value
HITCBC 764   2 return; 764   2 return;
765   } 765   }
766   // reset and re-insert 766   // reset and re-insert
HITCBC 767   1 auto n = md.content_length.count; 767   1 auto n = md.content_length.count;
HITCBC 768   1 auto const p = cbuf + prefix; 768   1 auto const p = cbuf + prefix;
HITCBC 769   1 auto const* e = &tab()[0]; 769   1 auto const* e = &tab()[0];
HITCBC 770   1 md.content_length = {}; 770   1 md.content_length = {};
HITCBC 771   2 while(n > 0) 771   2 while(n > 0)
772   { 772   {
HITCBC 773   1 if(e->id == field::content_length) 773   1 if(e->id == field::content_length)
774   { 774   {
HITCBC 775   1 on_insert_content_length( 775   1 on_insert_content_length(
776   core::string_view( 776   core::string_view(
HITCBC 777   1 p + e->vp, e->vn)); 777   1 p + e->vp, e->vn));
HITCBC 778   1 --n; 778   1 --n;
779   } 779   }
HITCBC 780   1 --e; 780   1 --e;
781   } 781   }
HITCBC 782   1 update_payload(); 782   1 update_payload();
783   } 783   }
784   784  
785   void 785   void
HITCBC 786   10 header:: 786   10 header::
787   on_erase_expect() 787   on_erase_expect()
788   { 788   {
HITCBC 789   10 BOOST_ASSERT( 789   10 BOOST_ASSERT(
790   md.expect.count > 0); 790   md.expect.count > 0);
HITCBC 791   10 --md.expect.count; 791   10 --md.expect.count;
HITCBC 792   10 if(kind != detail::kind::request) 792   10 if(kind != detail::kind::request)
HITCBC 793   1 return; 793   1 return;
HITCBC 794   9 if(md.expect.count == 0) 794   9 if(md.expect.count == 0)
795   { 795   {
796   // no Expect 796   // no Expect
HITCBC 797   3 md.expect = {}; 797   3 md.expect = {};
HITCBC 798   3 return; 798   3 return;
799   } 799   }
800   // VFALCO This should be uncommented 800   // VFALCO This should be uncommented
801   // if we want to allow multiple Expect 801   // if we want to allow multiple Expect
802   // fields with the value 100-continue 802   // fields with the value 100-continue
803   /* 803   /*
804   if(! md.expect.ec) 804   if(! md.expect.ec)
805   return; 805   return;
806   */ 806   */
807   // reset and re-insert 807   // reset and re-insert
HITCBC 808   6 auto n = md.expect.count; 808   6 auto n = md.expect.count;
HITCBC 809   6 auto const p = cbuf + prefix; 809   6 auto const p = cbuf + prefix;
HITCBC 810   6 auto const* e = &tab()[0]; 810   6 auto const* e = &tab()[0];
HITCBC 811   6 md.expect = {}; 811   6 md.expect = {};
HITCBC 812   18 while(n > 0) 812   18 while(n > 0)
813   { 813   {
HITCBC 814   12 if(e->id == field::expect) 814   12 if(e->id == field::expect)
815   { 815   {
HITCBC 816   6 on_insert_expect( 816   6 on_insert_expect(
817   core::string_view( 817   core::string_view(
HITCBC 818   6 p + e->vp, e->vn)); 818   6 p + e->vp, e->vn));
HITCBC 819   6 --n; 819   6 --n;
820   } 820   }
HITCBC 821   12 --e; 821   12 --e;
822   } 822   }
823   } 823   }
824   824  
825   void 825   void
HITCBC 826   4 header:: 826   4 header::
827   on_erase_transfer_encoding() 827   on_erase_transfer_encoding()
828   { 828   {
HITCBC 829   4 BOOST_ASSERT( 829   4 BOOST_ASSERT(
830   md.transfer_encoding.count > 0); 830   md.transfer_encoding.count > 0);
831   // reset and re-insert 831   // reset and re-insert
HITCBC 832   4 auto n = md.transfer_encoding.count - 1; 832   4 auto n = md.transfer_encoding.count - 1;
HITCBC 833   4 auto const p = cbuf + prefix; 833   4 auto const p = cbuf + prefix;
HITCBC 834   4 auto const* e = &tab()[0]; 834   4 auto const* e = &tab()[0];
HITCBC 835   4 md.transfer_encoding = {}; 835   4 md.transfer_encoding = {};
HITCBC 836   7 while(n > 0) 836   7 while(n > 0)
837   { 837   {
HITCBC 838   3 if(e->id == field::transfer_encoding) 838   3 if(e->id == field::transfer_encoding)
839   { 839   {
HITCBC 840   2 on_insert_transfer_encoding( 840   2 on_insert_transfer_encoding(
841   core::string_view( 841   core::string_view(
HITCBC 842   2 p + e->vp, e->vn)); 842   2 p + e->vp, e->vn));
HITCBC 843   2 --n; 843   2 --n;
844   } 844   }
HITCBC 845   3 --e; 845   3 --e;
846   } 846   }
HITCBC 847   4 } 847   4 }
848   848  
849   void 849   void
MISUBC 850   header:: 850   header::
851   on_erase_content_encoding() 851   on_erase_content_encoding()
852   { 852   {
MISUBC 853   BOOST_ASSERT( 853   BOOST_ASSERT(
854   md.content_encoding.count > 0); 854   md.content_encoding.count > 0);
MISUBC 855   --md.content_encoding.count; 855   --md.content_encoding.count;
MISUBC 856   if(md.content_encoding.count == 0) 856   if(md.content_encoding.count == 0)
857   { 857   {
858   // no Content-Encoding 858   // no Content-Encoding
MISUBC 859   md.content_encoding = {}; 859   md.content_encoding = {};
MISUBC 860   return; 860   return;
861   } 861   }
862   // re-insert everything 862   // re-insert everything
MISUBC 863   --md.content_encoding.count; 863   --md.content_encoding.count;
864   // TODO 864   // TODO
865   // on_insert_content_encoding(); 865   // on_insert_content_encoding();
866   } 866   }
867   867  
868   // called when Upgrade is erased 868   // called when Upgrade is erased
869   void 869   void
HITCBC 870   4 header:: 870   4 header::
871   on_erase_upgrade() 871   on_erase_upgrade()
872   { 872   {
HITCBC 873   4 BOOST_ASSERT( 873   4 BOOST_ASSERT(
874   md.upgrade.count > 0); 874   md.upgrade.count > 0);
HITCBC 875   4 --md.upgrade.count; 875   4 --md.upgrade.count;
HITCBC 876   4 if(md.upgrade.count == 0) 876   4 if(md.upgrade.count == 0)
877   { 877   {
878   // no Upgrade 878   // no Upgrade
HITCBC 879   2 md.upgrade = {}; 879   2 md.upgrade = {};
HITCBC 880   2 return; 880   2 return;
881   } 881   }
882   // reset and re-insert 882   // reset and re-insert
HITCBC 883   2 auto n = md.upgrade.count; 883   2 auto n = md.upgrade.count;
HITCBC 884   2 auto const p = cbuf + prefix; 884   2 auto const p = cbuf + prefix;
HITCBC 885   2 auto const* e = &tab()[0]; 885   2 auto const* e = &tab()[0];
HITCBC 886   2 md.upgrade = {}; 886   2 md.upgrade = {};
HITCBC 887   4 while(n > 0) 887   4 while(n > 0)
888   { 888   {
HITCBC 889   2 if(e->id == field::upgrade) 889   2 if(e->id == field::upgrade)
HITCBC 890   2 on_insert_upgrade( 890   2 on_insert_upgrade(
891   core::string_view( 891   core::string_view(
HITCBC 892   2 p + e->vp, e->vn)); 892   2 p + e->vp, e->vn));
HITCBC 893   2 --n; 893   2 --n;
HITCBC 894   2 --e; 894   2 --e;
895   } 895   }
896   } 896   }
897   897  
898   //------------------------------------------------ 898   //------------------------------------------------
899   899  
900   // called when all fields with id are removed 900   // called when all fields with id are removed
901   void 901   void
HITCBC 902   72 header:: 902   72 header::
903   on_erase_all( 903   on_erase_all(
904   field id) 904   field id)
905   { 905   {
HITCBC 906   72 if(kind == detail::kind::fields) 906   72 if(kind == detail::kind::fields)
HITCBC 907   21 return; 907   21 return;
HITCBC 908   51 switch(id) 908   51 switch(id)
909   { 909   {
HITCBC 910   3 case field::connection: 910   3 case field::connection:
HITCBC 911   3 md.connection = {}; 911   3 md.connection = {};
HITCBC 912   3 return; 912   3 return;
913   913  
HITCBC 914   2 case field::content_length: 914   2 case field::content_length:
HITCBC 915   2 md.content_length = {}; 915   2 md.content_length = {};
HITCBC 916   2 update_payload(); 916   2 update_payload();
HITCBC 917   2 return; 917   2 return;
918   918  
HITCBC 919   5 case field::expect: 919   5 case field::expect:
HITCBC 920   5 md.expect = {}; 920   5 md.expect = {};
HITCBC 921   5 update_payload(); 921   5 update_payload();
HITCBC 922   5 return; 922   5 return;
923   923  
HITCBC 924   1 case field::transfer_encoding: 924   1 case field::transfer_encoding:
HITCBC 925   1 md.transfer_encoding = {}; 925   1 md.transfer_encoding = {};
HITCBC 926   1 update_payload(); 926   1 update_payload();
HITCBC 927   1 return; 927   1 return;
928   928  
HITCBC 929   1 case field::upgrade: 929   1 case field::upgrade:
HITCBC 930   1 md.upgrade = {}; 930   1 md.upgrade = {};
HITCBC 931   1 return; 931   1 return;
932   932  
HITCBC 933   39 default: 933   39 default:
HITCBC 934   39 break; 934   39 break;
935   } 935   }
936   } 936   }
937   937  
938   //------------------------------------------------ 938   //------------------------------------------------
939   939  
940   /* References: 940   /* References:
941   941  
942   3.3. Message Body 942   3.3. Message Body
943   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3 943   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3
944   944  
945   3.3.1. Transfer-Encoding 945   3.3.1. Transfer-Encoding
946   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1 946   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.1
947   947  
948   3.3.2. Content-Length 948   3.3.2. Content-Length
949   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2 949   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
950   */ 950   */
951   void 951   void
HITCBC 952   19520 header:: 952   19537 header::
953   update_payload() noexcept 953   update_payload() noexcept
954   { 954   {
HITCBC 955   19520 BOOST_ASSERT(kind != 955   19537 BOOST_ASSERT(kind !=
956   detail::kind::fields); 956   detail::kind::fields);
HITCBC 957   19520 if(md.payload_override) 957   19537 if(md.payload_override)
958   { 958   {
959   // e.g. response to 959   // e.g. response to
960   // a HEAD request 960   // a HEAD request
MISUBC 961   return; 961   return;
962   } 962   }
963   963  
964   /* If there is an error in either Content-Length 964   /* If there is an error in either Content-Length
965   or Transfer-Encoding, then the payload is 965   or Transfer-Encoding, then the payload is
966   undefined. Clients should probably close the 966   undefined. Clients should probably close the
967   connection. Servers can send a Bad Request 967   connection. Servers can send a Bad Request
968   and avoid reading any payload bytes. 968   and avoid reading any payload bytes.
969   */ 969   */
HITCBC 970   19520 if(md.content_length.ec) 970   19537 if(md.content_length.ec)
971   { 971   {
972   // invalid Content-Length 972   // invalid Content-Length
HITCBC 973   68 md.payload = payload::error; 973   68 md.payload = payload::error;
HITCBC 974   68 md.payload_size = 0; 974   68 md.payload_size = 0;
HITCBC 975   68 return; 975   68 return;
976   } 976   }
HITCBC 977   19452 if(md.transfer_encoding.ec) 977   19469 if(md.transfer_encoding.ec)
978   { 978   {
979   // invalid Transfer-Encoding 979   // invalid Transfer-Encoding
HITCBC 980   8 md.payload = payload::error; 980   8 md.payload = payload::error;
HITCBC 981   8 md.payload_size = 0; 981   8 md.payload_size = 0;
HITCBC 982   8 return; 982   8 return;
983   } 983   }
984   984  
985   /* A sender MUST NOT send a Content-Length 985   /* A sender MUST NOT send a Content-Length
986   header field in any message that contains 986   header field in any message that contains
987   a Transfer-Encoding header field. 987   a Transfer-Encoding header field.
988   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2 988   https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.2
989   */ 989   */
HITCBC 990   19444 if( md.content_length.count > 0 && 990   19461 if( md.content_length.count > 0 &&
HITCBC 991   4449 md.transfer_encoding.count > 0) 991   4455 md.transfer_encoding.count > 0)
992   { 992   {
HITCBC 993   3 md.payload = payload::error; 993   3 md.payload = payload::error;
HITCBC 994   3 md.payload_size = 0; 994   3 md.payload_size = 0;
HITCBC 995   3 return; 995   3 return;
996   } 996   }
997   997  
HITCBC 998   19441 if(kind == detail::kind::response) 998   19458 if(kind == detail::kind::response)
HITCBC 999   1805 goto do_response; 999   1822 goto do_response;
1000   1000  
1001   //-------------------------------------------- 1001   //--------------------------------------------
1002   1002  
1003   /* The presence of a message body in a 1003   /* The presence of a message body in a
1004   request is signaled by a Content-Length 1004   request is signaled by a Content-Length
1005   or Transfer-Encoding header field. Request 1005   or Transfer-Encoding header field. Request
1006   message framing is independent of method 1006   message framing is independent of method
1007   semantics, even if the method does not 1007   semantics, even if the method does not
1008   define any use for a message body. 1008   define any use for a message body.
1009   */ 1009   */
HITCBC 1010   17636 if(md.content_length.count > 0) 1010   17636 if(md.content_length.count > 0)
1011   { 1011   {
HITCBC 1012   4177 if(md.content_length.value > 0) 1012   4177 if(md.content_length.value > 0)
1013   { 1013   {
1014   // non-zero Content-Length 1014   // non-zero Content-Length
HITCBC 1015   4150 md.payload = payload::size; 1015   4150 md.payload = payload::size;
HITCBC 1016   4150 md.payload_size = md.content_length.value; 1016   4150 md.payload_size = md.content_length.value;
HITCBC 1017   4150 return; 1017   4150 return;
1018   } 1018   }
1019   // Content-Length: 0 1019   // Content-Length: 0
HITCBC 1020   27 md.payload = payload::none; 1020   27 md.payload = payload::none;
HITCBC 1021   27 md.payload_size = 0; 1021   27 md.payload_size = 0;
HITCBC 1022   27 return; 1022   27 return;
1023   } 1023   }
HITCBC 1024   13459 if(md.transfer_encoding.is_chunked) 1024   13459 if(md.transfer_encoding.is_chunked)
1025   { 1025   {
1026   // chunked 1026   // chunked
HITCBC 1027   4012 md.payload = payload::chunked; 1027   4012 md.payload = payload::chunked;
HITCBC 1028   4012 md.payload_size = 0; 1028   4012 md.payload_size = 0;
HITCBC 1029   4012 return; 1029   4012 return;
1030   } 1030   }
1031   // no payload 1031   // no payload
HITCBC 1032   9447 md.payload = payload::none; 1032   9447 md.payload = payload::none;
HITCBC 1033   9447 md.payload_size = 0; 1033   9447 md.payload_size = 0;
HITCBC 1034   9447 return; 1034   9447 return;
1035   1035  
1036   //-------------------------------------------- 1036   //--------------------------------------------
HITCBC 1037   1805 do_response: 1037   1822 do_response:
1038   1038  
HITCBC 1039   1805 if( res.status_int / 100 == 1 || // 1xx e.g. Continue 1039   1822 if( res.status_int / 100 == 1 || // 1xx e.g. Continue
HITCBC 1040   1794 res.status_int == 204 || // No Content 1040   1811 res.status_int == 204 || // No Content
HITCBC 1041   1792 res.status_int == 304) // Not Modified 1041   1808 res.status_int == 304) // Not Modified
1042   { 1042   {
1043   /* The correctness of any Content-Length 1043   /* The correctness of any Content-Length
1044   here is defined by the particular 1044   here is defined by the particular
1045   resource, and cannot be determined 1045   resource, and cannot be determined
1046   here. In any case there is no payload. 1046   here. In any case there is no payload.
1047   */ 1047   */
HITCBC 1048   15 md.payload = payload::none; 1048   16 md.payload = payload::none;
HITCBC 1049   15 md.payload_size = 0; 1049   16 md.payload_size = 0;
HITCBC 1050   15 return; 1050   16 return;
1051   } 1051   }
HITCBC 1052   1790 if(md.content_length.count > 0) 1052   1806 if(md.content_length.count > 0)
1053   { 1053   {
HITCBC 1054   266 if(md.content_length.value > 0) 1054   272 if(md.content_length.value > 0)
1055   { 1055   {
1056   // Content-Length > 0 1056   // Content-Length > 0
HITCBC 1057   247 md.payload = payload::size; 1057   253 md.payload = payload::size;
HITCBC 1058   247 md.payload_size = md.content_length.value; 1058   253 md.payload_size = md.content_length.value;
HITCBC 1059   247 return; 1059   253 return;
1060   } 1060   }
1061   // Content-Length: 0 1061   // Content-Length: 0
HITCBC 1062   19 md.payload = payload::none; 1062   19 md.payload = payload::none;
HITCBC 1063   19 md.payload_size = 0; 1063   19 md.payload_size = 0;
HITCBC 1064   19 return; 1064   19 return;
1065   } 1065   }
HITCBC 1066   1524 if(md.transfer_encoding.is_chunked) 1066   1534 if(md.transfer_encoding.is_chunked)
1067   { 1067   {
1068   // chunked 1068   // chunked
HITCBC 1069   375 md.payload = payload::chunked; 1069   377 md.payload = payload::chunked;
HITCBC 1070   375 md.payload_size = 0; 1070   377 md.payload_size = 0;
HITCBC 1071   375 return; 1071   377 return;
1072   } 1072   }
1073   1073  
1074   // eof needed 1074   // eof needed
HITCBC 1075   1149 md.payload = payload::to_eof; 1075   1157 md.payload = payload::to_eof;
HITCBC 1076   1149 md.payload_size = 0; 1076   1157 md.payload_size = 0;
1077   } 1077   }
1078   1078  
1079   //------------------------------------------------ 1079   //------------------------------------------------
1080   1080  
1081   std::size_t 1081   std::size_t
HITCBC 1082   547 header:: 1082   547 header::
1083   count_crlf( 1083   count_crlf(
1084   core::string_view s) noexcept 1084   core::string_view s) noexcept
1085   { 1085   {
HITCBC 1086   547 auto it = s.data(); 1086   547 auto it = s.data();
HITCBC 1087   547 auto len = s.size(); 1087   547 auto len = s.size();
HITCBC 1088   547 std::size_t n = 0; 1088   547 std::size_t n = 0;
HITCBC 1089   19042 while(len >= 2) 1089   19042 while(len >= 2)
1090   { 1090   {
HITCBC 1091   18495 if( it[0] == '\r' && 1091   18495 if( it[0] == '\r' &&
HITCBC 1092   1743 it[1] != '\r') 1092   1743 it[1] != '\r')
1093   { 1093   {
HITCBC 1094   1743 if(it[1] == '\n') 1094   1743 if(it[1] == '\n')
HITCBC 1095   1743 n++; 1095   1743 n++;
HITCBC 1096   1743 it += 2; 1096   1743 it += 2;
HITCBC 1097   1743 len -= 2; 1097   1743 len -= 2;
1098   } 1098   }
1099   else 1099   else
1100   { 1100   {
HITCBC 1101   16752 it++; 1101   16752 it++;
HITCBC 1102   16752 len--; 1102   16752 len--;
1103   } 1103   }
1104   } 1104   }
HITCBC 1105   547 return n; 1105   547 return n;
1106   } 1106   }
1107   1107  
1108   static 1108   static
1109   void 1109   void
HITCBC 1110   27530 parse_start_line( 1110   27539 parse_start_line(
1111   header& h, 1111   header& h,
1112   header_limits const& lim, 1112   header_limits const& lim,
1113   std::size_t new_size, 1113   std::size_t new_size,
1114   system::error_code& ec) noexcept 1114   system::error_code& ec) noexcept
1115   { 1115   {
HITCBC 1116   27530 BOOST_ASSERT(h.size == 0); 1116   27539 BOOST_ASSERT(h.size == 0);
HITCBC 1117   27530 BOOST_ASSERT(h.prefix == 0); 1117   27539 BOOST_ASSERT(h.prefix == 0);
HITCBC 1118   27530 BOOST_ASSERT(h.cbuf != nullptr); 1118   27539 BOOST_ASSERT(h.cbuf != nullptr);
HITCBC 1119   27530 BOOST_ASSERT( 1119   27539 BOOST_ASSERT(
1120   h.kind != detail::kind::fields); 1120   h.kind != detail::kind::fields);
1121   1121  
HITCBC 1122   27530 auto const it0 = h.cbuf; 1122   27539 auto const it0 = h.cbuf;
HITCBC 1123   27530 auto const end = it0 + new_size; 1123   27539 auto const end = it0 + new_size;
HITCBC 1124   27530 char const* it = it0; 1124   27539 char const* it = it0;
HITCBC 1125   27530 if( new_size > lim.max_start_line) 1125   27539 if( new_size > lim.max_start_line)
HITCBC 1126   10 new_size = lim.max_start_line; 1126   10 new_size = lim.max_start_line;
HITCBC 1127   27530 if(h.kind == detail::kind::request) 1127   27539 if(h.kind == detail::kind::request)
1128   { 1128   {
1129   auto rv = grammar::parse( 1129   auto rv = grammar::parse(
HITCBC 1130   11373 it, end, request_line_rule); 1130   11373 it, end, request_line_rule);
HITCBC 1131   11373 if(! rv) 1131   11373 if(! rv)
1132   { 1132   {
HITCBC 1133   1991 ec = rv.error(); 1133   1991 ec = rv.error();
HITCBC 1134   3982 if( ec == grammar::error::need_more && 1134   3982 if( ec == grammar::error::need_more &&
HITCBC 1135   1991 new_size == lim.max_start_line) 1135   1991 new_size == lim.max_start_line)
MISUBC 1136   ec = BOOST_HTTP_ERR( 1136   ec = BOOST_HTTP_ERR(
1137   error::start_line_limit); 1137   error::start_line_limit);
HITCBC 1138   1991 return; 1138   1991 return;
1139   } 1139   }
1140   // method 1140   // method
HITCBC 1141   9382 auto sm = std::get<0>(*rv); 1141   9382 auto sm = std::get<0>(*rv);
HITCBC 1142   9382 h.req.method = string_to_method(sm); 1142   9382 h.req.method = string_to_method(sm);
HITCBC 1143   9382 h.req.method_len = 1143   9382 h.req.method_len =
HITCBC 1144   9382 static_cast<header::offset_type>(sm.size()); 1144   9382 static_cast<header::offset_type>(sm.size());
1145   // target 1145   // target
HITCBC 1146   9382 auto st = std::get<1>(*rv); 1146   9382 auto st = std::get<1>(*rv);
HITCBC 1147   9382 h.req.target_len = 1147   9382 h.req.target_len =
HITCBC 1148   9382 static_cast<header::offset_type>(st.size()); 1148   9382 static_cast<header::offset_type>(st.size());
1149   // version 1149   // version
HITCBC 1150   9382 switch(std::get<2>(*rv)) 1150   9382 switch(std::get<2>(*rv))
1151   { 1151   {
HITCBC 1152   25 case 10: 1152   25 case 10:
HITCBC 1153   25 h.version = 1153   25 h.version =
1154   http::version::http_1_0; 1154   http::version::http_1_0;
HITCBC 1155   25 break; 1155   25 break;
HITCBC 1156   9357 case 11: 1156   9357 case 11:
HITCBC 1157   9357 h.version = 1157   9357 h.version =
1158   http::version::http_1_1; 1158   http::version::http_1_1;
HITCBC 1159   9357 break; 1159   9357 break;
MISUBC 1160   default: 1160   default:
1161   { 1161   {
MISUBC 1162   ec = BOOST_HTTP_ERR( 1162   ec = BOOST_HTTP_ERR(
1163   error::bad_version); 1163   error::bad_version);
MISUBC 1164   return; 1164   return;
1165   } 1165   }
1166   } 1166   }
1167   } 1167   }
1168   else 1168   else
1169   { 1169   {
1170   auto rv = grammar::parse( 1170   auto rv = grammar::parse(
HITCBC 1171   16157 it, end, status_line_rule); 1171   16166 it, end, status_line_rule);
HITCBC 1172   16157 if(! rv) 1172   16166 if(! rv)
1173   { 1173   {
HITCBC 1174   15022 ec = rv.error(); 1174   15022 ec = rv.error();
HITCBC 1175   30044 if( ec == grammar::error::need_more && 1175   30044 if( ec == grammar::error::need_more &&
HITCBC 1176   15022 new_size == lim.max_start_line) 1176   15022 new_size == lim.max_start_line)
MISUBC 1177   ec = BOOST_HTTP_ERR( 1177   ec = BOOST_HTTP_ERR(
1178   error::start_line_limit); 1178   error::start_line_limit);
HITCBC 1179   15022 return; 1179   15022 return;
1180   } 1180   }
1181   // version 1181   // version
HITCBC 1182   1135 switch(std::get<0>(*rv)) 1182   1144 switch(std::get<0>(*rv))
1183   { 1183   {
HITCBC 1184   4 case 10: 1184   4 case 10:
HITCBC 1185   4 h.version = 1185   4 h.version =
1186   http::version::http_1_0; 1186   http::version::http_1_0;
HITCBC 1187   4 break; 1187   4 break;
HITCBC 1188   1131 case 11: 1188   1140 case 11:
HITCBC 1189   1131 h.version = 1189   1140 h.version =
1190   http::version::http_1_1; 1190   http::version::http_1_1;
HITCBC 1191   1131 break; 1191   1140 break;
MISUBC 1192   default: 1192   default:
1193   { 1193   {
MISUBC 1194   ec = BOOST_HTTP_ERR( 1194   ec = BOOST_HTTP_ERR(
1195   error::bad_version); 1195   error::bad_version);
MISUBC 1196   return; 1196   return;
1197   } 1197   }
1198   } 1198   }
1199   // status-code 1199   // status-code
HITCBC 1200   1135 h.res.status_int = 1200   1144 h.res.status_int =
1201   static_cast<unsigned short>( 1201   static_cast<unsigned short>(
HITCBC 1202   1135 std::get<1>(*rv).v); 1202   1144 std::get<1>(*rv).v);
HITCBC 1203   1135 h.res.status = std::get<1>(*rv).st; 1203   1144 h.res.status = std::get<1>(*rv).st;
1204   } 1204   }
HITCBC 1205   10517 h.prefix = static_cast<header::offset_type>(it - it0); 1205   10526 h.prefix = static_cast<header::offset_type>(it - it0);
HITCBC 1206   10517 h.size = h.prefix; 1206   10526 h.size = h.prefix;
HITCBC 1207   10517 h.on_start_line(); 1207   10526 h.on_start_line();
1208   } 1208   }
1209   1209  
1210   // returns: true if we added a field 1210   // returns: true if we added a field
1211   static 1211   static
1212   void 1212   void
HITCBC 1213   36543 parse_field( 1213   36560 parse_field(
1214   header& h, 1214   header& h,
1215   header_limits const& lim, 1215   header_limits const& lim,
1216   std::size_t new_size, 1216   std::size_t new_size,
1217   system::error_code& ec) noexcept 1217   system::error_code& ec) noexcept
1218   { 1218   {
HITCBC 1219   36543 if( new_size > lim.max_field) 1219   36560 if( new_size > lim.max_field)
HITCBC 1220   20 new_size = lim.max_field; 1220   20 new_size = lim.max_field;
HITCBC 1221   36543 auto const it0 = h.cbuf + h.size; 1221   36560 auto const it0 = h.cbuf + h.size;
HITCBC 1222   36543 auto const end = h.cbuf + new_size; 1222   36560 auto const end = h.cbuf + new_size;
HITCBC 1223   36543 char const* it = it0; 1223   36560 char const* it = it0;
HITCBC 1224   36543 auto rv = grammar::parse( 1224   36560 auto rv = grammar::parse(
1225   it, end, field_rule); 1225   it, end, field_rule);
HITCBC 1226   36543 if(rv.has_error()) 1226   36560 if(rv.has_error())
1227   { 1227   {
HITCBC 1228   25869 ec = rv.error(); 1228   25878 ec = rv.error();
HITCBC 1229   25869 if(ec == grammar::error::end_of_range) 1229   25878 if(ec == grammar::error::end_of_range)
1230   { 1230   {
1231   // final CRLF 1231   // final CRLF
HITCBC 1232   10092 h.size = static_cast< 1232   10101 h.size = static_cast<
HITCBC 1233   10092 header::offset_type>(it - h.cbuf); 1233   10101 header::offset_type>(it - h.cbuf);
HITCBC 1234   25869 return; 1234   25878 return;
1235   } 1235   }
HITCBC 1236   31295 if( ec == grammar::error::need_more && 1236   31295 if( ec == grammar::error::need_more &&
HITCBC 1237   15518 new_size == lim.max_field) 1237   15518 new_size == lim.max_field)
1238   { 1238   {
MISUBC 1239   ec = BOOST_HTTP_ERR( 1239   ec = BOOST_HTTP_ERR(
1240   error::field_size_limit); 1240   error::field_size_limit);
1241   } 1241   }
HITCBC 1242   15777 return; 1242   15777 return;
1243   } 1243   }
HITCBC 1244   10674 if(h.count >= lim.max_fields) 1244   10682 if(h.count >= lim.max_fields)
1245   { 1245   {
MISUBC 1246   ec = BOOST_HTTP_ERR( 1246   ec = BOOST_HTTP_ERR(
1247   error::fields_limit); 1247   error::fields_limit);
MISUBC 1248   return; 1248   return;
1249   } 1249   }
HITCBC 1250   10674 if(rv->has_obs_fold) 1250   10682 if(rv->has_obs_fold)
1251   { 1251   {
1252   // obs fold not allowed in test views 1252   // obs fold not allowed in test views
HITCBC 1253   210 BOOST_ASSERT(h.buf != nullptr); 1253   210 BOOST_ASSERT(h.buf != nullptr);
HITCBC 1254   210 remove_obs_fold(h.buf + h.size, it); 1254   210 remove_obs_fold(h.buf + h.size, it);
1255   } 1255   }
HITCBC 1256   10674 auto id = string_to_field(rv->name) 1256   10682 auto id = string_to_field(rv->name)
HITCBC 1257   10674 .value_or(header::unknown_field); 1257   10682 .value_or(header::unknown_field);
HITCBC 1258   10674 h.size = static_cast<header::offset_type>(it - h.cbuf); 1258   10682 h.size = static_cast<header::offset_type>(it - h.cbuf);
1259   1259  
1260   // add field table entry 1260   // add field table entry
HITCBC 1261   10674 if(h.buf != nullptr) 1261   10682 if(h.buf != nullptr)
1262   { 1262   {
HITCBC 1263   21348 auto& e = header::table( 1263   21364 auto& e = header::table(
HITCBC 1264   10674 h.buf + h.cap)[h.count]; 1264   10682 h.buf + h.cap)[h.count];
HITCBC 1265   10674 auto const base = 1265   10682 auto const base =
HITCBC 1266   10674 h.buf + h.prefix; 1266   10682 h.buf + h.prefix;
HITCBC 1267   10674 e.np = static_cast<header::offset_type>( 1267   10682 e.np = static_cast<header::offset_type>(
HITCBC 1268   10674 rv->name.data() - base); 1268   10682 rv->name.data() - base);
HITCBC 1269   10674 e.nn = static_cast<header::offset_type>( 1269   10682 e.nn = static_cast<header::offset_type>(
HITCBC 1270   10674 rv->name.size()); 1270   10682 rv->name.size());
HITCBC 1271   10674 e.vp = static_cast<header::offset_type>( 1271   10682 e.vp = static_cast<header::offset_type>(
HITCBC 1272   10674 rv->value.data() - base); 1272   10682 rv->value.data() - base);
HITCBC 1273   10674 e.vn = static_cast<header::offset_type>( 1273   10682 e.vn = static_cast<header::offset_type>(
HITCBC 1274   10674 rv->value.size()); 1274   10682 rv->value.size());
HITCBC 1275   10674 e.id = id; 1275   10682 e.id = id;
1276   } 1276   }
HITCBC 1277   10674 ++h.count; 1277   10682 ++h.count;
HITCBC 1278   10674 h.on_insert(id, rv->value); 1278   10682 h.on_insert(id, rv->value);
HITCBC 1279   10674 ec = {}; 1279   10682 ec = {};
1280   } 1280   }
1281   1281  
1282   void 1282   void
HITCBC 1283   42882 header:: 1283   42891 header::
1284   parse( 1284   parse(
1285   std::size_t new_size, 1285   std::size_t new_size,
1286   header_limits const& lim, 1286   header_limits const& lim,
1287   system::error_code& ec) noexcept 1287   system::error_code& ec) noexcept
1288   { 1288   {
HITCBC 1289   42882 if( new_size > lim.max_size) 1289   42891 if( new_size > lim.max_size)
HITCBC 1290   10 new_size = lim.max_size; 1290   10 new_size = lim.max_size;
HITCBC 1291   42882 if( this->prefix == 0 && 1291   42891 if( this->prefix == 0 &&
HITCBC 1292   27764 this->kind != 1292   27773 this->kind !=
1293   detail::kind::fields) 1293   detail::kind::fields)
1294   { 1294   {
HITCBC 1295   27530 parse_start_line( 1295   27539 parse_start_line(
1296   *this, lim, new_size, ec); 1296   *this, lim, new_size, ec);
HITCBC 1297   27530 if(ec) 1297   27539 if(ec)
1298   { 1298   {
HITCBC 1299   34026 if( ec == grammar::error::need_more && 1299   34026 if( ec == grammar::error::need_more &&
HITCBC 1300   17013 new_size == lim.max_fields) 1300   17013 new_size == lim.max_fields)
1301   { 1301   {
MISUBC 1302   ec = BOOST_HTTP_ERR( 1302   ec = BOOST_HTTP_ERR(
1303   error::headers_limit); 1303   error::headers_limit);
1304   } 1304   }
HITCBC 1305   17013 return; 1305   17013 return;
1306   } 1306   }
1307   } 1307   }
1308   for(;;) 1308   for(;;)
1309   { 1309   {
HITCBC 1310   36543 parse_field( 1310   36560 parse_field(
1311   *this, lim, new_size, ec); 1311   *this, lim, new_size, ec);
HITCBC 1312   36543 if(ec) 1312   36560 if(ec)
1313   { 1313   {
HITCBC 1314   41387 if( ec == grammar::error::need_more && 1314   41396 if( ec == grammar::error::need_more &&
HITCBC 1315   15518 new_size == lim.max_size) 1315   15518 new_size == lim.max_size)
1316   { 1316   {
MISUBC 1317   ec = BOOST_HTTP_ERR( 1317   ec = BOOST_HTTP_ERR(
1318   error::headers_limit); 1318   error::headers_limit);
MISUBC 1319   return; 1319   return;
1320   } 1320   }
HITCBC 1321   25869 break; 1321   25878 break;
1322   } 1322   }
HITCBC 1323   10674 } 1323   10682 }
HITCBC 1324   25869 if(ec == grammar::error::end_of_range) 1324   25878 if(ec == grammar::error::end_of_range)
HITCBC 1325   10092 ec = {}; 1325   10101 ec = {};
1326   } 1326   }
1327   1327  
1328   } // detail 1328   } // detail
1329   } // http 1329   } // http
1330   } // boost 1330   } // boost