Line | Branch | Exec | Source |
---|---|---|---|
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 | ✗ | name() const noexcept override | |
55 | { | ||
56 | ✗ | return "boost.http.proto.zlib"; | |
57 | } | ||
58 | |||
59 | std::string | ||
60 | ✗ | message(int ev) const override | |
61 | { | ||
62 | ✗ | switch(static_cast<error>(ev)) | |
63 | { | ||
64 | ✗ | case error::ok: return "Z_OK"; | |
65 | ✗ | case error::stream_end: return "Z_STREAM_END"; | |
66 | ✗ | case error::need_dict: return "Z_NEED_DICT"; | |
67 | ✗ | case error::errno_: return "Z_ERRNO"; | |
68 | ✗ | case error::stream_err: return "Z_STREAM_ERROR"; | |
69 | ✗ | case error::data_err: return "Z_DATA_ERROR"; | |
70 | ✗ | case error::mem_err: return "Z_MEM_ERROR"; | |
71 | ✗ | case error::buf_err: return "Z_BUF_ERROR"; | |
72 | ✗ | case error::version_err: return "Z_VERSION_ERROR"; | |
73 | ✗ | default: | |
74 | ✗ | return "unknown"; | |
75 | } | ||
76 | } | ||
77 | }; | ||
78 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
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/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | deflateInit(&zs_, level)); |
120 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(ec.failed()) |
121 | ✗ | 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/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | deflate(&zs_, |
129 | 1 | Z_FINISH)); | |
130 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
2 | if( ec.failed() && |
131 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
2 | ec != error::stream_end) |
132 | ✗ | return ec; | |
133 | ec = static_cast<error>( | ||
134 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | deflateEnd(&zs_)); |
135 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if(ec.failed()) |
136 | ✗ | 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 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
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 | ✗ | auto n0 = p.deflate_init( | |
216 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
|
1 | Z_DEFAULT_COMPRESSION).value(); |
217 | (void)n0; | ||
218 | 1 | } | |
219 | |||
220 | private: | ||
221 | config cfg_; | ||
222 | |||
223 | config const& | ||
224 | ✗ | get_config() const noexcept override | |
225 | { | ||
226 | ✗ | return cfg_; | |
227 | } | ||
228 | |||
229 | std::size_t | ||
230 | ✗ | space_needed() const noexcept override | |
231 | { | ||
232 | ✗ | return 0; | |
233 | } | ||
234 | |||
235 | buffers::filter& | ||
236 | ✗ | make_filter(http_proto::detail::workspace& ws) const override | |
237 | { | ||
238 | buffers::filter* p; | ||
239 | (void)ws; | ||
240 | ✗ | p = nullptr; | |
241 | ✗ | 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 | ||
261 |