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