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/service/zlib_service.hpp> 14 : #include <boost/system/result.hpp> 15 : #include "zlib.h" 16 : 17 : namespace boost { 18 : namespace http_proto { 19 : namespace zlib { 20 : namespace detail { 21 : 22 : /* 23 : DEFLATE Compressed Data Format Specification version 1.3 24 : https://www.rfc-editor.org/rfc/rfc1951 25 : */ 26 : 27 : //------------------------------------------------ 28 : 29 : enum class error 30 : { 31 : ok = 0, 32 : stream_end = 1, 33 : need_dict = 2, 34 : errno_ = -1, 35 : stream_err = -2, 36 : data_err = -3, 37 : mem_err = -4, 38 : buf_err = -5, 39 : version_err = -6 40 : }; 41 : 42 : system::error_code 43 4 : make_error_code( 44 : error ev) noexcept 45 : { 46 : struct cat_t 47 : : system::error_category 48 : { 49 1 : cat_t() noexcept 50 1 : : error_category( 51 1 : 0xe6c6d0215d1d6e22) 52 : { 53 1 : } 54 : 55 : const char* 56 0 : name() const noexcept override 57 : { 58 0 : return "boost.http.proto.zlib"; 59 : } 60 : 61 : std::string 62 0 : message(int ev) const override 63 : { 64 0 : switch(static_cast<error>(ev)) 65 : { 66 0 : case error::ok: return "Z_OK"; 67 0 : case error::stream_end: return "Z_STREAM_END"; 68 0 : case error::need_dict: return "Z_NEED_DICT"; 69 0 : case error::errno_: return "Z_ERRNO"; 70 0 : case error::stream_err: return "Z_STREAM_ERROR"; 71 0 : case error::data_err: return "Z_DATA_ERROR"; 72 0 : case error::mem_err: return "Z_MEM_ERROR"; 73 0 : case error::buf_err: return "Z_BUF_ERROR"; 74 0 : case error::version_err: return "Z_VERSION_ERROR"; 75 0 : default: 76 0 : return "unknown"; 77 : } 78 : } 79 : }; 80 4 : static cat_t const cat{}; 81 : return system::error_code{static_cast< 82 : std::underlying_type< 83 4 : error>::type>(ev), cat}; 84 : } 85 : } // detail 86 : } // zlib 87 : } // http_proto 88 : namespace system { 89 : template<> 90 : struct is_error_code_enum< 91 : ::boost::http_proto::zlib::detail::error> 92 : { 93 : static bool const value = true; 94 : }; 95 : } // system 96 : namespace http_proto { 97 : namespace zlib { 98 : namespace detail { 99 : 100 : //------------------------------------------------ 101 : 102 : // probes memory usage for a config 103 : class probe 104 : { 105 : public: 106 : explicit 107 1 : probe() noexcept 108 1 : { 109 1 : zs_.zalloc = &zalloc; 110 1 : zs_.zfree = &zfree; 111 1 : zs_.opaque = this; 112 1 : } 113 : 114 : system::result<std::size_t> 115 1 : deflate_init( 116 : int level) 117 : { 118 1 : n_ = 0; 119 1 : system::error_code ec; 120 : ec = static_cast<error>( 121 1 : deflateInit(&zs_, level)); 122 1 : if(ec.failed()) 123 0 : return ec; 124 1 : Bytef tmp[24]{}; 125 1 : zs_.next_in = &tmp[0]; 126 1 : zs_.avail_in = 1; 127 1 : zs_.next_out = &tmp[1]; 128 1 : zs_.avail_out = 23; 129 : ec = static_cast<error>( 130 1 : deflate(&zs_, 131 1 : Z_FINISH)); 132 2 : if( ec.failed() && 133 2 : ec != error::stream_end) 134 0 : return ec; 135 : ec = static_cast<error>( 136 1 : deflateEnd(&zs_)); 137 1 : if(ec.failed()) 138 0 : return ec; 139 1 : return n_; 140 : } 141 : 142 : system::result<std::size_t> 143 : deflate_init2( 144 : int level, 145 : int method, 146 : int windowBits, 147 : int memLevel, 148 : int strategy) 149 : { 150 : n_ = 0; 151 : system::error_code ec; 152 : ec = static_cast<error>( 153 : deflateInit2(&zs_, 154 : level, 155 : method, 156 : windowBits, 157 : memLevel, 158 : strategy)); 159 : if(ec.failed()) 160 : return ec; 161 : Bytef tmp[2]; 162 : zs_.next_in = &tmp[0]; 163 : zs_.avail_in = 0; 164 : zs_.next_out = &tmp[1]; 165 : zs_.avail_out = 0; 166 : ec = static_cast<error>( 167 : deflate(&zs_, 168 : Z_FULL_FLUSH)); 169 : if(ec.failed()) 170 : return ec; 171 : ec = static_cast<error>( 172 : deflateEnd(&zs_)); 173 : if(ec.failed()) 174 : return ec; 175 : return n_; 176 : } 177 : 178 : private: 179 5 : static void* zalloc(void* opaque, 180 : uInt num, uInt size) 181 : { 182 5 : auto& self = 183 : *reinterpret_cast< 184 : probe*>(opaque); 185 5 : self.n_ += num * size; 186 5 : return new char[num * size]; 187 : } 188 : 189 5 : static void zfree( 190 : void*, void* address) 191 : { 192 : delete[] reinterpret_cast< 193 5 : char*>(address); 194 5 : } 195 : 196 : z_stream_s zs_{}; 197 : std::size_t n_ = 0; 198 : }; 199 : 200 : //------------------------------------------------ 201 : 202 : struct 203 : deflate_decoder_service_impl 204 : : deflate_decoder_service 205 : { 206 : using key_type = 207 : deflate_decoder_service; 208 : 209 : explicit 210 1 : deflate_decoder_service_impl( 211 : context& ctx, 212 : config const& cfg) 213 1 : : cfg_(cfg) 214 : { 215 : (void)ctx; 216 1 : probe p; 217 0 : auto n0 = p.deflate_init( 218 1 : Z_DEFAULT_COMPRESSION).value(); 219 : (void)n0; 220 1 : } 221 : 222 : private: 223 : config cfg_; 224 : 225 : config const& 226 0 : get_config() const noexcept override 227 : { 228 0 : return cfg_; 229 : } 230 : 231 : std::size_t 232 0 : space_needed() const noexcept override 233 : { 234 0 : return 0; 235 : } 236 : 237 : filter& 238 0 : make_filter(http_proto::detail::workspace& ws) const override 239 : { 240 : filter* p; 241 : (void)ws; 242 0 : p = nullptr; 243 0 : return *p; 244 : } 245 : }; 246 : 247 : } // detail 248 : 249 : void 250 1 : deflate_decoder_service:: 251 : config:: 252 : install(context& ctx) 253 : { 254 : ctx.make_service< 255 1 : detail::deflate_decoder_service_impl>(*this); 256 1 : } 257 : 258 : } // zlib 259 : } // http_proto 260 : } // boost 261 : 262 : #endif