xref: /openbmc/bmcweb/http/zstd_decompressor.cpp (revision b25390694f7015224fbf02de247faec4c50429aa)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 
4 #include "zstd_decompressor.hpp"
5 
6 #include "logging.hpp"
7 
8 #ifdef HAVE_ZSTD
9 #include <zstd.h>
10 #endif
11 #include <boost/asio/buffer.hpp>
12 
13 #include <cstddef>
14 #include <optional>
15 
16 #ifdef HAVE_ZSTD
ZstdDecompressor()17 ZstdDecompressor::ZstdDecompressor() : dctx(ZSTD_createDStream())
18 {
19     ZSTD_initDStream(dctx);
20 }
21 #else
ZstdDecompressor()22 ZstdDecompressor::ZstdDecompressor() {};
23 #endif
24 
decompress(boost::asio::const_buffer buffIn)25 std::optional<boost::asio::const_buffer> ZstdDecompressor::decompress(
26     [[maybe_unused]] boost::asio::const_buffer buffIn)
27 {
28 #ifdef HAVE_ZSTD
29     compressionBuf.clear();
30     ZSTD_inBuffer input = {buffIn.data(), buffIn.size(), 0};
31 
32     // Note, this loop is prone to compression bombs, decompressing chunks that
33     // appear very small, but decompress to be very large, given that they're
34     // highly decompressible. This algorithm assumes that at this time, the
35     // whole file will fit in ram.
36     while (input.pos != input.size)
37     {
38         constexpr size_t frameSize = 4096;
39         auto buffer = compressionBuf.prepare(frameSize);
40         ZSTD_outBuffer output = {buffer.data(), buffer.size(), 0};
41         const size_t ret = ZSTD_decompressStream(dctx, &output, &input);
42         if (ZSTD_isError(ret) != 0)
43         {
44             BMCWEB_LOG_ERROR("Decompression Failed with code {}:{}", ret,
45                              ZSTD_getErrorName(ret));
46             return std::nullopt;
47         }
48         compressionBuf.commit(output.pos);
49     }
50     return compressionBuf.cdata();
51 #else
52     BMCWEB_LOG_CRITICAL("Attempt to decompress, but libzstd not enabled");
53 
54     return std::nullopt;
55 #endif
56 }
57 
~ZstdDecompressor()58 ZstdDecompressor::~ZstdDecompressor()
59 {
60 #ifdef HAVE_ZSTD
61     ZSTD_freeDStream(dctx);
62 #endif
63 }
64