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