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