| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 | //// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)//// Distributed under the Boost Software License, Version 1.0. (See accompanying// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)//// Official repository: https://github.com/boostorg/beast//#ifndef BOOST_BEAST_HTTP_IMPL_SERIALIZER_HPP#define BOOST_BEAST_HTTP_IMPL_SERIALIZER_HPP#include <boost/beast/core/buffer_traits.hpp>#include <boost/beast/core/detail/buffers_ref.hpp>#include <boost/beast/http/error.hpp>#include <boost/beast/http/status.hpp>#include <boost/beast/core/detail/config.hpp>#include <boost/assert.hpp>#include <ostream>namespace boost {namespace beast {namespace http {template<    bool isRequest, class Body, class Fields>voidserializer<isRequest, Body, Fields>::fwrinit(std::true_type){    fwr_.emplace(m_, m_.version(), m_.method());}template<    bool isRequest, class Body, class Fields>voidserializer<isRequest, Body, Fields>::fwrinit(std::false_type){    fwr_.emplace(m_, m_.version(), m_.result_int());}template<    bool isRequest, class Body, class Fields>template<std::size_t I, class Visit>inlinevoidserializer<isRequest, Body, Fields>::do_visit(error_code& ec, Visit& visit){    pv_.template emplace<I>(limit_, v_.template get<I>());    visit(ec, beast::detail::make_buffers_ref(        pv_.template get<I>()));}//------------------------------------------------------------------------------template<    bool isRequest, class Body, class Fields>serializer<isRequest, Body, Fields>::serializer(value_type& m)    : m_(m)    , wr_(m_.base(), m_.body()){}template<    bool isRequest, class Body, class Fields>template<class Visit>voidserializer<isRequest, Body, Fields>::next(error_code& ec, Visit&& visit){    switch(s_)    {    case do_construct:    {        fwrinit(std::integral_constant<bool,            isRequest>{});        if(m_.chunked())            goto go_init_c;        s_ = do_init;        BOOST_FALLTHROUGH;    }    case do_init:    {        wr_.init(ec);        if(ec)            return;        if(split_)            goto go_header_only;        auto result = wr_.get(ec);        if(ec == error::need_more)            goto go_header_only;        if(ec)            return;        if(! result)            goto go_header_only;        more_ = result->second;        v_.template emplace<2>(            boost::in_place_init,            fwr_->get(),            result->first);        s_ = do_header;        BOOST_FALLTHROUGH;    }    case do_header:        do_visit<2>(ec, visit);        break;    go_header_only:        v_.template emplace<1>(fwr_->get());        s_ = do_header_only;        BOOST_FALLTHROUGH;    case do_header_only:        do_visit<1>(ec, visit);        break;    case do_body:        s_ = do_body + 1;        BOOST_FALLTHROUGH;    case do_body + 1:    {        auto result = wr_.get(ec);        if(ec)            return;        if(! result)            goto go_complete;        more_ = result->second;        v_.template emplace<3>(result->first);        s_ = do_body + 2;        BOOST_FALLTHROUGH;    }    case do_body + 2:        do_visit<3>(ec, visit);        break;    //----------------------------------------------------------------------        go_init_c:        s_ = do_init_c;        BOOST_FALLTHROUGH;    case do_init_c:    {        wr_.init(ec);        if(ec)            return;        if(split_)            goto go_header_only_c;        auto result = wr_.get(ec);        if(ec == error::need_more)            goto go_header_only_c;        if(ec)            return;        if(! result)            goto go_header_only_c;        more_ = result->second;        if(! more_)        {            // do it all in one buffer            v_.template emplace<7>(                boost::in_place_init,                fwr_->get(),                buffer_bytes(result->first),                net::const_buffer{nullptr, 0},                chunk_crlf{},                result->first,                chunk_crlf{},                detail::chunk_last(),                net::const_buffer{nullptr, 0},                chunk_crlf{});            goto go_all_c;        }        v_.template emplace<4>(            boost::in_place_init,            fwr_->get(),            buffer_bytes(result->first),            net::const_buffer{nullptr, 0},            chunk_crlf{},            result->first,            chunk_crlf{});        s_ = do_header_c;        BOOST_FALLTHROUGH;    }    case do_header_c:        do_visit<4>(ec, visit);        break;    go_header_only_c:        v_.template emplace<1>(fwr_->get());        s_ = do_header_only_c;        BOOST_FALLTHROUGH;    case do_header_only_c:        do_visit<1>(ec, visit);        break;    case do_body_c:        s_ = do_body_c + 1;        BOOST_FALLTHROUGH;    case do_body_c + 1:    {        auto result = wr_.get(ec);        if(ec)            return;        if(! result)            goto go_final_c;        more_ = result->second;        if(! more_)        {            // do it all in one buffer            v_.template emplace<6>(                boost::in_place_init,                buffer_bytes(result->first),                net::const_buffer{nullptr, 0},                chunk_crlf{},                result->first,                chunk_crlf{},                detail::chunk_last(),                net::const_buffer{nullptr, 0},                chunk_crlf{});            goto go_body_final_c;        }        v_.template emplace<5>(            boost::in_place_init,            buffer_bytes(result->first),            net::const_buffer{nullptr, 0},            chunk_crlf{},            result->first,            chunk_crlf{});        s_ = do_body_c + 2;        BOOST_FALLTHROUGH;    }    case do_body_c + 2:        do_visit<5>(ec, visit);        break;    go_body_final_c:        s_ = do_body_final_c;        BOOST_FALLTHROUGH;    case do_body_final_c:        do_visit<6>(ec, visit);        break;    go_all_c:        s_ = do_all_c;        BOOST_FALLTHROUGH;    case do_all_c:        do_visit<7>(ec, visit);        break;    go_final_c:    case do_final_c:        v_.template emplace<8>(            boost::in_place_init,            detail::chunk_last(),            net::const_buffer{nullptr, 0},            chunk_crlf{});        s_ = do_final_c + 1;        BOOST_FALLTHROUGH;    case do_final_c + 1:        do_visit<8>(ec, visit);        break;    //----------------------------------------------------------------------    default:    case do_complete:        BOOST_ASSERT(false);        break;    go_complete:        s_ = do_complete;        break;    }}template<    bool isRequest, class Body, class Fields>voidserializer<isRequest, Body, Fields>::consume(std::size_t n){    switch(s_)    {    case do_header:        BOOST_ASSERT(            n <= buffer_bytes(v_.template get<2>()));        v_.template get<2>().consume(n);        if(buffer_bytes(v_.template get<2>()) > 0)            break;        header_done_ = true;        v_.reset();        if(! more_)            goto go_complete;        s_ = do_body + 1;        break;    case do_header_only:        BOOST_ASSERT(            n <= buffer_bytes(v_.template get<1>()));        v_.template get<1>().consume(n);        if(buffer_bytes(v_.template get<1>()) > 0)            break;        fwr_ = boost::none;        header_done_ = true;        if(! split_)            goto go_complete;        s_ = do_body;        break;    case do_body + 2:    {        BOOST_ASSERT(            n <= buffer_bytes(v_.template get<3>()));        v_.template get<3>().consume(n);        if(buffer_bytes(v_.template get<3>()) > 0)            break;        v_.reset();        if(! more_)            goto go_complete;        s_ = do_body + 1;        break;    }    //----------------------------------------------------------------------    case do_header_c:        BOOST_ASSERT(            n <= buffer_bytes(v_.template get<4>()));        v_.template get<4>().consume(n);        if(buffer_bytes(v_.template get<4>()) > 0)            break;        header_done_ = true;        v_.reset();        if(more_)            s_ = do_body_c + 1;        else            s_ = do_final_c;        break;    case do_header_only_c:    {        BOOST_ASSERT(            n <= buffer_bytes(v_.template get<1>()));        v_.template get<1>().consume(n);        if(buffer_bytes(v_.template get<1>()) > 0)            break;        fwr_ = boost::none;        header_done_ = true;        if(! split_)        {            s_ = do_final_c;            break;        }        s_ = do_body_c;        break;    }    case do_body_c + 2:        BOOST_ASSERT(            n <= buffer_bytes(v_.template get<5>()));        v_.template get<5>().consume(n);        if(buffer_bytes(v_.template get<5>()) > 0)            break;        v_.reset();        if(more_)            s_ = do_body_c + 1;        else            s_ = do_final_c;        break;    case do_body_final_c:    {        BOOST_ASSERT(            n <= buffer_bytes(v_.template get<6>()));        v_.template get<6>().consume(n);        if(buffer_bytes(v_.template get<6>()) > 0)            break;        v_.reset();        s_ = do_complete;        break;    }    case do_all_c:    {        BOOST_ASSERT(            n <= buffer_bytes(v_.template get<7>()));        v_.template get<7>().consume(n);        if(buffer_bytes(v_.template get<7>()) > 0)            break;        header_done_ = true;        v_.reset();        s_ = do_complete;        break;    }    case do_final_c + 1:        BOOST_ASSERT(buffer_bytes(v_.template get<8>()));        v_.template get<8>().consume(n);        if(buffer_bytes(v_.template get<8>()) > 0)            break;        v_.reset();        goto go_complete;    //----------------------------------------------------------------------    default:        BOOST_ASSERT(false);    case do_complete:        break;    go_complete:        s_ = do_complete;        break;    }}} // http} // beast} // boost#endif
 |