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: 85.3 % 75 64
Test Date: 2025-05-26 06:53:20 Functions: 87.5 % 16 14

            Line data    Source code
       1              : //
       2              : // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
       3              : // Copyright (c) 2024 Mohammad Nejati
       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/service/zlib_service.hpp>
      12              : 
      13              : #include <boost/assert/source_location.hpp>
      14              : #include <boost/config.hpp>
      15              : #include <boost/system/result.hpp>
      16              : #include <boost/throw_exception.hpp>
      17              : #include <boost/static_assert.hpp>
      18              : #include <zlib.h>
      19              : 
      20              : namespace boost {
      21              : namespace http_proto {
      22              : namespace zlib {
      23              : 
      24              : //------------------------------------------------
      25              : 
      26              : namespace {
      27              : 
      28              : BOOST_NOINLINE BOOST_NORETURN
      29              : void
      30            0 : throw_zlib_error(
      31              :     int e,
      32              :     source_location const& loc = BOOST_CURRENT_LOCATION)
      33              : {
      34            0 :     throw_exception(
      35            0 :         system::system_error(static_cast<error>(e)), loc);
      36              : }
      37              : 
      38              : // probes memory usage for a config
      39              : class probe
      40              : {
      41              : public:
      42              :     explicit
      43              :     probe() noexcept
      44              :     {
      45              :         zs_.zalloc = &zalloc;
      46              :         zs_.zfree = &zfree;
      47              :         zs_.opaque = this;
      48              :     }
      49              : 
      50              :     system::result<std::size_t>
      51              :     deflate_init(
      52              :         int level)
      53              :     {
      54              :         n_ = 0;
      55              :         system::error_code ec;
      56              :         ec = static_cast<error>(
      57              :             deflateInit(&zs_, level));
      58              :         if(ec.failed())
      59              :             return ec;
      60              :         Bytef tmp[24]{};
      61              :         zs_.next_in = &tmp[0];
      62              :         zs_.avail_in = 1;
      63              :         zs_.next_out = &tmp[1];
      64              :         zs_.avail_out = 23;
      65              :         ec = static_cast<error>(
      66              :             deflate(&zs_,
      67              :                 Z_FINISH));
      68              :         if( ec.failed() &&
      69              :             ec != error::stream_end)
      70              :             return ec;
      71              :         ec = static_cast<error>(
      72              :             deflateEnd(&zs_));
      73              :         if(ec.failed())
      74              :             return ec;
      75              :         return n_;
      76              :     }
      77              : 
      78              :     system::result<std::size_t>
      79              :     deflate_init2(
      80              :         int level,
      81              :         int method,
      82              :         int windowBits,
      83              :         int memLevel,
      84              :         int strategy)
      85              :     {
      86              :         n_ = 0;
      87              :         system::error_code ec;
      88              :         ec = static_cast<error>(
      89              :             deflateInit2(&zs_,
      90              :                 level,
      91              :                 method,
      92              :                 windowBits,
      93              :                 memLevel,
      94              :                 strategy));
      95              :         if(ec.failed())
      96              :             return ec;
      97              :         Bytef tmp[2];
      98              :         zs_.next_in = &tmp[0];
      99              :         zs_.avail_in = 0;
     100              :         zs_.next_out = &tmp[1];
     101              :         zs_.avail_out = 0;
     102              :         ec = static_cast<error>(
     103              :             deflate(&zs_,
     104              :                 Z_FULL_FLUSH));
     105              :         if(ec.failed())
     106              :             return ec;
     107              :         ec = static_cast<error>(
     108              :             deflateEnd(&zs_));
     109              :         if(ec.failed())
     110              :             return ec;
     111              :         return n_;
     112              :     }
     113              : 
     114              : private:
     115              :     static void* zalloc(void* opaque,
     116              :         uInt num, uInt size)
     117              :     {
     118              :         auto& self =
     119              :             *reinterpret_cast<
     120              :                 probe*>(opaque);
     121              :         self.n_ += num * size;
     122              :         return new char[num * size];
     123              :     }
     124              : 
     125              :     static void zfree(
     126              :         void*, void* address)
     127              :     {
     128              :         delete[] reinterpret_cast<
     129              :             char*>(address);
     130              :     }
     131              : 
     132              :     z_stream_s zs_{};
     133              :     std::size_t n_ = 0;
     134              : };
     135              : 
     136          348 : void* zalloc(
     137              :     void* opaque,
     138              :     unsigned items,
     139              :     unsigned size)
     140              : {
     141              :     try
     142              :     {
     143          348 :         auto n = items * size;
     144          348 :         auto* ws =
     145              :             reinterpret_cast<
     146              :                 http_proto::detail::workspace*>(opaque);
     147              : 
     148          348 :         return ws->reserve_front(n);
     149              :     }
     150            0 :     catch(std::length_error const&) // represents OOM
     151              :     {
     152            0 :         return Z_NULL;
     153            0 :     }
     154              : }
     155              : 
     156            0 : void zfree(void* /* opaque */, void* /* addr */)
     157              : {
     158              :     // we call ws_.clear() before the serializer is reused
     159              :     // so all the allocations are passively freed
     160            0 : }
     161              : 
     162              : ::uInt
     163       660516 : clamp(std::size_t x) noexcept
     164              : {
     165       660516 :     if(x >= (std::numeric_limits<::uInt>::max)())
     166            0 :         return (std::numeric_limits<::uInt>::max)();
     167       660516 :     return static_cast<::uInt>(x);
     168              : }
     169              : 
     170              : void
     171       165129 : sync(z_stream* zs, params const& p) noexcept
     172              : {
     173       165129 :     zs->next_in   = reinterpret_cast<::Bytef*>(
     174       165129 :         const_cast<void*>(p.next_in));
     175       165129 :     zs->avail_in  = clamp(p.avail_in);
     176       165129 :     zs->next_out  = reinterpret_cast<::Bytef*>(p.next_out);
     177       165129 :     zs->avail_out = clamp(p.avail_out);
     178       165129 : }
     179              : 
     180              : void
     181       165129 : sync(z_stream const& zs, params* p) noexcept
     182              : {
     183       165129 :     p->next_in    = zs.next_in;
     184       165129 :     p->avail_in  -= clamp(p->avail_in) - zs.avail_in;
     185       165129 :     p->next_out   = zs.next_out;
     186       165129 :     p->avail_out -= clamp(p->avail_out) - zs.avail_out;
     187       165129 : }
     188              : 
     189              : class deflator
     190              :     : public stream
     191              : {
     192              :     z_stream zs_;
     193              : 
     194              : public:
     195           48 :     deflator(
     196              :         http_proto::detail::workspace& ws,
     197              :         int level,
     198              :         int window_bits,
     199              :         int mem_level)
     200           48 :     {
     201           48 :         zs_.zalloc = &zalloc;
     202           48 :         zs_.zfree  = &zfree;
     203           48 :         zs_.opaque = &ws;
     204              : 
     205           48 :         auto ret = deflateInit2(&zs_, level, Z_DEFLATED,
     206              :             window_bits, mem_level, Z_DEFAULT_STRATEGY);
     207           48 :         if(ret != Z_OK)
     208            0 :             throw_zlib_error(ret);
     209           48 :     }
     210              : 
     211              :     system::error_code
     212        45712 :     write(params& p, flush f) noexcept override
     213              :     {
     214        45712 :         sync(&zs_, p);
     215        45712 :         auto ret = deflate(&zs_, static_cast<int>(f));
     216        45712 :         sync(zs_, &p);
     217        45712 :         return static_cast<error>(ret);
     218              :     }
     219              : };
     220              : 
     221              : class inflator
     222              :     : public stream
     223              : {
     224              :     z_stream zs_;
     225              : 
     226              : public:
     227           72 :     inflator(
     228              :         http_proto::detail::workspace& ws,
     229              :         int window_bits)
     230           72 :     {
     231           72 :         zs_.zalloc = &zalloc;
     232           72 :         zs_.zfree  = &zfree;
     233           72 :         zs_.opaque = &ws;
     234              : 
     235           72 :         auto ret = inflateInit2(&zs_, window_bits);
     236           72 :         if(ret != Z_OK)
     237            0 :             throw_zlib_error(ret);
     238           72 :     }
     239              : 
     240              :     system::error_code
     241       119417 :     write(params& p, flush f) noexcept override
     242              :     {
     243       119417 :         sync(&zs_, p);
     244       119417 :         auto ret = inflate(&zs_, static_cast<int>(f));
     245       119417 :         sync(zs_, &p);
     246       119417 :         return static_cast<error>(ret);
     247              :     }
     248              : };
     249              : 
     250              : struct service_impl
     251              :     : public service
     252              : {
     253              :     using key_type = service;
     254              : 
     255              :     explicit
     256           27 :     service_impl(context&) noexcept
     257           27 :     {
     258           27 :     }
     259              : 
     260              :     std::size_t
     261           24 :     deflator_space_needed(
     262              :         int window_bits,
     263              :         int mem_level) const noexcept override
     264              :     {
     265              :         // TODO: Account for the number of allocations and
     266              :         // their overhead in the workspace.
     267              : 
     268              :         // https://www.zlib.net/zlib_tech.html
     269              :         return
     270           24 :             (1 << (window_bits + 2)) +
     271           24 :             (1 << (mem_level + 9)) +
     272              :             (6 * 1024) +
     273              :             #ifdef __s390x__
     274              :             5768 +
     275              :             #endif
     276              :             http_proto::detail::
     277           24 :                 workspace::space_needed<deflator>();
     278              :     }
     279              : 
     280              :     std::size_t
     281            2 :     inflator_space_needed(
     282              :         int window_bits) const noexcept override
     283              :     {
     284              :         // TODO: Account for the number of allocations and
     285              :         // their overhead in the workspace.
     286              : 
     287              :         // https://www.zlib.net/zlib_tech.html
     288              :         return
     289            2 :             (1 << window_bits) +
     290              :             (7 * 1024) +
     291              :             #ifdef __s390x__
     292              :             5768 +
     293              :             #endif
     294              :             http_proto::detail::
     295            2 :                 workspace::space_needed<inflator>();
     296              :     }
     297              : 
     298              :     stream&
     299           48 :     make_deflator(
     300              :         http_proto::detail::workspace& ws,
     301              :         int level,
     302              :         int window_bits,
     303              :         int mem_level) const override
     304              :     {
     305           48 :         return ws.emplace<deflator>(
     306           48 :             ws, level, window_bits, mem_level);
     307              :     }
     308              : 
     309              :     stream&
     310           72 :     make_inflator(
     311              :         http_proto::detail::workspace& ws,
     312              :         int window_bits) const override
     313              :     {
     314           72 :         return ws.emplace<inflator>(ws, window_bits);
     315              :     }
     316              : };
     317              : 
     318              : } // namespace
     319              : 
     320              : void
     321           27 : install_service(context& ctx)
     322              : {
     323           27 :     ctx.make_service<service_impl>();
     324           27 : }
     325              : 
     326              : //------------------------------------------------
     327              : 
     328              : } // zlib
     329              : } // http_proto
     330              : } // boost
        

Generated by: LCOV version 2.1