77.87% Lines (535/687) 81.82% Functions (72/88)
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 <boost/http/detail/except.hpp> 11   #include <boost/http/detail/except.hpp>
12   #include <boost/http/detail/workspace.hpp> 12   #include <boost/http/detail/workspace.hpp>
13   #include <boost/http/error.hpp> 13   #include <boost/http/error.hpp>
14   #include <boost/http/parser.hpp> 14   #include <boost/http/parser.hpp>
15   #include <boost/http/static_request.hpp> 15   #include <boost/http/static_request.hpp>
16   #include <boost/http/static_response.hpp> 16   #include <boost/http/static_response.hpp>
17   17  
18   #include <boost/http/detail/circular_buffer.hpp> 18   #include <boost/http/detail/circular_buffer.hpp>
19   #include <boost/http/detail/flat_buffer.hpp> 19   #include <boost/http/detail/flat_buffer.hpp>
20   20  
21   #include <boost/assert.hpp> 21   #include <boost/assert.hpp>
22   #include <boost/capy/buffers/buffer_copy.hpp> 22   #include <boost/capy/buffers/buffer_copy.hpp>
23   #include <boost/capy/buffers/front.hpp> 23   #include <boost/capy/buffers/front.hpp>
24   #include <boost/capy/buffers/buffer_slice.hpp> 24   #include <boost/capy/buffers/buffer_slice.hpp>
25   #include <boost/capy/ex/system_context.hpp> 25   #include <boost/capy/ex/system_context.hpp>
26   #include <boost/http/brotli/decode.hpp> 26   #include <boost/http/brotli/decode.hpp>
27   #include <boost/http/zlib/error.hpp> 27   #include <boost/http/zlib/error.hpp>
28   #include <boost/http/zlib/inflate.hpp> 28   #include <boost/http/zlib/inflate.hpp>
29   #include <boost/url/grammar/ci_string.hpp> 29   #include <boost/url/grammar/ci_string.hpp>
30   #include <boost/url/grammar/error.hpp> 30   #include <boost/url/grammar/error.hpp>
31   #include <boost/url/grammar/hexdig_chars.hpp> 31   #include <boost/url/grammar/hexdig_chars.hpp>
32   32  
33   #include "src/detail/brotli_filter_base.hpp" 33   #include "src/detail/brotli_filter_base.hpp"
34   #include "src/detail/buffer_utils.hpp" 34   #include "src/detail/buffer_utils.hpp"
35   #include "src/detail/zlib_filter_base.hpp" 35   #include "src/detail/zlib_filter_base.hpp"
36   36  
37   #include <array> 37   #include <array>
38   #include <memory> 38   #include <memory>
39   39  
40   namespace boost { 40   namespace boost {
41   namespace http { 41   namespace http {
42   42  
43   /* 43   /*
44   Principles for fixed-size buffer design 44   Principles for fixed-size buffer design
45   45  
46   axiom 1: 46   axiom 1:
47   To read data you must have a buffer. 47   To read data you must have a buffer.
48   48  
49   axiom 2: 49   axiom 2:
50   The size of the HTTP header is not 50   The size of the HTTP header is not
51   known in advance. 51   known in advance.
52   52  
53   conclusion 3: 53   conclusion 3:
54   A single I/O can produce a complete 54   A single I/O can produce a complete
55   HTTP header and additional payload 55   HTTP header and additional payload
56   data. 56   data.
57   57  
58   conclusion 4: 58   conclusion 4:
59   A single I/O can produce multiple 59   A single I/O can produce multiple
60   complete HTTP headers, complete 60   complete HTTP headers, complete
61   payloads, and a partial header or 61   payloads, and a partial header or
62   payload. 62   payload.
63   63  
64   axiom 5: 64   axiom 5:
65   A process is in one of two states: 65   A process is in one of two states:
66   1. at or below capacity 66   1. at or below capacity
67   2. above capacity 67   2. above capacity
68   68  
69   axiom 6: 69   axiom 6:
70   A program which can allocate an 70   A program which can allocate an
71   unbounded number of resources can 71   unbounded number of resources can
72   go above capacity. 72   go above capacity.
73   73  
74   conclusion 7: 74   conclusion 7:
75   A program can guarantee never going 75   A program can guarantee never going
76   above capacity if all resources are 76   above capacity if all resources are
77   provisioned at program startup. 77   provisioned at program startup.
78   78  
79   corollary 8: 79   corollary 8:
80   `parser` and `serializer` should each 80   `parser` and `serializer` should each
81   allocate a single buffer of calculated 81   allocate a single buffer of calculated
82   size, and never resize it. 82   size, and never resize it.
83   83  
84   axiom #: 84   axiom #:
85   A parser and a serializer are always 85   A parser and a serializer are always
86   used in pairs. 86   used in pairs.
87   87  
88   Buffer Usage 88   Buffer Usage
89   89  
90   | | begin 90   | | begin
91   | H | p | | f | read headers 91   | H | p | | f | read headers
92   | H | p | | T | f | set T body 92   | H | p | | T | f | set T body
93   | H | p | | C | T | f | make codec C 93   | H | p | | C | T | f | make codec C
94   | H | p | b | C | T | f | decode p into b 94   | H | p | b | C | T | f | decode p into b
95   | H | p | b | C | T | f | read/parse loop 95   | H | p | b | C | T | f | read/parse loop
96   | H | | T | f | destroy codec 96   | H | | T | f | destroy codec
97   | H | | T | f | finished 97   | H | | T | f | finished
98   98  
99   H headers 99   H headers
100   C codec 100   C codec
101   T body 101   T body
102   f table 102   f table
103   p partial payload 103   p partial payload
104   b body data 104   b body data
105   105  
106   "payload" is the bytes coming in from 106   "payload" is the bytes coming in from
107   the stream. 107   the stream.
108   108  
109   "body" is the logical body, after transfer 109   "body" is the logical body, after transfer
110   encoding is removed. This can be the 110   encoding is removed. This can be the
111   same as the payload. 111   same as the payload.
112   112  
113   A "plain payload" is when the payload and 113   A "plain payload" is when the payload and
114   body are identical (no transfer encodings). 114   body are identical (no transfer encodings).
115   115  
116   A "buffered payload" is any payload which is 116   A "buffered payload" is any payload which is
117   not plain. A second buffer is required 117   not plain. A second buffer is required
118   for reading. 118   for reading.
119   119  
120   "overread" is additional data received past 120   "overread" is additional data received past
121   the end of the headers when reading headers, 121   the end of the headers when reading headers,
122   or additional data received past the end of 122   or additional data received past the end of
123   the message payload. 123   the message payload.
124   */ 124   */
125   125  
126   namespace { 126   namespace {
127   127  
128   // Construct a 2-element const_buffer pair representing the first 128   // Construct a 2-element const_buffer pair representing the first
129   // `n` bytes of `src`. Replaces the pre-#262 `capy::prefix(src, n)` 129   // `n` bytes of `src`. Replaces the pre-#262 `capy::prefix(src, n)`
130   // idiom which yielded a slice convertible to std::array. 130   // idiom which yielded a slice convertible to std::array.
131   inline std::array<capy::const_buffer, 2> 131   inline std::array<capy::const_buffer, 2>
HITCBC 132   41410 prefix_pair( 132   41410 prefix_pair(
133   std::array<capy::const_buffer, 2> const& src, 133   std::array<capy::const_buffer, 2> const& src,
134   std::size_t n) noexcept 134   std::size_t n) noexcept
135   { 135   {
HITCBC 136   41410 std::array<capy::const_buffer, 2> result{}; 136   41410 std::array<capy::const_buffer, 2> result{};
HITCBC 137   41410 if(n <= src[0].size()) 137   41410 if(n <= src[0].size())
138   { 138   {
HITCBC 139   40911 result[0] = capy::const_buffer(src[0].data(), n); 139   40911 result[0] = capy::const_buffer(src[0].data(), n);
140   } 140   }
141   else 141   else
142   { 142   {
HITCBC 143   499 result[0] = src[0]; 143   499 result[0] = src[0];
HITCBC 144   499 std::size_t remaining = n - src[0].size(); 144   499 std::size_t remaining = n - src[0].size();
HITCBC 145   499 if(remaining > src[1].size()) 145   499 if(remaining > src[1].size())
MISUBC 146   ✗ remaining = src[1].size(); 146   ✗ remaining = src[1].size();
HITCBC 147   499 result[1] = capy::const_buffer(src[1].data(), remaining); 147   499 result[1] = capy::const_buffer(src[1].data(), remaining);
148   } 148   }
HITCBC 149   41410 return result; 149   41410 return result;
150   } 150   }
151   151  
152   class chained_sequence 152   class chained_sequence
153   { 153   {
154   char const* pos_; 154   char const* pos_;
155   char const* end_; 155   char const* end_;
156   char const* begin_b_; 156   char const* begin_b_;
157   char const* end_b_; 157   char const* end_b_;
158   158  
159   public: 159   public:
HITCBC 160   71617 chained_sequence(std::array<capy::const_buffer, 2> const& cbp) 160   71617 chained_sequence(std::array<capy::const_buffer, 2> const& cbp)
HITCBC 161   71617 : pos_(static_cast<char const*>(cbp[0].data())) 161   71617 : pos_(static_cast<char const*>(cbp[0].data()))
HITCBC 162   71617 , end_(pos_ + cbp[0].size()) 162   71617 , end_(pos_ + cbp[0].size())
HITCBC 163   71617 , begin_b_(static_cast<char const*>(cbp[1].data())) 163   71617 , begin_b_(static_cast<char const*>(cbp[1].data()))
HITCBC 164   71617 , end_b_(begin_b_ + cbp[1].size()) 164   71617 , end_b_(begin_b_ + cbp[1].size())
165   { 165   {
HITCBC 166   71617 } 166   71617 }
167   167  
168   char const* 168   char const*
HITCBC 169   319930 next() noexcept 169   319930 next() noexcept
170   { 170   {
HITCBC 171   319930 ++pos_; 171   319930 ++pos_;
172   // most frequently taken branch 172   // most frequently taken branch
HITCBC 173   319930 if(pos_ < end_) 173   319930 if(pos_ < end_)
HITCBC 174   297556 return pos_; 174   297556 return pos_;
175   175  
176   // bring the second range 176   // bring the second range
HITCBC 177   22374 if(begin_b_ != end_b_) 177   22374 if(begin_b_ != end_b_)
178   { 178   {
MISUBC 179   ✗ pos_ = begin_b_; 179   ✗ pos_ = begin_b_;
MISUBC 180   ✗ end_ = end_b_; 180   ✗ end_ = end_b_;
MISUBC 181   ✗ begin_b_ = end_b_; 181   ✗ begin_b_ = end_b_;
MISUBC 182   ✗ return pos_; 182   ✗ return pos_;
183   } 183   }
184   184  
185   // undo the increament 185   // undo the increament
HITCBC 186   22374 pos_ = end_; 186   22374 pos_ = end_;
HITCBC 187   22374 return nullptr; 187   22374 return nullptr;
188   } 188   }
189   189  
190   bool 190   bool
HITCBC 191   212674 is_empty() const noexcept 191   212674 is_empty() const noexcept
192   { 192   {
HITCBC 193   212674 return pos_ == end_; 193   212674 return pos_ == end_;
194   } 194   }
195   195  
196   char 196   char
HITCBC 197   305475 value() const noexcept 197   305475 value() const noexcept
198   { 198   {
HITCBC 199   305475 return *pos_; 199   305475 return *pos_;
200   } 200   }
201   201  
202   std::size_t 202   std::size_t
HITCBC 203   226936 size() const noexcept 203   226936 size() const noexcept
204   { 204   {
HITCBC 205   226936 return (end_ - pos_) + (end_b_ - begin_b_); 205   226936 return (end_ - pos_) + (end_b_ - begin_b_);
206   } 206   }
207   }; 207   };
208   208  
209   std::uint64_t 209   std::uint64_t
HITCBC 210   66939 parse_hex( 210   66939 parse_hex(
211   chained_sequence& cs, 211   chained_sequence& cs,
212 - std::error_code& ec) noexcept 212 + system::error_code& ec) noexcept
213   { 213   {
HITCBC 214   66939 std::uint64_t v = 0; 214   66939 std::uint64_t v = 0;
HITCBC 215   66939 std::size_t init_size = cs.size(); 215   66939 std::size_t init_size = cs.size();
HITCBC 216   154117 while(!cs.is_empty()) 216   154117 while(!cs.is_empty())
217   { 217   {
HITCBC 218   134169 auto n = grammar::hexdig_value(cs.value()); 218   134169 auto n = grammar::hexdig_value(cs.value());
HITCBC 219   134169 if(n < 0) 219   134169 if(n < 0)
220   { 220   {
HITCBC 221   46990 if(init_size == cs.size()) 221   46990 if(init_size == cs.size())
222   { 222   {
HITCBC 223 - 1 ec = error::bad_payload; 223 + 2 ec = BOOST_HTTP_ERR(
  224 + error::bad_payload);
HITCBC 224   1 return 0; 225   1 return 0;
225   } 226   }
HITCBC 226   46989 return v; 227   46989 return v;
227   } 228   }
228   229  
229   // at least 4 significant bits are free 230   // at least 4 significant bits are free
HITCBC 230   87179 if(v > (std::numeric_limits<std::uint64_t>::max)() >> 4) 231   87179 if(v > (std::numeric_limits<std::uint64_t>::max)() >> 4)
231   { 232   {
HITCBC 232 - 1 ec = error::bad_payload; 233 + 2 ec = BOOST_HTTP_ERR(
  234 + error::bad_payload);
HITCBC 233   1 return 0; 235   1 return 0;
234   } 236   }
235   237  
HITCBC 236   87178 v = (v << 4) | static_cast<std::uint64_t>(n); 238   87178 v = (v << 4) | static_cast<std::uint64_t>(n);
HITCBC 237   87178 cs.next(); 239   87178 cs.next();
238   } 240   }
HITCBC 239 - 19948 ec = error::need_data; 241 + 39896 ec = BOOST_HTTP_ERR(
  242 + error::need_data);
HITCBC 240   19948 return 0; 243   19948 return 0;
241   } 244   }
242   245  
243   void 246   void
HITCBC 244   47341 find_eol( 247   47341 find_eol(
245   chained_sequence& cs, 248   chained_sequence& cs,
246 - std::error_code& ec) noexcept 249 + system::error_code& ec) noexcept
247   { 250   {
HITCBC 248   54030 while(!cs.is_empty()) 251   54030 while(!cs.is_empty())
249   { 252   {
HITCBC 250   53942 if(cs.value() == '\r') 253   53942 if(cs.value() == '\r')
251   { 254   {
HITCBC 252   47253 if(!cs.next()) 255   47253 if(!cs.next())
HITCBC 253   330 break; 256   330 break;
HITCBC 254   46923 if(cs.value() != '\n') 257   46923 if(cs.value() != '\n')
255   { 258   {
HITCBC 256 - 2 ec = error::bad_payload; 259 + 4 ec = BOOST_HTTP_ERR(
  260 + error::bad_payload);
HITCBC 257   2 return; 261   2 return;
258   } 262   }
HITCBC 259   46921 cs.next(); 263   46921 cs.next();
HITCBC 260   46921 return; 264   46921 return;
261   } 265   }
HITCBC 262   6689 cs.next(); 266   6689 cs.next();
263   } 267   }
HITCBC 264 - 418 ec = error::need_data; 268 + 836 ec = BOOST_HTTP_ERR(
  269 + error::need_data);
265   } 270   }
266   271  
267   void 272   void
HITCBC 268   62239 parse_eol( 273   62239 parse_eol(
269   chained_sequence& cs, 274   chained_sequence& cs,
270 - std::error_code& ec) noexcept 275 + system::error_code& ec) noexcept
271   { 276   {
HITCBC 272   62239 if(cs.size() >= 2) 277   62239 if(cs.size() >= 2)
273   { 278   {
274   // we are sure size is at least 2 279   // we are sure size is at least 2
HITCBC 275   61807 if(cs.value() == '\r' && *cs.next() == '\n') 280   61807 if(cs.value() == '\r' && *cs.next() == '\n')
276   { 281   {
HITCBC 277   61804 cs.next(); 282   61804 cs.next();
HITCBC 278   61804 return; 283   61804 return;
279   } 284   }
HITCBC 280 - 3 ec = error::bad_payload; 285 + 6 ec = BOOST_HTTP_ERR(
  286 + error::bad_payload);
HITCBC 281   3 return; 287   3 return;
282   } 288   }
HITCBC 283 - 432 ec = error::need_data; 289 + 864 ec = BOOST_HTTP_ERR(
  290 + error::need_data);
284   } 291   }
285   292  
286   void 293   void
HITCBC 287   4243 skip_trailer_headers( 294   4243 skip_trailer_headers(
288   chained_sequence& cs, 295   chained_sequence& cs,
289 - std::error_code& ec) noexcept 296 + system::error_code& ec) noexcept
290   { 297   {
HITCBC 291   4527 while(!cs.is_empty()) 298   4527 while(!cs.is_empty())
292   { 299   {
HITCBC 293   4501 if(cs.value() == '\r') 300   4501 if(cs.value() == '\r')
294   { 301   {
HITCBC 295   4149 if(!cs.next()) 302   4149 if(!cs.next())
HITCBC 296   16 break; 303   16 break;
HITCBC 297   4133 if(cs.value() != '\n') 304   4133 if(cs.value() != '\n')
298   { 305   {
HITCBC 299 - 2 ec = error::bad_payload; 306 + 4 ec = BOOST_HTTP_ERR(
  307 + error::bad_payload);
HITCBC 300   2 return; 308   2 return;
301   } 309   }
HITCBC 302   4131 cs.next(); 310   4131 cs.next();
HITCBC 303   4131 return; 311   4131 return;
304   } 312   }
305   // skip to the end of field 313   // skip to the end of field
HITCBC 306   352 find_eol(cs, ec); 314   352 find_eol(cs, ec);
HITCBC 307   352 if(ec) 315   352 if(ec)
HITCBC 308   68 return; 316   68 return;
309   } 317   }
HITCBC 310 - 42 ec = error::need_data; 318 + 84 ec = BOOST_HTTP_ERR(
  319 + error::need_data);
311   } 320   }
312   321  
313   template<class UInt> 322   template<class UInt>
314   std::size_t 323   std::size_t
HITCBC 315   193623 clamp( 324   193623 clamp(
316   UInt x, 325   UInt x,
317   std::size_t limit = (std::numeric_limits< 326   std::size_t limit = (std::numeric_limits<
318   std::size_t>::max)()) noexcept 327   std::size_t>::max)()) noexcept
319   { 328   {
HITCBC 320   193623 if(x >= limit) 329   193623 if(x >= limit)
HITCBC 321   46527 return limit; 330   46527 return limit;
HITCBC 322   147096 return static_cast<std::size_t>(x); 331   147096 return static_cast<std::size_t>(x);
323   } 332   }
324   333  
325   class zlib_filter 334   class zlib_filter
326   : public detail::zlib_filter_base 335   : public detail::zlib_filter_base
327   { 336   {
328   http::zlib::inflate_service& svc_; 337   http::zlib::inflate_service& svc_;
329   338  
330   public: 339   public:
MISUBC 331   ✗ zlib_filter( 340   ✗ zlib_filter(
332   http::zlib::inflate_service& svc, 341   http::zlib::inflate_service& svc,
333   int window_bits) 342   int window_bits)
MISUBC 334   ✗ : svc_(svc) 343   ✗ : svc_(svc)
335   { 344   {
336 - std::error_code ec = static_cast<http::zlib::error>( 345 + system::error_code ec = static_cast<http::zlib::error>(
MISUBC 337   ✗ svc_.init2(strm_, window_bits)); 346   ✗ svc_.init2(strm_, window_bits));
MISUBC 338   ✗ if(ec != http::zlib::error::ok) 347   ✗ if(ec != http::zlib::error::ok)
MISUBC 339   ✗ detail::throw_system_error(ec); 348   ✗ detail::throw_system_error(ec);
MISUBC 340   ✗ } 349   ✗ }
341   350  
342   private: 351   private:
343   virtual 352   virtual
344   results 353   results
MISUBC 345   ✗ do_process( 354   ✗ do_process(
346   capy::mutable_buffer out, 355   capy::mutable_buffer out,
347   capy::const_buffer in, 356   capy::const_buffer in,
348   bool more) noexcept override 357   bool more) noexcept override
349   { 358   {
MISUBC 350   ✗ strm_.next_out = static_cast<unsigned char*>(out.data()); 359   ✗ strm_.next_out = static_cast<unsigned char*>(out.data());
MISUBC 351   ✗ strm_.avail_out = saturate_cast(out.size()); 360   ✗ strm_.avail_out = saturate_cast(out.size());
MISUBC 352   ✗ strm_.next_in = static_cast<unsigned char*>(const_cast<void *>(in.data())); 361   ✗ strm_.next_in = static_cast<unsigned char*>(const_cast<void *>(in.data()));
MISUBC 353   ✗ strm_.avail_in = saturate_cast(in.size()); 362   ✗ strm_.avail_in = saturate_cast(in.size());
354   363  
355   auto rs = static_cast<http::zlib::error>( 364   auto rs = static_cast<http::zlib::error>(
MISUBC 356   ✗ svc_.inflate( 365   ✗ svc_.inflate(
MISUBC 357   ✗ strm_, 366   ✗ strm_,
358   more ? http::zlib::no_flush : http::zlib::finish)); 367   more ? http::zlib::no_flush : http::zlib::finish));
359   368  
MISUBC 360   ✗ results rv; 369   ✗ results rv;
MISUBC 361   ✗ rv.out_bytes = saturate_cast(out.size()) - strm_.avail_out; 370   ✗ rv.out_bytes = saturate_cast(out.size()) - strm_.avail_out;
MISUBC 362   ✗ rv.in_bytes = saturate_cast(in.size()) - strm_.avail_in; 371   ✗ rv.in_bytes = saturate_cast(in.size()) - strm_.avail_in;
MISUBC 363   ✗ rv.finished = (rs == http::zlib::error::stream_end); 372   ✗ rv.finished = (rs == http::zlib::error::stream_end);
364   373  
MISUBC 365   ✗ if(rs < http::zlib::error::ok && rs != http::zlib::error::buf_err) 374   ✗ if(rs < http::zlib::error::ok && rs != http::zlib::error::buf_err)
MISUBC 366   ✗ rv.ec = rs; 375   ✗ rv.ec = rs;
367   376  
MISUBC 368   ✗ return rv; 377   ✗ return rv;
369   } 378   }
370   }; 379   };
371   380  
372   class brotli_filter 381   class brotli_filter
373   : public detail::brotli_filter_base 382   : public detail::brotli_filter_base
374   { 383   {
375   http::brotli::decode_service& svc_; 384   http::brotli::decode_service& svc_;
376   http::brotli::decoder_state* state_; 385   http::brotli::decoder_state* state_;
377   386  
378   public: 387   public:
MISUBC 379   ✗ brotli_filter(http::brotli::decode_service& svc) 388   ✗ brotli_filter(http::brotli::decode_service& svc)
MISUBC 380   ✗ : svc_(svc) 389   ✗ : svc_(svc)
381   { 390   {
MISUBC 382   ✗ state_ = svc_.create_instance(nullptr, nullptr, nullptr); 391   ✗ state_ = svc_.create_instance(nullptr, nullptr, nullptr);
MISUBC 383   ✗ if(!state_) 392   ✗ if(!state_)
MISUBC 384   ✗ detail::throw_bad_alloc(); 393   ✗ detail::throw_bad_alloc();
MISUBC 385   ✗ } 394   ✗ }
386   395  
MISUBC 387   ✗ ~brotli_filter() 396   ✗ ~brotli_filter()
MISUBC 388   ✗ { 397   ✗ {
MISUBC 389   ✗ svc_.destroy_instance(state_); 398   ✗ svc_.destroy_instance(state_);
MISUBC 390   ✗ } 399   ✗ }
391   400  
392   private: 401   private:
393   virtual 402   virtual
394   results 403   results
MISUBC 395   ✗ do_process( 404   ✗ do_process(
396   capy::mutable_buffer out, 405   capy::mutable_buffer out,
397   capy::const_buffer in, 406   capy::const_buffer in,
398   bool more) noexcept override 407   bool more) noexcept override
399   { 408   {
MISUBC 400   ✗ auto* next_in = reinterpret_cast<const std::uint8_t*>(in.data()); 409   ✗ auto* next_in = reinterpret_cast<const std::uint8_t*>(in.data());
MISUBC 401   ✗ auto available_in = in.size(); 410   ✗ auto available_in = in.size();
MISUBC 402   ✗ auto* next_out = reinterpret_cast<std::uint8_t*>(out.data()); 411   ✗ auto* next_out = reinterpret_cast<std::uint8_t*>(out.data());
MISUBC 403   ✗ auto available_out = out.size(); 412   ✗ auto available_out = out.size();
404   413  
MISUBC 405   ✗ auto rs = svc_.decompress_stream( 414   ✗ auto rs = svc_.decompress_stream(
406   state_, 415   state_,
407   &available_in, 416   &available_in,
408   &next_in, 417   &next_in,
409   &available_out, 418   &available_out,
410   &next_out, 419   &next_out,
411   nullptr); 420   nullptr);
412   421  
MISUBC 413   ✗ results rv; 422   ✗ results rv;
MISUBC 414   ✗ rv.in_bytes = in.size() - available_in; 423   ✗ rv.in_bytes = in.size() - available_in;
MISUBC 415   ✗ rv.out_bytes = out.size() - available_out; 424   ✗ rv.out_bytes = out.size() - available_out;
MISUBC 416   ✗ rv.finished = svc_.is_finished(state_); 425   ✗ rv.finished = svc_.is_finished(state_);
417   426  
MISUBC 418   ✗ if(!more && rs == http::brotli::decoder_result::needs_more_input) 427   ✗ if(!more && rs == http::brotli::decoder_result::needs_more_input)
MISUBC 419 - ✗ rv.ec = error::bad_payload; 428 + ✗ rv.ec = BOOST_HTTP_ERR(error::bad_payload);
420   429  
MISUBC 421   ✗ if(rs == http::brotli::decoder_result::error) 430   ✗ if(rs == http::brotli::decoder_result::error)
MISUBC 422 - ✗ rv.ec = svc_.get_error_code(state_); 431 + ✗ rv.ec = BOOST_HTTP_ERR(
  432 + svc_.get_error_code(state_));
423   433  
MISUBC 424   ✗ return rv; 434   ✗ return rv;
425   } 435   }
426   }; 436   };
427   437  
428   } // namespace 438   } // namespace
429   439  
430   //------------------------------------------------ 440   //------------------------------------------------
431   441  
432   class parser::impl 442   class parser::impl
433   { 443   {
434   enum class state 444   enum class state
435   { 445   {
436   reset, 446   reset,
437   start, 447   start,
438   header, 448   header,
439   header_done, 449   header_done,
440   body, 450   body,
441   complete, 451   complete,
442   }; 452   };
443   453  
444   std::shared_ptr<parser_config_impl const> cfg_; 454   std::shared_ptr<parser_config_impl const> cfg_;
445   455  
446   detail::workspace ws_; 456   detail::workspace ws_;
447   static_request m_; 457   static_request m_;
448   std::uint64_t body_limit_; 458   std::uint64_t body_limit_;
449   std::uint64_t body_total_; 459   std::uint64_t body_total_;
450   std::uint64_t payload_remain_; 460   std::uint64_t payload_remain_;
451   std::uint64_t chunk_remain_; 461   std::uint64_t chunk_remain_;
452   std::size_t body_avail_; 462   std::size_t body_avail_;
453   std::size_t nprepare_; 463   std::size_t nprepare_;
454   464  
455   detail::flat_buffer fb_; 465   detail::flat_buffer fb_;
456   detail::circular_buffer cb0_; 466   detail::circular_buffer cb0_;
457   detail::circular_buffer cb1_; 467   detail::circular_buffer cb1_;
458   468  
459   std::array<capy::mutable_buffer, 2> mbp_; 469   std::array<capy::mutable_buffer, 2> mbp_;
460   std::array<capy::const_buffer, 2> cbp_; 470   std::array<capy::const_buffer, 2> cbp_;
461   471  
462   std::unique_ptr<detail::filter> filter_; 472   std::unique_ptr<detail::filter> filter_;
463   473  
464   state state_; 474   state state_;
465   bool got_header_; 475   bool got_header_;
466   bool got_eof_; 476   bool got_eof_;
467   bool head_response_; 477   bool head_response_;
468   bool needs_chunk_close_; 478   bool needs_chunk_close_;
469   bool trailer_headers_; 479   bool trailer_headers_;
470   bool chunked_body_ended; 480   bool chunked_body_ended;
471   481  
472   public: 482   public:
HITCBC 473   2175 impl(std::shared_ptr<parser_config_impl const> cfg, detail::kind k) 483   2175 impl(std::shared_ptr<parser_config_impl const> cfg, detail::kind k)
HITCBC 474   2175 : cfg_(std::move(cfg)) 484   2175 : cfg_(std::move(cfg))
HITCBC 475   2175 , ws_(cfg_->space_needed) 485   2175 , ws_(cfg_->space_needed)
HITCBC 476   2175 , m_(ws_.data(), ws_.size()) 486   2175 , m_(ws_.data(), ws_.size())
HITCBC 477   2175 , state_(state::reset) 487   2175 , state_(state::reset)
HITCBC 478   2175 , got_header_(false) 488   2175 , got_header_(false)
479   { 489   {
HITCBC 480   2175 m_.h_ = detail::header(detail::empty{ k }); 490   2175 m_.h_ = detail::header(detail::empty{ k });
HITCBC 481   2175 } 491   2175 }
482   492  
483   bool 493   bool
HITCBC 484   36129 got_header() const noexcept 494   36129 got_header() const noexcept
485   { 495   {
HITCBC 486   36129 return got_header_; 496   36129 return got_header_;
487   } 497   }
488   498  
489   bool 499   bool
HITCBC 490   59142 is_complete() const noexcept 500   59142 is_complete() const noexcept
491   { 501   {
HITCBC 492   59142 return state_ == state::complete; 502   59142 return state_ == state::complete;
493   } 503   }
494   504  
495   static_request const& 505   static_request const&
HITCBC 496   316 safe_get_request() const 506   316 safe_get_request() const
497   { 507   {
498   // headers must be received 508   // headers must be received
HITCBC 499   316 if(! got_header_) 509   316 if(! got_header_)
MISUBC 500   ✗ detail::throw_logic_error(); 510   ✗ detail::throw_logic_error();
501   511  
HITCBC 502   316 return m_; 512   316 return m_;
503   } 513   }
504   514  
505   static_response const& 515   static_response const&
HITCBC 506   3 safe_get_response() const 516   3 safe_get_response() const
507   { 517   {
508   // headers must be received 518   // headers must be received
HITCBC 509   3 if(! got_header_) 519   3 if(! got_header_)
MISUBC 510   ✗ detail::throw_logic_error(); 520   ✗ detail::throw_logic_error();
511   521  
512   // TODO: use a union 522   // TODO: use a union
HITCBC 513   3 return reinterpret_cast<static_response const&>(m_); 523   3 return reinterpret_cast<static_response const&>(m_);
514   } 524   }
515   525  
516   void 526   void
HITCBC 517   2722 reset() noexcept 527   2722 reset() noexcept
518   { 528   {
HITCBC 519   2722 ws_.clear(); 529   2722 ws_.clear();
HITCBC 520   2722 state_ = state::start; 530   2722 state_ = state::start;
HITCBC 521   2722 got_header_ = false; 531   2722 got_header_ = false;
HITCBC 522   2722 got_eof_ = false; 532   2722 got_eof_ = false;
HITCBC 523   2722 } 533   2722 }
524   534  
525   void 535   void
HITCBC 526   10651 start( 536   10651 start(
527   bool head_response) 537   bool head_response)
528   { 538   {
HITCBC 529   10651 std::size_t leftover = 0; 539   10651 std::size_t leftover = 0;
HITCBC 530   10651 switch(state_) 540   10651 switch(state_)
531   { 541   {
HITCBC 532   1 default: 542   1 default:
533   case state::reset: 543   case state::reset:
534   // reset must be called first 544   // reset must be called first
HITCBC 535   1 detail::throw_logic_error(); 545   1 detail::throw_logic_error();
536   546  
HITCBC 537   2647 case state::start: 547   2647 case state::start:
538   // reset required on eof 548   // reset required on eof
HITCBC 539   2647 if(got_eof_) 549   2647 if(got_eof_)
MISUBC 540   ✗ detail::throw_logic_error(); 550   ✗ detail::throw_logic_error();
HITCBC 541   2647 break; 551   2647 break;
542   552  
HITCBC 543   3 case state::header: 553   3 case state::header:
HITCBC 544   3 if(fb_.size() == 0) 554   3 if(fb_.size() == 0)
545   { 555   {
546   // start() called twice 556   // start() called twice
HITCBC 547   2 detail::throw_logic_error(); 557   2 detail::throw_logic_error();
548   } 558   }
549   BOOST_FALLTHROUGH; 559   BOOST_FALLTHROUGH;
550   560  
551   case state::header_done: 561   case state::header_done:
552   case state::body: 562   case state::body:
553   // current message is incomplete 563   // current message is incomplete
HITCBC 554   2 detail::throw_logic_error(); 564   2 detail::throw_logic_error();
555   565  
HITCBC 556   7999 case state::complete: 566   7999 case state::complete:
557   { 567   {
558   // remove available body. 568   // remove available body.
HITCBC 559   7999 if(is_plain()) 569   7999 if(is_plain())
HITCBC 560   4000 cb0_.consume(body_avail_); 570   4000 cb0_.consume(body_avail_);
561   // move leftovers to front 571   // move leftovers to front
562   572  
HITCBC 563   7999 ws_.clear(); 573   7999 ws_.clear();
HITCBC 564   7999 leftover = cb0_.size(); 574   7999 leftover = cb0_.size();
565   575  
HITCBC 566   7999 auto* dest = reinterpret_cast<char*>(ws_.data()); 576   7999 auto* dest = reinterpret_cast<char*>(ws_.data());
HITCBC 567   7999 auto cbp = cb0_.data(); 577   7999 auto cbp = cb0_.data();
HITCBC 568   7999 auto* a = static_cast<char const*>(cbp[0].data()); 578   7999 auto* a = static_cast<char const*>(cbp[0].data());
HITCBC 569   7999 auto* b = static_cast<char const*>(cbp[1].data()); 579   7999 auto* b = static_cast<char const*>(cbp[1].data());
HITCBC 570   7999 auto an = cbp[0].size(); 580   7999 auto an = cbp[0].size();
HITCBC 571   7999 auto bn = cbp[1].size(); 581   7999 auto bn = cbp[1].size();
572   582  
HITCBC 573   7999 if(bn == 0) 583   7999 if(bn == 0)
574   { 584   {
HITCBC 575   7561 std::memmove(dest, a, an); 585   7561 std::memmove(dest, a, an);
576   } 586   }
577   else 587   else
578   { 588   {
579   // if `a` can fit between `dest` and `b`, shift `b` to the left 589   // if `a` can fit between `dest` and `b`, shift `b` to the left
580   // and copy `a` to its position. if `a` fits perfectly, the 590   // and copy `a` to its position. if `a` fits perfectly, the
581   // shift will be of size 0. 591   // shift will be of size 0.
582   // if `a` requires more space, shift `b` to the right and 592   // if `a` requires more space, shift `b` to the right and
583   // copy `a` to its position. this process may require multiple 593   // copy `a` to its position. this process may require multiple
584   // iterations and should be done chunk by chunk to prevent `b` 594   // iterations and should be done chunk by chunk to prevent `b`
585   // from overlapping with `a`. 595   // from overlapping with `a`.
586   do 596   do
587   { 597   {
588   // clamp right shifts to prevent overlap with `a` 598   // clamp right shifts to prevent overlap with `a`
HITCBC 589   438 auto* bp = (std::min)(dest + an, const_cast<char*>(a) - bn); 599   438 auto* bp = (std::min)(dest + an, const_cast<char*>(a) - bn);
HITCBC 590   438 b = static_cast<char const*>(std::memmove(bp, b, bn)); 600   438 b = static_cast<char const*>(std::memmove(bp, b, bn));
591   601  
592   // a chunk or all of `a` based on available space 602   // a chunk or all of `a` based on available space
HITCBC 593   438 auto chunk_a = static_cast<std::size_t>(b - dest); 603   438 auto chunk_a = static_cast<std::size_t>(b - dest);
HITCBC 594   438 std::memcpy(dest, a, chunk_a); // never overlap 604   438 std::memcpy(dest, a, chunk_a); // never overlap
HITCBC 595   438 an -= chunk_a; 605   438 an -= chunk_a;
HITCBC 596   438 dest += chunk_a; 606   438 dest += chunk_a;
HITCBC 597   438 a += chunk_a; 607   438 a += chunk_a;
HITCBC 598   438 } while(an); 608   438 } while(an);
599   } 609   }
600   610  
HITCBC 601   7999 break; 611   7999 break;
602   } 612   }
603   } 613   }
604   614  
HITCBC 605   10646 ws_.clear(); 615   10646 ws_.clear();
606   616  
HITCBC 607   21292 fb_ = { 617   21292 fb_ = {
HITCBC 608   10646 ws_.data(), 618   10646 ws_.data(),
HITCBC 609   10646 cfg_->headers.max_size + cfg_->min_buffer, 619   10646 cfg_->headers.max_size + cfg_->min_buffer,
610   leftover }; 620   leftover };
611   621  
HITCBC 612   10646 BOOST_ASSERT( 622   10646 BOOST_ASSERT(
613   fb_.capacity() == cfg_->max_overread() - leftover); 623   fb_.capacity() == cfg_->max_overread() - leftover);
614   624  
HITCBC 615   10646 BOOST_ASSERT( 625   10646 BOOST_ASSERT(
616   head_response == false || 626   head_response == false ||
617   m_.h_.kind == detail::kind::response); 627   m_.h_.kind == detail::kind::response);
618   628  
HITCBC 619   10646 m_.h_ = detail::header(detail::empty{m_.h_.kind}); 629   10646 m_.h_ = detail::header(detail::empty{m_.h_.kind});
HITCBC 620   10646 m_.h_.buf = reinterpret_cast<char*>(ws_.data()); 630   10646 m_.h_.buf = reinterpret_cast<char*>(ws_.data());
HITCBC 621   10646 m_.h_.cbuf = m_.h_.buf; 631   10646 m_.h_.cbuf = m_.h_.buf;
HITCBC 622   10646 m_.h_.cap = ws_.size(); 632   10646 m_.h_.cap = ws_.size();
623   633  
HITCBC 624   10646 state_ = state::header; 634   10646 state_ = state::header;
625   635  
626   // reset to the configured default 636   // reset to the configured default
HITCBC 627   10646 body_limit_ = cfg_->body_limit; 637   10646 body_limit_ = cfg_->body_limit;
628   638  
HITCBC 629   10646 body_total_ = 0; 639   10646 body_total_ = 0;
HITCBC 630   10646 payload_remain_ = 0; 640   10646 payload_remain_ = 0;
HITCBC 631   10646 chunk_remain_ = 0; 641   10646 chunk_remain_ = 0;
HITCBC 632   10646 body_avail_ = 0; 642   10646 body_avail_ = 0;
HITCBC 633   10646 nprepare_ = 0; 643   10646 nprepare_ = 0;
634   644  
HITCBC 635   10646 filter_.reset(); 645   10646 filter_.reset();
636   646  
HITCBC 637   10646 got_header_ = false; 647   10646 got_header_ = false;
HITCBC 638   10646 head_response_ = head_response; 648   10646 head_response_ = head_response;
HITCBC 639   10646 needs_chunk_close_ = false; 649   10646 needs_chunk_close_ = false;
HITCBC 640   10646 trailer_headers_ = false; 650   10646 trailer_headers_ = false;
HITCBC 641   10646 chunked_body_ended = false; 651   10646 chunked_body_ended = false;
HITCBC 642   10646 } 652   10646 }
643   653  
644   auto 654   auto
HITCBC 645   81915 prepare() -> 655   81915 prepare() ->
646   mutable_buffers_type 656   mutable_buffers_type
647   { 657   {
HITCBC 648   81915 nprepare_ = 0; 658   81915 nprepare_ = 0;
649   659  
HITCBC 650   81915 switch(state_) 660   81915 switch(state_)
651   { 661   {
HITCBC 652   1 default: 662   1 default:
653   case state::reset: 663   case state::reset:
654   // reset must be called first 664   // reset must be called first
HITCBC 655   1 detail::throw_logic_error(); 665   1 detail::throw_logic_error();
656   666  
HITCBC 657   1 case state::start: 667   1 case state::start:
658   // start must be called first 668   // start must be called first
HITCBC 659   1 detail::throw_logic_error(); 669   1 detail::throw_logic_error();
660   670  
HITCBC 661   39828 case state::header: 671   39828 case state::header:
662   { 672   {
HITCBC 663   39828 BOOST_ASSERT( 673   39828 BOOST_ASSERT(
664   m_.h_.size < cfg_->headers.max_size); 674   m_.h_.size < cfg_->headers.max_size);
HITCBC 665   39828 std::size_t n = fb_.capacity(); 675   39828 std::size_t n = fb_.capacity();
HITCBC 666   39828 BOOST_ASSERT(n <= cfg_->max_overread()); 676   39828 BOOST_ASSERT(n <= cfg_->max_overread());
HITCBC 667   39828 n = clamp(n, cfg_->max_prepare); 677   39828 n = clamp(n, cfg_->max_prepare);
HITCBC 668   39828 mbp_[0] = fb_.prepare(n); 678   39828 mbp_[0] = fb_.prepare(n);
HITCBC 669   39828 nprepare_ = n; 679   39828 nprepare_ = n;
HITCBC 670   39828 return mutable_buffers_type(&mbp_[0], 1); 680   39828 return mutable_buffers_type(&mbp_[0], 1);
671   } 681   }
672   682  
MISUBC 673   ✗ case state::header_done: 683   ✗ case state::header_done:
674   // forgot to call parse() 684   // forgot to call parse()
MISUBC 675   ✗ detail::throw_logic_error(); 685   ✗ detail::throw_logic_error();
676   686  
HITCBC 677   42084 case state::body: 687   42084 case state::body:
678   { 688   {
HITCBC 679   42084 if(got_eof_) 689   42084 if(got_eof_)
680   { 690   {
681   // forgot to call parse() 691   // forgot to call parse()
MISUBC 682   ✗ detail::throw_logic_error(); 692   ✗ detail::throw_logic_error();
683   } 693   }
684   694  
HITCBC 685   42084 if(! is_plain()) 695   42084 if(! is_plain())
686   { 696   {
687   // buffered payload 697   // buffered payload
HITCBC 688   22017 std::size_t n = cb0_.capacity(); 698   22017 std::size_t n = cb0_.capacity();
HITCBC 689   22017 n = clamp(n, cfg_->max_prepare); 699   22017 n = clamp(n, cfg_->max_prepare);
HITCBC 690   22017 nprepare_ = n; 700   22017 nprepare_ = n;
HITCBC 691   22017 mbp_ = cb0_.prepare(n); 701   22017 mbp_ = cb0_.prepare(n);
HITCBC 692   22017 return detail::make_span(mbp_); 702   22017 return detail::make_span(mbp_);
693   } 703   }
694   else 704   else
695   { 705   {
696   // plain payload 706   // plain payload
HITCBC 697   20067 std::size_t n = cb0_.capacity(); 707   20067 std::size_t n = cb0_.capacity();
HITCBC 698   20067 n = clamp(n, cfg_->max_prepare); 708   20067 n = clamp(n, cfg_->max_prepare);
699   709  
HITCBC 700   20067 if(m_.payload() == payload::size) 710   20067 if(m_.payload() == payload::size)
701   { 711   {
HITCBC 702   20053 if(n > payload_remain_) 712   20053 if(n > payload_remain_)
703   { 713   {
HITCBC 704   18836 std::size_t overread = 714   18836 std::size_t overread =
HITCBC 705   18836 n - static_cast<std::size_t>(payload_remain_); 715   18836 n - static_cast<std::size_t>(payload_remain_);
HITCBC 706   18836 if(overread > cfg_->max_overread()) 716   18836 if(overread > cfg_->max_overread())
HITCBC 707   8920 n = static_cast<std::size_t>(payload_remain_) + 717   8920 n = static_cast<std::size_t>(payload_remain_) +
HITCBC 708   8920 cfg_->max_overread(); 718   8920 cfg_->max_overread();
709   } 719   }
710   } 720   }
711   else 721   else
712   { 722   {
HITCBC 713   14 BOOST_ASSERT( 723   14 BOOST_ASSERT(
714   m_.payload() == payload::to_eof); 724   m_.payload() == payload::to_eof);
715   // No more messages can be pipelined, so 725   // No more messages can be pipelined, so
716   // limit the output buffer to the remaining 726   // limit the output buffer to the remaining
717   // body limit plus one byte to detect 727   // body limit plus one byte to detect
718   // exhaustion. 728   // exhaustion.
HITCBC 719   14 std::uint64_t r = body_limit_remain(); 729   14 std::uint64_t r = body_limit_remain();
HITCBC 720   14 if(r != std::uint64_t(-1)) 730   14 if(r != std::uint64_t(-1))
HITCBC 721   14 r += 1; 731   14 r += 1;
HITCBC 722   14 n = clamp(r, n); 732   14 n = clamp(r, n);
723   } 733   }
724   734  
HITCBC 725   20067 nprepare_ = n; 735   20067 nprepare_ = n;
HITCBC 726   20067 mbp_ = cb0_.prepare(n); 736   20067 mbp_ = cb0_.prepare(n);
HITCBC 727   20067 return detail::make_span(mbp_); 737   20067 return detail::make_span(mbp_);
728   } 738   }
729   } 739   }
730   740  
HITCBC 731   1 case state::complete: 741   1 case state::complete:
732   // already complete 742   // already complete
HITCBC 733   1 detail::throw_logic_error(); 743   1 detail::throw_logic_error();
734   } 744   }
735   } 745   }
736   746  
737   void 747   void
HITCBC 738   80858 commit( 748   80858 commit(
739   std::size_t n) 749   std::size_t n)
740   { 750   {
HITCBC 741   80858 switch(state_) 751   80858 switch(state_)
742   { 752   {
HITCBC 743   1 default: 753   1 default:
744   case state::reset: 754   case state::reset:
745   { 755   {
746   // reset must be called first 756   // reset must be called first
HITCBC 747   1 detail::throw_logic_error(); 757   1 detail::throw_logic_error();
748   } 758   }
749   759  
HITCBC 750   1 case state::start: 760   1 case state::start:
751   { 761   {
752   // forgot to call start() 762   // forgot to call start()
HITCBC 753   1 detail::throw_logic_error(); 763   1 detail::throw_logic_error();
754   } 764   }
755   765  
HITCBC 756   39046 case state::header: 766   39046 case state::header:
757   { 767   {
HITCBC 758   39046 if(n > nprepare_) 768   39046 if(n > nprepare_)
759   { 769   {
760   // n can't be greater than size of 770   // n can't be greater than size of
761   // the buffers returned by prepare() 771   // the buffers returned by prepare()
HITCBC 762   1 detail::throw_invalid_argument(); 772   1 detail::throw_invalid_argument();
763   } 773   }
764   774  
HITCBC 765   39045 if(got_eof_) 775   39045 if(got_eof_)
766   { 776   {
767   // can't commit after EOF 777   // can't commit after EOF
HITCBC 768   1 detail::throw_logic_error(); 778   1 detail::throw_logic_error();
769   } 779   }
770   780  
HITCBC 771   39044 nprepare_ = 0; // invalidate 781   39044 nprepare_ = 0; // invalidate
HITCBC 772   39044 fb_.commit(n); 782   39044 fb_.commit(n);
HITCBC 773   39044 break; 783   39044 break;
774   } 784   }
775   785  
MISUBC 776   ✗ case state::header_done: 786   ✗ case state::header_done:
777   { 787   {
778   // forgot to call parse() 788   // forgot to call parse()
MISUBC 779   ✗ detail::throw_logic_error(); 789   ✗ detail::throw_logic_error();
780   } 790   }
781   791  
HITCBC 782   41810 case state::body: 792   41810 case state::body:
783   { 793   {
HITCBC 784   41810 if(n > nprepare_) 794   41810 if(n > nprepare_)
785   { 795   {
786   // n can't be greater than size of 796   // n can't be greater than size of
787   // the buffers returned by prepare() 797   // the buffers returned by prepare()
HITCBC 788   2 detail::throw_invalid_argument(); 798   2 detail::throw_invalid_argument();
789   } 799   }
790   800  
HITCBC 791   41808 if(got_eof_) 801   41808 if(got_eof_)
792   { 802   {
793   // can't commit after EOF 803   // can't commit after EOF
MISUBC 794   ✗ detail::throw_logic_error(); 804   ✗ detail::throw_logic_error();
795   } 805   }
796   806  
HITCBC 797   41808 nprepare_ = 0; // invalidate 807   41808 nprepare_ = 0; // invalidate
HITCBC 798   41808 cb0_.commit(n); 808   41808 cb0_.commit(n);
HITCBC 799   41808 break; 809   41808 break;
800   } 810   }
801   811  
MISUBC 802   ✗ case state::complete: 812   ✗ case state::complete:
803   { 813   {
804   // already complete 814   // already complete
MISUBC 805   ✗ detail::throw_logic_error(); 815   ✗ detail::throw_logic_error();
806   } 816   }
807   } 817   }
HITCBC 808   80852 } 818   80852 }
809   819  
810   void 820   void
HITCBC 811   134 commit_eof() 821   134 commit_eof()
812   { 822   {
HITCBC 813   134 nprepare_ = 0; // invalidate 823   134 nprepare_ = 0; // invalidate
814   824  
HITCBC 815   134 switch(state_) 825   134 switch(state_)
816   { 826   {
HITCBC 817   1 default: 827   1 default:
818   case state::reset: 828   case state::reset:
819   // reset must be called first 829   // reset must be called first
HITCBC 820   1 detail::throw_logic_error(); 830   1 detail::throw_logic_error();
821   831  
HITCBC 822   1 case state::start: 832   1 case state::start:
823   // forgot to call start() 833   // forgot to call start()
HITCBC 824   1 detail::throw_logic_error(); 834   1 detail::throw_logic_error();
825   835  
HITCBC 826   14 case state::header: 836   14 case state::header:
HITCBC 827   14 got_eof_ = true; 837   14 got_eof_ = true;
HITCBC 828   14 break; 838   14 break;
829   839  
MISUBC 830   ✗ case state::header_done: 840   ✗ case state::header_done:
831   // forgot to call parse() 841   // forgot to call parse()
MISUBC 832   ✗ detail::throw_logic_error(); 842   ✗ detail::throw_logic_error();
833   843  
HITCBC 834   117 case state::body: 844   117 case state::body:
HITCBC 835   117 got_eof_ = true; 845   117 got_eof_ = true;
HITCBC 836   117 break; 846   117 break;
837   847  
HITCBC 838   1 case state::complete: 848   1 case state::complete:
839   // can't commit eof when complete 849   // can't commit eof when complete
HITCBC 840   1 detail::throw_logic_error(); 850   1 detail::throw_logic_error();
841   } 851   }
HITCBC 842   131 } 852   131 }
843   853  
844   void 854   void
HITCBC 845   98769 parse( 855   98769 parse(
846 - std::error_code& ec) 856 + system::error_code& ec)
847   { 857   {
HITCBC 848   98769 ec = {}; 858   98769 ec = {};
HITCBC 849   98769 switch(state_) 859   98769 switch(state_)
850   { 860   {
HITCBC 851   1 default: 861   1 default:
852   case state::reset: 862   case state::reset:
853   // reset must be called first 863   // reset must be called first
HITCBC 854   1 detail::throw_logic_error(); 864   1 detail::throw_logic_error();
855   865  
HITCBC 856   1 case state::start: 866   1 case state::start:
857   // start must be called first 867   // start must be called first
HITCBC 858   1 detail::throw_logic_error(); 868   1 detail::throw_logic_error();
859   869  
HITCBC 860   45029 case state::header: 870   45029 case state::header:
861   { 871   {
HITCBC 862   45029 BOOST_ASSERT(m_.h_.buf == static_cast< 872   45029 BOOST_ASSERT(m_.h_.buf == static_cast<
863   void const*>(ws_.data())); 873   void const*>(ws_.data()));
HITCBC 864   45029 BOOST_ASSERT(m_.h_.cbuf == static_cast< 874   45029 BOOST_ASSERT(m_.h_.cbuf == static_cast<
865   void const*>(ws_.data())); 875   void const*>(ws_.data()));
866   876  
HITCBC 867   45029 m_.h_.parse(fb_.size(), cfg_->headers, ec); 877   45029 m_.h_.parse(fb_.size(), cfg_->headers, ec);
868   878  
HITCBC 869   45029 if(ec == condition::need_more_input) 879   45029 if(ec == condition::need_more_input)
870   { 880   {
HITCBC 871   35185 if(! got_eof_) 881   35185 if(! got_eof_)
872   { 882   {
873   // headers incomplete 883   // headers incomplete
HITCBC 874   35174 return; 884   35174 return;
875   } 885   }
876   886  
HITCBC 877   11 if(fb_.size() == 0) 887   11 if(fb_.size() == 0)
878   { 888   {
879   // stream closed cleanly 889   // stream closed cleanly
HITCBC 880   6 state_ = state::reset; 890   6 state_ = state::reset;
HITCBC 881 - 6 ec = error::end_of_stream; 891 + 12 ec = BOOST_HTTP_ERR(
  892 + error::end_of_stream);
HITCBC 882   6 return; 893   6 return;
883   } 894   }
884   895  
885   // stream closed with a 896   // stream closed with a
886   // partial message received 897   // partial message received
HITCBC 887   5 state_ = state::reset; 898   5 state_ = state::reset;
HITCBC 888 - 5 ec = error::incomplete; 899 + 10 ec = BOOST_HTTP_ERR(
  900 + error::incomplete);
HITCBC 889   5 return; 901   5 return;
890   } 902   }
HITCBC 891   9844 else if(ec) 903   9844 else if(ec)
892   { 904   {
893   // other error, 905   // other error,
894   // 906   //
895   // VFALCO map this to a bad 907   // VFALCO map this to a bad
896   // request or bad response error? 908   // request or bad response error?
897   // 909   //
HITCBC 898   259 state_ = state::reset; // unrecoverable 910   259 state_ = state::reset; // unrecoverable
HITCBC 899   259 return; 911   259 return;
900   } 912   }
901   913  
HITCBC 902   9585 got_header_ = true; 914   9585 got_header_ = true;
903   915  
904   // reserve headers + table 916   // reserve headers + table
HITCBC 905   9585 ws_.reserve_front(m_.h_.size); 917   9585 ws_.reserve_front(m_.h_.size);
HITCBC 906   9585 ws_.reserve_back(m_.h_.table_space()); 918   9585 ws_.reserve_back(m_.h_.table_space());
907   919  
908   // no payload 920   // no payload
HITCBC 909   18362 if(m_.payload() == payload::none || 921   18362 if(m_.payload() == payload::none ||
HITCBC 910   8777 head_response_) 922   8777 head_response_)
911   { 923   {
912   // octets of the next message 924   // octets of the next message
HITCBC 913   808 auto overread = fb_.size() - m_.h_.size; 925   808 auto overread = fb_.size() - m_.h_.size;
HITCBC 914   808 cb0_ = { ws_.data(), overread, overread }; 926   808 cb0_ = { ws_.data(), overread, overread };
HITCBC 915   808 ws_.reserve_front(overread); 927   808 ws_.reserve_front(overread);
HITCBC 916   808 state_ = state::complete; 928   808 state_ = state::complete;
HITCBC 917   808 return; 929   808 return;
918   } 930   }
919   931  
HITCBC 920   8777 state_ = state::header_done; 932   8777 state_ = state::header_done;
HITCBC 921   8777 break; 933   8777 break;
922   } 934   }
923   935  
HITCBC 924   8774 case state::header_done: 936   8774 case state::header_done:
925   { 937   {
926   // metadata error 938   // metadata error
HITCBC 927   8774 if(m_.payload() == payload::error) 939   8774 if(m_.payload() == payload::error)
928   { 940   {
929   // VFALCO This needs looking at 941   // VFALCO This needs looking at
HITCBC 930 - 60 ec = error::bad_payload; 942 + 120 ec = BOOST_HTTP_ERR(
  943 + error::bad_payload);
HITCBC 931   60 state_ = state::reset; // unrecoverable 944   60 state_ = state::reset; // unrecoverable
HITCBC 932   60 return; 945   60 return;
933   } 946   }
934   947  
935   // overread currently includes any and all octets that 948   // overread currently includes any and all octets that
936   // extend beyond the current end of the header 949   // extend beyond the current end of the header
937   // this can include associated body octets for the 950   // this can include associated body octets for the
938   // current message or octets of the next message in the 951   // current message or octets of the next message in the
939   // stream, e.g. pipelining is being used 952   // stream, e.g. pipelining is being used
HITCBC 940   8714 auto const overread = fb_.size() - m_.h_.size; 953   8714 auto const overread = fb_.size() - m_.h_.size;
HITCBC 941   8714 BOOST_ASSERT(overread <= cfg_->max_overread()); 954   8714 BOOST_ASSERT(overread <= cfg_->max_overread());
942   955  
HITCBC 943   8714 auto cap = fb_.capacity() + overread + 956   8714 auto cap = fb_.capacity() + overread +
HITCBC 944   8714 cfg_->min_buffer; 957   8714 cfg_->min_buffer;
945   958  
946   // reserve body buffers first, as the decoder 959   // reserve body buffers first, as the decoder
947   // must be installed after them. 960   // must be installed after them.
HITCBC 948   8714 auto const p = ws_.reserve_front(cap); 961   8714 auto const p = ws_.reserve_front(cap);
949   962  
950   // Content-Encoding 963   // Content-Encoding
HITCBC 951   8714 switch(m_.metadata().content_encoding.coding) 964   8714 switch(m_.metadata().content_encoding.coding)
952   { 965   {
MISUBC 953   ✗ case content_coding::deflate: 966   ✗ case content_coding::deflate:
MISUBC 954   ✗ if(!cfg_->apply_deflate_decoder) 967   ✗ if(!cfg_->apply_deflate_decoder)
MISUBC 955   ✗ goto no_filter; 968   ✗ goto no_filter;
MISUBC 956   ✗ if(auto* svc = capy::get_system_context().find_service<http::zlib::inflate_service>()) 969   ✗ if(auto* svc = capy::get_system_context().find_service<http::zlib::inflate_service>())
957   { 970   {
MISUBC 958   ✗ filter_.reset(new zlib_filter( 971   ✗ filter_.reset(new zlib_filter(
959   *svc, 972   *svc,
MISUBC 960   ✗ cfg_->zlib_window_bits)); 973   ✗ cfg_->zlib_window_bits));
961   } 974   }
MISUBC 962   ✗ break; 975   ✗ break;
963   976  
MISUBC 964   ✗ case content_coding::gzip: 977   ✗ case content_coding::gzip:
MISUBC 965   ✗ if(!cfg_->apply_gzip_decoder) 978   ✗ if(!cfg_->apply_gzip_decoder)
MISUBC 966   ✗ goto no_filter; 979   ✗ goto no_filter;
MISUBC 967   ✗ if(auto* svc = capy::get_system_context().find_service<http::zlib::inflate_service>()) 980   ✗ if(auto* svc = capy::get_system_context().find_service<http::zlib::inflate_service>())
968   { 981   {
MISUBC 969   ✗ filter_.reset(new zlib_filter( 982   ✗ filter_.reset(new zlib_filter(
970   *svc, 983   *svc,
MISUBC 971   ✗ cfg_->zlib_window_bits + 16)); 984   ✗ cfg_->zlib_window_bits + 16));
972   } 985   }
MISUBC 973   ✗ break; 986   ✗ break;
974   987  
MISUBC 975   ✗ case content_coding::br: 988   ✗ case content_coding::br:
MISUBC 976   ✗ if(!cfg_->apply_brotli_decoder) 989   ✗ if(!cfg_->apply_brotli_decoder)
MISUBC 977   ✗ goto no_filter; 990   ✗ goto no_filter;
MISUBC 978   ✗ if(auto* svc = capy::get_system_context().find_service<http::brotli::decode_service>()) 991   ✗ if(auto* svc = capy::get_system_context().find_service<http::brotli::decode_service>())
979   { 992   {
MISUBC 980   ✗ filter_.reset(new brotli_filter(*svc)); 993   ✗ filter_.reset(new brotli_filter(*svc));
981   } 994   }
MISUBC 982   ✗ break; 995   ✗ break;
983   996  
MISUBC 984   ✗ no_filter: 997   ✗ no_filter:
HITCBC 985   8714 default: 998   8714 default:
HITCBC 986   8714 break; 999   8714 break;
987   } 1000   }
988   1001  
HITCBC 989   8714 if(is_plain()) 1002   8714 if(is_plain())
990   { 1003   {
HITCBC 991   4385 cb0_ = { p, cap, overread }; 1004   4385 cb0_ = { p, cap, overread };
HITCBC 992   4385 cb1_ = {}; 1005   4385 cb1_ = {};
993   } 1006   }
994   else 1007   else
995   { 1008   {
996   // buffered payload 1009   // buffered payload
HITCBC 997   4329 std::size_t n0 = (overread > cfg_->min_buffer) 1010   4329 std::size_t n0 = (overread > cfg_->min_buffer)
HITCBC 998   8658 ? overread 1011   8658 ? overread
HITCBC 999   4329 : cfg_->min_buffer; 1012   4329 : cfg_->min_buffer;
HITCBC 1000   4329 std::size_t n1 = cfg_->min_buffer; 1013   4329 std::size_t n1 = cfg_->min_buffer;
1001   1014  
HITCBC 1002   4329 cb0_ = { p , n0, overread }; 1015   4329 cb0_ = { p , n0, overread };
HITCBC 1003   4329 cb1_ = { p + n0 , n1 }; 1016   4329 cb1_ = { p + n0 , n1 };
1004   } 1017   }
1005   1018  
HITCBC 1006   8714 if(m_.payload() == payload::size) 1019   8714 if(m_.payload() == payload::size)
1007   { 1020   {
HITCBC 1008   8536 if(!filter_ && 1021   8536 if(!filter_ &&
HITCBC 1009   4268 body_limit_ < m_.payload_size()) 1022   4268 body_limit_ < m_.payload_size())
1010   { 1023   {
HITCBC 1011 - 3 ec = error::body_too_large; 1024 + 6 ec = BOOST_HTTP_ERR(
  1025 + error::body_too_large);
HITCBC 1012   3 state_ = state::reset; 1026   3 state_ = state::reset;
HITCBC 1013   3 return; 1027   3 return;
1014   } 1028   }
HITCBC 1015   4265 payload_remain_ = m_.payload_size(); 1029   4265 payload_remain_ = m_.payload_size();
1016   } 1030   }
1017   1031  
HITCBC 1018   8711 state_ = state::body; 1032   8711 state_ = state::body;
1019   BOOST_FALLTHROUGH; 1033   BOOST_FALLTHROUGH;
1020   } 1034   }
1021   1035  
HITCBC 1022   51462 case state::body: 1036   51462 case state::body:
1023   { 1037   {
HITCBC 1024   51462 BOOST_ASSERT(state_ == state::body); 1038   51462 BOOST_ASSERT(state_ == state::body);
HITCBC 1025   51462 BOOST_ASSERT(m_.payload() != payload::none); 1039   51462 BOOST_ASSERT(m_.payload() != payload::none);
HITCBC 1026   51462 BOOST_ASSERT(m_.payload() != payload::error); 1040   51462 BOOST_ASSERT(m_.payload() != payload::error);
1027   1041  
HITCBC 1028   8364 auto set_state_to_complete = [&]() 1042   8364 auto set_state_to_complete = [&]()
1029   { 1043   {
HITCBC 1030   8364 state_ = state::complete; 1044   8364 state_ = state::complete;
HITCBC 1031   59826 }; 1045   59826 };
1032   1046  
HITCBC 1033   51462 if(m_.payload() == payload::chunked) 1047   51462 if(m_.payload() == payload::chunked)
1034   { 1048   {
1035   for(;;) 1049   for(;;)
1036   { 1050   {
HITCBC 1037   78651 if(chunk_remain_ == 0 1051   78651 if(chunk_remain_ == 0
HITCBC 1038   75748 && !chunked_body_ended) 1052   75748 && !chunked_body_ended)
1039   { 1053   {
HITCBC 1040   71617 auto cs = chained_sequence(cb0_.data()); 1054   71617 auto cs = chained_sequence(cb0_.data());
HITCBC 1041   20849 auto check_ec = [&]() 1055   20849 auto check_ec = [&]()
1042   { 1056   {
HITCBC 1043   20849 if(ec == condition::need_more_input && got_eof_) 1057   20849 if(ec == condition::need_more_input && got_eof_)
1044   { 1058   {
MISUBC 1045 - ✗ ec = error::incomplete; 1059 + ✗ ec = BOOST_HTTP_ERR(error::incomplete);
MISUBC 1046   ✗ state_ = state::reset; 1060   ✗ state_ = state::reset;
1047   } 1061   }
HITCBC 1048   92466 }; 1062   92466 };
1049   1063  
HITCBC 1050   71617 if(needs_chunk_close_) 1064   71617 if(needs_chunk_close_)
1051   { 1065   {
HITCBC 1052   62239 parse_eol(cs, ec); 1066   62239 parse_eol(cs, ec);
HITCBC 1053   62239 if(ec) 1067   62239 if(ec)
1054   { 1068   {
HITCBC 1055   435 check_ec(); 1069   435 check_ec();
HITCBC 1056   20849 return; 1070   20849 return;
1057   } 1071   }
1058   } 1072   }
HITCBC 1059   9378 else if(trailer_headers_) 1073   9378 else if(trailer_headers_)
1060   { 1074   {
HITCBC 1061   4243 skip_trailer_headers(cs, ec); 1075   4243 skip_trailer_headers(cs, ec);
HITCBC 1062   4243 if(ec) 1076   4243 if(ec)
1063   { 1077   {
HITCBC 1064   112 check_ec(); 1078   112 check_ec();
HITCBC 1065   112 return; 1079   112 return;
1066   } 1080   }
HITCBC 1067   4131 cb0_.consume(cb0_.size() - cs.size()); 1081   4131 cb0_.consume(cb0_.size() - cs.size());
HITCBC 1068   4131 chunked_body_ended = true; 1082   4131 chunked_body_ended = true;
HITCBC 1069   8276 continue; 1083   8276 continue;
1070   } 1084   }
1071   1085  
HITCBC 1072   66939 auto chunk_size = parse_hex(cs, ec); 1086   66939 auto chunk_size = parse_hex(cs, ec);
HITCBC 1073   66939 if(ec) 1087   66939 if(ec)
1074   { 1088   {
HITCBC 1075   19950 check_ec(); 1089   19950 check_ec();
HITCBC 1076   19950 return; 1090   19950 return;
1077   } 1091   }
1078   1092  
1079   // skip chunk extensions 1093   // skip chunk extensions
HITCBC 1080   46989 find_eol(cs, ec); 1094   46989 find_eol(cs, ec);
HITCBC 1081   46989 if(ec) 1095   46989 if(ec)
1082   { 1096   {
HITCBC 1083   352 check_ec(); 1097   352 check_ec();
HITCBC 1084   352 return; 1098   352 return;
1085   } 1099   }
1086   1100  
HITCBC 1087   46637 cb0_.consume(cb0_.size() - cs.size()); 1101   46637 cb0_.consume(cb0_.size() - cs.size());
HITCBC 1088   46637 chunk_remain_ = chunk_size; 1102   46637 chunk_remain_ = chunk_size;
1089   1103  
HITCBC 1090   46637 needs_chunk_close_ = true; 1104   46637 needs_chunk_close_ = true;
HITCBC 1091   46637 if(chunk_remain_ == 0) 1105   46637 if(chunk_remain_ == 0)
1092   { 1106   {
HITCBC 1093   4145 needs_chunk_close_ = false; 1107   4145 needs_chunk_close_ = false;
HITCBC 1094   4145 trailer_headers_ = true; 1108   4145 trailer_headers_ = true;
HITCBC 1095   4145 continue; 1109   4145 continue;
1096   } 1110   }
1097   } 1111   }
1098   1112  
HITCBC 1099   49526 if(cb0_.size() == 0 && !chunked_body_ended) 1113   49526 if(cb0_.size() == 0 && !chunked_body_ended)
1100   { 1114   {
HITCBC 1101   1830 if(got_eof_) 1115   1830 if(got_eof_)
1102   { 1116   {
HITCBC 1103 - 1 ec = error::incomplete; 1117 + 2 ec = BOOST_HTTP_ERR(
  1118 + error::incomplete);
HITCBC 1104   1 state_ = state::reset; 1119   1 state_ = state::reset;
HITCBC 1105   1 return; 1120   1 return;
1106   } 1121   }
1107   1122  
HITCBC 1108 - 1829 ec = error::need_data; 1123 + 3658 ec = BOOST_HTTP_ERR(
  1124 + error::need_data);
HITCBC 1109   1829 return; 1125   1829 return;
1110   } 1126   }
1111   1127  
HITCBC 1112   47696 if(filter_) 1128   47696 if(filter_)
1113   { 1129   {
MISUBC 1114   ✗ chunk_remain_ -= apply_filter( 1130   ✗ chunk_remain_ -= apply_filter(
1115   ec, 1131   ec,
1116   clamp(chunk_remain_, cb0_.size()), 1132   clamp(chunk_remain_, cb0_.size()),
MISUBC 1117   ✗ !chunked_body_ended); 1133   ✗ !chunked_body_ended);
1118   1134  
MISUBC 1119   ✗ if(ec || chunked_body_ended) 1135   ✗ if(ec || chunked_body_ended)
MISUBC 1120   ✗ return; 1136   ✗ return;
1121   } 1137   }
1122   else 1138   else
1123   { 1139   {
1124   const std::size_t chunk_avail = 1140   const std::size_t chunk_avail =
HITCBC 1125   47696 clamp(chunk_remain_, cb0_.size()); 1141   47696 clamp(chunk_remain_, cb0_.size());
HITCBC 1126   47696 auto cb0_data = cb0_.data(); 1142   47696 auto cb0_data = cb0_.data();
HITCBC 1127   47696 auto chunk = capy::buffer_slice( 1143   47696 auto chunk = capy::buffer_slice(
1128   cb0_data, 0, chunk_avail); 1144   cb0_data, 0, chunk_avail);
1129   1145  
HITCBC 1130   47696 if(body_limit_remain() < chunk_avail) 1146   47696 if(body_limit_remain() < chunk_avail)
1131   { 1147   {
MISUBC 1132 - ✗ ec = error::body_too_large; 1148 + ✗ ec = BOOST_HTTP_ERR(
  1149 + error::body_too_large);
MISUBC 1133   ✗ state_ = state::reset; 1150   ✗ state_ = state::reset;
HITCBC 1134   4131 return; 1151   4131 return;
1135   } 1152   }
1136   1153  
1137   // in_place style 1154   // in_place style
HITCBC 1138   47696 auto copied = capy::buffer_copy( 1155   47696 auto copied = capy::buffer_copy(
HITCBC 1139   47696 cb1_.prepare(cb1_.capacity()), 1156   47696 cb1_.prepare(cb1_.capacity()),
1140   chunk); 1157   chunk);
HITCBC 1141   47696 chunk_remain_ -= copied; 1158   47696 chunk_remain_ -= copied;
HITCBC 1142   47696 body_avail_ += copied; 1159   47696 body_avail_ += copied;
HITCBC 1143   47696 body_total_ += copied; 1160   47696 body_total_ += copied;
HITCBC 1144   47696 cb0_.consume(copied); 1161   47696 cb0_.consume(copied);
HITCBC 1145   47696 cb1_.commit(copied); 1162   47696 cb1_.commit(copied);
HITCBC 1146   47696 if(cb1_.capacity() == 0 1163   47696 if(cb1_.capacity() == 0
HITCBC 1147   47696 && !chunked_body_ended) 1164   47696 && !chunked_body_ended)
1148   { 1165   {
MISUBC 1149 - ✗ ec = error::in_place_overflow; 1166 + ✗ ec = BOOST_HTTP_ERR(
  1167 + error::in_place_overflow);
MISUBC 1150   ✗ return; 1168   ✗ return;
1151   } 1169   }
1152   1170  
HITCBC 1153   47696 if(chunked_body_ended) 1171   47696 if(chunked_body_ended)
1154   { 1172   {
HITCBC 1155   4131 set_state_to_complete(); 1173   4131 set_state_to_complete();
HITCBC 1156   4131 return; 1174   4131 return;
1157   } 1175   }
1158   } 1176   }
HITCBC 1159   51841 } 1177   51841 }
1160   } 1178   }
1161   else 1179   else
1162   { 1180   {
1163   // non-chunked payload 1181   // non-chunked payload
1164   1182  
HITCBC 1165   73956 const std::size_t payload_avail = [&]() 1183   73956 const std::size_t payload_avail = [&]()
1166   { 1184   {
HITCBC 1167   24652 auto ret = cb0_.size(); 1185   24652 auto ret = cb0_.size();
HITCBC 1168   24652 if(!filter_) 1186   24652 if(!filter_)
HITCBC 1169   24652 ret -= body_avail_; 1187   24652 ret -= body_avail_;
HITCBC 1170   24652 if(m_.payload() == payload::size) 1188   24652 if(m_.payload() == payload::size)
HITCBC 1171   24395 return clamp(payload_remain_, ret); 1189   24395 return clamp(payload_remain_, ret);
1172   // payload::eof 1190   // payload::eof
HITCBC 1173   257 return ret; 1191   257 return ret;
HITCBC 1174   24652 }(); 1192   24652 }();
1175   1193  
HITCBC 1176   73956 const bool is_complete = [&]() 1194   73956 const bool is_complete = [&]()
1177   { 1195   {
HITCBC 1178   24652 if(m_.payload() == payload::size) 1196   24652 if(m_.payload() == payload::size)
HITCBC 1179   24395 return payload_avail == payload_remain_; 1197   24395 return payload_avail == payload_remain_;
1180   // payload::eof 1198   // payload::eof
HITCBC 1181   257 return got_eof_; 1199   257 return got_eof_;
HITCBC 1182   24652 }(); 1200   24652 }();
1183   1201  
HITCBC 1184   24652 if(filter_) 1202   24652 if(filter_)
1185   { 1203   {
MISUBC 1186   ✗ payload_remain_ -= apply_filter( 1204   ✗ payload_remain_ -= apply_filter(
MISUBC 1187   ✗ ec, payload_avail, !is_complete); 1205   ✗ ec, payload_avail, !is_complete);
MISUBC 1188   ✗ if(ec || is_complete) 1206   ✗ if(ec || is_complete)
MISUBC 1189   ✗ return; 1207   ✗ return;
1190   } 1208   }
1191   else 1209   else
1192   { 1210   {
1193   // plain body 1211   // plain body
1194   1212  
HITCBC 1195   24652 if(m_.payload() == payload::to_eof) 1213   24652 if(m_.payload() == payload::to_eof)
1196   { 1214   {
HITCBC 1197   257 if(body_limit_remain() < payload_avail) 1215   257 if(body_limit_remain() < payload_avail)
1198   { 1216   {
HITCBC 1199 - 1 ec = error::body_too_large; 1217 + 2 ec = BOOST_HTTP_ERR(
  1218 + error::body_too_large);
HITCBC 1200   1 state_ = state::reset; 1219   1 state_ = state::reset;
HITCBC 1201   1 return; 1220   1 return;
1202   } 1221   }
1203   } 1222   }
1204   1223  
1205   // in_place style 1224   // in_place style
HITCBC 1206   24651 payload_remain_ -= payload_avail; 1225   24651 payload_remain_ -= payload_avail;
HITCBC 1207   24651 body_avail_ += payload_avail; 1226   24651 body_avail_ += payload_avail;
HITCBC 1208   24651 body_total_ += payload_avail; 1227   24651 body_total_ += payload_avail;
HITCBC 1209   24651 if(cb0_.capacity() == 0 && !is_complete) 1228   24651 if(cb0_.capacity() == 0 && !is_complete)
1210   { 1229   {
HITCBC 1211 - 7 ec = error::in_place_overflow; 1230 + 14 ec = BOOST_HTTP_ERR(
  1231 + error::in_place_overflow);
HITCBC 1212   7 return; 1232   7 return;
1213   } 1233   }
1214   1234  
HITCBC 1215   24644 if(is_complete) 1235   24644 if(is_complete)
1216   { 1236   {
HITCBC 1217   4233 set_state_to_complete(); 1237   4233 set_state_to_complete();
HITCBC 1218   4233 return; 1238   4233 return;
1219   } 1239   }
1220   } 1240   }
1221   1241  
HITCBC 1222   20411 if(m_.payload() == payload::size && got_eof_) 1242   20411 if(m_.payload() == payload::size && got_eof_)
1223   { 1243   {
HITCBC 1224 - 1 ec = error::incomplete; 1244 + 2 ec = BOOST_HTTP_ERR(
  1245 + error::incomplete);
HITCBC 1225   1 state_ = state::reset; 1246   1 state_ = state::reset;
HITCBC 1226   1 return; 1247   1 return;
1227   } 1248   }
1228   1249  
HITCBC 1229 - 20410 ec = error::need_data; 1250 + 40820 ec = BOOST_HTTP_ERR(
  1251 + error::need_data);
HITCBC 1230   20410 return; 1252   20410 return;
1231   } 1253   }
1232   1254  
1233   break; 1255   break;
1234   } 1256   }
1235   1257  
HITCBC 1236   2213 case state::complete: 1258   2213 case state::complete:
HITCBC 1237   2213 break; 1259   2213 break;
1238   } 1260   }
1239   } 1261   }
1240   1262  
1241   auto 1263   auto
HITCBC 1242   41440 pull_body() -> 1264   41440 pull_body() ->
1243   const_buffers_type 1265   const_buffers_type
1244   { 1266   {
HITCBC 1245   41440 switch(state_) 1267   41440 switch(state_)
1246   { 1268   {
HITCBC 1247   28 case state::header_done: 1269   28 case state::header_done:
HITCBC 1248   28 return {}; 1270   28 return {};
HITCBC 1249   41410 case state::body: 1271   41410 case state::body:
1250   case state::complete: 1272   case state::complete:
HITCBC 1251   41410 cbp_ = prefix_pair( 1273   41410 cbp_ = prefix_pair(
HITCBC 1252   41410 (is_plain() ? cb0_ : cb1_).data(), 1274   41410 (is_plain() ? cb0_ : cb1_).data(),
1253   body_avail_); 1275   body_avail_);
HITCBC 1254   41410 return detail::make_span(cbp_); 1276   41410 return detail::make_span(cbp_);
HITCBC 1255   2 case state::reset: 1277   2 case state::reset:
HITCBC 1256   2 if(got_header_) 1278   2 if(got_header_)
HITCBC 1257   2 return {}; 1279   2 return {};
1258   BOOST_FALLTHROUGH; 1280   BOOST_FALLTHROUGH;
1259   default: 1281   default:
MISUBC 1260   ✗ detail::throw_logic_error(); 1282   ✗ detail::throw_logic_error();
1261   } 1283   }
1262   } 1284   }
1263   1285  
1264   void 1286   void
HITCBC 1265   39606 consume_body(std::size_t n) 1287   39606 consume_body(std::size_t n)
1266   { 1288   {
HITCBC 1267   39606 switch(state_) 1289   39606 switch(state_)
1268   { 1290   {
MISUBC 1269   ✗ case state::header_done: 1291   ✗ case state::header_done:
MISUBC 1270   ✗ return; 1292   ✗ return;
HITCBC 1271   39606 case state::body: 1293   39606 case state::body:
1272   case state::complete: 1294   case state::complete:
HITCBC 1273   39606 n = clamp(n, body_avail_); 1295   39606 n = clamp(n, body_avail_);
HITCBC 1274   39606 (is_plain() ? cb0_ : cb1_).consume(n); 1296   39606 (is_plain() ? cb0_ : cb1_).consume(n);
HITCBC 1275   39606 body_avail_ -= n; 1297   39606 body_avail_ -= n;
HITCBC 1276   39606 return; 1298   39606 return;
MISUBC 1277   ✗ case state::reset: 1299   ✗ case state::reset:
MISUBC 1278   ✗ if(got_header_) 1300   ✗ if(got_header_)
MISUBC 1279   ✗ return; 1301   ✗ return;
1280   BOOST_FALLTHROUGH; 1302   BOOST_FALLTHROUGH;
1281   default: 1303   default:
MISUBC 1282   ✗ detail::throw_logic_error(); 1304   ✗ detail::throw_logic_error();
1283   } 1305   }
1284   } 1306   }
1285   1307  
1286   core::string_view 1308   core::string_view
HITCBC 1287   712 body() const 1309   712 body() const
1288   { 1310   {
1289   // Precondition violation 1311   // Precondition violation
HITCBC 1290   712 if(state_ != state::complete) 1312   712 if(state_ != state::complete)
MISUBC 1291   ✗ detail::throw_logic_error(); 1313   ✗ detail::throw_logic_error();
1292   1314  
1293   // Precondition violation 1315   // Precondition violation
HITCBC 1294   712 if(body_avail_ != body_total_) 1316   712 if(body_avail_ != body_total_)
MISUBC 1295   ✗ detail::throw_logic_error(); 1317   ✗ detail::throw_logic_error();
1296   1318  
HITCBC 1297   712 auto cbp = (is_plain() ? cb0_ : cb1_).data(); 1319   712 auto cbp = (is_plain() ? cb0_ : cb1_).data();
HITCBC 1298   712 BOOST_ASSERT(body_avail_ <= cbp[0].size()); 1320   712 BOOST_ASSERT(body_avail_ <= cbp[0].size());
HITCBC 1299   712 return core::string_view( 1321   712 return core::string_view(
HITCBC 1300   712 static_cast<char const*>(cbp[0].data()), 1322   712 static_cast<char const*>(cbp[0].data()),
HITCBC 1301   1424 body_avail_); 1323   1424 body_avail_);
1302   } 1324   }
1303   1325  
1304   bool 1326   bool
HITCBC 1305   9 has_buffered_data() const noexcept 1327   9 has_buffered_data() const noexcept
1306   { 1328   {
HITCBC 1307   9 if(state_ != state::complete) 1329   9 if(state_ != state::complete)
HITCBC 1308   1 return false; 1330   1 return false;
1309   1331  
HITCBC 1310   8 if(is_plain()) 1332   8 if(is_plain())
HITCBC 1311   6 return cb0_.size() > body_avail_; 1333   6 return cb0_.size() > body_avail_;
HITCBC 1312   2 return cb0_.size() > 0; 1334   2 return cb0_.size() > 0;
1313   } 1335   }
1314   1336  
1315   void 1337   void
HITCBC 1316   5 set_body_limit(std::uint64_t n) 1338   5 set_body_limit(std::uint64_t n)
1317   { 1339   {
HITCBC 1318   5 switch(state_) 1340   5 switch(state_)
1319   { 1341   {
HITCBC 1320   1 case state::header: 1342   1 case state::header:
1321   case state::header_done: 1343   case state::header_done:
HITCBC 1322   1 body_limit_ = n; 1344   1 body_limit_ = n;
HITCBC 1323   1 break; 1345   1 break;
HITCBC 1324   2 case state::complete: 1346   2 case state::complete:
1325   // only allowed for empty bodies 1347   // only allowed for empty bodies
HITCBC 1326   2 if(body_total_ == 0) 1348   2 if(body_total_ == 0)
HITCBC 1327   1 break; 1349   1 break;
1328   BOOST_FALLTHROUGH; 1350   BOOST_FALLTHROUGH;
1329   default: 1351   default:
1330   // set body_limit before parsing the body 1352   // set body_limit before parsing the body
HITCBC 1331   3 detail::throw_logic_error(); 1353   3 detail::throw_logic_error();
1332   } 1354   }
HITCBC 1333   2 } 1355   2 }
1334   1356  
1335   private: 1357   private:
1336   bool 1358   bool
HITCBC 1337   140533 is_plain() const noexcept 1359   140533 is_plain() const noexcept
1338   { 1360   {
HITCBC 1339   281066 return ! filter_ && 1361   281066 return ! filter_ &&
HITCBC 1340   281066 m_.payload() != payload::chunked; 1362   281066 m_.payload() != payload::chunked;
1341   } 1363   }
1342   1364  
1343   std::uint64_t 1365   std::uint64_t
HITCBC 1344   47967 body_limit_remain() const noexcept 1366   47967 body_limit_remain() const noexcept
1345   { 1367   {
HITCBC 1346   47967 return body_limit_ - body_total_; 1368   47967 return body_limit_ - body_total_;
1347   } 1369   }
1348   1370  
1349   std::size_t 1371   std::size_t
MISUBC 1350   ✗ apply_filter( 1372   ✗ apply_filter(
1351 - std::error_code& ec, 1373 + system::error_code& ec,
1352   std::size_t payload_avail, 1374   std::size_t payload_avail,
1353   bool more) 1375   bool more)
1354   { 1376   {
MISUBC 1355   ✗ std::size_t p0 = payload_avail; 1377   ✗ std::size_t p0 = payload_avail;
1356   for(;;) 1378   for(;;)
1357   { 1379   {
MISUBC 1358   ✗ if(payload_avail == 0 && more) 1380   ✗ if(payload_avail == 0 && more)
MISUBC 1359   ✗ break; 1381   ✗ break;
1360   1382  
MISUBC 1361   ✗ auto f_rs = [&](){ 1383   ✗ auto f_rs = [&](){
MISUBC 1362   ✗ BOOST_ASSERT(filter_ != nullptr); 1384   ✗ BOOST_ASSERT(filter_ != nullptr);
MISUBC 1363   ✗ std::size_t n = clamp(body_limit_remain()); 1385   ✗ std::size_t n = clamp(body_limit_remain());
MISUBC 1364   ✗ n = clamp(n, cb1_.capacity()); 1386   ✗ n = clamp(n, cb1_.capacity());
1365   1387  
MISUBC 1366   ✗ return filter_->process( 1388   ✗ return filter_->process(
MISUBC 1367   ✗ detail::make_span(cb1_.prepare(n)), 1389   ✗ detail::make_span(cb1_.prepare(n)),
MISUBC 1368   ✗ prefix_pair(cb0_.data(), payload_avail), 1390   ✗ prefix_pair(cb0_.data(), payload_avail),
MISUBC 1369   ✗ more); 1391   ✗ more);
MISUBC 1370   ✗ }(); 1392   ✗ }();
1371   1393  
MISUBC 1372   ✗ cb0_.consume(f_rs.in_bytes); 1394   ✗ cb0_.consume(f_rs.in_bytes);
MISUBC 1373   ✗ payload_avail -= f_rs.in_bytes; 1395   ✗ payload_avail -= f_rs.in_bytes;
MISUBC 1374   ✗ body_total_ += f_rs.out_bytes; 1396   ✗ body_total_ += f_rs.out_bytes;
1375   1397  
1376   // in_place style 1398   // in_place style
MISUBC 1377   ✗ cb1_.commit(f_rs.out_bytes); 1399   ✗ cb1_.commit(f_rs.out_bytes);
MISUBC 1378   ✗ body_avail_ += f_rs.out_bytes; 1400   ✗ body_avail_ += f_rs.out_bytes;
MISUBC 1379   ✗ if(cb1_.capacity() == 0 && 1401   ✗ if(cb1_.capacity() == 0 &&
MISUBC 1380   ✗ !f_rs.finished && f_rs.in_bytes == 0) 1402   ✗ !f_rs.finished && f_rs.in_bytes == 0)
1381   { 1403   {
MISUBC 1382 - ✗ ec = error::in_place_overflow; 1404 + ✗ ec = BOOST_HTTP_ERR(
  1405 + error::in_place_overflow);
MISUBC 1383   ✗ goto done; 1406   ✗ goto done;
1384   } 1407   }
1385   1408  
MISUBC 1386   ✗ if(f_rs.ec) 1409   ✗ if(f_rs.ec)
1387   { 1410   {
MISUBC 1388   ✗ ec = f_rs.ec; 1411   ✗ ec = f_rs.ec;
MISUBC 1389   ✗ state_ = state::reset; 1412   ✗ state_ = state::reset;
MISUBC 1390   ✗ break; 1413   ✗ break;
1391   } 1414   }
1392   1415  
MISUBC 1393   ✗ if(body_limit_remain() == 0 && 1416   ✗ if(body_limit_remain() == 0 &&
MISUBC 1394   ✗ !f_rs.finished && f_rs.in_bytes == 0) 1417   ✗ !f_rs.finished && f_rs.in_bytes == 0)
1395   { 1418   {
MISUBC 1396 - ✗ ec = error::body_too_large; 1419 + ✗ ec = BOOST_HTTP_ERR(
  1420 + error::body_too_large);
MISUBC 1397   ✗ state_ = state::reset; 1421   ✗ state_ = state::reset;
MISUBC 1398   ✗ break; 1422   ✗ break;
1399   } 1423   }
1400   1424  
MISUBC 1401   ✗ if(f_rs.finished) 1425   ✗ if(f_rs.finished)
1402   { 1426   {
MISUBC 1403   ✗ if(!more) 1427   ✗ if(!more)
MISUBC 1404   ✗ state_ = state::complete; 1428   ✗ state_ = state::complete;
MISUBC 1405   ✗ break; 1429   ✗ break;
1406   } 1430   }
MISUBC 1407   ✗ } 1431   ✗ }
1408   1432  
MISUBC 1409   ✗ done: 1433   ✗ done:
MISUBC 1410   ✗ return p0 - payload_avail; 1434   ✗ return p0 - payload_avail;
1411   } 1435   }
1412   }; 1436   };
1413   1437  
1414   //------------------------------------------------ 1438   //------------------------------------------------
1415   // 1439   //
1416   // Special Members 1440   // Special Members
1417   // 1441   //
1418   //------------------------------------------------ 1442   //------------------------------------------------
1419   1443  
HITCBC 1420   2190 parser:: 1444   2190 parser::
1421   ~parser() 1445   ~parser()
1422   { 1446   {
HITCBC 1423   2190 delete impl_; 1447   2190 delete impl_;
HITCBC 1424   2190 } 1448   2190 }
1425   1449  
HITCBC 1426   12 parser:: 1450   12 parser::
HITCBC 1427   12 parser() noexcept 1451   12 parser() noexcept
HITCBC 1428   12 : impl_(nullptr) 1452   12 : impl_(nullptr)
1429   { 1453   {
HITCBC 1430   12 } 1454   12 }
1431   1455  
HITCBC 1432   3 parser:: 1456   3 parser::
HITCBC 1433   3 parser(parser&& other) noexcept 1457   3 parser(parser&& other) noexcept
HITCBC 1434   3 : impl_(other.impl_) 1458   3 : impl_(other.impl_)
1435   { 1459   {
HITCBC 1436   3 other.impl_ = nullptr; 1460   3 other.impl_ = nullptr;
HITCBC 1437   3 } 1461   3 }
1438   1462  
HITCBC 1439   2175 parser:: 1463   2175 parser::
1440   parser( 1464   parser(
1441   std::shared_ptr<parser_config_impl const> cfg, 1465   std::shared_ptr<parser_config_impl const> cfg,
HITCBC 1442   2175 detail::kind k) 1466   2175 detail::kind k)
HITCBC 1443   2175 : impl_(new impl(std::move(cfg), k)) 1467   2175 : impl_(new impl(std::move(cfg), k))
1444   { 1468   {
1445   // TODO: use a single allocation for 1469   // TODO: use a single allocation for
1446   // impl and workspace buffer. 1470   // impl and workspace buffer.
HITCBC 1447   2175 } 1471   2175 }
1448   1472  
1449   void 1473   void
HITCBC 1450   4 parser:: 1474   4 parser::
1451   assign(parser&& other) noexcept 1475   assign(parser&& other) noexcept
1452   { 1476   {
HITCBC 1453   4 if(this == &other) 1477   4 if(this == &other)
MISUBC 1454   ✗ return; 1478   ✗ return;
HITCBC 1455   4 delete impl_; 1479   4 delete impl_;
HITCBC 1456   4 impl_ = other.impl_; 1480   4 impl_ = other.impl_;
HITCBC 1457   4 other.impl_ = nullptr; 1481   4 other.impl_ = nullptr;
1458   } 1482   }
1459   1483  
1460   //-------------------------------------------- 1484   //--------------------------------------------
1461   // 1485   //
1462   // Observers 1486   // Observers
1463   // 1487   //
1464   //-------------------------------------------- 1488   //--------------------------------------------
1465   1489  
1466   bool 1490   bool
HITCBC 1467   36129 parser::got_header() const noexcept 1491   36129 parser::got_header() const noexcept
1468   { 1492   {
HITCBC 1469   36129 BOOST_ASSERT(impl_); 1493   36129 BOOST_ASSERT(impl_);
HITCBC 1470   36129 return impl_->got_header(); 1494   36129 return impl_->got_header();
1471   } 1495   }
1472   1496  
1473   bool 1497   bool
HITCBC 1474   59142 parser::is_complete() const noexcept 1498   59142 parser::is_complete() const noexcept
1475   { 1499   {
HITCBC 1476   59142 BOOST_ASSERT(impl_); 1500   59142 BOOST_ASSERT(impl_);
HITCBC 1477   59142 return impl_->is_complete(); 1501   59142 return impl_->is_complete();
1478   } 1502   }
1479   1503  
1480   //------------------------------------------------ 1504   //------------------------------------------------
1481   // 1505   //
1482   // Modifiers 1506   // Modifiers
1483   // 1507   //
1484   //------------------------------------------------ 1508   //------------------------------------------------
1485   1509  
1486   void 1510   void
HITCBC 1487   2722 parser:: 1511   2722 parser::
1488   reset() noexcept 1512   reset() noexcept
1489   { 1513   {
HITCBC 1490   2722 BOOST_ASSERT(impl_); 1514   2722 BOOST_ASSERT(impl_);
HITCBC 1491   2722 impl_->reset(); 1515   2722 impl_->reset();
HITCBC 1492   2722 } 1516   2722 }
1493   1517  
1494   void 1518   void
HITCBC 1495   10651 parser::start() 1519   10651 parser::start()
1496   { 1520   {
HITCBC 1497   10651 BOOST_ASSERT(impl_); 1521   10651 BOOST_ASSERT(impl_);
HITCBC 1498   10651 impl_->start(false); 1522   10651 impl_->start(false);
HITCBC 1499   10646 } 1523   10646 }
1500   1524  
1501   auto 1525   auto
HITCBC 1502   81915 parser:: 1526   81915 parser::
1503   prepare() -> 1527   prepare() ->
1504   mutable_buffers_type 1528   mutable_buffers_type
1505   { 1529   {
HITCBC 1506   81915 BOOST_ASSERT(impl_); 1530   81915 BOOST_ASSERT(impl_);
HITCBC 1507   81915 return impl_->prepare(); 1531   81915 return impl_->prepare();
1508   } 1532   }
1509   1533  
1510   void 1534   void
HITCBC 1511   80858 parser:: 1535   80858 parser::
1512   commit( 1536   commit(
1513   std::size_t n) 1537   std::size_t n)
1514   { 1538   {
HITCBC 1515   80858 BOOST_ASSERT(impl_); 1539   80858 BOOST_ASSERT(impl_);
HITCBC 1516   80858 impl_->commit(n); 1540   80858 impl_->commit(n);
HITCBC 1517   80852 } 1541   80852 }
1518   1542  
1519   void 1543   void
HITCBC 1520   134 parser:: 1544   134 parser::
1521   commit_eof() 1545   commit_eof()
1522   { 1546   {
HITCBC 1523   134 BOOST_ASSERT(impl_); 1547   134 BOOST_ASSERT(impl_);
HITCBC 1524   134 impl_->commit_eof(); 1548   134 impl_->commit_eof();
HITCBC 1525   131 } 1549   131 }
1526   1550  
1527   void 1551   void
HITCBC 1528   98769 parser:: 1552   98769 parser::
1529   parse( 1553   parse(
1530 - std::error_code& ec) 1554 + system::error_code& ec)
1531   { 1555   {
HITCBC 1532   98769 BOOST_ASSERT(impl_); 1556   98769 BOOST_ASSERT(impl_);
HITCBC 1533   98769 impl_->parse(ec); 1557   98769 impl_->parse(ec);
HITCBC 1534   98767 } 1558   98767 }
1535   1559  
1536   auto 1560   auto
HITCBC 1537   41440 parser:: 1561   41440 parser::
1538   pull_body() -> 1562   pull_body() ->
1539   const_buffers_type 1563   const_buffers_type
1540   { 1564   {
HITCBC 1541   41440 BOOST_ASSERT(impl_); 1565   41440 BOOST_ASSERT(impl_);
HITCBC 1542   41440 return impl_->pull_body(); 1566   41440 return impl_->pull_body();
1543   } 1567   }
1544   1568  
1545   void 1569   void
HITCBC 1546   39606 parser:: 1570   39606 parser::
1547   consume_body(std::size_t n) 1571   consume_body(std::size_t n)
1548   { 1572   {
HITCBC 1549   39606 BOOST_ASSERT(impl_); 1573   39606 BOOST_ASSERT(impl_);
HITCBC 1550   39606 impl_->consume_body(n); 1574   39606 impl_->consume_body(n);
HITCBC 1551   39606 } 1575   39606 }
1552   1576  
1553   core::string_view 1577   core::string_view
HITCBC 1554   712 parser:: 1578   712 parser::
1555   body() const 1579   body() const
1556   { 1580   {
HITCBC 1557   712 BOOST_ASSERT(impl_); 1581   712 BOOST_ASSERT(impl_);
HITCBC 1558   712 return impl_->body(); 1582   712 return impl_->body();
1559   } 1583   }
1560   1584  
1561   core::string_view 1585   core::string_view
MISUBC 1562   ✗ parser:: 1586   ✗ parser::
1563   release_buffered_data() noexcept 1587   release_buffered_data() noexcept
1564   { 1588   {
1565   // TODO 1589   // TODO
MISUBC 1566   ✗ return {}; 1590   ✗ return {};
1567   } 1591   }
1568   1592  
1569   bool 1593   bool
HITCBC 1570   9 parser:: 1594   9 parser::
1571   has_buffered_data() const noexcept 1595   has_buffered_data() const noexcept
1572   { 1596   {
HITCBC 1573   9 BOOST_ASSERT(impl_); 1597   9 BOOST_ASSERT(impl_);
HITCBC 1574   9 return impl_->has_buffered_data(); 1598   9 return impl_->has_buffered_data();
1575   } 1599   }
1576   1600  
1577   void 1601   void
HITCBC 1578   5 parser:: 1602   5 parser::
1579   set_body_limit(std::uint64_t n) 1603   set_body_limit(std::uint64_t n)
1580   { 1604   {
HITCBC 1581   5 BOOST_ASSERT(impl_); 1605   5 BOOST_ASSERT(impl_);
HITCBC 1582   5 impl_->set_body_limit(n); 1606   5 impl_->set_body_limit(n);
HITCBC 1583   2 } 1607   2 }
1584   1608  
1585   //------------------------------------------------ 1609   //------------------------------------------------
1586   // 1610   //
1587   // Implementation 1611   // Implementation
1588   // 1612   //
1589   //------------------------------------------------ 1613   //------------------------------------------------
1590   1614  
1591   void 1615   void
MISUBC 1592   ✗ parser:: 1616   ✗ parser::
1593   start_impl(bool head_response) 1617   start_impl(bool head_response)
1594   { 1618   {
MISUBC 1595   ✗ BOOST_ASSERT(impl_); 1619   ✗ BOOST_ASSERT(impl_);
MISUBC 1596   ✗ impl_->start(head_response); 1620   ✗ impl_->start(head_response);
MISUBC 1597   ✗ } 1621   ✗ }
1598   1622  
1599   static_request const& 1623   static_request const&
HITCBC 1600   316 parser:: 1624   316 parser::
1601   safe_get_request() const 1625   safe_get_request() const
1602   { 1626   {
HITCBC 1603   316 BOOST_ASSERT(impl_); 1627   316 BOOST_ASSERT(impl_);
HITCBC 1604   316 return impl_->safe_get_request(); 1628   316 return impl_->safe_get_request();
1605   } 1629   }
1606   1630  
1607   static_response const& 1631   static_response const&
HITCBC 1608   3 parser:: 1632   3 parser::
1609   safe_get_response() const 1633   safe_get_response() const
1610   { 1634   {
HITCBC 1611   3 BOOST_ASSERT(impl_); 1635   3 BOOST_ASSERT(impl_);
HITCBC 1612   3 return impl_->safe_get_response(); 1636   3 return impl_->safe_get_response();
1613   } 1637   }
1614   1638  
1615   } // http 1639   } // http
1616   } // boost 1640   } // boost