Subject: Re: [boost] [beast] Chunking example
From: Vinnie Falco (vinnie.falco_at_[hidden])
Date: 2017-07-02 14:44:37


On Sun, Jul 2, 2017 at 7:34 AM, Bjorn Reese via Boost
<boost_at_[hidden]> wrote:
> So chunk-ext fields are not passed to the user unless they write a
> parser to extract them?

If you want the chunk extensions you have to subclass basic_parser
(not the same as writing a parser). Here's an example of what a
user-defined subclass could start with:

    template<bool isRequest, class Body,
        class Allocator = std::allocator<char>>
    class parser
        : public basic_parser<isRequest,
            parser<isRequest, Body, Allocator>>
    {
        using base_type = basic_parser<isRequest,
            parser<isRequest, Body, Allocator>>;

        message<isRequest, Body, basic_fields<Allocator>> m_;
        boost::optional<typename Body::writer> wr_;

    public:
        using value_type =
            message<isRequest, Body, basic_fields<Allocator>>;

        parser() = default;
        parser(parser const&) = delete;
        parser(parser&& other) = default;
        parser& operator=(parser const&) = delete;

        template<class... Args>
        explicit
        parser(Args&&... args)
          : m_(std::forward<Args>(args))
        {
        }

        value_type const&
        get() const { return m_; }
        value_type& get() { return m_; }
        value_type release() { return std::move(m_); }

    private:
        friend class basic_parser<isRequest, parser>;

        void
        on_request(verb method, string_view method_str,
            string_view target, int version, error_code& ec)
        {
            try
            {
                m_.target(target);
                if(method != verb::unknown)
                    m_.method(method);
                else
                    m_.method_string(method_str);
                ec.assign(0, ec.category());
            }
            catch(std::bad_alloc const&)
            {
                ec = error::bad_alloc;
            }
            m_.version = version;
        }

        void
        on_response(int code,
            string_view reason,
                int version, error_code& ec)
        {
            m_.result(code);
            m_.version = version;
            try
            {
                m_.reason(reason);
                ec.assign(0, ec.category());
            }
            catch(std::bad_alloc const&)
            {
                ec = error::bad_alloc;
            }
        }

        void
        on_field(field name, string_view name_string,
            string_view value, error_code& ec)
        {
            try
            {
                m_.insert(name, name_string, value);
                ec.assign(0, ec.category());
            }
            catch(std::bad_alloc const&)
            {
                ec = error::bad_alloc;
            }
        }

        void
        on_header(error_code& ec)
        {
            ec.assign(0, ec.category());
        }

        void
        on_body(boost::optional<
            std::uint64_t> const& content_length,
                error_code& ec)
        {
            wr_.emplace(m_, content_length, ec);
        }

        std::size_t
        on_data(string_view s, error_code& ec)
        {
            return wr_->put(boost::asio::buffer(
                s.data(), s.size()), ec);
        }

        void
        on_chunk(std::uint64_t size,
            string_view ext, error_code& ec)
        {
            ec.assign(0, ec.category());
        }

        void
        on_complete(error_code& ec)
        {
            if(wr_)
                wr_->finish(ec);
            else
                ec.assign(0, ec.category());
        }
    };

The function on_chunk() is called for each new chunk header, and gets
passed the size of the chunk as well as the extension.