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  
#ifndef BOOST_HTTP_PARSER_HPP
11  
#ifndef BOOST_HTTP_PARSER_HPP
12  
#define BOOST_HTTP_PARSER_HPP
12  
#define BOOST_HTTP_PARSER_HPP
13  

13  

14  
#include <boost/http/config.hpp>
14  
#include <boost/http/config.hpp>
15  
#include <boost/http/detail/header.hpp>
15  
#include <boost/http/detail/header.hpp>
16  
#include <boost/http/detail/type_traits.hpp>
16  
#include <boost/http/detail/type_traits.hpp>
17  
#include <boost/http/error.hpp>
17  
#include <boost/http/error.hpp>
18  

18  

19  
#include <boost/capy/buffers/buffer_copy.hpp>
19  
#include <boost/capy/buffers/buffer_copy.hpp>
20  
#include <boost/capy/buffers/buffer_pair.hpp>
20  
#include <boost/capy/buffers/buffer_pair.hpp>
21  
#include <boost/capy/buffers/slice.hpp>
21  
#include <boost/capy/buffers/slice.hpp>
22  
#include <boost/capy/concept/read_stream.hpp>
22  
#include <boost/capy/concept/read_stream.hpp>
23  
#include <boost/capy/concept/write_sink.hpp>
23  
#include <boost/capy/concept/write_sink.hpp>
24  
#include <boost/capy/cond.hpp>
24  
#include <boost/capy/cond.hpp>
25  
#include <boost/capy/error.hpp>
25  
#include <boost/capy/error.hpp>
26  
#include <boost/capy/io_task.hpp>
26  
#include <boost/capy/io_task.hpp>
27  
#include <boost/core/span.hpp>
27  
#include <boost/core/span.hpp>
28  

28  

29  
#include <cstddef>
29  
#include <cstddef>
30  
#include <cstdint>
30  
#include <cstdint>
31  
#include <memory>
31  
#include <memory>
32  

32  

