// // Copyright (c) 2013-2017 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) // #ifndef BEAST_HTTP_IMPL_SERIALIZER_IPP #define BEAST_HTTP_IMPL_SERIALIZER_IPP #include #include #include #include #include #include namespace beast { namespace http { template void serializer:: frdinit(std::true_type) { frd_.emplace(m_, m_.version, m_.method()); } template void serializer:: frdinit(std::false_type) { frd_.emplace(m_, m_.version, m_.result_int()); } template template inline void serializer:: do_visit(error_code& ec, Visit& visit) { // VFALCO work-around for missing variant::emplace pv_.~variant(); new(&pv_) decltype(pv_){ T1{limit_, boost::get(v_)}}; visit(ec, beast::detail::make_buffers_ref( boost::get(pv_))); } //------------------------------------------------------------------------------ template serializer:: serializer(value_type& m) : m_(m) { } template serializer:: serializer(value_type& m, ChunkDecorator const& d) : m_(m) , d_(d) { } template template void serializer:: next(error_code& ec, Visit&& visit) { using boost::asio::buffer_size; using beast::detail::make_buffers_ref; switch(s_) { case do_construct: { frdinit(std::integral_constant{}); close_ = ! frd_->keep_alive(); if(frd_->chunked()) goto go_init_c; s_ = do_init; BEAST_FALLTHROUGH; } case do_init: { if(split_) goto go_header_only; rd_.emplace(m_, ec); if(ec) return; auto result = rd_->get(ec); if(ec == error::need_more) goto go_header_only; if(ec) return; if(! result) goto go_header_only; more_ = result->second; v_ = cb2_t{ boost::in_place_init, frd_->get(), result->first}; s_ = do_header; BEAST_FALLTHROUGH; } case do_header: do_visit(ec, visit); break; go_header_only: v_ = cb1_t{frd_->get()}; s_ = do_header_only; case do_header_only: do_visit(ec, visit); break; case do_body: if(! rd_) { rd_.emplace(m_, ec); if(ec) return; } s_ = do_body + 1; BEAST_FALLTHROUGH; case do_body + 1: { auto result = rd_->get(ec); if(ec) return; if(! result) goto go_complete; more_ = result->second; v_ = cb3_t{result->first}; s_ = do_body + 2; BEAST_FALLTHROUGH; } case do_body + 2: do_visit(ec, visit); break; //---------------------------------------------------------------------- go_init_c: s_ = do_init_c; case do_init_c: { if(split_) goto go_header_only_c; rd_.emplace(m_, ec); if(ec) return; auto result = rd_->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; #ifndef BEAST_NO_BIG_VARIANTS if(! more_) { // do it all in one buffer v_ = cb7_t{ boost::in_place_init, frd_->get(), detail::chunk_header{ buffer_size(result->first)}, [&]() { auto sv = d_(result->first); return boost::asio::const_buffers_1{ sv.data(), sv.size()}; }(), detail::chunk_crlf(), result->first, detail::chunk_crlf(), detail::chunk_final(), [&]() { auto sv = d_( boost::asio::null_buffers{}); return boost::asio::const_buffers_1{ sv.data(), sv.size()}; }(), detail::chunk_crlf()}; goto go_all_c; } #endif v_ = cb4_t{ boost::in_place_init, frd_->get(), detail::chunk_header{ buffer_size(result->first)}, [&]() { auto sv = d_(result->first); return boost::asio::const_buffers_1{ sv.data(), sv.size()}; }(), detail::chunk_crlf(), result->first, detail::chunk_crlf()}; s_ = do_header_c; BEAST_FALLTHROUGH; } case do_header_c: do_visit(ec, visit); break; go_header_only_c: v_ = cb1_t{frd_->get()}; s_ = do_header_only_c; case do_header_only_c: do_visit(ec, visit); break; case do_body_c: if(! rd_) { rd_.emplace(m_, ec); if(ec) return; } s_ = do_body_c + 1; BEAST_FALLTHROUGH; case do_body_c + 1: { auto result = rd_->get(ec); if(ec) return; if(! result) goto go_final_c; more_ = result->second; #ifndef BEAST_NO_BIG_VARIANTS if(! more_) { // do it all in one buffer v_ = cb6_t{ boost::in_place_init, detail::chunk_header{ buffer_size(result->first)}, [&]() { auto sv = d_(result->first); return boost::asio::const_buffers_1{ sv.data(), sv.size()}; }(), detail::chunk_crlf(), result->first, detail::chunk_crlf(), detail::chunk_final(), [&]() { auto sv = d_( boost::asio::null_buffers{}); return boost::asio::const_buffers_1{ sv.data(), sv.size()}; }(), detail::chunk_crlf()}; goto go_body_final_c; } #endif v_ = cb5_t{ boost::in_place_init, detail::chunk_header{ buffer_size(result->first)}, [&]() { auto sv = d_(result->first); return boost::asio::const_buffers_1{ sv.data(), sv.size()}; }(), detail::chunk_crlf(), result->first, detail::chunk_crlf()}; s_ = do_body_c + 2; BEAST_FALLTHROUGH; } case do_body_c + 2: do_visit(ec, visit); break; #ifndef BEAST_NO_BIG_VARIANTS go_body_final_c: s_ = do_body_final_c; case do_body_final_c: do_visit(ec, visit); break; go_all_c: s_ = do_all_c; case do_all_c: do_visit(ec, visit); break; #endif go_final_c: case do_final_c: v_ = cb8_t{ boost::in_place_init, detail::chunk_final(), [&]() { auto sv = d_( boost::asio::null_buffers{}); return boost::asio::const_buffers_1{ sv.data(), sv.size()}; }(), detail::chunk_crlf()}; s_ = do_final_c + 1; BEAST_FALLTHROUGH; case do_final_c + 1: do_visit(ec, visit); break; //---------------------------------------------------------------------- default: case do_complete: BOOST_ASSERT(false); break; go_complete: s_ = do_complete; break; } } template void serializer:: consume(std::size_t n) { using boost::asio::buffer_size; switch(s_) { case do_header: BOOST_ASSERT(n <= buffer_size( boost::get(v_))); boost::get(v_).consume(n); if(buffer_size(boost::get(v_)) > 0) break; header_done_ = true; v_ = boost::blank{}; if(! more_) goto go_complete; s_ = do_body + 1; break; case do_header_only: BOOST_ASSERT(n <= buffer_size( boost::get(v_))); boost::get(v_).consume(n); if(buffer_size(boost::get(v_)) > 0) break; frd_ = boost::none; header_done_ = true; if(! split_) goto go_complete; s_ = do_body; break; case do_body + 2: { BOOST_ASSERT(n <= buffer_size( boost::get(v_))); boost::get(v_).consume(n); if(buffer_size(boost::get(v_)) > 0) break; v_ = boost::blank{}; if(! more_) goto go_complete; s_ = do_body + 1; break; } //---------------------------------------------------------------------- case do_header_c: BOOST_ASSERT(n <= buffer_size( boost::get(v_))); boost::get(v_).consume(n); if(buffer_size(boost::get(v_)) > 0) break; header_done_ = true; v_ = boost::blank{}; if(more_) s_ = do_body_c + 1; else s_ = do_final_c; break; case do_header_only_c: { BOOST_ASSERT(n <= buffer_size( boost::get(v_))); boost::get(v_).consume(n); if(buffer_size(boost::get(v_)) > 0) break; frd_ = 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_size( boost::get(v_))); boost::get(v_).consume(n); if(buffer_size(boost::get(v_)) > 0) break; v_ = boost::blank{}; if(more_) s_ = do_body_c + 1; else s_ = do_final_c; break; #ifndef BEAST_NO_BIG_VARIANTS case do_body_final_c: { auto& b = boost::get(v_); BOOST_ASSERT(n <= buffer_size(b)); b.consume(n); if(buffer_size(b) > 0) break; v_ = boost::blank{}; s_ = do_complete; break; } case do_all_c: { auto& b = boost::get(v_); BOOST_ASSERT(n <= buffer_size(b)); b.consume(n); if(buffer_size(b) > 0) break; header_done_ = true; v_ = boost::blank{}; s_ = do_complete; break; } #endif case do_final_c + 1: BOOST_ASSERT(buffer_size( boost::get(v_))); boost::get(v_).consume(n); if(buffer_size(boost::get(v_)) > 0) break; v_ = boost::blank{}; goto go_complete; //---------------------------------------------------------------------- default: BOOST_ASSERT(false); case do_complete: break; go_complete: s_ = do_complete; break; } } } // http } // beast #endif