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