GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src_zlib/service/zlib_service.cpp
Date: 2024-05-23 18:56:45
Exec Total Coverage
Lines: 0 144 0.0%
Functions: 0 20 0.0%
Branches: 0 74 0.0%

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
15 #include <boost/http_proto/metadata.hpp>
16 #include <boost/http_proto/detail/workspace.hpp>
17
18 #include <boost/buffers/circular_buffer.hpp>
19 #include <boost/system/result.hpp>
20
21 #include <list>
22
23 #include "zlib.h"
24
25 namespace boost {
26 namespace http_proto {
27 namespace zlib {
28 namespace detail {
29
30 static
31 constexpr
32 std::size_t
33 crlf_len_ = 2;
34
35 // last-chunk = 1*("0") [ chunk-ext ] CRLF
36 static
37 constexpr
38 std::size_t
39 last_chunk_len_ =
40 1 + // "0"
41 crlf_len_ +
42 crlf_len_; // chunked-body termination requires an extra CRLF
43
44 /*
45 DEFLATE Compressed Data Format Specification version 1.3
46 https://www.rfc-editor.org/rfc/rfc1951
47 */
48
49 //------------------------------------------------
50
51 enum class error
52 {
53 ok = 0,
54 stream_end = 1,
55 need_dict = 2,
56 errno_ = -1,
57 stream_err = -2,
58 data_err = -3,
59 mem_err = -4,
60 buf_err = -5,
61 version_err = -6
62 };
63
64 //------------------------------------------------
65 } // detail
66 } // zlib
67 } // http_proto
68 namespace system {
69 template<>
70 struct is_error_code_enum<
71 ::boost::http_proto::zlib::detail::error>
72 {
73 static bool const value = true;
74 };
75 } // system
76 namespace http_proto {
77 namespace zlib {
78 namespace detail {
79 //------------------------------------------------
80
81 struct error_cat_type
82 : system::error_category
83 {
84 BOOST_SYSTEM_CONSTEXPR
85 error_cat_type() noexcept
86 : error_category(
87 0xe6c6d0215d1d6e22)
88 {
89 }
90
91 const char*
92 name() const noexcept override
93 {
94 return "boost.http.proto.zlib";
95 }
96
97 std::string
98 message( int ev ) const override
99 {
100 return message( ev, nullptr, 0 );
101 }
102
103 char const*
104 message(
105 int ev,
106 char*,
107 std::size_t) const noexcept override
108 {
109 switch(static_cast<error>(ev))
110 {
111 case error::ok: return "Z_OK";
112 case error::stream_end: return "Z_STREAM_END";
113 case error::need_dict: return "Z_NEED_DICT";
114 case error::errno_: return "Z_ERRNO";
115 case error::stream_err: return "Z_STREAM_ERROR";
116 case error::data_err: return "Z_DATA_ERROR";
117 case error::mem_err: return "Z_MEM_ERROR";
118 case error::buf_err: return "Z_BUF_ERROR";
119 case error::version_err: return "Z_VERSION_ERROR";
120 default:
121 return "unknown";
122 }
123 }
124 };
125
126 system::error_code
127 make_error_code(
128 error ev) noexcept
129 {
130 static BOOST_SYSTEM_CONSTEXPR
131 error_cat_type cat{};
132 return system::error_code{static_cast<
133 std::underlying_type<
134 error>::type>(ev), cat};
135 }
136
137 //------------------------------------------------
138
139 // probes memory usage for a config
140 class probe
141 {
142 public:
143 explicit
144 probe() noexcept
145 {
146 zs_.zalloc = &zalloc;
147 zs_.zfree = &zfree;
148 zs_.opaque = this;
149 }
150
151 system::result<std::size_t>
152 deflate_init(
153 int level)
154 {
155 n_ = 0;
156 system::error_code ec;
157 ec = static_cast<error>(
158 deflateInit(&zs_, level));
159 if(ec.failed())
160 return ec;
161 Bytef tmp[24]{};
162 zs_.next_in = &tmp[0];
163 zs_.avail_in = 1;
164 zs_.next_out = &tmp[1];
165 zs_.avail_out = 23;
166 ec = static_cast<error>(
167 deflate(&zs_,
168 Z_FINISH));
169 if( ec.failed() &&
170 ec != error::stream_end)
171 return ec;
172 ec = static_cast<error>(
173 deflateEnd(&zs_));
174 if(ec.failed())
175 return ec;
176 return n_;
177 }
178
179 system::result<std::size_t>
180 deflate_init2(
181 int level,
182 int method,
183 int windowBits,
184 int memLevel,
185 int strategy)
186 {
187 n_ = 0;
188 system::error_code ec;
189 ec = static_cast<error>(
190 deflateInit2(&zs_,
191 level,
192 method,
193 windowBits,
194 memLevel,
195 strategy));
196 if(ec.failed())
197 return ec;
198 Bytef tmp[2];
199 zs_.next_in = &tmp[0];
200 zs_.avail_in = 0;
201 zs_.next_out = &tmp[1];
202 zs_.avail_out = 0;
203 ec = static_cast<error>(
204 deflate(&zs_,
205 Z_FULL_FLUSH));
206 if(ec.failed())
207 return ec;
208 ec = static_cast<error>(
209 deflateEnd(&zs_));
210 if(ec.failed())
211 return ec;
212 return n_;
213 }
214
215 private:
216 static void* zalloc(void* opaque,
217 uInt num, uInt size)
218 {
219 auto& self =
220 *reinterpret_cast<
221 probe*>(opaque);
222 self.n_ += num * size;
223 return new char[num * size];
224 }
225
226 static void zfree(
227 void*, void* address)
228 {
229 delete[] reinterpret_cast<
230 char*>(address);
231 }
232
233 z_stream_s zs_{};
234 std::size_t n_ = 0;
235 };
236
237 //------------------------------------------------
238
239
240 namespace {
241 void* zalloc_impl(
242 void* /* opaque */,
243 unsigned items,
244 unsigned size)
245 {
246 try {
247 return ::operator new(items * size);
248 } catch(std::bad_alloc const&) {
249 return Z_NULL;
250 }
251 }
252
253 void zfree_impl(void* /* opaque */, void* addr)
254 {
255 ::operator delete(addr);
256 }
257 } // namespace
258
259 class BOOST_HTTP_PROTO_ZLIB_DECL
260 zlib_filter final : public filter
261 {
262 private:
263 z_stream stream_;
264 content_coding_type coding_ = content_coding_type::none;
265
266 void init();
267
268 public:
269 zlib_filter();
270 ~zlib_filter();
271
272 zlib_filter(zlib_filter const&) = delete;
273 zlib_filter& operator=(zlib_filter const&) = delete;
274
275 filter::results
276 on_process(
277 buffers::mutable_buffer out,
278 buffers::const_buffer in,
279 bool more) override;
280 };
281
282 zlib_filter::
283 zlib_filter()
284 {
285 stream_.zalloc = &zalloc_impl;
286 stream_.zfree = &zfree_impl;
287 stream_.opaque = nullptr;
288 init();
289 }
290
291 zlib_filter::
292 ~zlib_filter()
293 {
294 deflateEnd(&stream_);
295 }
296
297 void
298 zlib_filter::
299 init()
300 {
301 int ret = -1;
302
303 int window_bits = 15;
304 // if( coding_ == content_coding_type::gzip )
305 // window_bits += 16;
306
307 int mem_level = 8;
308
309 ret = deflateInit2(
310 &stream_, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
311 window_bits, mem_level, Z_DEFAULT_STRATEGY);
312
313 if( ret != Z_OK )
314 throw ret;
315
316 stream_.next_out = nullptr;
317 stream_.avail_out = 0;
318
319 stream_.next_in = nullptr;
320 stream_.avail_in = 0;
321 }
322
323 filter::results
324 zlib_filter::
325 on_process(
326 buffers::mutable_buffer out,
327 buffers::const_buffer in,
328 bool more)
329 {
330 auto& zstream = stream_;
331
332 BOOST_ASSERT(out.size() > 6);
333
334 auto flush = more ? Z_NO_FLUSH : Z_FINISH;
335 int ret = -1337;
336 filter::results results;
337
338 while( true )
339 {
340 zstream.next_in =
341 reinterpret_cast<unsigned char*>(
342 const_cast<void*>(in.data()));
343 zstream.avail_in = static_cast<unsigned>(
344 in.size());
345
346 zstream.next_out =
347 reinterpret_cast<unsigned char*>(
348 out.data());
349 zstream.avail_out =
350 static_cast<unsigned>(out.size());
351
352 auto n1 = zstream.avail_in;
353 auto n2 = zstream.avail_out;
354 ret = deflate(&zstream, flush);
355
356 in += (n1 - zstream.avail_in);
357 out += (n2 - zstream.avail_out);
358
359 results.in_bytes += (n1 - zstream.avail_in);
360 results.out_bytes += (n2 - zstream.avail_out);
361
362 auto is_empty = (in.size() == 0);
363
364 if( ret != Z_OK &&
365 ret != Z_BUF_ERROR &&
366 ret != Z_STREAM_END )
367 throw ret;
368
369 if( is_empty &&
370 n2 == zstream.avail_out &&
371 ret == Z_OK )
372 {
373 flush = Z_SYNC_FLUSH;
374 continue;
375 }
376
377 if( ret == Z_STREAM_END )
378 results.finished = true;
379
380 if( ret == Z_BUF_ERROR )
381 break;
382
383 if( ret == Z_STREAM_END )
384 break;
385
386 if( ret == Z_OK &&
387 out.size() <
388 detail::last_chunk_len_ +
389 detail::crlf_len_ + 1 )
390 break;
391 }
392 return results;
393 }
394
395 //------------------------------------------------
396
397 struct
398 deflate_decoder_service_impl
399 : deflate_decoder_service
400 {
401 using key_type =
402 deflate_decoder_service;
403
404 explicit
405 deflate_decoder_service_impl(
406 context& ctx,
407 config const& cfg)
408 : cfg_(cfg)
409 {
410 (void)ctx;
411 probe p;
412 auto n0 = p.deflate_init(
413 Z_DEFAULT_COMPRESSION).value();
414 (void)n0;
415 }
416
417 private:
418 config cfg_;
419
420 config const&
421 get_config() const noexcept override
422 {
423 return cfg_;
424 }
425
426 std::size_t
427 space_needed() const noexcept override
428 {
429 return 0;
430 }
431
432 filter&
433 make_filter(
434 http_proto::detail::workspace& ws) const override
435 {
436 return ws.emplace<zlib_filter>();
437 }
438 };
439
440 } // detail
441
442 void
443 deflate_decoder_service::
444 config::
445 install(context& ctx)
446 {
447 ctx.make_service<
448 detail::deflate_decoder_service_impl>(*this);
449 }
450
451 } // zlib
452 } // http_proto
453 } // boost
454
455 #endif
456