GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src_zlib/service/zlib_service.cpp
Date: 2024-09-20 16:11:52
Exec Total Coverage
Lines: 44 70 62.9%
Functions: 10 15 66.7%
Branches: 3 12 25.0%

Line Branch Exec Source
1 //
2 // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com)
3 // Copyright (c) 2024 Mohammad Nejati
4 //
5 // Distributed under the Boost Software License, Version 1.0. (See accompanying
6 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // Official repository: https://github.com/cppalliance/http_proto
9 //
10
11 #include <boost/http_proto/service/zlib_service.hpp>
12
13 #include <boost/assert/source_location.hpp>
14 #include <boost/config.hpp>
15 #include <boost/system/result.hpp>
16 #include <boost/throw_exception.hpp>
17
18 #include <zlib.h>
19
20 namespace boost {
21 namespace http_proto {
22 namespace zlib {
23
24 namespace {
25
26 BOOST_NOINLINE BOOST_NORETURN
27 void
28 throw_zlib_error(
29 int e,
30 source_location const& loc = BOOST_CURRENT_LOCATION)
31 {
32 throw_exception(
33 system::system_error(static_cast<error>(e)), loc);
34 }
35
36 // probes memory usage for a config
37 class probe
38 {
39 public:
40 explicit
41 probe() noexcept
42 {
43 zs_.zalloc = &zalloc;
44 zs_.zfree = &zfree;
45 zs_.opaque = this;
46 }
47
48 system::result<std::size_t>
49 deflate_init(
50 int level)
51 {
52 n_ = 0;
53 system::error_code ec;
54 ec = static_cast<error>(
55 deflateInit(&zs_, level));
56 if(ec.failed())
57 return ec;
58 Bytef tmp[24]{};
59 zs_.next_in = &tmp[0];
60 zs_.avail_in = 1;
61 zs_.next_out = &tmp[1];
62 zs_.avail_out = 23;
63 ec = static_cast<error>(
64 deflate(&zs_,
65 Z_FINISH));
66 if( ec.failed() &&
67 ec != error::stream_end)
68 return ec;
69 ec = static_cast<error>(
70 deflateEnd(&zs_));
71 if(ec.failed())
72 return ec;
73 return n_;
74 }
75
76 system::result<std::size_t>
77 deflate_init2(
78 int level,
79 int method,
80 int windowBits,
81 int memLevel,
82 int strategy)
83 {
84 n_ = 0;
85 system::error_code ec;
86 ec = static_cast<error>(
87 deflateInit2(&zs_,
88 level,
89 method,
90 windowBits,
91 memLevel,
92 strategy));
93 if(ec.failed())
94 return ec;
95 Bytef tmp[2];
96 zs_.next_in = &tmp[0];
97 zs_.avail_in = 0;
98 zs_.next_out = &tmp[1];
99 zs_.avail_out = 0;
100 ec = static_cast<error>(
101 deflate(&zs_,
102 Z_FULL_FLUSH));
103 if(ec.failed())
104 return ec;
105 ec = static_cast<error>(
106 deflateEnd(&zs_));
107 if(ec.failed())
108 return ec;
109 return n_;
110 }
111
112 private:
113 static void* zalloc(void* opaque,
114 uInt num, uInt size)
115 {
116 auto& self =
117 *reinterpret_cast<
118 probe*>(opaque);
119 self.n_ += num * size;
120 return new char[num * size];
121 }
122
123 static void zfree(
124 void*, void* address)
125 {
126 delete[] reinterpret_cast<
127 char*>(address);
128 }
129
130 z_stream_s zs_{};
131 std::size_t n_ = 0;
132 };
133
134 240 void* zalloc(
135 void* opaque,
136 unsigned items,
137 unsigned size)
138 {
139 try
140 {
141 240 auto n = items * size;
142 240 auto* ws =
143 reinterpret_cast<
144 http_proto::detail::workspace*>(opaque);
145
146
1/2
✓ Branch 1 taken 240 times.
✗ Branch 2 not taken.
240 return ws->reserve_front(n);
147 }
148 catch(std::length_error const&) // represents OOM
149 {
150 return Z_NULL;
151 }
152 }
153
154 void zfree(void* /* opaque */, void* /* addr */)
155 {
156 // we call ws_.clear() before the serializer is reused
157 // so all the allocations are passively freed
158 }
159
160 static ::uInt
161 144928 clamp(std::size_t x) noexcept
162 {
163
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 144928 times.
144928 if(x >= (std::numeric_limits<::uInt>::max)())
164 return (std::numeric_limits<::uInt>::max)();
165 144928 return static_cast<::uInt>(x);
166 }
167
168 void
169 36232 sync(z_stream* zs, params const& p) noexcept
170 {
171 36232 zs->next_in = reinterpret_cast<::Bytef*>(
172 36232 const_cast<void*>(p.next_in));
173 36232 zs->avail_in = clamp(p.avail_in);
174 36232 zs->next_out = reinterpret_cast<::Bytef*>(p.next_out);
175 36232 zs->avail_out = clamp(p.avail_out);
176 36232 }
177
178 void
179 36232 sync(z_stream const& zs, params* p) noexcept
180 {
181 36232 p->next_in = zs.next_in;
182 36232 p->avail_in -= clamp(p->avail_in) - zs.avail_in;
183 36232 p->next_out = zs.next_out;
184 36232 p->avail_out -= clamp(p->avail_out) - zs.avail_out;
185 36232 }
186
187 class deflator
188 : public stream
189 {
190 z_stream zs_;
191
192 public:
193 48 deflator(
194 http_proto::detail::workspace& ws,
195 int level,
196 int window_bits,
197 int mem_level)
198 48 {
199 48 zs_.zalloc = &zalloc;
200 48 zs_.zfree = &zfree;
201 48 zs_.opaque = &ws;
202
203 48 auto ret = deflateInit2(&zs_, level, Z_DEFLATED,
204 window_bits, mem_level, Z_DEFAULT_STRATEGY);
205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if(ret != Z_OK)
206 throw_zlib_error(ret);
207 48 }
208
209 system::error_code
210 36232 write(params& p, flush f) noexcept override
211 {
212 36232 sync(&zs_, p);
213 36232 auto ret = deflate(&zs_, static_cast<int>(f));
214 36232 sync(zs_, &p);
215 36232 return static_cast<error>(ret);
216 }
217 };
218
219 class inflator
220 : public stream
221 {
222 z_stream zs_;
223
224 public:
225 inflator(
226 http_proto::detail::workspace& ws,
227 int window_bits)
228 {
229 zs_.zalloc = &zalloc;
230 zs_.zfree = &zfree;
231 zs_.opaque = &ws;
232
233 auto ret = inflateInit2(&zs_, window_bits);
234 if(ret != Z_OK)
235 throw_zlib_error(ret);
236 }
237
238 system::error_code
239 write(params& p, flush f) noexcept override
240 {
241 sync(&zs_, p);
242 auto ret = inflate(&zs_, static_cast<int>(f));
243 sync(zs_, &p);
244 return static_cast<error>(ret);
245 }
246 };
247
248 struct service_impl
249 : public service
250 {
251 using key_type = service;
252
253 explicit
254 26 service_impl(context&) noexcept
255 26 {
256 26 }
257
258 std::size_t
259 1 space_needed() const noexcept override
260 {
261 1 return 0; // TODO
262 }
263
264 stream&
265 48 make_deflator(
266 http_proto::detail::workspace& ws,
267 int level,
268 int window_bits,
269 int mem_level) const override
270 {
271 48 return ws.emplace<deflator>(
272 48 ws, level, window_bits, mem_level);
273 }
274
275 stream&
276 make_inflator(
277 http_proto::detail::workspace& ws,
278 int window_bits) const override
279 {
280 return ws.emplace<inflator>(ws, window_bits);
281 }
282 };
283
284 } // namespace
285
286 void
287 26 install_service(context& ctx)
288 {
289 26 ctx.make_service<service_impl>();
290 26 }
291
292 } // zlib
293 } // http_proto
294 } // boost
295