LCOV - code coverage report
Current view: top level - libs/http_proto/src/serializer.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 91.1 % 350 319
Test Date: 2024-07-08 21:32:34 Functions: 92.3 % 26 24

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
       3              : // Copyright (c) 2024 Christian Mazakas
       4              : //
       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)
       7              : //
       8              : // Official repository: https://github.com/cppalliance/http_proto
       9              : //
      10              : 
      11              : #include <boost/http_proto/serializer.hpp>
      12              : #include <boost/http_proto/message_view_base.hpp>
      13              : #include <boost/http_proto/filter.hpp>
      14              : #include <boost/http_proto/detail/except.hpp>
      15              : #include <boost/buffers/algorithm.hpp>
      16              : #include <boost/buffers/buffer_copy.hpp>
      17              : #include <boost/buffers/buffer_size.hpp>
      18              : #include <boost/core/ignore_unused.hpp>
      19              : #include <stddef.h>
      20              : 
      21              : #include "zlib_service.hpp"
      22              : 
      23              : namespace boost {
      24              : namespace http_proto {
      25              : 
      26              : //------------------------------------------------
      27              : 
      28              : void
      29            0 : consume_buffers(
      30              :     buffers::const_buffer*& p,
      31              :     std::size_t& n,
      32              :     std::size_t bytes)
      33              : {
      34            0 :     while(n > 0)
      35              :     {
      36            0 :         if(bytes < p->size())
      37              :         {
      38            0 :             *p += bytes;
      39            0 :             return;
      40              :         }
      41            0 :         bytes -= p->size();
      42            0 :         ++p;
      43            0 :         --n;
      44              :     }
      45              : 
      46              :     // Precondition violation
      47            0 :     if(bytes > 0)
      48            0 :         detail::throw_invalid_argument();
      49              : }
      50              : 
      51              : template<class MutableBuffers>
      52              : void
      53         6296 : write_chunk_header(
      54              :     MutableBuffers const& dest0,
      55              :     std::size_t size) noexcept
      56              : {
      57              :     static constexpr char hexdig[] =
      58              :         "0123456789ABCDEF";
      59              :     char buf[18];
      60         6296 :     auto p = buf + 16;
      61       107032 :     for(std::size_t i = 16; i--;)
      62              :     {
      63       100736 :         *--p = hexdig[size & 0xf];
      64       100736 :         size >>= 4;
      65              :     }
      66         6296 :     buf[16] = '\r';
      67         6296 :     buf[17] = '\n';
      68         6296 :     auto n = buffers::buffer_copy(
      69              :         dest0,
      70        12592 :         buffers::const_buffer(
      71              :             buf, sizeof(buf)));
      72              :     ignore_unused(n);
      73         6296 :     BOOST_ASSERT(n == 18);
      74         6296 :     BOOST_ASSERT(
      75              :         buffers::buffer_size(dest0) == n);
      76         6296 : }
      77              : 
      78              : template<class DynamicBuffer>
      79              : void
      80              : write_chunk_close(DynamicBuffer& db)
      81              : {
      82              :     db.commit(
      83              :         buffers::buffer_copy(
      84              :             db.prepare(2),
      85              :             buffers::const_buffer("\r\n", 2)));
      86              : }
      87              : 
      88              : template<class DynamicBuffer>
      89              : void
      90              : write_last_chunk(DynamicBuffer& db)
      91              : {
      92              :     db.commit(
      93              :         buffers::buffer_copy(
      94              :             db.prepare(5),
      95              :             buffers::const_buffer("0\r\n\r\n", 5)));
      96              : }
      97              : 
      98              : //------------------------------------------------
      99              : 
     100           43 : serializer::
     101              : ~serializer()
     102              : {
     103           43 : }
     104              : 
     105            0 : serializer::
     106              : serializer(
     107              :     serializer&&) noexcept = default;
     108              : 
     109            9 : serializer::
     110              : serializer(
     111            9 :     context& ctx)
     112            9 :     : serializer(ctx, 65536)
     113              : {
     114            9 : }
     115              : 
     116           43 : serializer::
     117              : serializer(
     118              :     context& ctx,
     119           43 :     std::size_t buffer_size)
     120           43 :     : ws_(buffer_size)
     121           43 :     , ctx_(ctx)
     122              : {
     123           43 : }
     124              : 
     125              : void
     126           56 : serializer::
     127              : reset() noexcept
     128              : {
     129           56 :     chunk_header_ = {};
     130           56 :     chunk_close_ = {};
     131           56 :     last_chunk_ = {};
     132           56 :     filter_ = nullptr;
     133           56 :     more_ = false;
     134           56 :     is_done_ = false;
     135           56 :     is_chunked_ = false;
     136           56 :     is_expect_continue_ = false;
     137           56 :     is_compressed_ = false;
     138           56 :     filter_done_ = false;
     139           56 :     in_ = nullptr;
     140           56 :     out_ = nullptr;
     141           56 :     ws_.clear();
     142           56 : }
     143              : 
     144              : //------------------------------------------------
     145              : 
     146              : auto
     147        12572 : serializer::
     148              : prepare() ->
     149              :     system::result<
     150              :         const_buffers_type>
     151              : {
     152              :     // Precondition violation
     153        12572 :     if( is_done_ )
     154            1 :         detail::throw_logic_error();
     155              : 
     156              :     // Expect: 100-continue
     157        12571 :     if( is_expect_continue_ )
     158              :     {
     159            4 :         if( !is_header_done_ )
     160            2 :             return const_buffers_type(hp_, 1);
     161            2 :         is_expect_continue_ = false;
     162            2 :         BOOST_HTTP_PROTO_RETURN_EC(
     163              :             error::expect_100_continue);
     164              :     }
     165              : 
     166        12567 :     if( st_ == style::empty )
     167            9 :         return const_buffers_type(
     168            6 :             prepped_.data(), prepped_.size());
     169              : 
     170        12564 :     if( st_ == style::buffers && !filter_ )
     171            9 :         return const_buffers_type(
     172            6 :             prepped_.data(), prepped_.size());
     173              : 
     174              :     // callers must consume() everything before invoking
     175              :     // prepare() again
     176        12620 :     if( !is_header_done_ &&
     177           59 :         buffers::buffer_size(prepped_) != prepped_[0].size() )
     178            0 :         detail::throw_logic_error();
     179              : 
     180        25063 :     if( is_header_done_ &&
     181        12502 :         buffers::buffer_size(prepped_) > 0 )
     182            0 :         detail::throw_logic_error();
     183              : 
     184        12561 :     auto& input = *in_;
     185        12561 :     auto& output = *out_;
     186        12561 :     if( st_ == style::source && more_ )
     187              :     {
     188         5490 :         auto results = src_->read(
     189         5490 :             input.prepare(input.capacity()));
     190         5490 :         more_ = !results.finished;
     191         5490 :         input.commit(results.bytes);
     192              :     }
     193              : 
     194        30653 :     if( st_ == style::stream &&
     195        18071 :         more_ &&
     196         5510 :         in_->size() == 0 )
     197            1 :         BOOST_HTTP_PROTO_RETURN_EC(error::need_data);
     198              : 
     199              :     bool has_avail_out =
     200        25081 :         ((!filter_ && (more_ || input.size() > 0)) ||
     201        12521 :         (filter_ && !filter_done_));
     202              : 
     203        25248 :     auto get_input = [&]() -> buffers::const_buffer
     204              :     {
     205        25248 :         if( st_ == style::buffers )
     206              :         {
     207         3296 :             if( buffers::buffer_size(buf_) == 0 )
     208           64 :                 return {};
     209              : 
     210         3232 :             auto buf = *(buf_.data());
     211         3232 :             BOOST_ASSERT(buf.size() > 0);
     212         3232 :             return buf;
     213              :         }
     214              :         else
     215              :         {
     216        21952 :             if( input.size() == 0 )
     217        10992 :                 return {};
     218              : 
     219        10960 :             auto cbs = input.data();
     220        10960 :             auto buf = *cbs.begin();
     221        10960 :             if( buf.size() == 0 )
     222              :             {
     223            0 :                 auto p = cbs.begin();
     224            0 :                 ++p;
     225            0 :                 buf = *p;
     226              :             }
     227        10960 :             if( buf.size() == 0 )
     228            0 :                 detail::throw_logic_error();
     229        10960 :             return buf;
     230              :         }
     231        12560 :     };
     232              : 
     233        25248 :     auto get_output = [&]() -> buffers::mutable_buffer
     234              :     {
     235        25248 :         auto mbs = output.prepare(output.capacity());
     236        25248 :         auto buf = *mbs.begin();
     237        25248 :         if( buf.size() == 0 )
     238              :         {
     239         1524 :             auto p = mbs.begin();
     240         1524 :             ++p;
     241         1524 :             buf = *p;
     242              :         }
     243        25248 :         return buf;
     244        12560 :     };
     245              : 
     246        23724 :     auto consume = [&](std::size_t n)
     247              :     {
     248        23724 :         if( st_ == style::buffers )
     249              :         {
     250         1772 :             buf_.consume(n);
     251         1772 :             if( buffers::buffer_size(buf_) == 0 )
     252           64 :                 more_ = false;
     253              :         }
     254              :         else
     255        21952 :             input.consume(n);
     256        36284 :     };
     257              : 
     258        12560 :     std::size_t num_written = 0;
     259        12560 :     if( !filter_ )
     260           44 :         num_written += input.size();
     261              :     else
     262              :     {
     263              :         for(;;)
     264              :         {
     265        25248 :             auto in = get_input();
     266        25248 :             auto out = get_output();
     267        25248 :             if( out.size() == 0 )
     268              :             {
     269         1524 :                 if( output.size() == 0 )
     270            0 :                     detail::throw_logic_error();
     271        12516 :                 break;
     272              :             }
     273              : 
     274        23724 :             auto rs = filter_->on_process(
     275        23724 :                 out, in, more_);
     276              : 
     277        23724 :             if( rs.finished )
     278           96 :                 filter_done_ = true;
     279              : 
     280        23724 :             consume(rs.in_bytes);
     281              : 
     282        23724 :             if( rs.out_bytes == 0 )
     283        10992 :                 break;
     284              : 
     285        12732 :             num_written += rs.out_bytes;
     286        12732 :             output.commit(rs.out_bytes);
     287        12732 :         }
     288              :     }
     289              : 
     290              :     // end:
     291        12560 :     std::size_t n = 0;
     292        12560 :     if( !is_header_done_ )
     293              :     {
     294           58 :         BOOST_ASSERT(hp_ == &prepped_[0]);
     295           58 :         ++n;
     296              :     }
     297              :     else
     298        12502 :         prepped_.reset(prepped_.capacity());
     299              : 
     300        12560 :     if( !is_chunked_ )
     301              :     {
     302        18786 :         for(buffers::const_buffer const& b : output.data())
     303        12524 :             prepped_[n++] = b;
     304              :     }
     305              :     else
     306              :     {
     307         6298 :         if( has_avail_out )
     308              :         {
     309         6295 :             write_chunk_header(
     310         6295 :                 chunk_header_, num_written);
     311         6295 :             prepped_[n++] = chunk_header_;
     312              : 
     313        18885 :             for(buffers::const_buffer const& b : output.data())
     314        12590 :                 prepped_[n++] = b;
     315              : 
     316         6295 :             prepped_[n++] = chunk_close_;
     317              :         }
     318              : 
     319         6298 :         if( (filter_ && filter_done_) ||
     320         6274 :             (!filter_ && !more_) )
     321           29 :             prepped_[n++] = last_chunk_;
     322              :     }
     323              : 
     324              :     auto cbs = const_buffers_type(
     325        12560 :         prepped_.data(), prepped_.size());
     326              : 
     327        12560 :     BOOST_ASSERT(buffers::buffer_size(cbs) > 0);
     328        12560 :     return cbs;
     329              : }
     330              : 
     331              : void
     332        14313 : serializer::
     333              : consume(
     334              :     std::size_t n)
     335              : {
     336              :     // Precondition violation
     337        14313 :     if( is_done_ )
     338            1 :         detail::throw_logic_error();
     339              : 
     340        14312 :     if( is_expect_continue_ )
     341              :     {
     342              :         // Cannot consume more than
     343              :         // the header on 100-continue
     344            3 :         if( n > hp_->size() )
     345            1 :             detail::throw_invalid_argument();
     346              :     }
     347              : 
     348        14311 :     if( !is_header_done_ )
     349              :     {
     350              :         // consume header
     351           76 :         if( n < hp_->size() )
     352              :         {
     353           11 :             prepped_.consume(n);
     354           11 :             return;
     355              :         }
     356           65 :         n -= hp_->size();
     357           65 :         prepped_.consume(hp_->size());
     358           65 :         is_header_done_ = true;
     359              :     }
     360              : 
     361        14300 :     prepped_.consume(n);
     362        14300 :     auto is_empty = (buffers::buffer_size(prepped_) == 0);
     363              : 
     364        14300 :     if( st_ == style::buffers && !filter_ && is_empty )
     365            3 :         more_ = false;
     366              : 
     367        14300 :     if( st_ == style::empty &&
     368            4 :         is_empty &&
     369            4 :         !is_expect_continue_ )
     370            3 :         more_ = false;
     371              : 
     372        14300 :     if( is_empty )
     373              :     {
     374        12568 :         if( out_ && out_->size() )
     375              :         {
     376        12555 :             BOOST_ASSERT(st_ != style::empty);
     377        12555 :             out_->consume(out_->size());
     378              :         }
     379        12568 :         is_done_ = filter_ ? filter_done_ : !more_;
     380              :     }
     381              : }
     382              : 
     383              : void
     384           24 : serializer::
     385              : use_deflate_encoding()
     386              : {
     387              :     // can only apply one encoding
     388           24 :     if( filter_ )
     389            0 :         detail::throw_logic_error();
     390              : 
     391           24 :     BOOST_ASSERT(!filter_);
     392              : 
     393           24 :     is_compressed_ = true;
     394              :     auto& svc =
     395           24 :         ctx_.get_service<
     396           24 :             zlib::detail::deflate_decoder_service>();
     397           24 :     filter_ = &svc.make_deflate_filter(ws_);
     398           24 : }
     399              : 
     400              : void
     401           24 : serializer::
     402              : use_gzip_encoding()
     403              : {
     404              :     // can only apply one encoding
     405           24 :     if( filter_ )
     406            0 :         detail::throw_logic_error();
     407              : 
     408           24 :     BOOST_ASSERT(!filter_);
     409              : 
     410           24 :     is_compressed_ = true;
     411              :     auto& svc =
     412           24 :         ctx_.get_service<
     413           24 :             zlib::detail::deflate_decoder_service>();
     414           24 :     filter_ = &svc.make_gzip_filter(ws_);
     415           24 : }
     416              : 
     417              : //------------------------------------------------
     418              : 
     419              : void
     420            7 : serializer::
     421              : copy(
     422              :     buffers::const_buffer* dest,
     423              :     buffers::const_buffer const* src,
     424              :     std::size_t n) noexcept
     425              : {
     426           14 :     while(n--)
     427            7 :         *dest++ = *src++;
     428            7 : }
     429              : 
     430              : void
     431           73 : serializer::
     432              : start_init(
     433              :     message_view_base const& m)
     434              : {
     435              :     // VFALCO what do we do with
     436              :     // metadata error code failures?
     437              :     // m.ph_->md.maybe_throw();
     438              : 
     439           73 :     auto const& md = m.metadata();
     440              : 
     441           73 :     is_done_ = false;
     442           73 :     is_header_done_ = false;
     443           73 :     is_expect_continue_ = md.expect.is_100_continue;
     444              : 
     445              :     // Transfer-Encoding
     446              :     {
     447           73 :         auto const& te = md.transfer_encoding;
     448           73 :         is_chunked_ = te.is_chunked;
     449              :     }
     450              : 
     451           73 :     if( is_chunked_)
     452              :     {
     453           31 :         auto* p = ws_.reserve_front(chunked_overhead_);
     454           31 :         chunk_header_ =
     455           31 :             buffers::mutable_buffer(p, chunk_header_len_);
     456           31 :         chunk_close_ =
     457           62 :             buffers::mutable_buffer(
     458           31 :                 p + chunk_header_len_, crlf_len_);
     459           31 :         last_chunk_ =
     460           62 :             buffers::mutable_buffer(
     461           31 :                 p + chunk_header_len_ + crlf_len_,
     462              :                 last_chunk_len_);
     463              : 
     464           31 :         buffers::buffer_copy(
     465           31 :             chunk_close_, buffers::const_buffer("\r\n", 2));
     466           31 :         buffers::buffer_copy(
     467           31 :             last_chunk_,
     468           62 :             buffers::const_buffer("0\r\n\r\n", 5));
     469              :     }
     470           73 : }
     471              : 
     472              : void
     473            4 : serializer::
     474              : start_empty(
     475              :     message_view_base const& m)
     476              : {
     477            4 :     start_init(m);
     478              : 
     479            4 :     st_ = style::empty;
     480            4 :     more_ = true;
     481              : 
     482            4 :     if(! is_chunked_)
     483              :     {
     484            3 :         prepped_ = make_array(
     485              :             1); // header
     486              :     }
     487              :     else
     488              :     {
     489            1 :         prepped_ = make_array(
     490              :             1 + // header
     491              :             1); // final chunk
     492              : 
     493              :         // Buffer is too small
     494            1 :         if(ws_.size() < 5)
     495            0 :             detail::throw_length_error();
     496              : 
     497              :         buffers::mutable_buffer dest(
     498            1 :             ws_.data(), 5);
     499            1 :         buffers::buffer_copy(
     500              :             dest,
     501            1 :             buffers::const_buffer(
     502              :                 "0\r\n\r\n", 5));
     503            1 :         prepped_[1] = dest;
     504              :     }
     505              : 
     506            4 :     hp_ = &prepped_[0];
     507            4 :     *hp_ = { m.ph_->cbuf, m.ph_->size };
     508            4 : }
     509              : 
     510              : void
     511           23 : serializer::
     512              : start_buffers(
     513              :     message_view_base const& m)
     514              : {
     515           23 :     st_ = style::buffers;
     516           23 :     tmp1_ = {};
     517              : 
     518           23 :     if( !filter_ && !is_chunked_ )
     519              :     {
     520            6 :         prepped_ = make_array(
     521              :             1 +           // header
     522            6 :             buf_.size()); // user input
     523              : 
     524            6 :         hp_ = &prepped_[0];
     525            6 :         *hp_ = { m.ph_->cbuf, m.ph_->size };
     526              : 
     527            6 :         copy(&prepped_[1], buf_.data(), buf_.size());
     528              : 
     529            6 :         more_ = (buffers::buffer_size(buf_) > 0);
     530            6 :         return;
     531              :     }
     532              : 
     533           17 :     if( !filter_ && is_chunked_ )
     534              :     {
     535            1 :         if( buffers::buffer_size(buf_) == 0 )
     536              :         {
     537            0 :             prepped_ = make_array(
     538              :                 1 +           // header
     539              :                 1);           // last chunk
     540              : 
     541            0 :             hp_ = &prepped_[0];
     542            0 :             *hp_ = { m.ph_->cbuf, m.ph_->size };
     543            0 :             prepped_[1] = last_chunk_;
     544            0 :             more_ = false;
     545            0 :             return;
     546              :         }
     547              : 
     548            2 :         write_chunk_header(
     549            1 :             chunk_header_, buffers::buffer_size(buf_));
     550              : 
     551            1 :         prepped_ = make_array(
     552              :             1 +           // header
     553              :             1 +           // chunk header
     554            1 :             buf_.size() + // user input
     555              :             1 +           // chunk close
     556              :             1);           // last chunk
     557              : 
     558            1 :         hp_ = &prepped_[0];
     559            1 :         *hp_ = { m.ph_->cbuf, m.ph_->size };
     560            1 :         prepped_[1] = chunk_header_;
     561            1 :         copy(&prepped_[2], buf_.data(), buf_.size());
     562              : 
     563            1 :         prepped_[prepped_.size() - 2] = chunk_close_;
     564            1 :         prepped_[prepped_.size() - 1] = last_chunk_;
     565            1 :         more_ = true;
     566            1 :         return;
     567              :     }
     568              : 
     569           16 :     if( is_chunked_ )
     570              :     {
     571            8 :         prepped_ = make_array(
     572              :             1 + // header
     573              :             1 + // chunk header
     574              :             2 + // tmp
     575              :             1 + // chunk close
     576              :             1); // last chunk
     577              :     }
     578              :     else
     579            8 :         prepped_ = make_array(
     580              :             1 + // header
     581              :             2); // tmp
     582              : 
     583           16 :     hp_ = &prepped_[0];
     584           16 :     *hp_ = { m.ph_->cbuf, m.ph_->size };
     585           16 :     tmp0_ = { ws_.data(), ws_.size() };
     586           16 :     out_ = &tmp0_;
     587           16 :     in_ = out_;
     588           16 :     more_ = true;
     589              : }
     590              : 
     591              : void
     592           24 : serializer::
     593              : start_source(
     594              :     message_view_base const& m,
     595              :     source* src)
     596              : {
     597           24 :     st_ = style::source;
     598           24 :     src_ = src;
     599              : 
     600           24 :     if( is_chunked_ )
     601              :     {
     602           10 :         prepped_ = make_array(
     603              :             1 + // header
     604              :             1 + // chunk header
     605              :             2 + // tmp
     606              :             1 + // chunk close
     607              :             1); // last chunk
     608              :     }
     609              :     else
     610           14 :         prepped_ = make_array(
     611              :             1 + // header
     612              :             2); // tmp
     613              : 
     614           24 :     if( !filter_ )
     615              :     {
     616            8 :         tmp0_ = { ws_.data(), ws_.size() };
     617            8 :         if( tmp0_.capacity() < 1 )
     618            0 :             detail::throw_length_error();
     619              : 
     620            8 :         in_ = &tmp0_;
     621            8 :         out_ = &tmp0_;
     622              :     }
     623              :     else
     624              :     {
     625           16 :         auto n = ws_.size() / 2;
     626           16 :         auto* p = ws_.reserve_front(n);
     627           16 :         tmp1_ = buffers::circular_buffer(p, n);
     628              : 
     629           16 :         tmp0_ = { ws_.data(), ws_.size() };
     630           16 :         if( tmp0_.capacity() < 1 )
     631            0 :             detail::throw_length_error();
     632              : 
     633           16 :         in_ = &tmp1_;
     634           16 :         out_ = &tmp0_;
     635              :     }
     636              : 
     637           24 :     hp_ = &prepped_[0];
     638           24 :     *hp_ = { m.ph_->cbuf, m.ph_->size };
     639           24 :     more_ = true;
     640           24 : }
     641              : 
     642              : auto
     643           22 : serializer::
     644              : start_stream(
     645              :     message_view_base const& m) ->
     646              :         stream
     647              : {
     648           22 :     start_init(m);
     649              : 
     650           22 :     st_ = style::stream;
     651           22 :     if( is_chunked_ )
     652              :     {
     653           11 :         prepped_ = make_array(
     654              :             1 + // header
     655              :             1 + // chunk header
     656              :             2 + // tmp
     657              :             1 + // chunk close
     658              :             1); // last chunk
     659              :     }
     660              :     else
     661           11 :         prepped_ = make_array(
     662              :             1 + // header
     663              :             2); // tmp
     664              : 
     665           22 :     if( !filter_ )
     666              :     {
     667            6 :         tmp0_ = { ws_.data(), ws_.size() };
     668            6 :         if( tmp0_.capacity() < 1 )
     669            0 :             detail::throw_length_error();
     670              : 
     671            6 :         in_ = &tmp0_;
     672            6 :         out_ = &tmp0_;
     673              :     }
     674              :     else
     675              :     {
     676           16 :         auto n = ws_.size() / 2;
     677           16 :         auto* p = ws_.reserve_front(n);
     678           16 :         tmp1_ = buffers::circular_buffer(p, n);
     679              : 
     680           16 :         tmp0_ = { ws_.data(), ws_.size() };
     681           16 :         if( tmp0_.capacity() < 1 )
     682            0 :             detail::throw_length_error();
     683              : 
     684           16 :         in_ = &tmp1_;
     685           16 :         out_ = &tmp0_;
     686              :     }
     687              : 
     688           22 :     hp_ = &prepped_[0];
     689           22 :     *hp_ = { m.ph_->cbuf, m.ph_->size };
     690           22 :     more_ = true;
     691           22 :     return stream{*this};
     692              : }
     693              : 
     694              : //------------------------------------------------
     695              : 
     696              : std::size_t
     697          139 : serializer::
     698              : stream::
     699              : capacity() const noexcept
     700              : {
     701          139 :     return sr_->in_->capacity();
     702              : }
     703              : 
     704              : std::size_t
     705           72 : serializer::
     706              : stream::
     707              : size() const noexcept
     708              : {
     709           72 :     return sr_->in_->size();
     710              : }
     711              : 
     712              : bool
     713           63 : serializer::
     714              : stream::
     715              : is_full() const noexcept
     716              : {
     717           63 :     return capacity() == 0;
     718              : }
     719              : 
     720              : auto
     721         5512 : serializer::
     722              : stream::
     723              : prepare() const ->
     724              :     buffers_type
     725              : {
     726         5512 :     return sr_->in_->prepare(sr_->in_->capacity());
     727              : }
     728              : 
     729              : void
     730         5512 : serializer::
     731              : stream::
     732              : commit(std::size_t n) const
     733              : {
     734              :     // the stream must make a non-zero amount of bytes
     735              :     // available to the serializer
     736         5512 :     if( n == 0 )
     737            1 :         detail::throw_logic_error();
     738              : 
     739         5511 :     sr_->in_->commit(n);
     740         5511 : }
     741              : 
     742              : void
     743           25 : serializer::
     744              : stream::
     745              : close() const
     746              : {
     747              :     // Precondition violation
     748           25 :     if(! sr_->more_ )
     749            4 :         detail::throw_logic_error();
     750           21 :     sr_->more_ = false;
     751           21 : }
     752              : 
     753              : //------------------------------------------------
     754              : 
     755              : } // http_proto
     756              : } // boost
        

Generated by: LCOV version 2.1