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