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/slice.hpp>
23  
#include <boost/capy/buffers/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 <memory>
36  
#include <memory>
37  

37  

38  
namespace boost {
38  
namespace boost {
39  
namespace http {
39  
namespace http {
40  

40  

41  
/*
41  
/*
42  
    Principles for fixed-size buffer design
42  
    Principles for fixed-size buffer design
43  

43  

44  
    axiom 1:
44  
    axiom 1:
45  
        To read data you must have a buffer.
45  
        To read data you must have a buffer.
46  

46  

47  
    axiom 2:
47  
    axiom 2:
48  
        The size of the HTTP header is not
48  
        The size of the HTTP header is not
49  
        known in advance.
49  
        known in advance.
50  

50  

51  
    conclusion 3:
51  
    conclusion 3:
52  
        A single I/O can produce a complete
52  
        A single I/O can produce a complete
53  
        HTTP header and additional payload
53  
        HTTP header and additional payload
54  
        data.
54  
        data.
55  

55  

56  
    conclusion 4:
56  
    conclusion 4:
57  
        A single I/O can produce multiple
57  
        A single I/O can produce multiple
58  
        complete HTTP headers, complete
58  
        complete HTTP headers, complete
59  
        payloads, and a partial header or
59  
        payloads, and a partial header or
60  
        payload.
60  
        payload.
61  

61  

62  
    axiom 5:
62  
    axiom 5:
63  
        A process is in one of two states:
63  
        A process is in one of two states:
64  
            1. at or below capacity
64  
            1. at or below capacity
65  
            2. above capacity
65  
            2. above capacity
66  

66  

67  
    axiom 6:
67  
    axiom 6:
68  
        A program which can allocate an
68  
        A program which can allocate an
69  
        unbounded number of resources can
69  
        unbounded number of resources can
70  
        go above capacity.
70  
        go above capacity.
71  

71  

72  
    conclusion 7:
72  
    conclusion 7:
73  
        A program can guarantee never going
73  
        A program can guarantee never going
74  
        above capacity if all resources are
74  
        above capacity if all resources are
75  
        provisioned at program startup.
75  
        provisioned at program startup.
76  

76  

77  
    corollary 8:
77  
    corollary 8:
78  
        `parser` and `serializer` should each
78  
        `parser` and `serializer` should each
79  
        allocate a single buffer of calculated
79  
        allocate a single buffer of calculated
80  
        size, and never resize it.
80  
        size, and never resize it.
81  

81  

82  
    axiom #:
82  
    axiom #:
83  
        A parser and a serializer are always
83  
        A parser and a serializer are always
84  
        used in pairs.
84  
        used in pairs.
85  

85  

86  
Buffer Usage
86  
Buffer Usage
87  

87  

88  
|                                               | begin
88  
|                                               | begin
89  
| H |   p   |                               | f | read headers
89  
| H |   p   |                               | f | read headers
90  
| H |   p   |                           | T | f | set T body
90  
| H |   p   |                           | T | f | set T body
91  
| H |   p   |                       | C | T | f | make codec C
91  
| H |   p   |                       | C | T | f | make codec C
92  
| H |   p           |       b       | C | T | f | decode p into b
92  
| H |   p           |       b       | C | T | f | decode p into b
93  
| H |       p       |       b       | C | T | f | read/parse loop
93  
| H |       p       |       b       | C | T | f | read/parse loop
94  
| H |                                   | T | f | destroy codec
94  
| H |                                   | T | f | destroy codec
95  
| H |                                   | T | f | finished
95  
| H |                                   | T | f | finished
96  

96  

97  
    H   headers
97  
    H   headers
98  
    C   codec
98  
    C   codec
99  
    T   body
99  
    T   body
100  
    f   table
100  
    f   table
101  
    p   partial payload
101  
    p   partial payload
102  
    b   body data
102  
    b   body data
103  

103  

104  
    "payload" is the bytes coming in from
104  
    "payload" is the bytes coming in from
105  
        the stream.
105  
        the stream.
106  

106  

107  
    "body" is the logical body, after transfer
107  
    "body" is the logical body, after transfer
108  
        encoding is removed. This can be the
108  
        encoding is removed. This can be the
109  
        same as the payload.
109  
        same as the payload.
110  

110  

111  
    A "plain payload" is when the payload and
111  
    A "plain payload" is when the payload and
112  
        body are identical (no transfer encodings).
112  
        body are identical (no transfer encodings).
113  

113  

114  
    A "buffered payload" is any payload which is
114  
    A "buffered payload" is any payload which is
115  
        not plain. A second buffer is required
115  
        not plain. A second buffer is required
116  
        for reading.
116  
        for reading.
117  

117  

118  
    "overread" is additional data received past
118  
    "overread" is additional data received past
119  
    the end of the headers when reading headers,
119  
    the end of the headers when reading headers,
120  
    or additional data received past the end of
120  
    or additional data received past the end of
121  
    the message payload.
121  
    the message payload.
122  
*/
122  
*/
123  

123  

124  
namespace {
124  
namespace {
125  

125  

126  
class chained_sequence
126  
class chained_sequence
127  
{
127  
{
128  
    char const* pos_;
128  
    char const* pos_;
129  
    char const* end_;
129  
    char const* end_;
130  
    char const* begin_b_;
130  
    char const* begin_b_;
131  
    char const* end_b_;
131  
    char const* end_b_;
132  

132  

133  
public:
133  
public:
134  
    chained_sequence(capy::const_buffer_pair const& cbp)
134  
    chained_sequence(capy::const_buffer_pair const& cbp)
135  
        : pos_(static_cast<char const*>(cbp[0].data()))
135  
        : pos_(static_cast<char const*>(cbp[0].data()))
136  
        , end_(pos_ + cbp[0].size())
136  
        , end_(pos_ + cbp[0].size())
137  
        , begin_b_(static_cast<char const*>(cbp[1].data()))
137  
        , begin_b_(static_cast<char const*>(cbp[1].data()))
138  
        , end_b_(begin_b_ + cbp[1].size())
138  
        , end_b_(begin_b_ + cbp[1].size())
139  
    {
139  
    {
140  
    }
140  
    }
141  

141  

142  
    char const*
142  
    char const*
143  
    next() noexcept
143  
    next() noexcept
144  
    {
144  
    {
145  
        ++pos_;
145  
        ++pos_;
146  
        // most frequently taken branch
146  
        // most frequently taken branch
147  
        if(pos_ < end_)
147  
        if(pos_ < end_)
148  
            return pos_;
148  
            return pos_;
149  

149  

150  
        // bring the second range
150  
        // bring the second range
151  
        if(begin_b_ != end_b_)
151  
        if(begin_b_ != end_b_)
152  
        {
152  
        {
153  
            pos_ = begin_b_;
153  
            pos_ = begin_b_;
154  
            end_ = end_b_;
154  
            end_ = end_b_;
155  
            begin_b_ = end_b_;
155  
            begin_b_ = end_b_;
156  
            return pos_;
156  
            return pos_;
157  
        }
157  
        }
158  

158  

159  
        // undo the increament
159  
        // undo the increament
160  
        pos_ = end_;
160  
        pos_ = end_;
161  
        return nullptr;
161  
        return nullptr;
162  
    }
162  
    }
163  

163  

164  
    bool
164  
    bool
165  
    is_empty() const noexcept
165  
    is_empty() const noexcept
166  
    {
166  
    {
167  
        return pos_ == end_;
167  
        return pos_ == end_;
168  
    }
168  
    }
169  

169  

170  
    char
170  
    char
171  
    value() const noexcept
171  
    value() const noexcept
172  
    {
172  
    {
173  
        return *pos_;
173  
        return *pos_;
174  
    }
174  
    }
175  

175  

176  
    std::size_t
176  
    std::size_t
177  
    size() const noexcept
177  
    size() const noexcept
178  
    {
178  
    {
179  
        return (end_ - pos_) + (end_b_ - begin_b_);
179  
        return (end_ - pos_) + (end_b_ - begin_b_);
180  
    }
180  
    }
181  
};
181  
};
182  

182  

183  
std::uint64_t
183  
std::uint64_t
184  
parse_hex(
184  
parse_hex(
185  
    chained_sequence& cs,
185  
    chained_sequence& cs,
186  
    system::error_code& ec) noexcept
186  
    system::error_code& ec) noexcept
187  
{
187  
{
188  
    std::uint64_t v   = 0;
188  
    std::uint64_t v   = 0;
189  
    std::size_t init_size = cs.size();
189  
    std::size_t init_size = cs.size();
190  
    while(!cs.is_empty())
190  
    while(!cs.is_empty())
191  
    {
191  
    {
192  
        auto n = grammar::hexdig_value(cs.value());
192  
        auto n = grammar::hexdig_value(cs.value());
193  
        if(n < 0)
193  
        if(n < 0)
194  
        {
194  
        {
195  
            if(init_size == cs.size())
195  
            if(init_size == cs.size())
196  
            {
196  
            {
197  
                ec = BOOST_HTTP_ERR(
197  
                ec = BOOST_HTTP_ERR(
198  
                    error::bad_payload);
198  
                    error::bad_payload);
199  
                return 0;
199  
                return 0;
200  
            }
200  
            }
201  
            return v;
201  
            return v;
202  
        }
202  
        }
203  

203  

204  
        // at least 4 significant bits are free
204  
        // at least 4 significant bits are free
205  
        if(v > (std::numeric_limits<std::uint64_t>::max)() >> 4)
205  
        if(v > (std::numeric_limits<std::uint64_t>::max)() >> 4)
206  
        {
206  
        {
207  
            ec = BOOST_HTTP_ERR(
207  
            ec = BOOST_HTTP_ERR(
208  
                error::bad_payload);
208  
                error::bad_payload);
209  
            return 0;
209  
            return 0;
210  
        }
210  
        }
211  

211  

212  
        v = (v << 4) | static_cast<std::uint64_t>(n);
212  
        v = (v << 4) | static_cast<std::uint64_t>(n);
213  
        cs.next();
213  
        cs.next();
214  
    }
214  
    }
215  
    ec = BOOST_HTTP_ERR(
215  
    ec = BOOST_HTTP_ERR(
216  
        error::need_data);
216  
        error::need_data);
217  
    return 0;
217  
    return 0;
218  
}
218  
}
219  

219  

220  
void
220  
void
221  
find_eol(
221  
find_eol(
222  
    chained_sequence& cs,
222  
    chained_sequence& cs,
223  
    system::error_code& ec) noexcept
223  
    system::error_code& ec) noexcept
224  
{
224  
{
225  
    while(!cs.is_empty())
225  
    while(!cs.is_empty())
226  
    {
226  
    {
227  
        if(cs.value() == '\r')
227  
        if(cs.value() == '\r')
228  
        {
228  
        {
229  
            if(!cs.next())
229  
            if(!cs.next())
230  
                break;
230  
                break;
231  
            if(cs.value() != '\n')
231  
            if(cs.value() != '\n')
232  
            {
232  
            {
233  
                ec = BOOST_HTTP_ERR(
233  
                ec = BOOST_HTTP_ERR(
234  
                    error::bad_payload);
234  
                    error::bad_payload);
235  
                return;
235  
                return;
236  
            }
236  
            }
237  
            cs.next();
237  
            cs.next();
238  
            return;
238  
            return;
239  
        }
239  
        }
240  
        cs.next();
240  
        cs.next();
241  
    }
241  
    }
242  
    ec = BOOST_HTTP_ERR(
242  
    ec = BOOST_HTTP_ERR(
243  
        error::need_data);
243  
        error::need_data);
244  
}
244  
}
245  

245  

246  
void
246  
void
247  
parse_eol(
247  
parse_eol(
248  
    chained_sequence& cs,
248  
    chained_sequence& cs,
249  
    system::error_code& ec) noexcept
249  
    system::error_code& ec) noexcept
250  
{
250  
{
251  
    if(cs.size() >= 2)
251  
    if(cs.size() >= 2)
252  
    {
252  
    {
253  
        // we are sure size is at least 2
253  
        // we are sure size is at least 2
254  
        if(cs.value() == '\r' && *cs.next() == '\n')
254  
        if(cs.value() == '\r' && *cs.next() == '\n')
255  
        {
255  
        {
256  
            cs.next();
256  
            cs.next();
257  
            return;
257  
            return;
258  
        }
258  
        }
259  
        ec = BOOST_HTTP_ERR(
259  
        ec = BOOST_HTTP_ERR(
260  
            error::bad_payload);
260  
            error::bad_payload);
261  
        return;
261  
        return;
262  
    }
262  
    }
263  
    ec = BOOST_HTTP_ERR(
263  
    ec = BOOST_HTTP_ERR(
264  
        error::need_data);
264  
        error::need_data);
265  
}
265  
}
266  

266  

267  
void
267  
void
268  
skip_trailer_headers(
268  
skip_trailer_headers(
269  
    chained_sequence& cs,
269  
    chained_sequence& cs,
270  
    system::error_code& ec) noexcept
270  
    system::error_code& ec) noexcept
271  
{
271  
{
272  
    while(!cs.is_empty())
272  
    while(!cs.is_empty())
273  
    {
273  
    {
274  
        if(cs.value() == '\r')
274  
        if(cs.value() == '\r')
275  
        {
275  
        {
276  
            if(!cs.next())
276  
            if(!cs.next())
277  
                break;
277  
                break;
278  
            if(cs.value() != '\n')
278  
            if(cs.value() != '\n')
279  
            {
279  
            {
280  
                ec = BOOST_HTTP_ERR(
280  
                ec = BOOST_HTTP_ERR(
281  
                    error::bad_payload);
281  
                    error::bad_payload);
282  
                return;
282  
                return;
283  
            }
283  
            }
284  
            cs.next();
284  
            cs.next();
285  
            return;
285  
            return;
286  
        }
286  
        }
287  
        // skip to the end of field
287  
        // skip to the end of field
288  
        find_eol(cs, ec);
288  
        find_eol(cs, ec);
289  
        if(ec)
289  
        if(ec)
290  
            return;
290  
            return;
291  
    }
291  
    }
292  
    ec = BOOST_HTTP_ERR(
292  
    ec = BOOST_HTTP_ERR(
293  
        error::need_data);
293  
        error::need_data);
294  
}
294  
}
295  

295  

296  
template<class UInt>
296  
template<class UInt>
297  
std::size_t
297  
std::size_t
298  
clamp(
298  
clamp(
299  
    UInt x,
299  
    UInt x,
300  
    std::size_t limit = (std::numeric_limits<
300  
    std::size_t limit = (std::numeric_limits<
301  
        std::size_t>::max)()) noexcept
301  
        std::size_t>::max)()) noexcept
302  
{
302  
{
303  
    if(x >= limit)
303  
    if(x >= limit)
304  
        return limit;
304  
        return limit;
305  
    return static_cast<std::size_t>(x);
305  
    return static_cast<std::size_t>(x);
306  
}
306  
}
307  

307  

308  
class zlib_filter
308  
class zlib_filter
309  
    : public detail::zlib_filter_base
309  
    : public detail::zlib_filter_base
310  
{
310  
{
311  
    http::zlib::inflate_service& svc_;
311  
    http::zlib::inflate_service& svc_;
312  

312  

313  
public:
313  
public:
314  
    zlib_filter(
314  
    zlib_filter(
315  
        http::zlib::inflate_service& svc,
315  
        http::zlib::inflate_service& svc,
316  
        int window_bits)
316  
        int window_bits)
317  
        : svc_(svc)
317  
        : svc_(svc)
318  
    {
318  
    {
319  
        system::error_code ec = static_cast<http::zlib::error>(
319  
        system::error_code ec = static_cast<http::zlib::error>(
320  
            svc_.init2(strm_, window_bits));
320  
            svc_.init2(strm_, window_bits));
321  
        if(ec != http::zlib::error::ok)
321  
        if(ec != http::zlib::error::ok)
322  
            detail::throw_system_error(ec);
322  
            detail::throw_system_error(ec);
323  
    }
323  
    }
324  

324  

325  
private:
325  
private:
326  
    virtual
326  
    virtual
327  
    results
327  
    results
328  
    do_process(
328  
    do_process(
329  
        capy::mutable_buffer out,
329  
        capy::mutable_buffer out,
330  
        capy::const_buffer in,
330  
        capy::const_buffer in,
331  
        bool more) noexcept override
331  
        bool more) noexcept override
332  
    {
332  
    {
333  
        strm_.next_out  = static_cast<unsigned char*>(out.data());
333  
        strm_.next_out  = static_cast<unsigned char*>(out.data());
334  
        strm_.avail_out = saturate_cast(out.size());
334  
        strm_.avail_out = saturate_cast(out.size());
335  
        strm_.next_in   = static_cast<unsigned char*>(const_cast<void *>(in.data()));
335  
        strm_.next_in   = static_cast<unsigned char*>(const_cast<void *>(in.data()));
336  
        strm_.avail_in  = saturate_cast(in.size());
336  
        strm_.avail_in  = saturate_cast(in.size());
337  

337  

338  
        auto rs = static_cast<http::zlib::error>(
338  
        auto rs = static_cast<http::zlib::error>(
339  
            svc_.inflate(
339  
            svc_.inflate(
340  
                strm_,
340  
                strm_,
341  
                more ? http::zlib::no_flush : http::zlib::finish));
341  
                more ? http::zlib::no_flush : http::zlib::finish));
342  

342  

343  
        results rv;
343  
        results rv;
344  
        rv.out_bytes = saturate_cast(out.size()) - strm_.avail_out;
344  
        rv.out_bytes = saturate_cast(out.size()) - strm_.avail_out;
345  
        rv.in_bytes  = saturate_cast(in.size()) - strm_.avail_in;
345  
        rv.in_bytes  = saturate_cast(in.size()) - strm_.avail_in;
346  
        rv.finished  = (rs == http::zlib::error::stream_end);
346  
        rv.finished  = (rs == http::zlib::error::stream_end);
347  

347  

348  
        if(rs < http::zlib::error::ok && rs != http::zlib::error::buf_err)
348  
        if(rs < http::zlib::error::ok && rs != http::zlib::error::buf_err)
349  
            rv.ec = rs;
349  
            rv.ec = rs;
350  

350  

351  
        return rv;
351  
        return rv;
352  
    }
352  
    }
353  
};
353  
};
354  

354  

355  
class brotli_filter
355  
class brotli_filter
356  
    : public detail::brotli_filter_base
356  
    : public detail::brotli_filter_base
357  
{
357  
{
358  
    http::brotli::decode_service& svc_;
358  
    http::brotli::decode_service& svc_;
359  
    http::brotli::decoder_state* state_;
359  
    http::brotli::decoder_state* state_;
360  

360  

361  
public:
361  
public:
362  
    brotli_filter(http::brotli::decode_service& svc)
362  
    brotli_filter(http::brotli::decode_service& svc)
363  
        : svc_(svc)
363  
        : svc_(svc)
364  
    {
364  
    {
365  
        state_ = svc_.create_instance(nullptr, nullptr, nullptr);
365  
        state_ = svc_.create_instance(nullptr, nullptr, nullptr);
366  
        if(!state_)
366  
        if(!state_)
367  
            detail::throw_bad_alloc();
367  
            detail::throw_bad_alloc();
368  
    }
368  
    }
369  

369  

370  
    ~brotli_filter()
370  
    ~brotli_filter()
371  
    {
371  
    {
372  
        svc_.destroy_instance(state_);
372  
        svc_.destroy_instance(state_);
373  
    }
373  
    }
374  

374  

375  
private:
375  
private:
376  
    virtual
376  
    virtual
377  
    results
377  
    results
378  
    do_process(
378  
    do_process(
379  
        capy::mutable_buffer out,
379  
        capy::mutable_buffer out,
380  
        capy::const_buffer in,
380  
        capy::const_buffer in,
381  
        bool more) noexcept override
381  
        bool more) noexcept override
382  
    {
382  
    {
383  
        auto* next_in = reinterpret_cast<const std::uint8_t*>(in.data());
383  
        auto* next_in = reinterpret_cast<const std::uint8_t*>(in.data());
384  
        auto available_in = in.size();
384  
        auto available_in = in.size();
385  
        auto* next_out = reinterpret_cast<std::uint8_t*>(out.data());
385  
        auto* next_out = reinterpret_cast<std::uint8_t*>(out.data());
386  
        auto available_out = out.size();
386  
        auto available_out = out.size();
387  

387  

388  
        auto rs = svc_.decompress_stream(
388  
        auto rs = svc_.decompress_stream(
389  
            state_,
389  
            state_,
390  
            &available_in,
390  
            &available_in,
391  
            &next_in,
391  
            &next_in,
392  
            &available_out,
392  
            &available_out,
393  
            &next_out,
393  
            &next_out,
394  
            nullptr);
394  
            nullptr);
395  

395  

396  
        results rv;
396  
        results rv;
397  
        rv.in_bytes  = in.size()  - available_in;
397  
        rv.in_bytes  = in.size()  - available_in;
398  
        rv.out_bytes = out.size() - available_out;
398  
        rv.out_bytes = out.size() - available_out;
399  
        rv.finished  = svc_.is_finished(state_);
399  
        rv.finished  = svc_.is_finished(state_);
400  

400  

401  
        if(!more && rs == http::brotli::decoder_result::needs_more_input)
401  
        if(!more && rs == http::brotli::decoder_result::needs_more_input)
402  
            rv.ec = BOOST_HTTP_ERR(error::bad_payload);
402  
            rv.ec = BOOST_HTTP_ERR(error::bad_payload);
403  

403  

404  
        if(rs == http::brotli::decoder_result::error)
404  
        if(rs == http::brotli::decoder_result::error)
405  
            rv.ec = BOOST_HTTP_ERR(
405  
            rv.ec = BOOST_HTTP_ERR(
406  
                svc_.get_error_code(state_));
406  
                svc_.get_error_code(state_));
407  

407  

408  
        return rv;
408  
        return rv;
409  
    }
409  
    }
410  
};
410  
};
411  

411  

412  
} // namespace
412  
} // namespace
413  

413  

414  
//------------------------------------------------
414  
//------------------------------------------------
415  

415  

416  
class parser::impl
416  
class parser::impl
417  
{
417  
{
418  
    enum class state
418  
    enum class state
419  
    {
419  
    {
420  
        reset,
420  
        reset,
421  
        start,
421  
        start,
422  
        header,
422  
        header,
423  
        header_done,
423  
        header_done,
424  
        body,
424  
        body,
425  
        complete,
425  
        complete,
426  
    };
426  
    };
427  

427  

428  
    std::shared_ptr<parser_config_impl const> cfg_;
428  
    std::shared_ptr<parser_config_impl const> cfg_;
429  

429  

430  
    detail::workspace ws_;
430  
    detail::workspace ws_;
431  
    static_request m_;
431  
    static_request m_;
432  
    std::uint64_t body_limit_;
432  
    std::uint64_t body_limit_;
433  
    std::uint64_t body_total_;
433  
    std::uint64_t body_total_;
434  
    std::uint64_t payload_remain_;
434  
    std::uint64_t payload_remain_;
435  
    std::uint64_t chunk_remain_;
435  
    std::uint64_t chunk_remain_;
436  
    std::size_t body_avail_;
436  
    std::size_t body_avail_;
437  
    std::size_t nprepare_;
437  
    std::size_t nprepare_;
438  

438  

439  
    capy::flat_dynamic_buffer fb_;
439  
    capy::flat_dynamic_buffer fb_;
440  
    capy::circular_dynamic_buffer cb0_;
440  
    capy::circular_dynamic_buffer cb0_;
441  
    capy::circular_dynamic_buffer cb1_;
441  
    capy::circular_dynamic_buffer cb1_;
442  

442  

443  
    capy::mutable_buffer_pair mbp_;
443  
    capy::mutable_buffer_pair mbp_;
444  
    capy::const_buffer_pair cbp_;
444  
    capy::const_buffer_pair cbp_;
445  

445  

446  
    std::unique_ptr<detail::filter> filter_;
446  
    std::unique_ptr<detail::filter> filter_;
447  

447  

448  
    state state_;
448  
    state state_;
449  
    bool got_header_;
449  
    bool got_header_;
450  
    bool got_eof_;
450  
    bool got_eof_;
451  
    bool head_response_;
451  
    bool head_response_;
452  
    bool needs_chunk_close_;
452  
    bool needs_chunk_close_;
453  
    bool trailer_headers_;
453  
    bool trailer_headers_;
454  
    bool chunked_body_ended;
454  
    bool chunked_body_ended;
455  

455  

456  
public:
456  
public:
457  
    impl(std::shared_ptr<parser_config_impl const> cfg, detail::kind k)
457  
    impl(std::shared_ptr<parser_config_impl const> cfg, detail::kind k)
458  
        : cfg_(std::move(cfg))
458  
        : cfg_(std::move(cfg))
459  
        , ws_(cfg_->space_needed)
459  
        , ws_(cfg_->space_needed)
460  
        , m_(ws_.data(), ws_.size())
460  
        , m_(ws_.data(), ws_.size())
461  
        , state_(state::reset)
461  
        , state_(state::reset)
462  
        , got_header_(false)
462  
        , got_header_(false)
463  
    {
463  
    {
464  
        m_.h_ = detail::header(detail::empty{ k });
464  
        m_.h_ = detail::header(detail::empty{ k });
465  
    }
465  
    }
466  

466  

467  
    bool
467  
    bool
468  
    got_header() const noexcept
468  
    got_header() const noexcept
469  
    {
469  
    {
470  
        return got_header_;
470  
        return got_header_;
471  
    }
471  
    }
472  

472  

473  
    bool
473  
    bool
474  
    is_complete() const noexcept
474  
    is_complete() const noexcept
475  
    {
475  
    {
476  
        return state_ == state::complete;
476  
        return state_ == state::complete;
477  
    }
477  
    }
478  

478  

479  
    static_request const&
479  
    static_request const&
480  
    safe_get_request() const
480  
    safe_get_request() const
481  
    {
481  
    {
482  
        // headers must be received
482  
        // headers must be received
483  
        if(! got_header_)
483  
        if(! got_header_)
484  
            detail::throw_logic_error();
484  
            detail::throw_logic_error();
485  

485  

486  
        return m_;
486  
        return m_;
487  
    }
487  
    }
488  

488  

489  
    static_response const&
489  
    static_response const&
490  
    safe_get_response() const
490  
    safe_get_response() const
491  
    {
491  
    {
492  
        // headers must be received
492  
        // headers must be received
493  
        if(! got_header_)
493  
        if(! got_header_)
494  
            detail::throw_logic_error();
494  
            detail::throw_logic_error();
495  

495  

496  
        // TODO: use a union
496  
        // TODO: use a union
497  
        return reinterpret_cast<static_response const&>(m_);
497  
        return reinterpret_cast<static_response const&>(m_);
498  
    }
498  
    }
499  

499  

500  
    void
500  
    void
501  
    reset() noexcept
501  
    reset() noexcept
502  
    {
502  
    {
503  
        ws_.clear();
503  
        ws_.clear();
504  
        state_ = state::start;
504  
        state_ = state::start;
505  
        got_header_ = false;
505  
        got_header_ = false;
506  
        got_eof_ = false;
506  
        got_eof_ = false;
507  
    }
507  
    }
508  

508  

509  
    void
509  
    void
510  
    start(
510  
    start(
511  
        bool head_response)
511  
        bool head_response)
512  
    {
512  
    {
513  
        std::size_t leftover = 0;
513  
        std::size_t leftover = 0;
514  
        switch(state_)
514  
        switch(state_)
515  
        {
515  
        {
516  
        default:
516  
        default:
517  
        case state::reset:
517  
        case state::reset:
518  
            // reset must be called first
518  
            // reset must be called first
519  
            detail::throw_logic_error();
519  
            detail::throw_logic_error();
520  

520  

521  
        case state::start:
521  
        case state::start:
522  
            // reset required on eof
522  
            // reset required on eof
523  
            if(got_eof_)
523  
            if(got_eof_)
524  
                detail::throw_logic_error();
524  
                detail::throw_logic_error();
525  
            break;
525  
            break;
526  

526  

527  
        case state::header:
527  
        case state::header:
528  
            if(fb_.size() == 0)
528  
            if(fb_.size() == 0)
529  
            {
529  
            {
530  
                // start() called twice
530  
                // start() called twice
531  
                detail::throw_logic_error();
531  
                detail::throw_logic_error();
532  
            }
532  
            }
533  
            BOOST_FALLTHROUGH;
533  
            BOOST_FALLTHROUGH;
534  

534  

535  
        case state::header_done:
535  
        case state::header_done:
536  
        case state::body:
536  
        case state::body:
537  
            // current message is incomplete
537  
            // current message is incomplete
538  
            detail::throw_logic_error();
538  
            detail::throw_logic_error();
539  

539  

540  
        case state::complete:
540  
        case state::complete:
541  
        {
541  
        {
542  
            // remove available body.
542  
            // remove available body.
543  
            if(is_plain())
543  
            if(is_plain())
544  
                cb0_.consume(body_avail_);
544  
                cb0_.consume(body_avail_);
545  
            // move leftovers to front
545  
            // move leftovers to front
546  

546  

547  
            ws_.clear();
547  
            ws_.clear();
548  
            leftover = cb0_.size();
548  
            leftover = cb0_.size();
549  

549  

550  
            auto* dest = reinterpret_cast<char*>(ws_.data());
550  
            auto* dest = reinterpret_cast<char*>(ws_.data());
551  
            auto cbp   = cb0_.data();
551  
            auto cbp   = cb0_.data();
552  
            auto* a    = static_cast<char const*>(cbp[0].data());
552  
            auto* a    = static_cast<char const*>(cbp[0].data());
553  
            auto* b    = static_cast<char const*>(cbp[1].data());
553  
            auto* b    = static_cast<char const*>(cbp[1].data());
554  
            auto an    = cbp[0].size();
554  
            auto an    = cbp[0].size();
555  
            auto bn    = cbp[1].size();
555  
            auto bn    = cbp[1].size();
556  

556  

557  
            if(bn == 0)
557  
            if(bn == 0)
558  
            {
558  
            {
559  
                std::memmove(dest, a, an);
559  
                std::memmove(dest, a, an);
560  
            }
560  
            }
561  
            else
561  
            else
562  
            {
562  
            {
563  
                // if `a` can fit between `dest` and `b`, shift `b` to the left
563  
                // if `a` can fit between `dest` and `b`, shift `b` to the left
564  
                // and copy `a` to its position. if `a` fits perfectly, the
564  
                // and copy `a` to its position. if `a` fits perfectly, the
565  
                // shift will be of size 0.
565  
                // shift will be of size 0.
566  
                // if `a` requires more space, shift `b` to the right and
566  
                // if `a` requires more space, shift `b` to the right and
567  
                // copy `a` to its position. this process may require multiple
567  
                // copy `a` to its position. this process may require multiple
568  
                // iterations and should be done chunk by chunk to prevent `b`
568  
                // iterations and should be done chunk by chunk to prevent `b`
569  
                // from overlapping with `a`.
569  
                // from overlapping with `a`.
570  
                do
570  
                do
571  
                {
571  
                {
572  
                    // clamp right shifts to prevent overlap with `a`
572  
                    // clamp right shifts to prevent overlap with `a`
573  
                    auto* bp = (std::min)(dest + an, const_cast<char*>(a) - bn);
573  
                    auto* bp = (std::min)(dest + an, const_cast<char*>(a) - bn);
574  
                    b = static_cast<char const*>(std::memmove(bp, b, bn));
574  
                    b = static_cast<char const*>(std::memmove(bp, b, bn));
575  

575  

576  
                    // a chunk or all of `a` based on available space
576  
                    // a chunk or all of `a` based on available space
577  
                    auto chunk_a = static_cast<std::size_t>(b - dest);
577  
                    auto chunk_a = static_cast<std::size_t>(b - dest);
578  
                    std::memcpy(dest, a, chunk_a); // never overlap
578  
                    std::memcpy(dest, a, chunk_a); // never overlap
579  
                    an   -= chunk_a;
579  
                    an   -= chunk_a;
580  
                    dest += chunk_a;
580  
                    dest += chunk_a;
581  
                    a    += chunk_a;
581  
                    a    += chunk_a;
582  
                } while(an);
582  
                } while(an);
583  
            }
583  
            }
584  

584  

585  
            break;
585  
            break;
586  
        }
586  
        }
587  
        }
587  
        }
588  

588  

589  
        ws_.clear();
589  
        ws_.clear();
590  

590  

591  
        fb_ = {
591  
        fb_ = {
592  
            ws_.data(),
592  
            ws_.data(),
593  
            cfg_->headers.max_size + cfg_->min_buffer,
593  
            cfg_->headers.max_size + cfg_->min_buffer,
594  
            leftover };
594  
            leftover };
595  

595  

596  
        BOOST_ASSERT(
596  
        BOOST_ASSERT(
597  
            fb_.capacity() == cfg_->max_overread() - leftover);
597  
            fb_.capacity() == cfg_->max_overread() - leftover);
598  

598  

599  
        BOOST_ASSERT(
599  
        BOOST_ASSERT(
600  
            head_response == false ||
600  
            head_response == false ||
601  
            m_.h_.kind == detail::kind::response);
601  
            m_.h_.kind == detail::kind::response);
602  

602  

603  
        m_.h_ = detail::header(detail::empty{m_.h_.kind});
603  
        m_.h_ = detail::header(detail::empty{m_.h_.kind});
604  
        m_.h_.buf = reinterpret_cast<char*>(ws_.data());
604  
        m_.h_.buf = reinterpret_cast<char*>(ws_.data());
605  
        m_.h_.cbuf = m_.h_.buf;
605  
        m_.h_.cbuf = m_.h_.buf;
606  
        m_.h_.cap = ws_.size();
606  
        m_.h_.cap = ws_.size();
607  

607  

608  
        state_ = state::header;
608  
        state_ = state::header;
609  

609  

610  
        // reset to the configured default
610  
        // reset to the configured default
611  
        body_limit_ = cfg_->body_limit;
611  
        body_limit_ = cfg_->body_limit;
612  

612  

613  
        body_total_ = 0;
613  
        body_total_ = 0;
614  
        payload_remain_ = 0;
614  
        payload_remain_ = 0;
615  
        chunk_remain_ = 0;
615  
        chunk_remain_ = 0;
616  
        body_avail_ = 0;
616  
        body_avail_ = 0;
617  
        nprepare_ = 0;
617  
        nprepare_ = 0;
618  

618  

619  
        filter_.reset();
619  
        filter_.reset();
620  

620  

621  
        got_header_ = false;
621  
        got_header_ = false;
622  
        head_response_ = head_response;
622  
        head_response_ = head_response;
623  
        needs_chunk_close_ = false;
623  
        needs_chunk_close_ = false;
624  
        trailer_headers_ = false;
624  
        trailer_headers_ = false;
625  
        chunked_body_ended = false;
625  
        chunked_body_ended = false;
626  
    }
626  
    }
627  

627  

628  
    auto
628  
    auto
629  
    prepare() ->
629  
    prepare() ->
630  
        mutable_buffers_type
630  
        mutable_buffers_type
631  
    {
631  
    {
632  
        nprepare_ = 0;
632  
        nprepare_ = 0;
633  

633  

634  
        switch(state_)
634  
        switch(state_)
635  
        {
635  
        {
636  
        default:
636  
        default:
637  
        case state::reset:
637  
        case state::reset:
638  
            // reset must be called first
638  
            // reset must be called first
639  
            detail::throw_logic_error();
639  
            detail::throw_logic_error();
640  

640  

641  
        case state::start:
641  
        case state::start:
642  
            // start must be called first
642  
            // start must be called first
643  
            detail::throw_logic_error();
643  
            detail::throw_logic_error();
644  

644  

645  
        case state::header:
645  
        case state::header:
646  
        {
646  
        {
647  
            BOOST_ASSERT(
647  
            BOOST_ASSERT(
648  
                m_.h_.size < cfg_->headers.max_size);
648  
                m_.h_.size < cfg_->headers.max_size);
649  
            std::size_t n = fb_.capacity();
649  
            std::size_t n = fb_.capacity();
650  
            BOOST_ASSERT(n <= cfg_->max_overread());
650  
            BOOST_ASSERT(n <= cfg_->max_overread());
651  
            n = clamp(n, cfg_->max_prepare);
651  
            n = clamp(n, cfg_->max_prepare);
652  
            mbp_[0] = fb_.prepare(n);
652  
            mbp_[0] = fb_.prepare(n);
653  
            nprepare_ = n;
653  
            nprepare_ = n;
654  
            return mutable_buffers_type(&mbp_[0], 1);
654  
            return mutable_buffers_type(&mbp_[0], 1);
655  
        }
655  
        }
656  

656  

657  
        case state::header_done:
657  
        case state::header_done:
658  
            // forgot to call parse()
658  
            // forgot to call parse()
659  
            detail::throw_logic_error();
659  
            detail::throw_logic_error();
660  

660  

661  
        case state::body:
661  
        case state::body:
662  
        {
662  
        {
663  
            if(got_eof_)
663  
            if(got_eof_)
664  
            {
664  
            {
665  
                // forgot to call parse()
665  
                // forgot to call parse()
666  
                detail::throw_logic_error();
666  
                detail::throw_logic_error();
667  
            }
667  
            }
668  

668  

669  
            if(! is_plain())
669  
            if(! is_plain())
670  
            {
670  
            {
671  
                // buffered payload
671  
                // buffered payload
672  
                std::size_t n = cb0_.capacity();
672  
                std::size_t n = cb0_.capacity();
673  
                n = clamp(n, cfg_->max_prepare);
673  
                n = clamp(n, cfg_->max_prepare);
674  
                nprepare_ = n;
674  
                nprepare_ = n;
675  
                mbp_ = cb0_.prepare(n);
675  
                mbp_ = cb0_.prepare(n);
676  
                return detail::make_span(mbp_);
676  
                return detail::make_span(mbp_);
677  
            }
677  
            }
678  
            else
678  
            else
679  
            {
679  
            {
680  
                // plain payload
680  
                // plain payload
681  
                std::size_t n = cb0_.capacity();
681  
                std::size_t n = cb0_.capacity();
682  
                n = clamp(n, cfg_->max_prepare);
682  
                n = clamp(n, cfg_->max_prepare);
683  

683  

684  
                if(m_.payload() == payload::size)
684  
                if(m_.payload() == payload::size)
685  
                {
685  
                {
686  
                    if(n > payload_remain_)
686  
                    if(n > payload_remain_)
687  
                    {
687  
                    {
688  
                        std::size_t overread =
688  
                        std::size_t overread =
689  
                            n - static_cast<std::size_t>(payload_remain_);
689  
                            n - static_cast<std::size_t>(payload_remain_);
690  
                        if(overread > cfg_->max_overread())
690  
                        if(overread > cfg_->max_overread())
691  
                            n = static_cast<std::size_t>(payload_remain_) +
691  
                            n = static_cast<std::size_t>(payload_remain_) +
692  
                                cfg_->max_overread();
692  
                                cfg_->max_overread();
693  
                    }
693  
                    }
694  
                }
694  
                }
695  
                else
695  
                else
696  
                {
696  
                {
697  
                    BOOST_ASSERT(
697  
                    BOOST_ASSERT(
698  
                        m_.payload() == payload::to_eof);
698  
                        m_.payload() == payload::to_eof);
699  
                    // No more messages can be pipelined, so
699  
                    // No more messages can be pipelined, so
700  
                    // limit the output buffer to the remaining
700  
                    // limit the output buffer to the remaining
701  
                    // body limit plus one byte to detect
701  
                    // body limit plus one byte to detect
702  
                    // exhaustion.
702  
                    // exhaustion.
703  
                    std::uint64_t r = body_limit_remain();
703  
                    std::uint64_t r = body_limit_remain();
704  
                    if(r != std::uint64_t(-1))
704  
                    if(r != std::uint64_t(-1))
705  
                        r += 1;
705  
                        r += 1;
706  
                    n = clamp(r, n);
706  
                    n = clamp(r, n);
707  
                }
707  
                }
708  

708  

709  
                nprepare_ = n;
709  
                nprepare_ = n;
710  
                mbp_ = cb0_.prepare(n);
710  
                mbp_ = cb0_.prepare(n);
711  
                return detail::make_span(mbp_);
711  
                return detail::make_span(mbp_);
712  
            }
712  
            }
713  
        }
713  
        }
714  

714  

715  
        case state::complete:
715  
        case state::complete:
716  
            // already complete
716  
            // already complete
717  
            detail::throw_logic_error();
717  
            detail::throw_logic_error();
718  
        }
718  
        }
719  
    }
719  
    }
720  

720  

721  
    void
721  
    void
722  
    commit(
722  
    commit(
723  
        std::size_t n)
723  
        std::size_t n)
724  
    {
724  
    {
725  
        switch(state_)
725  
        switch(state_)
726  
        {
726  
        {
727  
        default:
727  
        default:
728  
        case state::reset:
728  
        case state::reset:
729  
        {
729  
        {
730  
            // reset must be called first
730  
            // reset must be called first
731  
            detail::throw_logic_error();
731  
            detail::throw_logic_error();
732  
        }
732  
        }
733  

733  

734  
        case state::start:
734  
        case state::start:
735  
        {
735  
        {
736  
            // forgot to call start()
736  
            // forgot to call start()
737  
            detail::throw_logic_error();
737  
            detail::throw_logic_error();
738  
        }
738  
        }
739  

739  

740  
        case state::header:
740  
        case state::header:
741  
        {
741  
        {
742  
            if(n > nprepare_)
742  
            if(n > nprepare_)
743  
            {
743  
            {
744  
                // n can't be greater than size of
744  
                // n can't be greater than size of
745  
                // the buffers returned by prepare()
745  
                // the buffers returned by prepare()
746  
                detail::throw_invalid_argument();
746  
                detail::throw_invalid_argument();
747  
            }
747  
            }
748  

748  

749  
            if(got_eof_)
749  
            if(got_eof_)
750  
            {
750  
            {
751  
                // can't commit after EOF
751  
                // can't commit after EOF
752  
                detail::throw_logic_error();
752  
                detail::throw_logic_error();
753  
            }
753  
            }
754  

754  

755  
            nprepare_ = 0; // invalidate
755  
            nprepare_ = 0; // invalidate
756  
            fb_.commit(n);
756  
            fb_.commit(n);
757  
            break;
757  
            break;
758  
        }
758  
        }
759  

759  

760  
        case state::header_done:
760  
        case state::header_done:
761  
        {
761  
        {
762  
            // forgot to call parse()
762  
            // forgot to call parse()
763  
            detail::throw_logic_error();
763  
            detail::throw_logic_error();
764  
        }
764  
        }
765  

765  

766  
        case state::body:
766  
        case state::body:
767  
        {
767  
        {
768  
            if(n > nprepare_)
768  
            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()
772  
                detail::throw_invalid_argument();
772  
                detail::throw_invalid_argument();
773  
            }
773  
            }
774  

774  

775  
            if(got_eof_)
775  
            if(got_eof_)
776  
            {
776  
            {
777  
                // can't commit after EOF
777  
                // can't commit after EOF
778  
                detail::throw_logic_error();
778  
                detail::throw_logic_error();
779  
            }
779  
            }
780  
        
780  
        
781  
            nprepare_ = 0; // invalidate
781  
            nprepare_ = 0; // invalidate
782  
            cb0_.commit(n);
782  
            cb0_.commit(n);
783  
            break;
783  
            break;
784  
        }
784  
        }
785  

785  

786  
        case state::complete:
786  
        case state::complete:
787  
        {
787  
        {
788  
            // already complete
788  
            // already complete
789  
            detail::throw_logic_error();
789  
            detail::throw_logic_error();
790  
        }
790  
        }
791  
        }
791  
        }
792  
    }
792  
    }
793  

793  

794  
    void
794  
    void
795  
    commit_eof()
795  
    commit_eof()
796  
    {
796  
    {
797  
        nprepare_ = 0; // invalidate
797  
        nprepare_ = 0; // invalidate
798  

798  

799  
        switch(state_)
799  
        switch(state_)
800  
        {
800  
        {
801  
        default:
801  
        default:
802  
        case state::reset:
802  
        case state::reset:
803  
            // reset must be called first
803  
            // reset must be called first
804  
            detail::throw_logic_error();
804  
            detail::throw_logic_error();
805  

805  

806  
        case state::start:
806  
        case state::start:
807  
            // forgot to call start()
807  
            // forgot to call start()
808  
            detail::throw_logic_error();
808  
            detail::throw_logic_error();
809  

809  

810  
        case state::header:
810  
        case state::header:
811  
            got_eof_ = true;
811  
            got_eof_ = true;
812  
            break;
812  
            break;
813  

813  

814  
        case state::header_done:
814  
        case state::header_done:
815  
            // forgot to call parse()
815  
            // forgot to call parse()
816  
            detail::throw_logic_error();
816  
            detail::throw_logic_error();
817  

817  

818  
        case state::body:
818  
        case state::body:
819  
            got_eof_ = true;
819  
            got_eof_ = true;
820  
            break;
820  
            break;
821  

821  

822  
        case state::complete:
822  
        case state::complete:
823  
            // can't commit eof when complete
823  
            // can't commit eof when complete
824  
            detail::throw_logic_error();
824  
            detail::throw_logic_error();
825  
        }
825  
        }
826  
    }
826  
    }
827  

827  

828  
    void
828  
    void
829  
    parse(
829  
    parse(
830  
        system::error_code& ec)
830  
        system::error_code& ec)
831  
    {
831  
    {
832  
        ec = {};
832  
        ec = {};
833  
        switch(state_)
833  
        switch(state_)
834  
        {
834  
        {
835  
        default:
835  
        default:
836  
        case state::reset:
836  
        case state::reset:
837  
            // reset must be called first
837  
            // reset must be called first
838  
            detail::throw_logic_error();
838  
            detail::throw_logic_error();
839  

839  

840  
        case state::start:
840  
        case state::start:
841  
            // start must be called first
841  
            // start must be called first
842  
            detail::throw_logic_error();
842  
            detail::throw_logic_error();
843  

843  

844  
        case state::header:
844  
        case state::header:
845  
        {
845  
        {
846  
            BOOST_ASSERT(m_.h_.buf == static_cast<
846  
            BOOST_ASSERT(m_.h_.buf == static_cast<
847  
                void const*>(ws_.data()));
847  
                void const*>(ws_.data()));
848  
            BOOST_ASSERT(m_.h_.cbuf == static_cast<
848  
            BOOST_ASSERT(m_.h_.cbuf == static_cast<
849  
                void const*>(ws_.data()));
849  
                void const*>(ws_.data()));
850  

850  

851  
            m_.h_.parse(fb_.size(), cfg_->headers, ec);
851  
            m_.h_.parse(fb_.size(), cfg_->headers, ec);
852  

852  

853  
            if(ec == condition::need_more_input)
853  
            if(ec == condition::need_more_input)
854  
            {
854  
            {
855  
                if(! got_eof_)
855  
                if(! got_eof_)
856  
                {
856  
                {
857  
                    // headers incomplete
857  
                    // headers incomplete
858  
                    return;
858  
                    return;
859  
                }
859  
                }
860  

860  

861  
                if(fb_.size() == 0)
861  
                if(fb_.size() == 0)
862  
                {
862  
                {
863  
                    // stream closed cleanly
863  
                    // stream closed cleanly
864  
                    state_ = state::reset;
864  
                    state_ = state::reset;
865  
                    ec = BOOST_HTTP_ERR(
865  
                    ec = BOOST_HTTP_ERR(
866  
                        error::end_of_stream);
866  
                        error::end_of_stream);
867  
                    return;
867  
                    return;
868  
                }
868  
                }
869  

869  

870  
                // stream closed with a
870  
                // stream closed with a
871  
                // partial message received
871  
                // partial message received
872  
                state_ = state::reset;
872  
                state_ = state::reset;
873  
                ec = BOOST_HTTP_ERR(
873  
                ec = BOOST_HTTP_ERR(
874  
                    error::incomplete);
874  
                    error::incomplete);
875  
                return;
875  
                return;
876  
            }
876  
            }
877  
            else if(ec)
877  
            else if(ec)
878  
            {
878  
            {
879  
                // other error,
879  
                // other error,
880  
                //
880  
                //
881  
                // VFALCO map this to a bad
881  
                // VFALCO map this to a bad
882  
                // request or bad response error?
882  
                // request or bad response error?
883  
                //
883  
                //
884  
                state_ = state::reset; // unrecoverable
884  
                state_ = state::reset; // unrecoverable
885  
                return;
885  
                return;
886  
            }
886  
            }
887  

887  

888  
            got_header_ = true;
888  
            got_header_ = true;
889  

889  

890  
            // reserve headers + table
890  
            // reserve headers + table
891  
            ws_.reserve_front(m_.h_.size);
891  
            ws_.reserve_front(m_.h_.size);
892  
            ws_.reserve_back(m_.h_.table_space());
892  
            ws_.reserve_back(m_.h_.table_space());
893  

893  

894  
            // no payload
894  
            // no payload
895  
            if(m_.payload() == payload::none ||
895  
            if(m_.payload() == payload::none ||
896  
                head_response_)
896  
                head_response_)
897  
            {
897  
            {
898  
                // octets of the next message
898  
                // octets of the next message
899  
                auto overread = fb_.size() - m_.h_.size;
899  
                auto overread = fb_.size() - m_.h_.size;
900  
                cb0_ = { ws_.data(), overread, overread };
900  
                cb0_ = { ws_.data(), overread, overread };
901  
                ws_.reserve_front(overread);
901  
                ws_.reserve_front(overread);
902  
                state_ = state::complete;
902  
                state_ = state::complete;
903  
                return;
903  
                return;
904  
            }
904  
            }
905  

905  

906  
            state_ = state::header_done;
906  
            state_ = state::header_done;
907  
            break;
907  
            break;
908  
        }
908  
        }
909  

909  

910  
        case state::header_done:
910  
        case state::header_done:
911  
        {
911  
        {
912  
            // metadata error
912  
            // metadata error
913  
            if(m_.payload() == payload::error)
913  
            if(m_.payload() == payload::error)
914  
            {
914  
            {
915  
                // VFALCO This needs looking at
915  
                // VFALCO This needs looking at
916  
                ec = BOOST_HTTP_ERR(
916  
                ec = BOOST_HTTP_ERR(
917  
                    error::bad_payload);
917  
                    error::bad_payload);
918  
                state_ = state::reset; // unrecoverable
918  
                state_ = state::reset; // unrecoverable
919  
                return;
919  
                return;
920  
            }
920  
            }
921  

921  

922  
            // overread currently includes any and all octets that
922  
            // overread currently includes any and all octets that
923  
            // extend beyond the current end of the header
923  
            // extend beyond the current end of the header
924  
            // this can include associated body octets for the
924  
            // this can include associated body octets for the
925  
            // current message or octets of the next message in the
925  
            // current message or octets of the next message in the
926  
            // stream, e.g. pipelining is being used
926  
            // stream, e.g. pipelining is being used
927  
            auto const overread = fb_.size() - m_.h_.size;
927  
            auto const overread = fb_.size() - m_.h_.size;
928  
            BOOST_ASSERT(overread <= cfg_->max_overread());
928  
            BOOST_ASSERT(overread <= cfg_->max_overread());
929  

929  

930  
            auto cap = fb_.capacity() + overread +
930  
            auto cap = fb_.capacity() + overread +
931  
                cfg_->min_buffer;
931  
                cfg_->min_buffer;
932  

932  

933  
            // reserve body buffers first, as the decoder
933  
            // reserve body buffers first, as the decoder
934  
            // must be installed after them.
934  
            // must be installed after them.
935  
            auto const p = ws_.reserve_front(cap);
935  
            auto const p = ws_.reserve_front(cap);
936  

936  

937  
            // Content-Encoding
937  
            // Content-Encoding
938  
            switch(m_.metadata().content_encoding.coding)
938  
            switch(m_.metadata().content_encoding.coding)
939  
            {
939  
            {
940  
            case content_coding::deflate:
940  
            case content_coding::deflate:
941  
                if(!cfg_->apply_deflate_decoder)
941  
                if(!cfg_->apply_deflate_decoder)
942  
                    goto no_filter;
942  
                    goto no_filter;
943  
                if(auto* svc = capy::get_system_context().find_service<http::zlib::inflate_service>())
943  
                if(auto* svc = capy::get_system_context().find_service<http::zlib::inflate_service>())
944  
                {
944  
                {
945  
                    filter_.reset(new zlib_filter(
945  
                    filter_.reset(new zlib_filter(
946  
                        *svc,
946  
                        *svc,
947  
                        cfg_->zlib_window_bits));
947  
                        cfg_->zlib_window_bits));
948  
                }
948  
                }
949  
                break;
949  
                break;
950  

950  

951  
            case content_coding::gzip:
951  
            case content_coding::gzip:
952  
                if(!cfg_->apply_gzip_decoder)
952  
                if(!cfg_->apply_gzip_decoder)
953  
                    goto no_filter;
953  
                    goto no_filter;
954  
                if(auto* svc = capy::get_system_context().find_service<http::zlib::inflate_service>())
954  
                if(auto* svc = capy::get_system_context().find_service<http::zlib::inflate_service>())
955  
                {
955  
                {
956  
                    filter_.reset(new zlib_filter(
956  
                    filter_.reset(new zlib_filter(
957  
                        *svc,
957  
                        *svc,
958  
                        cfg_->zlib_window_bits + 16));
958  
                        cfg_->zlib_window_bits + 16));
959  
                }
959  
                }
960  
                break;
960  
                break;
961  

961  

962  
            case content_coding::br:
962  
            case content_coding::br:
963  
                if(!cfg_->apply_brotli_decoder)
963  
                if(!cfg_->apply_brotli_decoder)
964  
                    goto no_filter;
964  
                    goto no_filter;
965  
                if(auto* svc = capy::get_system_context().find_service<http::brotli::decode_service>())
965  
                if(auto* svc = capy::get_system_context().find_service<http::brotli::decode_service>())
966  
                {
966  
                {
967  
                    filter_.reset(new brotli_filter(*svc));
967  
                    filter_.reset(new brotli_filter(*svc));
968  
                }
968  
                }
969  
                break;
969  
                break;
970  

970  

971  
            no_filter:
971  
            no_filter:
972  
            default:
972  
            default:
973  
                break;
973  
                break;
974  
            }
974  
            }
975  

975  

976  
            if(is_plain())
976  
            if(is_plain())
977  
            {
977  
            {
978  
                cb0_ = { p, cap, overread };
978  
                cb0_ = { p, cap, overread };
979  
                cb1_ = {};
979  
                cb1_ = {};
980  
            }
980  
            }
981  
            else
981  
            else
982  
            {
982  
            {
983  
                // buffered payload
983  
                // buffered payload
984  
                std::size_t n0 = (overread > cfg_->min_buffer)
984  
                std::size_t n0 = (overread > cfg_->min_buffer)
985  
                    ? overread
985  
                    ? overread
986  
                    : cfg_->min_buffer;
986  
                    : cfg_->min_buffer;
987  
                std::size_t n1 = cfg_->min_buffer;
987  
                std::size_t n1 = cfg_->min_buffer;
988  

988  

989  
                cb0_ = { p      , n0, overread };
989  
                cb0_ = { p      , n0, overread };
990  
                cb1_ = { p + n0 , n1 };
990  
                cb1_ = { p + n0 , n1 };
991  
            }
991  
            }
992  

992  

993  
            if(m_.payload() == payload::size)
993  
            if(m_.payload() == payload::size)
994  
            {
994  
            {
995  
                if(!filter_ &&
995  
                if(!filter_ &&
996  
                    body_limit_ < m_.payload_size())
996  
                    body_limit_ < m_.payload_size())
997  
                {
997  
                {
998  
                    ec = BOOST_HTTP_ERR(
998  
                    ec = BOOST_HTTP_ERR(
999  
                        error::body_too_large);
999  
                        error::body_too_large);
1000  
                    state_ = state::reset;
1000  
                    state_ = state::reset;
1001  
                    return;
1001  
                    return;
1002  
                }
1002  
                }
1003  
                payload_remain_ = m_.payload_size();
1003  
                payload_remain_ = m_.payload_size();
1004  
            }
1004  
            }
1005  

1005  

1006  
            state_ = state::body;
1006  
            state_ = state::body;
1007  
            BOOST_FALLTHROUGH;
1007  
            BOOST_FALLTHROUGH;
1008  
        }
1008  
        }
1009  

1009  

1010  
        case state::body:
1010  
        case state::body:
1011  
        {
1011  
        {
1012  
            BOOST_ASSERT(state_ == state::body);
1012  
            BOOST_ASSERT(state_ == state::body);
1013  
            BOOST_ASSERT(m_.payload() != payload::none);
1013  
            BOOST_ASSERT(m_.payload() != payload::none);
1014  
            BOOST_ASSERT(m_.payload() != payload::error);
1014  
            BOOST_ASSERT(m_.payload() != payload::error);
1015  

1015  

1016  
            auto set_state_to_complete = [&]()
1016  
            auto set_state_to_complete = [&]()
1017  
            {
1017  
            {
1018  
                state_ = state::complete;
1018  
                state_ = state::complete;
1019  
            };
1019  
            };
1020  

1020  

1021  
            if(m_.payload() == payload::chunked)
1021  
            if(m_.payload() == payload::chunked)
1022  
            {
1022  
            {
1023  
                for(;;)
1023  
                for(;;)
1024  
                {
1024  
                {
1025  
                    if(chunk_remain_ == 0
1025  
                    if(chunk_remain_ == 0
1026  
                        && !chunked_body_ended)
1026  
                        && !chunked_body_ended)
1027  
                    {
1027  
                    {
1028  
                        auto cs = chained_sequence(cb0_.data());
1028  
                        auto cs = chained_sequence(cb0_.data());
1029  
                        auto check_ec = [&]()
1029  
                        auto check_ec = [&]()
1030  
                        {
1030  
                        {
1031  
                            if(ec == condition::need_more_input && got_eof_)
1031  
                            if(ec == condition::need_more_input && got_eof_)
1032  
                            {
1032  
                            {
1033  
                                ec = BOOST_HTTP_ERR(error::incomplete);
1033  
                                ec = BOOST_HTTP_ERR(error::incomplete);
1034  
                                state_ = state::reset;
1034  
                                state_ = state::reset;
1035  
                            }
1035  
                            }
1036  
                        };
1036  
                        };
1037  

1037  

1038  
                        if(needs_chunk_close_)
1038  
                        if(needs_chunk_close_)
1039  
                        {
1039  
                        {
1040  
                            parse_eol(cs, ec);
1040  
                            parse_eol(cs, ec);
1041  
                            if(ec)
1041  
                            if(ec)
1042  
                            {
1042  
                            {
1043  
                                check_ec();
1043  
                                check_ec();
1044  
                                return;
1044  
                                return;
1045  
                            }
1045  
                            }
1046  
                        }
1046  
                        }
1047  
                        else if(trailer_headers_)
1047  
                        else if(trailer_headers_)
1048  
                        {
1048  
                        {
1049  
                            skip_trailer_headers(cs, ec);
1049  
                            skip_trailer_headers(cs, ec);
1050  
                            if(ec)
1050  
                            if(ec)
1051  
                            {
1051  
                            {
1052  
                                check_ec();
1052  
                                check_ec();
1053  
                                return;
1053  
                                return;
1054  
                            }
1054  
                            }
1055  
                            cb0_.consume(cb0_.size() - cs.size());
1055  
                            cb0_.consume(cb0_.size() - cs.size());
1056  
                            chunked_body_ended = true;
1056  
                            chunked_body_ended = true;
1057  
                            continue;
1057  
                            continue;
1058  
                        }
1058  
                        }
1059  
                        
1059  
                        
1060  
                        auto chunk_size = parse_hex(cs, ec);
1060  
                        auto chunk_size = parse_hex(cs, ec);
1061  
                        if(ec)
1061  
                        if(ec)
1062  
                        {
1062  
                        {
1063  
                            check_ec();
1063  
                            check_ec();
1064  
                            return;
1064  
                            return;
1065  
                        }
1065  
                        }
1066  

1066  

1067  
                        // skip chunk extensions
1067  
                        // skip chunk extensions
1068  
                        find_eol(cs, ec);
1068  
                        find_eol(cs, ec);
1069  
                        if(ec)
1069  
                        if(ec)
1070  
                        {
1070  
                        {
1071  
                            check_ec();
1071  
                            check_ec();
1072  
                            return;
1072  
                            return;
1073  
                        }
1073  
                        }
1074  

1074  

1075  
                        cb0_.consume(cb0_.size() - cs.size());
1075  
                        cb0_.consume(cb0_.size() - cs.size());
1076  
                        chunk_remain_ = chunk_size;
1076  
                        chunk_remain_ = chunk_size;
1077  

1077  

1078  
                        needs_chunk_close_ = true;
1078  
                        needs_chunk_close_ = true;
1079  
                        if(chunk_remain_ == 0)
1079  
                        if(chunk_remain_ == 0)
1080  
                        {
1080  
                        {
1081  
                            needs_chunk_close_ = false;
1081  
                            needs_chunk_close_ = false;
1082  
                            trailer_headers_ = true;
1082  
                            trailer_headers_ = true;
1083  
                            continue;
1083  
                            continue;
1084  
                        }
1084  
                        }
1085  
                    }
1085  
                    }
1086  

1086  

1087  
                    if(cb0_.size() == 0 && !chunked_body_ended)
1087  
                    if(cb0_.size() == 0 && !chunked_body_ended)
1088  
                    {
1088  
                    {
1089  
                        if(got_eof_)
1089  
                        if(got_eof_)
1090  
                        {
1090  
                        {
1091  
                            ec = BOOST_HTTP_ERR(
1091  
                            ec = BOOST_HTTP_ERR(
1092  
                                error::incomplete);
1092  
                                error::incomplete);
1093  
                            state_ = state::reset;
1093  
                            state_ = state::reset;
1094  
                            return;
1094  
                            return;
1095  
                        }
1095  
                        }
1096  

1096  

1097  
                        ec = BOOST_HTTP_ERR(
1097  
                        ec = BOOST_HTTP_ERR(
1098  
                            error::need_data);
1098  
                            error::need_data);
1099  
                        return;
1099  
                        return;
1100  
                    }
1100  
                    }
1101  

1101  

1102  
                    if(filter_)
1102  
                    if(filter_)
1103  
                    {
1103  
                    {
1104  
                        chunk_remain_ -= apply_filter(
1104  
                        chunk_remain_ -= apply_filter(
1105  
                            ec,
1105  
                            ec,
1106  
                            clamp(chunk_remain_, cb0_.size()),
1106  
                            clamp(chunk_remain_, cb0_.size()),
1107  
                            !chunked_body_ended);
1107  
                            !chunked_body_ended);
1108  

1108  

1109  
                        if(ec || chunked_body_ended)
1109  
                        if(ec || chunked_body_ended)
1110  
                            return;
1110  
                            return;
1111  
                    }
1111  
                    }
1112  
                    else
1112  
                    else
1113  
                    {
1113  
                    {
1114  
                        const std::size_t chunk_avail =
1114  
                        const std::size_t chunk_avail =
1115  
                            clamp(chunk_remain_, cb0_.size());
1115  
                            clamp(chunk_remain_, cb0_.size());
1116  
                        const auto chunk =
1116  
                        const auto chunk =
1117  
                            capy::prefix(cb0_.data(), chunk_avail);
1117  
                            capy::prefix(cb0_.data(), chunk_avail);
1118  

1118  

1119  
                        if(body_limit_remain() < chunk_avail)
1119  
                        if(body_limit_remain() < chunk_avail)
1120  
                        {
1120  
                        {
1121  
                            ec = BOOST_HTTP_ERR(
1121  
                            ec = BOOST_HTTP_ERR(
1122  
                                error::body_too_large);
1122  
                                error::body_too_large);
1123  
                            state_ = state::reset;
1123  
                            state_ = state::reset;
1124  
                            return;
1124  
                            return;
1125  
                        }
1125  
                        }
1126  

1126  

1127  
                        // in_place style
1127  
                        // in_place style
1128  
                        auto copied = capy::buffer_copy(
1128  
                        auto copied = capy::buffer_copy(
1129  
                            cb1_.prepare(cb1_.capacity()),
1129  
                            cb1_.prepare(cb1_.capacity()),
1130  
                            chunk);
1130  
                            chunk);
1131  
                        chunk_remain_ -= copied;
1131  
                        chunk_remain_ -= copied;
1132  
                        body_avail_   += copied;
1132  
                        body_avail_   += copied;
1133  
                        body_total_   += copied;
1133  
                        body_total_   += copied;
1134  
                        cb0_.consume(copied);
1134  
                        cb0_.consume(copied);
1135  
                        cb1_.commit(copied);
1135  
                        cb1_.commit(copied);
1136  
                        if(cb1_.capacity() == 0
1136  
                        if(cb1_.capacity() == 0
1137  
                            && !chunked_body_ended)
1137  
                            && !chunked_body_ended)
1138  
                        {
1138  
                        {
1139  
                            ec = BOOST_HTTP_ERR(
1139  
                            ec = BOOST_HTTP_ERR(
1140  
                                error::in_place_overflow);
1140  
                                error::in_place_overflow);
1141  
                            return;
1141  
                            return;
1142  
                        }
1142  
                        }
1143  

1143  

1144  
                        if(chunked_body_ended)
1144  
                        if(chunked_body_ended)
1145  
                        {
1145  
                        {
1146  
                            set_state_to_complete();
1146  
                            set_state_to_complete();
1147  
                            return;
1147  
                            return;
1148  
                        }
1148  
                        }
1149  
                    }
1149  
                    }
1150  
                }
1150  
                }
1151  
            }
1151  
            }
1152  
            else
1152  
            else
1153  
            {
1153  
            {
1154  
                // non-chunked payload
1154  
                // non-chunked payload
1155  

1155  

1156  
                const std::size_t payload_avail = [&]()
1156  
                const std::size_t payload_avail = [&]()
1157  
                {
1157  
                {
1158  
                    auto ret = cb0_.size();
1158  
                    auto ret = cb0_.size();
1159  
                    if(!filter_)
1159  
                    if(!filter_)
1160  
                        ret -= body_avail_;
1160  
                        ret -= body_avail_;
1161  
                    if(m_.payload() == payload::size)
1161  
                    if(m_.payload() == payload::size)
1162  
                        return clamp(payload_remain_, ret);
1162  
                        return clamp(payload_remain_, ret);
1163  
                    // payload::eof
1163  
                    // payload::eof
1164  
                    return ret;
1164  
                    return ret;
1165  
                }();
1165  
                }();
1166  

1166  

1167  
                const bool is_complete = [&]()
1167  
                const bool is_complete = [&]()
1168  
                {
1168  
                {
1169  
                    if(m_.payload() == payload::size)
1169  
                    if(m_.payload() == payload::size)
1170  
                        return payload_avail == payload_remain_;
1170  
                        return payload_avail == payload_remain_;
1171  
                    // payload::eof
1171  
                    // payload::eof
1172  
                    return got_eof_;
1172  
                    return got_eof_;
1173  
                }();
1173  
                }();
1174  

1174  

1175  
                if(filter_)
1175  
                if(filter_)
1176  
                {
1176  
                {
1177  
                    payload_remain_ -= apply_filter(
1177  
                    payload_remain_ -= apply_filter(
1178  
                        ec, payload_avail, !is_complete);
1178  
                        ec, payload_avail, !is_complete);
1179  
                    if(ec || is_complete)
1179  
                    if(ec || is_complete)
1180  
                        return;
1180  
                        return;
1181  
                }
1181  
                }
1182  
                else
1182  
                else
1183  
                {
1183  
                {
1184  
                    // plain body
1184  
                    // plain body
1185  

1185  

1186  
                    if(m_.payload() == payload::to_eof)
1186  
                    if(m_.payload() == payload::to_eof)
1187  
                    {
1187  
                    {
1188  
                        if(body_limit_remain() < payload_avail)
1188  
                        if(body_limit_remain() < payload_avail)
1189  
                        {
1189  
                        {
1190  
                            ec = BOOST_HTTP_ERR(
1190  
                            ec = BOOST_HTTP_ERR(
1191  
                                error::body_too_large);
1191  
                                error::body_too_large);
1192  
                            state_ = state::reset;
1192  
                            state_ = state::reset;
1193  
                            return;
1193  
                            return;
1194  
                        }
1194  
                        }
1195  
                    }
1195  
                    }
1196  

1196  

1197  
                    // in_place style
1197  
                    // in_place style
1198  
                    payload_remain_ -= payload_avail;
1198  
                    payload_remain_ -= payload_avail;
1199  
                    body_avail_     += payload_avail;
1199  
                    body_avail_     += payload_avail;
1200  
                    body_total_     += payload_avail;
1200  
                    body_total_     += payload_avail;
1201  
                    if(cb0_.capacity() == 0 && !is_complete)
1201  
                    if(cb0_.capacity() == 0 && !is_complete)
1202  
                    {
1202  
                    {
1203  
                        ec = BOOST_HTTP_ERR(
1203  
                        ec = BOOST_HTTP_ERR(
1204  
                            error::in_place_overflow);
1204  
                            error::in_place_overflow);
1205  
                        return;
1205  
                        return;
1206  
                    }
1206  
                    }
1207  

1207  

1208  
                    if(is_complete)
1208  
                    if(is_complete)
1209  
                    {
1209  
                    {
1210  
                        set_state_to_complete();
1210  
                        set_state_to_complete();
1211  
                        return;
1211  
                        return;
1212  
                    }
1212  
                    }
1213  
                }
1213  
                }
1214  

1214  

1215  
                if(m_.payload() == payload::size && got_eof_)
1215  
                if(m_.payload() == payload::size && got_eof_)
1216  
                {
1216  
                {
1217  
                    ec = BOOST_HTTP_ERR(
1217  
                    ec = BOOST_HTTP_ERR(
1218  
                        error::incomplete);
1218  
                        error::incomplete);
1219  
                    state_ = state::reset;
1219  
                    state_ = state::reset;
1220  
                    return;
1220  
                    return;
1221  
                }
1221  
                }
1222  

1222  

1223  
                ec = BOOST_HTTP_ERR(
1223  
                ec = BOOST_HTTP_ERR(
1224  
                    error::need_data);
1224  
                    error::need_data);
1225  
                return;
1225  
                return;
1226  
            }
1226  
            }
1227  

1227  

1228  
            break;
1228  
            break;
1229  
        }
1229  
        }
1230  

1230  

1231  
        case state::complete:
1231  
        case state::complete:
1232  
            break;
1232  
            break;
1233  
        }
1233  
        }
1234  
    }
1234  
    }
1235  

1235  

1236  
    auto
1236  
    auto
1237  
    pull_body() ->
1237  
    pull_body() ->
1238  
        const_buffers_type
1238  
        const_buffers_type
1239  
    {
1239  
    {
1240  
        switch(state_)
1240  
        switch(state_)
1241  
        {
1241  
        {
1242  
        case state::header_done:
1242  
        case state::header_done:
1243  
            return {};
1243  
            return {};
1244  
        case state::body:
1244  
        case state::body:
1245  
        case state::complete:
1245  
        case state::complete:
1246  
            cbp_ = capy::prefix(
1246  
            cbp_ = capy::prefix(
1247  
                (is_plain() ? cb0_ : cb1_).data(),
1247  
                (is_plain() ? cb0_ : cb1_).data(),
1248  
                body_avail_);
1248  
                body_avail_);
1249  
            return detail::make_span(cbp_);
1249  
            return detail::make_span(cbp_);
1250  
        default:
1250  
        default:
1251  
            detail::throw_logic_error();
1251  
            detail::throw_logic_error();
1252  
        }
1252  
        }
1253  
    }
1253  
    }
1254  

1254  

1255  
    void
1255  
    void
1256  
    consume_body(std::size_t n)
1256  
    consume_body(std::size_t n)
1257  
    {
1257  
    {
1258  
        switch(state_)
1258  
        switch(state_)
1259  
        {
1259  
        {
1260  
        case state::header_done:
1260  
        case state::header_done:
1261  
            return;
1261  
            return;
1262  
        case state::body:
1262  
        case state::body:
1263  
        case state::complete:
1263  
        case state::complete:
1264  
            n = clamp(n, body_avail_);
1264  
            n = clamp(n, body_avail_);
1265  
            (is_plain() ? cb0_ : cb1_).consume(n);
1265  
            (is_plain() ? cb0_ : cb1_).consume(n);
1266  
            body_avail_ -= n;
1266  
            body_avail_ -= n;
1267  
            return;
1267  
            return;
1268  
        default:
1268  
        default:
1269  
            detail::throw_logic_error();
1269  
            detail::throw_logic_error();
1270  
        }
1270  
        }
1271  
    }
1271  
    }
1272  

1272  

1273  
    core::string_view
1273  
    core::string_view
1274  
    body() const
1274  
    body() const
1275  
    {
1275  
    {
1276  
        // Precondition violation
1276  
        // Precondition violation
1277  
        if(state_ != state::complete)
1277  
        if(state_ != state::complete)
1278  
            detail::throw_logic_error();
1278  
            detail::throw_logic_error();
1279  

1279  

1280  
        // Precondition violation
1280  
        // Precondition violation
1281  
        if(body_avail_ != body_total_)
1281  
        if(body_avail_ != body_total_)
1282  
            detail::throw_logic_error();
1282  
            detail::throw_logic_error();
1283  

1283  

1284  
        auto cbp = (is_plain() ? cb0_ : cb1_).data();
1284  
        auto cbp = (is_plain() ? cb0_ : cb1_).data();
1285  
        BOOST_ASSERT(cbp[1].size() == 0);
1285  
        BOOST_ASSERT(cbp[1].size() == 0);
1286  
        BOOST_ASSERT(cbp[0].size() == body_avail_);
1286  
        BOOST_ASSERT(cbp[0].size() == body_avail_);
1287  
        return core::string_view(
1287  
        return core::string_view(
1288  
            static_cast<char const*>(cbp[0].data()),
1288  
            static_cast<char const*>(cbp[0].data()),
1289  
            body_avail_);
1289  
            body_avail_);
1290  
    }
1290  
    }
1291  

1291  

1292  
    void
1292  
    void
1293  
    set_body_limit(std::uint64_t n)
1293  
    set_body_limit(std::uint64_t n)
1294  
    {
1294  
    {
1295  
        switch(state_)
1295  
        switch(state_)
1296  
        {
1296  
        {
1297  
        case state::header:
1297  
        case state::header:
1298  
        case state::header_done:
1298  
        case state::header_done:
1299  
            body_limit_ = n;
1299  
            body_limit_ = n;
1300  
            break;
1300  
            break;
1301  
        case state::complete:
1301  
        case state::complete:
1302  
            // only allowed for empty bodies
1302  
            // only allowed for empty bodies
1303  
            if(body_total_ == 0)
1303  
            if(body_total_ == 0)
1304  
                break;
1304  
                break;
1305  
            BOOST_FALLTHROUGH;
1305  
            BOOST_FALLTHROUGH;
1306  
        default:
1306  
        default:
1307  
            // set body_limit before parsing the body
1307  
            // set body_limit before parsing the body
1308  
            detail::throw_logic_error();
1308  
            detail::throw_logic_error();
1309  
        }
1309  
        }
1310  
    }
1310  
    }
1311  

1311  

1312  
private:
1312  
private:
1313  
    bool
1313  
    bool
1314  
    is_plain() const noexcept
1314  
    is_plain() const noexcept
1315  
    {
1315  
    {
1316  
        return ! filter_ &&
1316  
        return ! filter_ &&
1317  
            m_.payload() != payload::chunked;
1317  
            m_.payload() != payload::chunked;
1318  
    }
1318  
    }
1319  

1319  

1320  
    std::uint64_t
1320  
    std::uint64_t
1321  
    body_limit_remain() const noexcept
1321  
    body_limit_remain() const noexcept
1322  
    {
1322  
    {
1323  
        return body_limit_ - body_total_;
1323  
        return body_limit_ - body_total_;
1324  
    }
1324  
    }
1325  

1325  

1326  
    std::size_t
1326  
    std::size_t
1327  
    apply_filter(
1327  
    apply_filter(
1328  
        system::error_code& ec,
1328  
        system::error_code& ec,
1329  
        std::size_t payload_avail,
1329  
        std::size_t payload_avail,
1330  
        bool more)
1330  
        bool more)
1331  
    {
1331  
    {
1332  
        std::size_t p0 = payload_avail;
1332  
        std::size_t p0 = payload_avail;
1333  
        for(;;)
1333  
        for(;;)
1334  
        {
1334  
        {
1335  
            if(payload_avail == 0 && more)
1335  
            if(payload_avail == 0 && more)
1336  
                break;
1336  
                break;
1337  

1337  

1338  
            auto f_rs = [&](){
1338  
            auto f_rs = [&](){
1339  
                BOOST_ASSERT(filter_ != nullptr);
1339  
                BOOST_ASSERT(filter_ != nullptr);
1340  
                std::size_t n = clamp(body_limit_remain());
1340  
                std::size_t n = clamp(body_limit_remain());
1341  
                n = clamp(n, cb1_.capacity());
1341  
                n = clamp(n, cb1_.capacity());
1342  

1342  

1343  
                return filter_->process(
1343  
                return filter_->process(
1344  
                    detail::make_span(cb1_.prepare(n)),
1344  
                    detail::make_span(cb1_.prepare(n)),
1345  
                    capy::prefix(cb0_.data(), payload_avail),
1345  
                    capy::prefix(cb0_.data(), payload_avail),
1346  
                    more);
1346  
                    more);
1347  
            }();
1347  
            }();
1348  

1348  

1349  
            cb0_.consume(f_rs.in_bytes);
1349  
            cb0_.consume(f_rs.in_bytes);
1350  
            payload_avail -= f_rs.in_bytes;
1350  
            payload_avail -= f_rs.in_bytes;
1351  
            body_total_   += f_rs.out_bytes;
1351  
            body_total_   += f_rs.out_bytes;
1352  

1352  

1353  
            // in_place style
1353  
            // in_place style
1354  
            cb1_.commit(f_rs.out_bytes);
1354  
            cb1_.commit(f_rs.out_bytes);
1355  
            body_avail_ += f_rs.out_bytes;
1355  
            body_avail_ += f_rs.out_bytes;
1356  
            if(cb1_.capacity() == 0 &&
1356  
            if(cb1_.capacity() == 0 &&
1357  
                !f_rs.finished && f_rs.in_bytes == 0)
1357  
                !f_rs.finished && f_rs.in_bytes == 0)
1358  
            {
1358  
            {
1359  
                ec = BOOST_HTTP_ERR(
1359  
                ec = BOOST_HTTP_ERR(
1360  
                    error::in_place_overflow);
1360  
                    error::in_place_overflow);
1361  
                goto done;
1361  
                goto done;
1362  
            }
1362  
            }
1363  

1363  

1364  
            if(f_rs.ec)
1364  
            if(f_rs.ec)
1365  
            {
1365  
            {
1366  
                ec = f_rs.ec;
1366  
                ec = f_rs.ec;
1367  
                state_ = state::reset;
1367  
                state_ = state::reset;
1368  
                break;
1368  
                break;
1369  
            }
1369  
            }
1370  

1370  

1371  
            if(body_limit_remain() == 0 &&
1371  
            if(body_limit_remain() == 0 &&
1372  
                !f_rs.finished && f_rs.in_bytes == 0)
1372  
                !f_rs.finished && f_rs.in_bytes == 0)
1373  
            {
1373  
            {
1374  
                ec = BOOST_HTTP_ERR(
1374  
                ec = BOOST_HTTP_ERR(
1375  
                    error::body_too_large);
1375  
                    error::body_too_large);
1376  
                state_ = state::reset;
1376  
                state_ = state::reset;
1377  
                break;
1377  
                break;
1378  
            }
1378  
            }
1379  

1379  

1380  
            if(f_rs.finished)
1380  
            if(f_rs.finished)
1381  
            {
1381  
            {
1382  
                if(!more)
1382  
                if(!more)
1383  
                    state_ = state::complete;
1383  
                    state_ = state::complete;
1384  
                break;
1384  
                break;
1385  
            }
1385  
            }
1386  
        }
1386  
        }
1387  

1387  

1388  
    done:
1388  
    done:
1389  
        return p0 - payload_avail;
1389  
        return p0 - payload_avail;
1390  
    }
1390  
    }
1391  
};
1391  
};
1392  

1392  

1393  
//------------------------------------------------
1393  
//------------------------------------------------
1394  
//
1394  
//
1395  
// Special Members
1395  
// Special Members
1396  
//
1396  
//
1397  
//------------------------------------------------
1397  
//------------------------------------------------
1398  

1398  

1399  
parser::
1399  
parser::
1400  
~parser()
1400  
~parser()
1401  
{
1401  
{
1402  
    delete impl_;
1402  
    delete impl_;
1403  
}
1403  
}
1404  

1404  

1405  
parser::
1405  
parser::
1406  
parser() noexcept
1406  
parser() noexcept
1407  
    : impl_(nullptr)
1407  
    : impl_(nullptr)
1408  
{
1408  
{
1409  
}
1409  
}
1410  

1410  

1411  
parser::
1411  
parser::
1412  
parser(parser&& other) noexcept
1412  
parser(parser&& other) noexcept
1413  
    : impl_(other.impl_)
1413  
    : impl_(other.impl_)
1414  
{
1414  
{
1415  
    other.impl_ = nullptr;
1415  
    other.impl_ = nullptr;
1416  
}
1416  
}
1417  

1417  

1418  
parser::
1418  
parser::
1419  
parser(
1419  
parser(
1420  
    std::shared_ptr<parser_config_impl const> cfg,
1420  
    std::shared_ptr<parser_config_impl const> cfg,
1421  
    detail::kind k)
1421  
    detail::kind k)
1422  
    : impl_(new impl(std::move(cfg), k))
1422  
    : impl_(new impl(std::move(cfg), k))
1423  
{
1423  
{
1424  
    // TODO: use a single allocation for
1424  
    // TODO: use a single allocation for
1425  
    // impl and workspace buffer.
1425  
    // impl and workspace buffer.
1426  
}
1426  
}
1427  

1427  

1428  
void
1428  
void
1429  
parser::
1429  
parser::
1430  
assign(parser&& other) noexcept
1430  
assign(parser&& other) noexcept
1431  
{
1431  
{
1432  
    if(this == &other)
1432  
    if(this == &other)
1433  
        return;
1433  
        return;
1434  
    delete impl_;
1434  
    delete impl_;
1435  
    impl_ = other.impl_;
1435  
    impl_ = other.impl_;
1436  
    other.impl_ = nullptr;
1436  
    other.impl_ = nullptr;
1437  
}
1437  
}
1438  

1438  

1439  
//--------------------------------------------
1439  
//--------------------------------------------
1440  
//
1440  
//
1441  
// Observers
1441  
// Observers
1442  
//
1442  
//
1443  
//--------------------------------------------
1443  
//--------------------------------------------
1444  

1444  

1445  
bool
1445  
bool
1446  
parser::got_header() const noexcept
1446  
parser::got_header() const noexcept
1447  
{
1447  
{
1448  
    BOOST_ASSERT(impl_);
1448  
    BOOST_ASSERT(impl_);
1449  
    return impl_->got_header();
1449  
    return impl_->got_header();
1450  
}
1450  
}
1451  

1451  

1452  
bool
1452  
bool
1453  
parser::is_complete() const noexcept
1453  
parser::is_complete() const noexcept
1454  
{
1454  
{
1455  
    BOOST_ASSERT(impl_);
1455  
    BOOST_ASSERT(impl_);
1456  
    return impl_->is_complete();
1456  
    return impl_->is_complete();
1457  
}
1457  
}
1458  

1458  

1459  
//------------------------------------------------
1459  
//------------------------------------------------
1460  
//
1460  
//
1461  
// Modifiers
1461  
// Modifiers
1462  
//
1462  
//
1463  
//------------------------------------------------
1463  
//------------------------------------------------
1464  

1464  

1465  
void
1465  
void
1466  
parser::
1466  
parser::
1467  
reset() noexcept
1467  
reset() noexcept
1468  
{
1468  
{
1469  
    BOOST_ASSERT(impl_);
1469  
    BOOST_ASSERT(impl_);
1470  
    impl_->reset();
1470  
    impl_->reset();
1471  
}
1471  
}
1472  

1472  

1473  
void
1473  
void
1474  
parser::start()
1474  
parser::start()
1475  
{
1475  
{
1476  
    BOOST_ASSERT(impl_);
1476  
    BOOST_ASSERT(impl_);
1477  
    impl_->start(false);
1477  
    impl_->start(false);
1478  
}
1478  
}
1479  

1479  

1480  
auto
1480  
auto
1481  
parser::
1481  
parser::
1482  
prepare() ->
1482  
prepare() ->
1483  
    mutable_buffers_type
1483  
    mutable_buffers_type
1484  
{
1484  
{
1485  
    BOOST_ASSERT(impl_);
1485  
    BOOST_ASSERT(impl_);
1486  
    return impl_->prepare();
1486  
    return impl_->prepare();
1487  
}
1487  
}
1488  

1488  

1489  
void
1489  
void
1490  
parser::
1490  
parser::
1491  
commit(
1491  
commit(
1492  
    std::size_t n)
1492  
    std::size_t n)
1493  
{
1493  
{
1494  
    BOOST_ASSERT(impl_);
1494  
    BOOST_ASSERT(impl_);
1495  
    impl_->commit(n);
1495  
    impl_->commit(n);
1496  
}
1496  
}
1497  

1497  

1498  
void
1498  
void
1499  
parser::
1499  
parser::
1500  
commit_eof()
1500  
commit_eof()
1501  
{
1501  
{
1502  
    BOOST_ASSERT(impl_);
1502  
    BOOST_ASSERT(impl_);
1503  
    impl_->commit_eof();
1503  
    impl_->commit_eof();
1504  
}
1504  
}
1505  

1505  

1506  
void
1506  
void
1507  
parser::
1507  
parser::
1508  
parse(
1508  
parse(
1509  
    system::error_code& ec)
1509  
    system::error_code& ec)
1510  
{
1510  
{
1511  
    BOOST_ASSERT(impl_);
1511  
    BOOST_ASSERT(impl_);
1512  
    impl_->parse(ec);
1512  
    impl_->parse(ec);
1513  
}
1513  
}
1514  

1514  

1515  
auto
1515  
auto
1516  
parser::
1516  
parser::
1517  
pull_body() ->
1517  
pull_body() ->
1518  
    const_buffers_type
1518  
    const_buffers_type
1519  
{
1519  
{
1520  
    BOOST_ASSERT(impl_);
1520  
    BOOST_ASSERT(impl_);
1521  
    return impl_->pull_body();
1521  
    return impl_->pull_body();
1522  
}
1522  
}
1523  

1523  

1524  
void
1524  
void
1525  
parser::
1525  
parser::
1526  
consume_body(std::size_t n)
1526  
consume_body(std::size_t n)
1527  
{
1527  
{
1528  
    BOOST_ASSERT(impl_);
1528  
    BOOST_ASSERT(impl_);
1529  
    impl_->consume_body(n);
1529  
    impl_->consume_body(n);
1530  
}
1530  
}
1531  

1531  

1532  
core::string_view
1532  
core::string_view
1533  
parser::
1533  
parser::
1534  
body() const
1534  
body() const
1535  
{
1535  
{
1536  
    BOOST_ASSERT(impl_);
1536  
    BOOST_ASSERT(impl_);
1537  
    return impl_->body();
1537  
    return impl_->body();
1538  
}
1538  
}
1539  

1539  

1540  
core::string_view
1540  
core::string_view
1541  
parser::
1541  
parser::
1542  
release_buffered_data() noexcept
1542  
release_buffered_data() noexcept
1543  
{
1543  
{
1544  
    // TODO
1544  
    // TODO
1545  
    return {};
1545  
    return {};
1546  
}
1546  
}
1547  

1547  

1548  
void
1548  
void
1549  
parser::
1549  
parser::
1550  
set_body_limit(std::uint64_t n)
1550  
set_body_limit(std::uint64_t n)
1551  
{
1551  
{
1552  
    BOOST_ASSERT(impl_);
1552  
    BOOST_ASSERT(impl_);
1553  
    impl_->set_body_limit(n);
1553  
    impl_->set_body_limit(n);
1554  
}
1554  
}
1555  

1555  

1556  
//------------------------------------------------
1556  
//------------------------------------------------
1557  
//
1557  
//
1558  
// Implementation
1558  
// Implementation
1559  
//
1559  
//
1560  
//------------------------------------------------
1560  
//------------------------------------------------
1561  

1561  

1562  
void
1562  
void
1563  
parser::
1563  
parser::
1564  
start_impl(bool head_response)
1564  
start_impl(bool head_response)
1565  
{
1565  
{
1566  
    BOOST_ASSERT(impl_);
1566  
    BOOST_ASSERT(impl_);
1567  
    impl_->start(head_response);
1567  
    impl_->start(head_response);
1568  
}
1568  
}
1569  

1569  

1570  
static_request const&
1570  
static_request const&
1571  
parser::
1571  
parser::
1572  
safe_get_request() const
1572  
safe_get_request() const
1573  
{
1573  
{
1574  
    BOOST_ASSERT(impl_);
1574  
    BOOST_ASSERT(impl_);
1575  
    return impl_->safe_get_request();
1575  
    return impl_->safe_get_request();
1576  
}
1576  
}
1577  

1577  

1578  
static_response const&
1578  
static_response const&
1579  
parser::
1579  
parser::
1580  
safe_get_response() const
1580  
safe_get_response() const
1581  
{
1581  
{
1582  
    BOOST_ASSERT(impl_);
1582  
    BOOST_ASSERT(impl_);
1583  
    return impl_->safe_get_response();
1583  
    return impl_->safe_get_response();
1584  
}
1584  
}
1585  

1585  

1586  
} // http
1586  
} // http
1587  
} // boost
1587  
} // boost