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