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