LCOV - code coverage report
Current view: top level - libs/http_proto/src_zlib/service/zlib_service.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 53.8 % 91 49
Test Date: 2024-09-18 08:42:22 Functions: 60.0 % 20 12

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
       3              : //
       4              : // Distributed under the Boost Software License, Version 1.0. (See accompanying
       5              : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
       6              : //
       7              : // Official repository: https://github.com/cppalliance/http_proto
       8              : //
       9              : 
      10              : #ifndef BOOST_HTTP_PROTO_SERVICE_IMPL_ZLIB_SERVICE_IPP
      11              : #define BOOST_HTTP_PROTO_SERVICE_IMPL_ZLIB_SERVICE_IPP
      12              : 
      13              : #include <boost/http_proto/metadata.hpp>
      14              : #include <boost/http_proto/service/zlib_service.hpp>
      15              : 
      16              : #include <boost/assert/source_location.hpp>
      17              : #include <boost/buffers/circular_buffer.hpp>
      18              : #include <boost/config.hpp>
      19              : #include <boost/system/result.hpp>
      20              : #include <boost/throw_exception.hpp>
      21              : 
      22              : #include <zlib.h>
      23              : 
      24              : namespace boost {
      25              : namespace http_proto {
      26              : namespace zlib {
      27              : namespace {
      28              : 
      29              : /*
      30              :     DEFLATE Compressed Data Format Specification version 1.3
      31              :     https://www.rfc-editor.org/rfc/rfc1951
      32              : */
      33              : 
      34              : enum class error
      35              : {
      36              :     ok          =  0,
      37              :     stream_end  =  1,
      38              :     need_dict   =  2,
      39              :     errno_      = -1,
      40              :     stream_err  = -2,
      41              :     data_err    = -3,
      42              :     mem_err     = -4,
      43              :     buf_err     = -5,
      44              :     version_err = -6
      45              : };
      46              : 
      47              : } // namespace
      48              : } // zlib
      49              : } // http_proto
      50              : namespace system {
      51              : template<>
      52              : struct is_error_code_enum<
      53              :     ::boost::http_proto::zlib::error>
      54              : {
      55              :     static bool const value = true;
      56              : };
      57              : } // system
      58              : namespace http_proto {
      59              : namespace zlib {
      60              : namespace {
      61              : struct error_cat_type
      62              :     : system::error_category
      63              : {
      64              :     BOOST_SYSTEM_CONSTEXPR
      65            1 :     error_cat_type() noexcept
      66            1 :         : error_category(
      67            1 :             0xe6c6d0215d1d6e22)
      68              :     {
      69            1 :     }
      70              : 
      71              :     const char*
      72            0 :     name() const noexcept override
      73              :     {
      74            0 :         return "boost.http.proto.zlib";
      75              :     }
      76              : 
      77              :     std::string
      78            0 :     message( int ev ) const override
      79              :     {
      80            0 :         return message( ev, nullptr, 0 );
      81              :     }
      82              : 
      83              :     char const*
      84            0 :     message(
      85              :         int ev,
      86              :         char*,
      87              :         std::size_t) const noexcept override
      88              :     {
      89            0 :         switch(static_cast<error>(ev))
      90              :         {
      91            0 :         case error::ok: return "Z_OK";
      92            0 :         case error::stream_end: return "Z_STREAM_END";
      93            0 :         case error::need_dict: return "Z_NEED_DICT";
      94            0 :         case error::errno_: return "Z_ERRNO";
      95            0 :         case error::stream_err: return "Z_STREAM_ERROR";
      96            0 :         case error::data_err: return "Z_DATA_ERROR";
      97            0 :         case error::mem_err: return "Z_MEM_ERROR";
      98            0 :         case error::buf_err: return "Z_BUF_ERROR";
      99            0 :         case error::version_err: return "Z_VERSION_ERROR";
     100            0 :         default:
     101            0 :             return "unknown";
     102              :         }
     103              :     }
     104              : };
     105              : 
     106              : system::error_code
     107        12320 : make_error_code(
     108              :     error ev) noexcept
     109              : {
     110              :     static BOOST_SYSTEM_CONSTEXPR
     111        12320 :         error_cat_type cat{};
     112              :     return system::error_code{static_cast<
     113              :         std::underlying_type<
     114        12320 :             error>::type>(ev), cat};
     115              : }
     116              : 
     117              : BOOST_NOINLINE BOOST_NORETURN
     118              : void
     119            0 : throw_zlib_error(
     120              :     int e,
     121              :     source_location const& loc = BOOST_CURRENT_LOCATION)
     122              : {
     123            0 :     throw_exception(
     124            0 :         system::system_error(static_cast<error>(e)), loc);
     125              : }
     126              : 
     127              : // probes memory usage for a config
     128              : class probe
     129              : {
     130              : public:
     131              :     explicit
     132              :     probe() noexcept
     133              :     {
     134              :         zs_.zalloc = &zalloc;
     135              :         zs_.zfree = &zfree;
     136              :         zs_.opaque = this;
     137              :     }
     138              : 
     139              :     system::result<std::size_t>
     140              :     deflate_init(
     141              :         int level)
     142              :     {
     143              :         n_ = 0;
     144              :         system::error_code ec;
     145              :         ec = static_cast<error>(
     146              :             deflateInit(&zs_, level));
     147              :         if(ec.failed())
     148              :             return ec;
     149              :         Bytef tmp[24]{};
     150              :         zs_.next_in = &tmp[0];
     151              :         zs_.avail_in = 1;
     152              :         zs_.next_out = &tmp[1];
     153              :         zs_.avail_out = 23;
     154              :         ec = static_cast<error>(
     155              :             deflate(&zs_,
     156              :                 Z_FINISH));
     157              :         if( ec.failed() &&
     158              :             ec != error::stream_end)
     159              :             return ec;
     160              :         ec = static_cast<error>(
     161              :             deflateEnd(&zs_));
     162              :         if(ec.failed())
     163              :             return ec;
     164              :         return n_;
     165              :     }
     166              : 
     167              :     system::result<std::size_t>
     168              :     deflate_init2(
     169              :         int level,
     170              :         int method,
     171              :         int windowBits,
     172              :         int memLevel,
     173              :         int strategy)
     174              :     {
     175              :         n_ = 0;
     176              :         system::error_code ec;
     177              :         ec = static_cast<error>(
     178              :             deflateInit2(&zs_,
     179              :                 level,
     180              :                 method,
     181              :                 windowBits,
     182              :                 memLevel,
     183              :                 strategy));
     184              :         if(ec.failed())
     185              :             return ec;
     186              :         Bytef tmp[2];
     187              :         zs_.next_in = &tmp[0];
     188              :         zs_.avail_in = 0;
     189              :         zs_.next_out = &tmp[1];
     190              :         zs_.avail_out = 0;
     191              :         ec = static_cast<error>(
     192              :             deflate(&zs_,
     193              :                 Z_FULL_FLUSH));
     194              :         if(ec.failed())
     195              :             return ec;
     196              :         ec = static_cast<error>(
     197              :             deflateEnd(&zs_));
     198              :         if(ec.failed())
     199              :             return ec;
     200              :         return n_;
     201              :     }
     202              : 
     203              : private:
     204              :     static void* zalloc(void* opaque,
     205              :         uInt num, uInt size)
     206              :     {
     207              :         auto& self =
     208              :             *reinterpret_cast<
     209              :                 probe*>(opaque);
     210              :         self.n_ += num * size;
     211              :         return new char[num * size];
     212              :     }
     213              : 
     214              :     static void zfree(
     215              :         void*, void* address)
     216              :     {
     217              :         delete[] reinterpret_cast<
     218              :             char*>(address);
     219              :     }
     220              : 
     221              :     z_stream_s zs_{};
     222              :     std::size_t n_ = 0;
     223              : };
     224              : 
     225          240 : void* zalloc_impl(
     226              :     void* opaque,
     227              :     unsigned items,
     228              :     unsigned size)
     229              : {
     230              :     try
     231              :     {
     232          240 :         auto n = items * size;
     233          240 :         auto* ws =
     234              :             reinterpret_cast<
     235              :                 http_proto::detail::workspace*>(opaque);
     236              : 
     237          240 :         return ws->reserve_front(n);
     238              :     }
     239            0 :     catch(std::length_error const&) // represents OOM
     240              :     {
     241            0 :         return Z_NULL;
     242            0 :     }
     243              : }
     244              : 
     245            0 : void zfree_impl(void* /* opaque */, void* /* addr */)
     246              : {
     247              :     // we call ws_.clear() before the serializer is reused
     248              :     // so all the allocations are passively freed
     249            0 : }
     250              : } // namespace
     251              : 
     252              : struct service_impl
     253              :     : public service
     254              : {
     255              :     using key_type = service;
     256              : 
     257              :     static ::uInt
     258       144944 :     clamp(std::size_t x) noexcept
     259              :     {
     260       144944 :         if(x >= (std::numeric_limits<::uInt>::max)())
     261            0 :             return (std::numeric_limits<::uInt>::max)();
     262       144944 :         return static_cast<::uInt>(x);
     263              :     }
     264              : 
     265              :     static void
     266        36236 :     sync(
     267              :         z_stream* zs,
     268              :         buffers::mutable_buffer const& out,
     269              :         buffers::const_buffer const& in) noexcept
     270              :     {
     271        36236 :         zs->next_in   = reinterpret_cast<
     272        36236 :             unsigned char*>(const_cast<void*>(in.data()));
     273        36236 :         zs->avail_in  = clamp(in.size());
     274        36236 :         zs->next_out  = reinterpret_cast<
     275        36236 :             unsigned char*>(out.data());
     276        36236 :         zs->avail_out = clamp(out.size());
     277        36236 :     }
     278              : 
     279              :     static stream::results
     280        36236 :     make_results(
     281              :         z_stream const& zs,
     282              :         buffers::mutable_buffer const& out,
     283              :         buffers::const_buffer const& in,
     284              :         int ret) noexcept
     285              :     {
     286              :         return {
     287        36236 :             clamp(out.size()) - zs.avail_out,
     288        36236 :             clamp(in.size()) - zs.avail_in,
     289              :             ret < 0 ? static_cast<error>(ret) : system::error_code{},
     290        72472 :             ret == Z_STREAM_END };
     291              :     }
     292              : 
     293              :     class deflator
     294              :         : public stream
     295              :     {
     296              :         z_stream zs_;
     297              : 
     298              :     public:
     299           48 :         deflator(
     300              :             http_proto::detail::workspace& ws,
     301              :             int level,
     302              :             int window_bits,
     303              :             int mem_level)
     304           48 :         {
     305           48 :             zs_.zalloc = &zalloc_impl;
     306           48 :             zs_.zfree  = &zfree_impl;
     307           48 :             zs_.opaque = &ws;
     308              : 
     309           48 :             auto ret = deflateInit2(&zs_, level, Z_DEFLATED,
     310              :                 window_bits, mem_level, Z_DEFAULT_STRATEGY);
     311           48 :             if(ret != Z_OK)
     312            0 :                 throw_zlib_error(ret);
     313           48 :         }
     314              : 
     315              :         virtual results
     316        36236 :         write(
     317              :             buffers::mutable_buffer out,
     318              :             buffers::const_buffer in,
     319              :             flush flush) noexcept override
     320              :         {
     321        36236 :             sync(&zs_, out, in);
     322        36236 :             return make_results(zs_, out, in,
     323        36236 :                 deflate(&zs_, static_cast<int>(flush)));
     324              :         }
     325              :     };
     326              : 
     327              :     class inflator
     328              :         : public stream
     329              :     {
     330              :         z_stream zs_;
     331              : 
     332              :     public:
     333            0 :         inflator(
     334              :             http_proto::detail::workspace& ws,
     335              :             int window_bits)
     336            0 :         {
     337            0 :             zs_.zalloc = &zalloc_impl;
     338            0 :             zs_.zfree  = &zfree_impl;
     339            0 :             zs_.opaque = &ws;
     340              : 
     341            0 :             auto ret = inflateInit2(&zs_, window_bits);
     342            0 :             if(ret != Z_OK)
     343            0 :                 throw_zlib_error(ret);
     344            0 :         }
     345              : 
     346              :         virtual results
     347            0 :         write(
     348              :             buffers::mutable_buffer out,
     349              :             buffers::const_buffer in,
     350              :             flush flush) noexcept override
     351              :         {
     352            0 :             sync(&zs_, out, in);
     353            0 :             return make_results(zs_, out, in,
     354            0 :                 inflate(&zs_, static_cast<int>(flush)));
     355              :         }
     356              :     };
     357              : 
     358              :     explicit
     359           26 :     service_impl(context&) noexcept
     360           26 :     {
     361           26 :     }
     362              : 
     363              :     virtual std::size_t
     364            1 :     space_needed() const noexcept override
     365              :     {
     366            1 :         return 0; // TODO
     367              :     }
     368              : 
     369              :     virtual stream&
     370           48 :     make_deflator(
     371              :         http_proto::detail::workspace& ws,
     372              :         int level,
     373              :         int window_bits,
     374              :         int mem_level) const override
     375              :     {
     376           48 :         return ws.emplace<deflator>(
     377           48 :             ws, level, window_bits, mem_level);
     378              :     }
     379              : 
     380              :     virtual stream&
     381            0 :     make_inflator(
     382              :         http_proto::detail::workspace& ws,
     383              :         int window_bits) const override
     384              :     {
     385            0 :         return ws.emplace<inflator>(ws, window_bits);
     386              :     }
     387              : };
     388              : 
     389              : void BOOST_HTTP_PROTO_ZLIB_DECL
     390           26 : install_service(context& ctx)
     391              : {
     392           26 :     ctx.make_service<service_impl>();
     393           26 : }
     394              : } // zlib
     395              : } // http_proto
     396              : } // boost
     397              : 
     398              : #endif
        

Generated by: LCOV version 2.1