33  
namespace boost {
33  
namespace boost {
34  
namespace http {
34  
namespace http {
35  

35  

36  
// Forward declaration
36  
// Forward declaration
37  
class request_parser;
37  
class request_parser;
38  
class response_parser;
38  
class response_parser;
39  
class static_request;
39  
class static_request;
40  
class static_response;
40  
class static_response;
41  

41  

42  
//------------------------------------------------
42  
//------------------------------------------------
43  

43  

44  
/** A parser for HTTP/1 messages.
44  
/** A parser for HTTP/1 messages.
45  

45  

46  
    This parser uses a single block of memory allocated
46  
    This parser uses a single block of memory allocated
47  
    during construction and guarantees it will never
47  
    during construction and guarantees it will never
48  
    exceed the specified size. This space is reused for
48  
    exceed the specified size. This space is reused for
49  
    parsing multiple HTTP messages ( one at a time ).
49  
    parsing multiple HTTP messages ( one at a time ).
50  

50  

51  
    The allocated space is used for:
51  
    The allocated space is used for:
52  

52  

53  
    @li Buffering raw input from a socket
53  
    @li Buffering raw input from a socket
54  
    @li Storing HTTP headers with O(1) access to
54  
    @li Storing HTTP headers with O(1) access to
55  
        method, target, and status code
55  
        method, target, and status code
56  
    @li Storing all or part of an HTTP message body
56  
    @li Storing all or part of an HTTP message body
57  
    @li Storing state for inflate algorithms
57  
    @li Storing state for inflate algorithms
58  

58  

59  
    The parser is strict. Any malformed input according
59  
    The parser is strict. Any malformed input according
60  
    to the HTTP ABNFs is treated as an unrecoverable
60  
    to the HTTP ABNFs is treated as an unrecoverable
61  
    error.
61  
    error.
62  

62  

63  
    @see
63  
    @see
64  
        @ref response_parser,
64  
        @ref response_parser,
65  
        @ref request_parser.
65  
        @ref request_parser.
66  
*/
66  
*/
67  
class parser
67  
class parser
68  
{
68  
{
69  
public:
69  
public:
70  
    template<capy::ReadStream Stream>
70  
    template<capy::ReadStream Stream>
71  
    class source;
71  
    class source;
72  

72  

73  
    /// Buffer type returned from @ref prepare.
73  
    /// Buffer type returned from @ref prepare.
74  
    using mutable_buffers_type =
74  
    using mutable_buffers_type =
75  
        boost::span<capy::mutable_buffer const>;
75  
        boost::span<capy::mutable_buffer const>;
76  

76  

77  
    /// Buffer type returned from @ref pull_body.
77  
    /// Buffer type returned from @ref pull_body.
78  
    using const_buffers_type =
78  
    using const_buffers_type =
79  
        boost::span<capy::const_buffer const>;
79  
        boost::span<capy::const_buffer const>;
80  

80  

81  
    //--------------------------------------------
81  
    //--------------------------------------------
82  
    //
82  
    //
83  
    // Observers
83  
    // Observers
84  
    //
84  
    //
85  
    //--------------------------------------------
85  
    //--------------------------------------------
86  

86  

87  
    /// Check if a complete header has been parsed.
87  
    /// Check if a complete header has been parsed.
88  
    BOOST_HTTP_DECL
88  
    BOOST_HTTP_DECL
89  
    bool
89  
    bool
90  
    got_header() const noexcept;
90  
    got_header() const noexcept;
91  

91  

92  
    /// Check if a complete message has been parsed.
92  
    /// Check if a complete message has been parsed.
93  
    BOOST_HTTP_DECL
93  
    BOOST_HTTP_DECL
94  
    bool
94  
    bool
95  
    is_complete() const noexcept;
95  
    is_complete() const noexcept;
96  

96  

97  
    //--------------------------------------------
97  
    //--------------------------------------------
98  
    //
98  
    //
99  
    // Modifiers
99  
    // Modifiers
100  
    //
100  
    //
101  
    //--------------------------------------------
101  
    //--------------------------------------------
102  

102  

103  
    /// Prepare for a new stream.
103  
    /// Prepare for a new stream.
104  
    BOOST_HTTP_DECL
104  
    BOOST_HTTP_DECL
105  
    void
105  
    void
106  
    reset() noexcept;
106  
    reset() noexcept;
107  

107  

108  
    /** Prepare for a new message.
108  
    /** Prepare for a new message.
109  

109  

110  
        @par Preconditions
110  
        @par Preconditions
111  
        Either this is the first message in the stream,
111  
        Either this is the first message in the stream,
112  
        or the previous message has been fully parsed.
112  
        or the previous message has been fully parsed.
113  
    */
113  
    */
114  
    BOOST_HTTP_DECL
114  
    BOOST_HTTP_DECL
115  
    void
115  
    void
116  
    start();
116  
    start();
117  

117  

118  
    /** Return a buffer for reading input.
118  
    /** Return a buffer for reading input.
119  

119  

120  
        After writing to the buffer, call @ref commit
120  
        After writing to the buffer, call @ref commit
121  
        with the number of bytes written.
121  
        with the number of bytes written.
122  

122  

123  
        @par Preconditions
123  
        @par Preconditions
124  
        @ref parse returned @ref condition::need_more_input.
124  
        @ref parse returned @ref condition::need_more_input.
125  

125  

126  
        @par Postconditions
126  
        @par Postconditions
127  
        A call to @ref commit or @ref commit_eof is
127  
        A call to @ref commit or @ref commit_eof is
128  
        required before calling @ref prepare again.
128  
        required before calling @ref prepare again.
129  

129  

130  
        @par Exception Safety
130  
        @par Exception Safety
131  
        Strong guarantee.
131  
        Strong guarantee.
132  

132  

133  
        @return A non-empty mutable buffer.
133  
        @return A non-empty mutable buffer.
134  

134  

135  
        @see @ref commit, @ref commit_eof.
135  
        @see @ref commit, @ref commit_eof.
136  
    */
136  
    */
137  
    BOOST_HTTP_DECL
137  
    BOOST_HTTP_DECL
138  
    mutable_buffers_type
138  
    mutable_buffers_type
139  
    prepare();
139  
    prepare();
140  

140  

141  
    /** Commit bytes to the input buffer.
141  
    /** Commit bytes to the input buffer.
142  

142  

143  
        @par Preconditions
143  
        @par Preconditions
144  
        @li `n <= capy::buffer_size( this->prepare() )`
144  
        @li `n <= capy::buffer_size( this->prepare() )`
145  
        @li No prior call to @ref commit or @ref commit_eof
145  
        @li No prior call to @ref commit or @ref commit_eof
146  
            since the last @ref prepare
146  
            since the last @ref prepare
147  

147  

148  
        @par Postconditions
148  
        @par Postconditions
149  
        Buffers from @ref prepare are invalidated.
149  
        Buffers from @ref prepare are invalidated.
150  

150  

151  
        @par Exception Safety
151  
        @par Exception Safety
152  
        Strong guarantee.
152  
        Strong guarantee.
153  

153  

154  
        @param n The number of bytes written.
154  
        @param n The number of bytes written.
155  

155  

156  
        @see @ref parse, @ref prepare.
156  
        @see @ref parse, @ref prepare.
157  
    */
157  
    */
158  
    BOOST_HTTP_DECL
158  
    BOOST_HTTP_DECL
159  
    void
159  
    void
160  
    commit(
160  
    commit(
161  
        std::size_t n);
161  
        std::size_t n);
162  

162  

163  
    /** Indicate end of input.
163  
    /** Indicate end of input.
164  

164  

165  
        Call this when the underlying stream has closed
165  
        Call this when the underlying stream has closed
166  
        and no more data will arrive.
166  
        and no more data will arrive.
167  

167  

168  
        @par Postconditions
168  
        @par Postconditions
169  
        Buffers from @ref prepare are invalidated.
169  
        Buffers from @ref prepare are invalidated.
170  

170  

171  
        @par Exception Safety
171  
        @par Exception Safety
172  
        Strong guarantee.
172  
        Strong guarantee.
173  

173  

174  
        @see @ref parse, @ref prepare.
174  
        @see @ref parse, @ref prepare.
175  
    */
175  
    */
176  
    BOOST_HTTP_DECL
176  
    BOOST_HTTP_DECL
177  
    void
177  
    void
178  
    commit_eof();
178  
    commit_eof();
179  

179  

180  
    /** Parse pending input data.
180  
    /** Parse pending input data.
181  

181  

182  
        Returns immediately after the header is fully
182  
        Returns immediately after the header is fully
183  
        parsed to allow @ref set_body_limit to be called
183  
        parsed to allow @ref set_body_limit to be called
184  
        before body parsing begins. If an error occurs
184  
        before body parsing begins. If an error occurs
185  
        during body parsing, the parsed header remains
185  
        during body parsing, the parsed header remains
186  
        valid and accessible.
186  
        valid and accessible.
187  

187  

188  
        When `ec == condition::need_more_input`, read
188  
        When `ec == condition::need_more_input`, read
189  
        more data and call @ref commit before calling
189  
        more data and call @ref commit before calling
190  
        this function again.
190  
        this function again.
191  

191  

192  
        When `ec == error::end_of_stream`, the stream
192  
        When `ec == error::end_of_stream`, the stream
193  
        closed cleanly. Call @ref reset to reuse the
193  
        closed cleanly. Call @ref reset to reuse the
194  
        parser for a new stream.
194  
        parser for a new stream.
195  

195  

196  
        @param ec Set to the error, if any occurred.
196  
        @param ec Set to the error, if any occurred.
197  

197  

198  
        @see @ref start, @ref prepare, @ref commit.
198  
        @see @ref start, @ref prepare, @ref commit.
199  
    */
199  
    */
200  
    BOOST_HTTP_DECL
200  
    BOOST_HTTP_DECL
201  
    void
201  
    void
202  
    parse(
202  
    parse(
203  
        system::error_code& ec);
203  
        system::error_code& ec);
204  

204  

205  
    /** Set maximum body size for the current message.
205  
    /** Set maximum body size for the current message.
206  

206  

207  
        Overrides @ref parser_config::body_limit for this
207  
        Overrides @ref parser_config::body_limit for this
208  
        message only. The limit resets to the default
208  
        message only. The limit resets to the default
209  
        for subsequent messages.
209  
        for subsequent messages.
210  

210  

211  
        @par Preconditions
211  
        @par Preconditions
212  
        `this->got_header() == true` and body parsing
212  
        `this->got_header() == true` and body parsing
213  
        has not started.
213  
        has not started.
214  

214  

215  
        @par Exception Safety
215  
        @par Exception Safety
216  
        Strong guarantee.
216  
        Strong guarantee.
217  

217  

218  
        @param n The body size limit in bytes.
218  
        @param n The body size limit in bytes.
219  

219  

220  
        @see @ref parser_config::body_limit.
220  
        @see @ref parser_config::body_limit.
221  
    */
221  
    */
222  
    BOOST_HTTP_DECL
222  
    BOOST_HTTP_DECL
223  
    void
223  
    void
224  
    set_body_limit(std::uint64_t n);
224  
    set_body_limit(std::uint64_t n);
225  

225  

226  
    /** Return available body data.
226  
    /** Return available body data.
227  

227  

228  
        Use this to incrementally process body data.
228  
        Use this to incrementally process body data.
229  
        Call @ref consume_body after processing to
229  
        Call @ref consume_body after processing to
230  
        release the buffer space.
230  
        release the buffer space.
231  

231  

232  
        @par Example
232  
        @par Example
233  
        @code
233  
        @code
234  
        request_parser pr( ctx );
234  
        request_parser pr( ctx );
235  
        pr.start();
235  
        pr.start();
236  
        co_await pr.read_header( stream );
236  
        co_await pr.read_header( stream );
237  

237  

238  
        while( ! pr.is_complete() )
238  
        while( ! pr.is_complete() )
239  
        {
239  
        {
240  
            co_await read_some( stream, pr );
240  
            co_await read_some( stream, pr );
241  
            auto cbs = pr.pull_body();
241  
            auto cbs = pr.pull_body();
242  
            // process cbs ...
242  
            // process cbs ...
243  
            pr.consume_body( capy::buffer_size( cbs ) );
243  
            pr.consume_body( capy::buffer_size( cbs ) );
244  
        }
244  
        }
245  
        @endcode
245  
        @endcode
246  

246  

247  
        @par Preconditions
247  
        @par Preconditions
248  
        `this->got_header() == true`
248  
        `this->got_header() == true`
249  

249  

250  
        @par Postconditions
250  
        @par Postconditions
251  
        The returned buffer is invalidated by any
251  
        The returned buffer is invalidated by any
252  
        modifying member function.
252  
        modifying member function.
253  

253  

254  
        @par Exception Safety
254  
        @par Exception Safety
255  
        Strong guarantee.
255  
        Strong guarantee.
256  

256  

257  
        @return Buffers containing available body data.
257  
        @return Buffers containing available body data.
258  

258  

259  
        @see @ref consume_body.
259  
        @see @ref consume_body.
260  
    */
260  
    */
261  
    BOOST_HTTP_DECL
261  
    BOOST_HTTP_DECL
262  
    const_buffers_type
262  
    const_buffers_type
263  
    pull_body();
263  
    pull_body();
264  

264  

265  
    /** Consume bytes from available body data.
265  
    /** Consume bytes from available body data.
266  

266  

267  
        @par Preconditions
267  
        @par Preconditions
268  
        `n <= capy::buffer_size( this->pull_body() )`
268  
        `n <= capy::buffer_size( this->pull_body() )`
269  

269  

270  
        @par Exception Safety
270  
        @par Exception Safety
271  
        Strong guarantee.
271  
        Strong guarantee.
272  

272  

273  
        @param n The number of bytes to consume.
273  
        @param n The number of bytes to consume.
274  

274  

275  
        @see @ref pull_body.
275  
        @see @ref pull_body.
276  
    */
276  
    */
277  
    BOOST_HTTP_DECL
277  
    BOOST_HTTP_DECL
278  
    void
278  
    void
279  
    consume_body(std::size_t n);
279  
    consume_body(std::size_t n);
280  

280  

281  
    /** Return the complete body.
281  
    /** Return the complete body.
282  

282  

283  
        Use this when the entire message fits within
283  
        Use this when the entire message fits within
284  
        the parser's internal buffer.
284  
        the parser's internal buffer.
285  

285  

286  
        @par Example
286  
        @par Example
287  
        @code
287  
        @code
288  
        request_parser pr( ctx );
288  
        request_parser pr( ctx );
289  
        pr.start();
289  
        pr.start();
290  
        co_await pr.read_header( stream );
290  
        co_await pr.read_header( stream );
291  
        // ... read entire body ...
291  
        // ... read entire body ...
292  
        core::string_view body = pr.body();
292  
        core::string_view body = pr.body();
293  
        @endcode
293  
        @endcode
294  

294  

295  
        @par Preconditions
295  
        @par Preconditions
296  
        @li `this->is_complete() == true`
296  
        @li `this->is_complete() == true`
297  
        @li No previous call to @ref consume_body
297  
        @li No previous call to @ref consume_body
298  

298  

299  
        @par Exception Safety
299  
        @par Exception Safety
300  
        Strong guarantee.
300  
        Strong guarantee.
301  

301  

302  
        @return A string view of the complete body.
302  
        @return A string view of the complete body.
303  

303  

304  
        @see @ref is_complete.
304  
        @see @ref is_complete.
305  
    */
305  
    */
306  
    BOOST_HTTP_DECL
306  
    BOOST_HTTP_DECL
307  
    core::string_view
307  
    core::string_view
308  
    body() const;
308  
    body() const;
309  

309  

310  
    /** Return unconsumed data past the last message.
310  
    /** Return unconsumed data past the last message.
311  

311  

312  
        Use this after an upgrade or CONNECT request
312  
        Use this after an upgrade or CONNECT request
313  
        to retrieve protocol-dependent data that
313  
        to retrieve protocol-dependent data that
314  
        follows the HTTP message.
314  
        follows the HTTP message.
315  

315  

316  
        @return A string view of leftover data.
316  
        @return A string view of leftover data.
317  

317  

318  
        @see @ref metadata::upgrade, @ref metadata::connection.
318  
        @see @ref metadata::upgrade, @ref metadata::connection.
319  
    */
319  
    */
320  
    BOOST_HTTP_DECL
320  
    BOOST_HTTP_DECL
321  
    core::string_view
321  
    core::string_view
322  
    release_buffered_data() noexcept;
322  
    release_buffered_data() noexcept;
323  

323  

324  
    /** Asynchronously read the HTTP headers.
324  
    /** Asynchronously read the HTTP headers.
325  

325  

326  
        Reads from the stream until the headers are
326  
        Reads from the stream until the headers are
327  
        complete or an error occurs.
327  
        complete or an error occurs.
328  

328  

329  
        @par Preconditions
329  
        @par Preconditions
330  
        @li @ref reset has been called
330  
        @li @ref reset has been called
331  
        @li @ref start has been called
331  
        @li @ref start has been called
332  

332  

333  
        @param stream The stream to read from.
333  
        @param stream The stream to read from.
334  

334  

335  
        @return An awaitable yielding `(error_code)`.
335  
        @return An awaitable yielding `(error_code)`.
336  

336  

337  
        @see @ref read.
337  
        @see @ref read.
338  
    */
338  
    */
339  
    template<capy::ReadStream Stream>
339  
    template<capy::ReadStream Stream>
340  
    capy::io_task<>
340  
    capy::io_task<>
341  
    read_header(Stream& stream);
341  
    read_header(Stream& stream);
342  

342  

343  
    /** Asynchronously read body data into buffers.
343  
    /** Asynchronously read body data into buffers.
344  

344  

345  
        Reads from the stream and copies body data into
345  
        Reads from the stream and copies body data into
346  
        the provided buffers with complete-fill semantics.
346  
        the provided buffers with complete-fill semantics.
347  
        Returns `capy::error::eof` when the body is complete.
347  
        Returns `capy::error::eof` when the body is complete.
348  

348  

349  
        @par Preconditions
349  
        @par Preconditions
350  
        @li @ref reset has been called
350  
        @li @ref reset has been called
351  
        @li @ref start has been called
351  
        @li @ref start has been called
352  

352  

353  
        @param stream The stream to read from.
353  
        @param stream The stream to read from.
354  

354  

355  
        @param buffers The buffers to read into.
355  
        @param buffers The buffers to read into.
356  

356  

357  
        @return An awaitable yielding `(error_code,std::size_t)`.
357  
        @return An awaitable yielding `(error_code,std::size_t)`.
358  

358  

359  
        @see @ref read_header.
359  
        @see @ref read_header.
360  
    */
360  
    */
361  
    template<capy::ReadStream Stream, capy::MutableBufferSequence MB>
361  
    template<capy::ReadStream Stream, capy::MutableBufferSequence MB>
362  
    capy::io_task<std::size_t>
362  
    capy::io_task<std::size_t>
363  
    read(Stream& stream, MB buffers);
363  
    read(Stream& stream, MB buffers);
364  

364  

365  
    /** Return a source for reading body data.
365  
    /** Return a source for reading body data.
366  

366  

367  
        The returned source satisfies @ref capy::BufferSource.
367  
        The returned source satisfies @ref capy::BufferSource.
368  
        On first pull, headers are automatically parsed if
368  
        On first pull, headers are automatically parsed if
369  
        not yet received.
369  
        not yet received.
370  

370  

371  
        @par Example
371  
        @par Example
372  
        @code
372  
        @code
373  
        request_parser pr( ctx );
373  
        request_parser pr( ctx );
374  
        pr.start();
374  
        pr.start();
375  
        auto body = pr.source_for( socket );
375  
        auto body = pr.source_for( socket );
376  

376  

377  
        capy::const_buffer arr[16];
377  
        capy::const_buffer arr[16];
378  
        auto [ec, bufs] = co_await body.pull( arr );
378  
        auto [ec, bufs] = co_await body.pull( arr );
379  
        body.consume( buffer_size( bufs ) );
379  
        body.consume( buffer_size( bufs ) );
380  
        @endcode
380  
        @endcode
381  

381  

382  
        @param stream The stream to read from.
382  
        @param stream The stream to read from.
383  

383  

384  
        @return A source satisfying @ref capy::BufferSource.
384  
        @return A source satisfying @ref capy::BufferSource.
385  

385  

386  
        @see @ref read_header, @ref capy::BufferSource.
386  
        @see @ref read_header, @ref capy::BufferSource.
387  
    */
387  
    */
388  
    template<capy::ReadStream Stream>
388  
    template<capy::ReadStream Stream>
389  
    source<Stream>
389  
    source<Stream>
390  
    source_for(Stream& stream) noexcept;
390  
    source_for(Stream& stream) noexcept;
391  

391  

392  
    /** Read body from stream and push to a WriteSink.
392  
    /** Read body from stream and push to a WriteSink.
393  

393  

394  
        Reads body data from the stream and pushes each chunk to
394  
        Reads body data from the stream and pushes each chunk to
395  
        the sink. The sink must consume all bytes from each write.
395  
        the sink. The sink must consume all bytes from each write.
396  

396  

397  
        @param stream The stream to read body data from.
397  
        @param stream The stream to read body data from.
398  

398  

399  
        @param sink The sink to receive body data.
399  
        @param sink The sink to receive body data.
400  

400  

401  
        @return An awaitable yielding `(error_code)`.
401  
        @return An awaitable yielding `(error_code)`.
402  

402  

403  
        @see WriteSink.
403  
        @see WriteSink.
404  
    */
404  
    */
405  
    template<capy::WriteSink Sink>
405  
    template<capy::WriteSink Sink>
406  
    capy::io_task<>
406  
    capy::io_task<>
407  
    read(capy::ReadStream auto& stream, Sink&& sink);
407  
    read(capy::ReadStream auto& stream, Sink&& sink);
408  

408  

409  
private:
409  
private:
410  
    friend class request_parser;
410  
    friend class request_parser;
411  
    friend class response_parser;
411  
    friend class response_parser;
412  
    class impl;
412  
    class impl;
413  

413  

414  
    BOOST_HTTP_DECL ~parser();
414  
    BOOST_HTTP_DECL ~parser();
415  
    BOOST_HTTP_DECL parser() noexcept;
415  
    BOOST_HTTP_DECL parser() noexcept;
416  
    BOOST_HTTP_DECL parser(parser&& other) noexcept;
416  
    BOOST_HTTP_DECL parser(parser&& other) noexcept;
417  
    BOOST_HTTP_DECL parser(
417  
    BOOST_HTTP_DECL parser(
418  
        std::shared_ptr<parser_config_impl const> cfg,
418  
        std::shared_ptr<parser_config_impl const> cfg,
419  
        detail::kind k);
419  
        detail::kind k);
420  
    BOOST_HTTP_DECL void assign(parser&& other) noexcept;
420  
    BOOST_HTTP_DECL void assign(parser&& other) noexcept;
421  

421  

422  
    BOOST_HTTP_DECL
422  
    BOOST_HTTP_DECL
423  
    void
423  
    void
424  
    start_impl(bool);
424  
    start_impl(bool);
425  

425  

426  
    static_request const&
426  
    static_request const&
427  
    safe_get_request() const;
427  
    safe_get_request() const;
428  

428  

429  
    static_response const&
429  
    static_response const&
430  
    safe_get_response() const;
430  
    safe_get_response() const;
431  

431  

432  
    impl* impl_;
432  
    impl* impl_;
433  
};
433  
};
434  

434  

435  
/** A source for reading the message body.
435  
/** A source for reading the message body.
436  

436  

437  
    This type satisfies @ref capy::BufferSource. It can be
437  
    This type satisfies @ref capy::BufferSource. It can be
438  
    constructed immediately after parser construction; on
438  
    constructed immediately after parser construction; on
439  
    first pull, headers are automatically parsed if not
439  
    first pull, headers are automatically parsed if not
440  
    yet received.
440  
    yet received.
441  

441  

442  
    @tparam Stream A type satisfying @ref capy::ReadStream.
442  
    @tparam Stream A type satisfying @ref capy::ReadStream.
443  

443  

444  
    @see @ref parser::source_for.
444  
    @see @ref parser::source_for.
445  
*/
445  
*/
446  
template<capy::ReadStream Stream>
446  
template<capy::ReadStream Stream>
447  
class parser::source
447  
class parser::source
448  
{
448  
{
449  
    Stream* stream_;
449  
    Stream* stream_;
450  
    parser* pr_;
450  
    parser* pr_;
451  

451  

452  
public:
452  
public:
453  
    /// Default constructor.
453  
    /// Default constructor.
454  
    source() noexcept
454  
    source() noexcept
455  
        : stream_(nullptr)
455  
        : stream_(nullptr)
456  
        , pr_(nullptr)
456  
        , pr_(nullptr)
457  
    {
457  
    {
458  
    }
458  
    }
459  

459  

460  
    /// Construct a source for reading body data.
460  
    /// Construct a source for reading body data.
461  
    source(Stream& stream, parser& pr) noexcept
461  
    source(Stream& stream, parser& pr) noexcept
462  
        : stream_(&stream)
462  
        : stream_(&stream)
463  
        , pr_(&pr)
463  
        , pr_(&pr)
464  
    {
464  
    {
465  
    }
465  
    }
466  

466  

467  
    /** Pull buffer data from the body.
467  
    /** Pull buffer data from the body.
468  

468  

469  
        On first invocation, reads headers if not yet parsed.
469  
        On first invocation, reads headers if not yet parsed.
470  
        Returns buffer descriptors pointing to internal parser
470  
        Returns buffer descriptors pointing to internal parser
471  
        memory. When the body is complete, returns an empty span.
471  
        memory. When the body is complete, returns an empty span.
472  

472  

473  
        @param dest Span of const_buffer to fill.
473  
        @param dest Span of const_buffer to fill.
474  

474  

475  
        @return An awaitable yielding `(error_code,std::span<const_buffer>)`.
475  
        @return An awaitable yielding `(error_code,std::span<const_buffer>)`.
476  
    */
476  
    */
477  
    capy::io_task<std::span<capy::const_buffer>>
477  
    capy::io_task<std::span<capy::const_buffer>>
478  
    pull(std::span<capy::const_buffer> dest);
478  
    pull(std::span<capy::const_buffer> dest);
479  

479  

480  
    /** Consume bytes from pulled body data.
480  
    /** Consume bytes from pulled body data.
481  

481  

482  
        Advances the read position by the specified number of
482  
        Advances the read position by the specified number of
483  
        bytes. The next pull returns data starting after the
483  
        bytes. The next pull returns data starting after the
484  
        consumed bytes.
484  
        consumed bytes.
485  

485  

486  
        @param n The number of bytes to consume.
486  
        @param n The number of bytes to consume.
487  
    */
487  
    */
488  
    void
488  
    void
489  
    consume(std::size_t n) noexcept;
489  
    consume(std::size_t n) noexcept;
490  
};
490  
};
491  

491  

492  
template<capy::ReadStream Stream>
492  
template<capy::ReadStream Stream>
493  
capy::io_task<>
493  
capy::io_task<>
494  
parser::
494  
parser::
495  
read_header(Stream& stream)
495  
read_header(Stream& stream)
496  
{
496  
{
497  
    system::error_code ec;
497  
    system::error_code ec;
498  
    for(;;)
498  
    for(;;)
499  
    {
499  
    {
500  
        parse(ec);
500  
        parse(ec);
501  

501  

502  
        if(got_header())
502  
        if(got_header())
503  
            co_return {};
503  
            co_return {};
504  

504  

505  
        if(ec != condition::need_more_input)
505  
        if(ec != condition::need_more_input)
506  
            co_return {ec};
506  
            co_return {ec};
507  

507  

508  
        auto mbs = prepare();
508  
        auto mbs = prepare();
509  

509  

510  
        auto [read_ec, n] = co_await stream.read_some(mbs);
510  
        auto [read_ec, n] = co_await stream.read_some(mbs);
511  
        if(read_ec == capy::cond::eof)
511  
        if(read_ec == capy::cond::eof)
512  
            commit_eof();
512  
            commit_eof();
513  
        else if(!read_ec)
513  
        else if(!read_ec)
514  
            commit(n);
514  
            commit(n);
515  
        else
515  
        else
516  
            co_return {read_ec};
516  
            co_return {read_ec};
517  
    }
517  
    }
518  
}
518  
}
519  

519  

520  
template<capy::ReadStream Stream, capy::MutableBufferSequence MB>
520  
template<capy::ReadStream Stream, capy::MutableBufferSequence MB>
521  
capy::io_task<std::size_t>
521  
capy::io_task<std::size_t>
522  
parser::
522  
parser::
523  
read(Stream& stream, MB buffers)
523  
read(Stream& stream, MB buffers)
524  
{
524  
{
525  
    if(capy::buffer_empty(buffers))
525  
    if(capy::buffer_empty(buffers))
526  
        co_return {{}, 0};
526  
        co_return {{}, 0};
527  

527  

528  
    std::size_t total = 0;
528  
    std::size_t total = 0;
529  
    auto dest = capy::sans_prefix(buffers, 0);
529  
    auto dest = capy::sans_prefix(buffers, 0);
530  

530  

531  
    for(;;)
531  
    for(;;)
532  
    {
532  
    {
533  
        system::error_code ec;
533  
        system::error_code ec;
534  
        parse(ec);
534  
        parse(ec);
535  

535  

536  
        if(got_header())
536  
        if(got_header())
537  
        {
537  
        {
538  
            auto body_data = pull_body();
538  
            auto body_data = pull_body();
539  
            if(capy::buffer_size(body_data) > 0)
539  
            if(capy::buffer_size(body_data) > 0)
540  
            {
540  
            {
541  
                std::size_t copied = capy::buffer_copy(dest, body_data);
541  
                std::size_t copied = capy::buffer_copy(dest, body_data);
542  
                consume_body(copied);
542  
                consume_body(copied);
543  
                total += copied;
543  
                total += copied;
544  
                dest = capy::sans_prefix(dest, copied);
544  
                dest = capy::sans_prefix(dest, copied);
545  

545  

546  
                if(capy::buffer_empty(dest))
546  
                if(capy::buffer_empty(dest))
547  
                    co_return {{}, total};
547  
                    co_return {{}, total};
548  
            }
548  
            }
549  

549  

550  
            if(is_complete())
550  
            if(is_complete())
551  
                co_return {capy::error::eof, total};
551  
                co_return {capy::error::eof, total};
552  
        }
552  
        }
553  

553  

554  
        if(ec == condition::need_more_input)
554  
        if(ec == condition::need_more_input)
555  
        {
555  
        {
556  
            auto mbs = prepare();
556  
            auto mbs = prepare();
557  
            auto [read_ec, n] = co_await stream.read_some(mbs);
557  
            auto [read_ec, n] = co_await stream.read_some(mbs);
558  

558  

559  
            if(read_ec == capy::cond::eof)
559  
            if(read_ec == capy::cond::eof)
560  
                commit_eof();
560  
                commit_eof();
561  
            else if(!read_ec)
561  
            else if(!read_ec)
562  
                commit(n);
562  
                commit(n);
563  
            else
563  
            else
564  
                co_return {read_ec, total};
564  
                co_return {read_ec, total};
565  

565  

566  
            continue;
566  
            continue;
567  
        }
567  
        }
568  

568  

569  
        if(ec)
569  
        if(ec)
570  
            co_return {ec, total};
570  
            co_return {ec, total};
571  
    }
571  
    }
572  
}
572  
}
573  

573  

574  
template<capy::ReadStream Stream>
574  
template<capy::ReadStream Stream>
575  
parser::source<Stream>
575  
parser::source<Stream>
576  
parser::
576  
parser::
577  
source_for(Stream& stream) noexcept
577  
source_for(Stream& stream) noexcept
578  
{
578  
{
579  
    return source<Stream>(stream, *this);
579  
    return source<Stream>(stream, *this);
580  
}
580  
}
581  

581  

582  
template<capy::ReadStream Stream>
582  
template<capy::ReadStream Stream>
583  
capy::io_task<std::span<capy::const_buffer>>
583  
capy::io_task<std::span<capy::const_buffer>>
584  
parser::source<Stream>::
584  
parser::source<Stream>::
585  
pull(std::span<capy::const_buffer> dest)
585  
pull(std::span<capy::const_buffer> dest)
586  
{
586  
{
587  
    // Read headers if not yet parsed
587  
    // Read headers if not yet parsed
588  
    if(!pr_->got_header())
588  
    if(!pr_->got_header())
589  
    {
589  
    {
590  
        auto [ec] = co_await pr_->read_header(*stream_);
590  
        auto [ec] = co_await pr_->read_header(*stream_);
591  
        if(ec)
591  
        if(ec)
592  
            co_return {ec, {}};
592  
            co_return {ec, {}};
593  
    }
593  
    }
594  

594  

595  
    for(;;)
595  
    for(;;)
596  
    {
596  
    {
597  
        system::error_code ec;
597  
        system::error_code ec;
598  
        pr_->parse(ec);
598  
        pr_->parse(ec);
599  

599  

600  
        auto body_data = pr_->pull_body();
600  
        auto body_data = pr_->pull_body();
601  
        if(capy::buffer_size(body_data) > 0)
601  
        if(capy::buffer_size(body_data) > 0)
602  
        {
602  
        {
603  
            std::size_t count = (std::min)(body_data.size(), dest.size());
603  
            std::size_t count = (std::min)(body_data.size(), dest.size());
604  
            for(std::size_t i = 0; i < count; ++i)
604  
            for(std::size_t i = 0; i < count; ++i)
605  
                dest[i] = body_data[i];
605  
                dest[i] = body_data[i];
606  
            co_return {{}, dest.first(count)};
606  
            co_return {{}, dest.first(count)};
607  
        }
607  
        }
608  

608  

609  
        if(pr_->is_complete())
609  
        if(pr_->is_complete())
610  
            co_return {capy::error::eof, {}};
610  
            co_return {capy::error::eof, {}};
611  

611  

612  
        if(ec == condition::need_more_input)
612  
        if(ec == condition::need_more_input)
613  
        {
613  
        {
614  
            auto mbs = pr_->prepare();
614  
            auto mbs = pr_->prepare();
615  
            auto [read_ec, n] = co_await stream_->read_some(mbs);
615  
            auto [read_ec, n] = co_await stream_->read_some(mbs);
616  

616  

617  
            if(read_ec == capy::cond::eof)
617  
            if(read_ec == capy::cond::eof)
618  
                pr_->commit_eof();
618  
                pr_->commit_eof();
619  
            else if(!read_ec)
619  
            else if(!read_ec)
620  
                pr_->commit(n);
620  
                pr_->commit(n);
621  
            else
621  
            else
622  
                co_return {read_ec, {}};
622  
                co_return {read_ec, {}};
623  

623  

624  
            continue;
624  
            continue;
625  
        }
625  
        }
626  

626  

627  
        if(ec)
627  
        if(ec)
628  
            co_return {ec, {}};
628  
            co_return {ec, {}};
629  
    }
629  
    }
630  
}
630  
}
631  

631  

632  
template<capy::ReadStream Stream>
632  
template<capy::ReadStream Stream>
633  
void
633  
void
634  
parser::source<Stream>::
634  
parser::source<Stream>::
635  
consume(std::size_t n) noexcept
635  
consume(std::size_t n) noexcept
636  
{
636  
{
637  
    pr_->consume_body(n);
637  
    pr_->consume_body(n);
638  
}
638  
}
639  

639  

640  
template<capy::WriteSink Sink>
640  
template<capy::WriteSink Sink>
641  
capy::io_task<>
641  
capy::io_task<>
642  
parser::
642  
parser::
643  
read(capy::ReadStream auto& stream, Sink&& sink)
643  
read(capy::ReadStream auto& stream, Sink&& sink)
644  
{
644  
{
645  
    for(;;)
645  
    for(;;)
646  
    {
646  
    {
647  
        system::error_code ec;
647  
        system::error_code ec;
648  
        parse(ec);
648  
        parse(ec);
649  

649  

650  
        if(got_header())
650  
        if(got_header())
651  
        {
651  
        {
652  
            auto body_data = pull_body();
652  
            auto body_data = pull_body();
653  
            if(capy::buffer_size(body_data) > 0)
653  
            if(capy::buffer_size(body_data) > 0)
654  
            {
654  
            {
655  
                auto [write_ec, n] = co_await sink.write(body_data);
655  
                auto [write_ec, n] = co_await sink.write(body_data);
656  
                if(write_ec)
656  
                if(write_ec)
657  
                    co_return {write_ec};
657  
                    co_return {write_ec};
658  
                consume_body(n);
658  
                consume_body(n);
659  
            }
659  
            }
660  

660  

661  
            if(is_complete())
661  
            if(is_complete())
662  
            {
662  
            {
663  
                auto [eof_ec] = co_await sink.write_eof();
663  
                auto [eof_ec] = co_await sink.write_eof();
664  
                co_return {eof_ec};
664  
                co_return {eof_ec};
665  
            }
665  
            }
666  
        }
666  
        }
667  

667  

668  
        if(ec == condition::need_more_input)
668  
        if(ec == condition::need_more_input)
669  
        {
669  
        {
670  
            auto mbs = prepare();
670  
            auto mbs = prepare();
671  
            auto [read_ec, n] = co_await stream.read_some(mbs);
671  
            auto [read_ec, n] = co_await stream.read_some(mbs);
672  

672  

673  
            if(read_ec == capy::cond::eof)
673  
            if(read_ec == capy::cond::eof)
674  
                commit_eof();
674  
                commit_eof();
675  
            else if(!read_ec)
675  
            else if(!read_ec)
676  
                commit(n);
676  
                commit(n);
677  
            else
677  
            else
678  
                co_return {read_ec};
678  
                co_return {read_ec};
679  

679  

680  
            continue;
680  
            continue;
681  
        }
681  
        }
682  

682  

683  
        if(ec)
683  
        if(ec)
684  
            co_return {ec};
684  
            co_return {ec};
685  
    }
685  
    }
686  
}
686  
}
687  

687  

688  
} // http
688  
} // http
689  
} // boost
689  
} // boost
690  

690  

691  
#endif
691  
#endif