mirror of
https://github.com/boostorg/beast.git
synced 2025-08-03 06:44:39 +02:00
Refactor zlib tests and fix typo:
close #1744 * Fixed typo in enum name * Added missing zlib error enumerator * Marked caveat in zlib impl to avoid future confusion * Created Compressor/Decompressor abstractions in Beast.zlib tests * Applied abstractions on Beast.zlib tests * Workaround Travis-CI' 10min silence timeout * Add test for Beast.zlib's need_dict error * Avoid breaking user-code dependant on deprecated enumerator interface Signed-off-by: AeroStun <24841307+AeroStun@users.noreply.github.com>
This commit is contained in:
@@ -6,6 +6,7 @@ Version 275:
|
|||||||
* Support Concepts for completion token params
|
* Support Concepts for completion token params
|
||||||
* https_get example sends the Host header
|
* https_get example sends the Host header
|
||||||
* Fix async_close error code when async_read times out
|
* Fix async_close error code when async_read times out
|
||||||
|
* Refactor zlib tests and fix enum typo
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@@ -399,7 +399,7 @@ doWrite(z_params& zs, boost::optional<Flush> flush, error_code& ec)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(zs.avail_in == 0 && (
|
else if(zs.avail_in == 0 && (
|
||||||
old_flush && flush <= *old_flush
|
old_flush && flush <= *old_flush // Caution: depends on enum order
|
||||||
) && flush != Flush::finish)
|
) && flush != Flush::finish)
|
||||||
{
|
{
|
||||||
/* Make sure there is something to do and avoid duplicate consecutive
|
/* Make sure there is something to do and avoid duplicate consecutive
|
||||||
|
@@ -66,6 +66,17 @@ enum class error
|
|||||||
*/
|
*/
|
||||||
end_of_stream,
|
end_of_stream,
|
||||||
|
|
||||||
|
/** Preset dictionary required
|
||||||
|
|
||||||
|
This error indicates that a preset dictionary was not provided and is now
|
||||||
|
needed at this point.
|
||||||
|
|
||||||
|
This does not always indicate a failure condition.
|
||||||
|
|
||||||
|
@note This is the same as `Z_NEED_DICT` returned by ZLib.
|
||||||
|
*/
|
||||||
|
need_dict,
|
||||||
|
|
||||||
/** Invalid stream or parameters.
|
/** Invalid stream or parameters.
|
||||||
|
|
||||||
This error is returned when invalid parameters are passed,
|
This error is returned when invalid parameters are passed,
|
||||||
@@ -95,7 +106,10 @@ enum class error
|
|||||||
too_many_symbols,
|
too_many_symbols,
|
||||||
|
|
||||||
/// Invalid code lengths
|
/// Invalid code lengths
|
||||||
invalid_code_lenths,
|
invalid_code_lengths,
|
||||||
|
#ifndef BOOST_BEAST_NO_DEPRECATED
|
||||||
|
invalid_code_lenths = invalid_code_lengths,
|
||||||
|
#endif
|
||||||
|
|
||||||
/// Invalid bit length repeat
|
/// Invalid bit length repeat
|
||||||
invalid_bit_length_repeat,
|
invalid_bit_length_repeat,
|
||||||
|
@@ -62,12 +62,13 @@ public:
|
|||||||
{
|
{
|
||||||
case error::need_buffers: return "need buffers";
|
case error::need_buffers: return "need buffers";
|
||||||
case error::end_of_stream: return "unexpected end of deflate stream";
|
case error::end_of_stream: return "unexpected end of deflate stream";
|
||||||
|
case error::need_dict: return "need dict";
|
||||||
case error::stream_error: return "stream error";
|
case error::stream_error: return "stream error";
|
||||||
|
|
||||||
case error::invalid_block_type: return "invalid block type";
|
case error::invalid_block_type: return "invalid block type";
|
||||||
case error::invalid_stored_length: return "invalid stored block length";
|
case error::invalid_stored_length: return "invalid stored block length";
|
||||||
case error::too_many_symbols: return "too many symbols";
|
case error::too_many_symbols: return "too many symbols";
|
||||||
case error::invalid_code_lenths: return "invalid code lengths";
|
case error::invalid_code_lengths: return "invalid code lengths";
|
||||||
case error::invalid_bit_length_repeat: return "invalid bit length repeat";
|
case error::invalid_bit_length_repeat: return "invalid bit length repeat";
|
||||||
case error::missing_eob: return "missing end of block code";
|
case error::missing_eob: return "missing end of block code";
|
||||||
case error::invalid_literal_length: return "invalid literal/length code";
|
case error::invalid_literal_length: return "invalid literal/length code";
|
||||||
|
@@ -25,6 +25,138 @@ namespace zlib {
|
|||||||
|
|
||||||
class deflate_stream_test : public beast::unit_test::suite
|
class deflate_stream_test : public beast::unit_test::suite
|
||||||
{
|
{
|
||||||
|
struct ICompressor {
|
||||||
|
virtual void init() = 0;
|
||||||
|
virtual void init(
|
||||||
|
int level,
|
||||||
|
int windowBits,
|
||||||
|
int memLevel,
|
||||||
|
int strategy) = 0;
|
||||||
|
|
||||||
|
virtual std::size_t avail_in() const noexcept = 0;
|
||||||
|
virtual void avail_in(std::size_t) noexcept = 0;
|
||||||
|
virtual void const* next_in() const noexcept = 0;
|
||||||
|
virtual void next_in(const void*) noexcept = 0;
|
||||||
|
virtual std::size_t avail_out() const noexcept = 0;
|
||||||
|
virtual void avail_out(std::size_t) noexcept = 0;
|
||||||
|
virtual void* next_out() const noexcept = 0;
|
||||||
|
virtual void next_out(void*) noexcept = 0;
|
||||||
|
virtual std::size_t total_out() const noexcept = 0;
|
||||||
|
|
||||||
|
virtual std::size_t bound(std::size_t) = 0;
|
||||||
|
virtual error_code write(Flush) = 0;
|
||||||
|
virtual ~ICompressor() = default;
|
||||||
|
};
|
||||||
|
class ZlibCompressor : public ICompressor {
|
||||||
|
z_stream zs{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
ZlibCompressor() = default;
|
||||||
|
void init() override {
|
||||||
|
deflateEnd(&zs);
|
||||||
|
zs = {};
|
||||||
|
const auto res = deflateInit2(&zs, -1, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY);
|
||||||
|
if(res != Z_OK)
|
||||||
|
throw std::invalid_argument{"zlib compressor: failure"};
|
||||||
|
}
|
||||||
|
void init(
|
||||||
|
int level,
|
||||||
|
int windowBits,
|
||||||
|
int memLevel,
|
||||||
|
int strategy) override
|
||||||
|
{
|
||||||
|
deflateEnd(&zs);
|
||||||
|
zs = {};
|
||||||
|
const auto res = deflateInit2(&zs, level, Z_DEFLATED, -windowBits, memLevel, strategy);
|
||||||
|
if(res != Z_OK)
|
||||||
|
BOOST_THROW_EXCEPTION(std::invalid_argument{"zlib compressor: bad arg"});
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::size_t avail_in() const noexcept override { return zs.avail_in; }
|
||||||
|
virtual void avail_in(std::size_t n) noexcept override { zs.avail_in = n; }
|
||||||
|
virtual void const* next_in() const noexcept override { return zs.next_in; }
|
||||||
|
virtual void next_in(const void* ptr) noexcept override { zs.next_in = const_cast<Bytef*>(static_cast<const Bytef*>(ptr)); }
|
||||||
|
virtual std::size_t avail_out() const noexcept override { return zs.avail_out; }
|
||||||
|
virtual void avail_out(std::size_t n_out) noexcept override { zs.avail_out = n_out; }
|
||||||
|
virtual void* next_out() const noexcept override { return zs.next_out; }
|
||||||
|
virtual void next_out(void* ptr) noexcept override { zs.next_out = (Bytef*)ptr; }
|
||||||
|
virtual std::size_t total_out() const noexcept override { return zs.total_out; }
|
||||||
|
|
||||||
|
std::size_t bound(std::size_t src_size) override {
|
||||||
|
return deflateBound(&zs, static_cast<uLong>(src_size));
|
||||||
|
}
|
||||||
|
error_code write(Flush flush) override {
|
||||||
|
constexpr static int zlib_flushes[] = {0, Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH, Z_TREES};
|
||||||
|
const auto zlib_flush = zlib_flushes[static_cast<int>(flush)];
|
||||||
|
if(zs.next_in == nullptr && zs.avail_in != 0)
|
||||||
|
BOOST_THROW_EXCEPTION(std::invalid_argument{"zlib compressor: invalid input"});
|
||||||
|
const auto res = deflate(&zs, zlib_flush);
|
||||||
|
switch(res){
|
||||||
|
case Z_OK:
|
||||||
|
return {};
|
||||||
|
case Z_STREAM_END:
|
||||||
|
return error::end_of_stream;
|
||||||
|
case Z_STREAM_ERROR:
|
||||||
|
return error::stream_error;
|
||||||
|
case Z_BUF_ERROR:
|
||||||
|
return error::need_buffers;
|
||||||
|
default:
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ZlibCompressor() override {
|
||||||
|
deflateEnd(&zs);
|
||||||
|
}
|
||||||
|
} zlib_compressor;
|
||||||
|
class BeastCompressor : public ICompressor {
|
||||||
|
z_params zp;
|
||||||
|
deflate_stream ds;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BeastCompressor() = default;
|
||||||
|
void init() override {
|
||||||
|
zp = {};
|
||||||
|
ds.clear();
|
||||||
|
ds.reset();
|
||||||
|
}
|
||||||
|
void init(
|
||||||
|
int level,
|
||||||
|
int windowBits,
|
||||||
|
int memLevel,
|
||||||
|
int strategy) override
|
||||||
|
{
|
||||||
|
zp = {};
|
||||||
|
ds.clear();
|
||||||
|
ds.reset(
|
||||||
|
level,
|
||||||
|
windowBits,
|
||||||
|
memLevel,
|
||||||
|
toStrategy(strategy));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::size_t avail_in() const noexcept override { return zp.avail_in; }
|
||||||
|
virtual void avail_in(std::size_t n) noexcept override { zp.avail_in = n; }
|
||||||
|
virtual void const* next_in() const noexcept override { return zp.next_in; }
|
||||||
|
virtual void next_in(const void* ptr) noexcept override { zp.next_in = ptr; }
|
||||||
|
virtual std::size_t avail_out() const noexcept override { return zp.avail_out; }
|
||||||
|
virtual void avail_out(std::size_t n_out) noexcept override { zp.avail_out = n_out; }
|
||||||
|
virtual void* next_out() const noexcept override { return zp.next_out; }
|
||||||
|
virtual void next_out(void* ptr) noexcept override { zp.next_out = (Bytef*)ptr; }
|
||||||
|
virtual std::size_t total_out() const noexcept override { return zp.total_out; }
|
||||||
|
|
||||||
|
std::size_t bound(std::size_t src_size) override {
|
||||||
|
return ds.upper_bound(src_size);
|
||||||
|
}
|
||||||
|
error_code write(Flush flush) override {
|
||||||
|
error_code ec{};
|
||||||
|
ds.write(zp, flush, ec);
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
~BeastCompressor() override = default;
|
||||||
|
} beast_compressor;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Lots of repeats, limited char range
|
// Lots of repeats, limited char range
|
||||||
static
|
static
|
||||||
@@ -151,6 +283,7 @@ public:
|
|||||||
|
|
||||||
using self = deflate_stream_test;
|
using self = deflate_stream_test;
|
||||||
typedef void(self::*pmf_t)(
|
typedef void(self::*pmf_t)(
|
||||||
|
ICompressor& c,
|
||||||
int level, int windowBits, int memLevel,
|
int level, int windowBits, int memLevel,
|
||||||
int strategy, std::string const&);
|
int strategy, std::string const&);
|
||||||
|
|
||||||
@@ -171,29 +304,26 @@ public:
|
|||||||
|
|
||||||
void
|
void
|
||||||
doDeflate1_beast(
|
doDeflate1_beast(
|
||||||
|
ICompressor& c,
|
||||||
int level, int windowBits, int memLevel,
|
int level, int windowBits, int memLevel,
|
||||||
int strategy, std::string const& check)
|
int strategy, std::string const& check)
|
||||||
{
|
{
|
||||||
std::string out;
|
std::string out;
|
||||||
z_params zs;
|
c.init(
|
||||||
deflate_stream ds;
|
|
||||||
ds.reset(
|
|
||||||
level,
|
level,
|
||||||
windowBits,
|
windowBits,
|
||||||
memLevel,
|
memLevel,
|
||||||
toStrategy(strategy));
|
strategy);
|
||||||
out.resize(ds.upper_bound(
|
out.resize(c.bound(check.size()));
|
||||||
static_cast<uLong>(check.size())));
|
c.next_in(check.data());
|
||||||
zs.next_in = (Bytef*)check.data();
|
c.avail_in(check.size());
|
||||||
zs.avail_in = static_cast<uInt>(check.size());
|
c.next_out((void*)out.data());
|
||||||
zs.next_out = (Bytef*)out.data();
|
c.avail_out(out.size());
|
||||||
zs.avail_out = static_cast<uInt>(out.size());
|
|
||||||
{
|
{
|
||||||
bool progress = true;
|
bool progress = true;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec = c.write(Flush::full);
|
||||||
ds.write(zs, Flush::full, ec);
|
|
||||||
if( ec == error::need_buffers ||
|
if( ec == error::need_buffers ||
|
||||||
ec == error::end_of_stream) // per zlib FAQ
|
ec == error::end_of_stream) // per zlib FAQ
|
||||||
goto fin;
|
goto fin;
|
||||||
@@ -206,7 +336,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
fin:
|
fin:
|
||||||
out.resize(zs.total_out);
|
out.resize(c.total_out());
|
||||||
BEAST_EXPECT(decompress(out) == check);
|
BEAST_EXPECT(decompress(out) == check);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -217,6 +347,7 @@ public:
|
|||||||
|
|
||||||
void
|
void
|
||||||
doDeflate2_beast(
|
doDeflate2_beast(
|
||||||
|
ICompressor& c,
|
||||||
int level, int windowBits, int memLevel,
|
int level, int windowBits, int memLevel,
|
||||||
int strategy, std::string const& check)
|
int strategy, std::string const& check)
|
||||||
{
|
{
|
||||||
@@ -224,50 +355,44 @@ public:
|
|||||||
{
|
{
|
||||||
for(std::size_t j = 1;; ++j)
|
for(std::size_t j = 1;; ++j)
|
||||||
{
|
{
|
||||||
z_params zs;
|
c.init(
|
||||||
deflate_stream ds;
|
|
||||||
ds.reset(
|
|
||||||
level,
|
level,
|
||||||
windowBits,
|
windowBits,
|
||||||
memLevel,
|
memLevel,
|
||||||
toStrategy(strategy));
|
strategy);
|
||||||
std::string out;
|
std::string out;
|
||||||
out.resize(ds.upper_bound(
|
out.resize(c.bound(check.size()));
|
||||||
static_cast<uLong>(check.size())));
|
|
||||||
if(j >= out.size())
|
if(j >= out.size())
|
||||||
break;
|
break;
|
||||||
zs.next_in = (Bytef*)check.data();
|
c.next_in((void*)check.data());
|
||||||
zs.avail_in = static_cast<uInt>(i);
|
c.avail_in(i);
|
||||||
zs.next_out = (Bytef*)out.data();
|
c.next_out((void*)out.data());
|
||||||
zs.avail_out = static_cast<uInt>(j);
|
c.avail_out(j);
|
||||||
bool bi = false;
|
bool bi = false;
|
||||||
bool bo = false;
|
bool bo = false;
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
error_code ec;
|
error_code ec = c.write(
|
||||||
ds.write(zs,
|
bi ? Flush::full : Flush::none);
|
||||||
bi ? Flush::full : Flush::none, ec);
|
|
||||||
if( ec == error::need_buffers ||
|
if( ec == error::need_buffers ||
|
||||||
ec == error::end_of_stream) // per zlib FAQ
|
ec == error::end_of_stream) // per zlib FAQ
|
||||||
goto fin;
|
goto fin;
|
||||||
if(! BEAST_EXPECTS(! ec, ec.message()))
|
if(! BEAST_EXPECTS(! ec, ec.message()))
|
||||||
goto err;
|
goto err;
|
||||||
if(zs.avail_in == 0 && ! bi)
|
if(c.avail_in() == 0 && ! bi)
|
||||||
{
|
{
|
||||||
bi = true;
|
bi = true;
|
||||||
zs.avail_in =
|
c.avail_in(check.size() - i);
|
||||||
static_cast<uInt>(check.size() - i);
|
|
||||||
}
|
}
|
||||||
if(zs.avail_out == 0 && ! bo)
|
if(c.avail_out() == 0 && ! bo)
|
||||||
{
|
{
|
||||||
bo = true;
|
bo = true;
|
||||||
zs.avail_out =
|
c.avail_out(out.size() - j);
|
||||||
static_cast<uInt>(out.size() - j);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fin:
|
fin:
|
||||||
out.resize(zs.total_out);
|
out.resize(c.total_out());
|
||||||
BEAST_EXPECT(decompress(out) == check);
|
BEAST_EXPECT(decompress(out) == check);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -279,7 +404,7 @@ public:
|
|||||||
//--------------------------------------------------------------------------
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
doMatrix(std::string const& check, pmf_t pmf)
|
doMatrix(ICompressor& c, std::string const& check, pmf_t pmf)
|
||||||
{
|
{
|
||||||
for(int level = 0; level <= 9; ++level)
|
for(int level = 0; level <= 9; ++level)
|
||||||
{
|
{
|
||||||
@@ -293,127 +418,115 @@ public:
|
|||||||
for (int memLevel = 8; memLevel <= 9; ++memLevel)
|
for (int memLevel = 8; memLevel <= 9; ++memLevel)
|
||||||
{
|
{
|
||||||
(this->*pmf)(
|
(this->*pmf)(
|
||||||
level, windowBits, memLevel, strategy, check);
|
c, level, windowBits, memLevel, strategy, check);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check default settings
|
// Check default settings
|
||||||
(this->*pmf)(compression::default_size, 15, 8, 0, check);
|
(this->*pmf)(c, compression::default_size, 15, 8, 0, check);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testDeflate()
|
testDeflate(ICompressor& c)
|
||||||
{
|
{
|
||||||
doMatrix("Hello, world!", &self::doDeflate1_beast);
|
doMatrix(c, "Hello, world!", &self::doDeflate1_beast);
|
||||||
doMatrix("Hello, world!", &self::doDeflate2_beast);
|
doMatrix(c, "Hello, world!", &self::doDeflate2_beast);
|
||||||
doMatrix(corpus1(56), &self::doDeflate2_beast);
|
log << "no-silence keepalive" << std::endl;
|
||||||
doMatrix(corpus1(1024), &self::doDeflate1_beast);
|
doMatrix(c, corpus1(56), &self::doDeflate2_beast);
|
||||||
|
doMatrix(c, corpus1(1024), &self::doDeflate1_beast);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testInvalidSettings()
|
void testInvalidSettings(ICompressor& c)
|
||||||
{
|
{
|
||||||
except<std::invalid_argument>(
|
except<std::invalid_argument>(
|
||||||
[]()
|
[&]()
|
||||||
{
|
{
|
||||||
deflate_stream ds;
|
c.init(-42, 15, 8, static_cast<int>(Strategy::normal));
|
||||||
ds.reset(-42, 15, 8, Strategy::normal);
|
|
||||||
});
|
});
|
||||||
except<std::invalid_argument>(
|
except<std::invalid_argument>(
|
||||||
[]()
|
[&]()
|
||||||
{
|
{
|
||||||
deflate_stream ds;
|
c.init(compression::default_size, -1, 8, static_cast<int>(Strategy::normal));
|
||||||
ds.reset(compression::default_size, -1, 8, Strategy::normal);
|
|
||||||
});
|
});
|
||||||
except<std::invalid_argument>(
|
except<std::invalid_argument>(
|
||||||
[]()
|
[&]()
|
||||||
{
|
{
|
||||||
deflate_stream ds;
|
c.init(compression::default_size, 15, -1, static_cast<int>(Strategy::normal));
|
||||||
ds.reset(compression::default_size, 15, -1, Strategy::normal);
|
|
||||||
});
|
});
|
||||||
except<std::invalid_argument>(
|
except<std::invalid_argument>(
|
||||||
[]()
|
[&]()
|
||||||
{
|
{
|
||||||
deflate_stream ds;
|
c.init();
|
||||||
ds.reset();
|
c.avail_in(1);
|
||||||
z_params zp{};
|
c.next_in(nullptr);
|
||||||
zp.avail_in = 1;
|
c.write(Flush::full);
|
||||||
zp.next_in = nullptr;
|
|
||||||
error_code ec;
|
|
||||||
ds.write(zp, Flush::full, ec);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testWriteAfterFinish()
|
testWriteAfterFinish(ICompressor& c)
|
||||||
{
|
{
|
||||||
z_params zp;
|
c.init();
|
||||||
deflate_stream ds;
|
|
||||||
ds.reset();
|
|
||||||
std::string out;
|
std::string out;
|
||||||
out.resize(1024);
|
out.resize(1024);
|
||||||
string_view s = "Hello";
|
string_view s = "Hello";
|
||||||
zp.next_in = s.data();
|
c.next_in(s.data());
|
||||||
zp.avail_in = s.size();
|
c.avail_in(s.size());
|
||||||
zp.next_out = &out.front();
|
c.next_out(&out.front());
|
||||||
zp.avail_out = out.size();
|
c.avail_out(out.size());
|
||||||
error_code ec;
|
error_code ec = c.write(Flush::sync);
|
||||||
ds.write(zp, Flush::sync, ec);
|
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
zp.next_in = nullptr;
|
c.next_in(nullptr);
|
||||||
zp.avail_in = 0;
|
c.avail_in(0);
|
||||||
ds.write(zp, Flush::finish, ec);
|
ec = c.write(Flush::finish);
|
||||||
BEAST_EXPECT(ec == error::end_of_stream);
|
BEAST_EXPECT(ec == error::end_of_stream);
|
||||||
zp.next_in = s.data();
|
c.next_in(s.data());
|
||||||
zp.avail_in = s.size();
|
c.avail_in(s.size());
|
||||||
zp.next_out = &out.front();
|
c.next_out(&out.front());
|
||||||
zp.avail_out = out.size();
|
c.avail_out(out.size());
|
||||||
ds.write(zp, Flush::sync, ec);
|
ec = c.write(Flush::sync);
|
||||||
BEAST_EXPECT(ec == error::stream_error);
|
BEAST_EXPECT(ec == error::stream_error);
|
||||||
ds.write(zp, Flush::finish, ec);
|
ec = c.write(Flush::finish);
|
||||||
BEAST_EXPECT(ec == error::need_buffers);
|
BEAST_EXPECT(ec == error::need_buffers);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testFlushPartial()
|
testFlushPartial(ICompressor& c)
|
||||||
{
|
{
|
||||||
z_params zp;
|
c.init();
|
||||||
deflate_stream ds;
|
|
||||||
ds.reset();
|
|
||||||
std::string out;
|
std::string out;
|
||||||
out.resize(1024);
|
out.resize(1024);
|
||||||
string_view s = "Hello";
|
string_view s = "Hello";
|
||||||
zp.next_in = s.data();
|
c.next_in(s.data());
|
||||||
zp.avail_in = s.size();
|
c.avail_in(s.size());
|
||||||
zp.next_out = &out.front();
|
c.next_out(&out.front());
|
||||||
zp.avail_out = out.size();
|
c.avail_out(out.size());
|
||||||
error_code ec;
|
error_code ec;
|
||||||
ds.write(zp, Flush::none, ec);
|
ec = c.write(Flush::none);
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
ds.write(zp, Flush::partial, ec);
|
ec = c.write(Flush::partial);
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testFlushAtLiteralBufferFull()
|
testFlushAtLiteralBufferFull(ICompressor& c)
|
||||||
{
|
{
|
||||||
struct fixture
|
struct fixture
|
||||||
{
|
{
|
||||||
explicit fixture(std::size_t n, Strategy s)
|
ICompressor& c;
|
||||||
|
explicit fixture(ICompressor&c, std::size_t n, Strategy s) : c(c)
|
||||||
{
|
{
|
||||||
ds.reset(8, 15, 1, s);
|
c.init(8, 15, 1, static_cast<int>(s));
|
||||||
std::iota(in.begin(), in.end(),
|
std::iota(in.begin(), in.end(), std::uint8_t{0});
|
||||||
static_cast<std::uint8_t>(0));
|
|
||||||
out.resize(n);
|
out.resize(n);
|
||||||
zp.next_in = in.data();
|
c.next_in(in.data());
|
||||||
zp.avail_in = in.size();
|
c.avail_in(in.size());
|
||||||
zp.next_out = &out.front();
|
c.next_out(&out.front());
|
||||||
zp.avail_out = out.size();
|
c.avail_out(out.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
z_params zp;
|
|
||||||
deflate_stream ds;
|
|
||||||
std::array<std::uint8_t, 255> in;
|
std::array<std::uint8_t, 255> in;
|
||||||
std::string out;
|
std::string out;
|
||||||
};
|
};
|
||||||
@@ -421,25 +534,22 @@ public:
|
|||||||
for (auto s : {Strategy::huffman, Strategy::rle, Strategy::normal})
|
for (auto s : {Strategy::huffman, Strategy::rle, Strategy::normal})
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
fixture f{264, s};
|
fixture f{c, 264, s};
|
||||||
error_code ec;
|
error_code ec = c.write(Flush::finish);
|
||||||
f.ds.write(f.zp, Flush::finish, ec);
|
|
||||||
BEAST_EXPECT(ec == error::end_of_stream);
|
BEAST_EXPECT(ec == error::end_of_stream);
|
||||||
BEAST_EXPECT(f.zp.avail_out == 1);
|
BEAST_EXPECT(c.avail_out() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
fixture f{263, s};
|
fixture f{c,263, s};
|
||||||
error_code ec;
|
error_code ec = c.write(Flush::finish);
|
||||||
f.ds.write(f.zp, Flush::finish, ec);
|
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
BEAST_EXPECT(f.zp.avail_out == 0);
|
BEAST_EXPECT(c.avail_out() == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
fixture f{20, s};
|
fixture f{c, 20, s};
|
||||||
error_code ec;
|
error_code ec = c.write(Flush::sync);
|
||||||
f.ds.write(f.zp, Flush::sync, ec);
|
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -447,35 +557,30 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testRLEMatchLengthExceedLookahead()
|
testRLEMatchLengthExceedLookahead(ICompressor& c)
|
||||||
{
|
{
|
||||||
z_params zp;
|
|
||||||
deflate_stream ds;
|
|
||||||
std::vector<std::uint8_t> in;
|
std::vector<std::uint8_t> in;
|
||||||
in.resize(300);
|
in.resize(300);
|
||||||
|
|
||||||
|
c.init(8, 15, 1, static_cast<int>(Strategy::rle));
|
||||||
ds.reset(8, 15, 1, Strategy::rle);
|
|
||||||
std::fill_n(in.begin(), 4, 'a');
|
std::fill_n(in.begin(), 4, 'a');
|
||||||
std::string out;
|
std::string out;
|
||||||
out.resize(in.size() * 2);
|
out.resize(in.size() * 2);
|
||||||
zp.next_in = in.data();
|
c.next_in(in.data());
|
||||||
zp.avail_in = in.size();
|
c.avail_in(in.size());
|
||||||
zp.next_out = &out.front();
|
c.next_out(&out.front());
|
||||||
zp.avail_out = out.size();
|
c.avail_out(out.size());
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
ds.write(zp, Flush::sync, ec);
|
ec = c.write(Flush::sync);
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testFlushAfterDistMatch()
|
testFlushAfterDistMatch(ICompressor& c)
|
||||||
{
|
{
|
||||||
for (auto out_size : {144, 129})
|
for (auto out_size : {144, 129})
|
||||||
{
|
{
|
||||||
z_params zp;
|
|
||||||
deflate_stream ds;
|
|
||||||
std::array<std::uint8_t, 256> in{};
|
std::array<std::uint8_t, 256> in{};
|
||||||
// 125 will mostly fill the lit buffer, so emitting a distance code
|
// 125 will mostly fill the lit buffer, so emitting a distance code
|
||||||
// results in a flush.
|
// results in a flush.
|
||||||
@@ -485,16 +590,16 @@ public:
|
|||||||
std::iota(in.begin() + n, in.end(),
|
std::iota(in.begin() + n, in.end(),
|
||||||
static_cast<std::uint8_t>(0));
|
static_cast<std::uint8_t>(0));
|
||||||
|
|
||||||
ds.reset(8, 15, 1, Strategy::normal);
|
c.init(8, 15, 1, static_cast<int>(Strategy::normal));
|
||||||
std::string out;
|
std::string out;
|
||||||
out.resize(out_size);
|
out.resize(out_size);
|
||||||
zp.next_in = in.data();
|
c.next_in(in.data());
|
||||||
zp.avail_in = in.size();
|
c.avail_in(in.size());
|
||||||
zp.next_out = &out.front();
|
c.next_out(&out.front());
|
||||||
zp.avail_out = out.size();
|
c.avail_out(out.size());
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
ds.write(zp, Flush::sync, ec);
|
ec = c.write(Flush::sync);
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -506,13 +611,20 @@ public:
|
|||||||
"sizeof(deflate_stream) == " <<
|
"sizeof(deflate_stream) == " <<
|
||||||
sizeof(deflate_stream) << std::endl;
|
sizeof(deflate_stream) << std::endl;
|
||||||
|
|
||||||
testDeflate();
|
testDeflate(zlib_compressor);
|
||||||
testInvalidSettings();
|
testDeflate(beast_compressor);
|
||||||
testWriteAfterFinish();
|
testInvalidSettings(zlib_compressor);
|
||||||
testFlushPartial();
|
testInvalidSettings(beast_compressor);
|
||||||
testFlushAtLiteralBufferFull();
|
testWriteAfterFinish(zlib_compressor);
|
||||||
testRLEMatchLengthExceedLookahead();
|
testWriteAfterFinish(beast_compressor);
|
||||||
testFlushAfterDistMatch();
|
testFlushPartial(zlib_compressor);
|
||||||
|
testFlushPartial(beast_compressor);
|
||||||
|
testFlushAtLiteralBufferFull(zlib_compressor);
|
||||||
|
testFlushAtLiteralBufferFull(beast_compressor);
|
||||||
|
testRLEMatchLengthExceedLookahead(zlib_compressor);
|
||||||
|
testRLEMatchLengthExceedLookahead(beast_compressor);
|
||||||
|
testFlushAfterDistMatch(zlib_compressor);
|
||||||
|
testFlushAfterDistMatch(beast_compressor);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -41,12 +41,13 @@ public:
|
|||||||
{
|
{
|
||||||
check("boost.beast.zlib", error::need_buffers);
|
check("boost.beast.zlib", error::need_buffers);
|
||||||
check("boost.beast.zlib", error::end_of_stream);
|
check("boost.beast.zlib", error::end_of_stream);
|
||||||
|
check("boost.beast.zlib", error::need_dict);
|
||||||
check("boost.beast.zlib", error::stream_error);
|
check("boost.beast.zlib", error::stream_error);
|
||||||
|
|
||||||
check("boost.beast.zlib", error::invalid_block_type);
|
check("boost.beast.zlib", error::invalid_block_type);
|
||||||
check("boost.beast.zlib", error::invalid_stored_length);
|
check("boost.beast.zlib", error::invalid_stored_length);
|
||||||
check("boost.beast.zlib", error::too_many_symbols);
|
check("boost.beast.zlib", error::too_many_symbols);
|
||||||
check("boost.beast.zlib", error::invalid_code_lenths);
|
check("boost.beast.zlib", error::invalid_code_lengths);
|
||||||
check("boost.beast.zlib", error::invalid_bit_length_repeat);
|
check("boost.beast.zlib", error::invalid_bit_length_repeat);
|
||||||
check("boost.beast.zlib", error::missing_eob);
|
check("boost.beast.zlib", error::missing_eob);
|
||||||
check("boost.beast.zlib", error::invalid_literal_length);
|
check("boost.beast.zlib", error::invalid_literal_length);
|
||||||
|
@@ -23,6 +23,127 @@ namespace zlib {
|
|||||||
|
|
||||||
class inflate_stream_test : public beast::unit_test::suite
|
class inflate_stream_test : public beast::unit_test::suite
|
||||||
{
|
{
|
||||||
|
struct IDecompressor {
|
||||||
|
virtual void init() = 0;
|
||||||
|
virtual void init(int windowBits) = 0;
|
||||||
|
|
||||||
|
virtual std::size_t avail_in() const noexcept = 0;
|
||||||
|
virtual void avail_in(std::size_t) noexcept = 0;
|
||||||
|
virtual void const* next_in() const noexcept = 0;
|
||||||
|
virtual void next_in(const void*) noexcept = 0;
|
||||||
|
virtual std::size_t avail_out() const noexcept = 0;
|
||||||
|
virtual void avail_out(std::size_t) noexcept = 0;
|
||||||
|
virtual void* next_out() const noexcept = 0;
|
||||||
|
virtual void next_out(void*) noexcept = 0;
|
||||||
|
|
||||||
|
virtual error_code write(Flush) = 0;
|
||||||
|
virtual ~IDecompressor() = default;
|
||||||
|
};
|
||||||
|
class ZlibDecompressor : public IDecompressor {
|
||||||
|
z_stream zs;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ZlibDecompressor() = default;
|
||||||
|
void init(int windowBits) override
|
||||||
|
{
|
||||||
|
inflateEnd(&zs);
|
||||||
|
zs = {};
|
||||||
|
const auto res = inflateInit2(&zs, windowBits);
|
||||||
|
switch(res){
|
||||||
|
case Z_OK:
|
||||||
|
break;
|
||||||
|
case Z_MEM_ERROR:
|
||||||
|
BOOST_THROW_EXCEPTION(std::runtime_error{"zlib decompressor: no memory"});
|
||||||
|
case Z_STREAM_ERROR:
|
||||||
|
BOOST_THROW_EXCEPTION(std::domain_error{"zlib decompressor: bad arg"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void init() override {
|
||||||
|
inflateEnd(&zs);
|
||||||
|
zs = {};
|
||||||
|
const auto res = inflateInit2(&zs, -15);
|
||||||
|
switch(res){
|
||||||
|
case Z_OK:
|
||||||
|
break;
|
||||||
|
case Z_MEM_ERROR:
|
||||||
|
BOOST_THROW_EXCEPTION(std::runtime_error{"zlib decompressor: no memory"});
|
||||||
|
case Z_STREAM_ERROR:
|
||||||
|
BOOST_THROW_EXCEPTION(std::domain_error{"zlib decompressor: bad arg"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::size_t avail_in() const noexcept override { return zs.avail_in; }
|
||||||
|
virtual void avail_in(std::size_t n) noexcept override { zs.avail_in = n; }
|
||||||
|
virtual void const* next_in() const noexcept override { return zs.next_in; }
|
||||||
|
virtual void next_in(const void* ptr) noexcept override { zs.next_in = const_cast<Bytef*>(static_cast<const Bytef*>(ptr)); }
|
||||||
|
virtual std::size_t avail_out() const noexcept override { return zs.avail_out; }
|
||||||
|
virtual void avail_out(std::size_t n_out) noexcept override { zs.avail_out = n_out; }
|
||||||
|
virtual void* next_out() const noexcept override { return zs.next_out; }
|
||||||
|
virtual void next_out(void* ptr) noexcept override { zs.next_out = (Bytef*)ptr; }
|
||||||
|
|
||||||
|
error_code write(Flush flush) override {
|
||||||
|
constexpr static int zlib_flushes[] = {0, Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, Z_FULL_FLUSH, Z_FINISH, Z_TREES};
|
||||||
|
const auto zlib_flush = zlib_flushes[static_cast<int>(flush)];
|
||||||
|
const auto res = inflate(&zs, zlib_flush);
|
||||||
|
switch(res){
|
||||||
|
case Z_OK:
|
||||||
|
return {};
|
||||||
|
case Z_STREAM_END:
|
||||||
|
return error::end_of_stream;
|
||||||
|
case Z_NEED_DICT:
|
||||||
|
return error::need_dict;
|
||||||
|
case Z_DATA_ERROR:
|
||||||
|
case Z_STREAM_ERROR:
|
||||||
|
return error::stream_error;
|
||||||
|
case Z_MEM_ERROR:
|
||||||
|
BOOST_THROW_EXCEPTION(std::bad_alloc{});
|
||||||
|
case Z_BUF_ERROR:
|
||||||
|
return error::need_buffers;
|
||||||
|
default:
|
||||||
|
BOOST_THROW_EXCEPTION(std::runtime_error{"zlib decompressor: impossible value"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~ZlibDecompressor() override {
|
||||||
|
inflateEnd(&zs);
|
||||||
|
}
|
||||||
|
} zlib_decompressor{};
|
||||||
|
class BeastCompressor : public IDecompressor {
|
||||||
|
z_params zp;
|
||||||
|
inflate_stream is;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BeastCompressor() = default;
|
||||||
|
|
||||||
|
void init(int windowBits) override
|
||||||
|
{
|
||||||
|
zp = {};
|
||||||
|
is.clear();
|
||||||
|
is.reset(windowBits);
|
||||||
|
}
|
||||||
|
void init() override {
|
||||||
|
zp = {};
|
||||||
|
is.clear();
|
||||||
|
is.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::size_t avail_in() const noexcept override { return zp.avail_in; }
|
||||||
|
virtual void avail_in(std::size_t n) noexcept override { zp.avail_in = n; }
|
||||||
|
virtual void const* next_in() const noexcept override { return zp.next_in; }
|
||||||
|
virtual void next_in(const void* ptr) noexcept override { zp.next_in = ptr; }
|
||||||
|
virtual std::size_t avail_out() const noexcept override { return zp.avail_out; }
|
||||||
|
virtual void avail_out(std::size_t n_out) noexcept override { zp.avail_out = n_out; }
|
||||||
|
virtual void* next_out() const noexcept override { return zp.next_out; }
|
||||||
|
virtual void next_out(void* ptr) noexcept override { zp.next_out = (Bytef*)ptr; }
|
||||||
|
|
||||||
|
error_code write(Flush flush) override {
|
||||||
|
error_code ec{};
|
||||||
|
is.write(zp, flush, ec);
|
||||||
|
return ec;
|
||||||
|
}
|
||||||
|
|
||||||
|
~BeastCompressor() override = default;
|
||||||
|
} beast_decompressor{};
|
||||||
public:
|
public:
|
||||||
// Lots of repeats, limited char range
|
// Lots of repeats, limited char range
|
||||||
static
|
static
|
||||||
@@ -283,7 +404,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
testInflate()
|
testInflate(IDecompressor& d)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
Matrix m{*this};
|
Matrix m{*this};
|
||||||
@@ -381,8 +502,8 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
check({0x63, 0x18, 0x05, 0x40, 0x0c, 0x00}, {}, 8, 3);
|
check(d, {0x63, 0x18, 0x05, 0x40, 0x0c, 0x00}, {}, 8, 3);
|
||||||
check({0xed, 0xc0, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80,
|
check(d, {0xed, 0xc0, 0x81, 0x00, 0x00, 0x00, 0x00, 0x80,
|
||||||
0xa0, 0xfd, 0xa9, 0x17, 0xa9, 0x00, 0x00, 0x00,
|
0xa0, 0xfd, 0xa9, 0x17, 0xa9, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
@@ -390,7 +511,7 @@ public:
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, {});
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x06}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string check(
|
std::string check(IDecompressor& d,
|
||||||
std::initializer_list<std::uint8_t> const& in,
|
std::initializer_list<std::uint8_t> const& in,
|
||||||
error_code expected,
|
error_code expected,
|
||||||
std::size_t window_size = 15,
|
std::size_t window_size = 15,
|
||||||
@@ -419,103 +540,97 @@ public:
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
void testInflateErrors()
|
void testInflateErrors(IDecompressor& d)
|
||||||
{
|
{
|
||||||
check({0x00, 0x00, 0x00, 0x00, 0x00},
|
check(d, {0x00, 0x00, 0x00, 0x00, 0x00},
|
||||||
error::invalid_stored_length);
|
error::invalid_stored_length);
|
||||||
check({0x03, 0x00},
|
check(d, {0x03, 0x00},
|
||||||
error::end_of_stream);
|
error::end_of_stream);
|
||||||
check({0x06},
|
check(d, {0x06},
|
||||||
error::invalid_block_type);
|
error::invalid_block_type);
|
||||||
check({0xfc, 0x00, 0x00},
|
check(d, {0xfc, 0x00, 0x00},
|
||||||
error::too_many_symbols);
|
error::too_many_symbols);
|
||||||
check({0x04, 0x00, 0xfe, 0xff},
|
check(d, {0x04, 0x00, 0xfe, 0xff},
|
||||||
error::incomplete_length_set);
|
error::incomplete_length_set);
|
||||||
check({0x04, 0x00, 0x24, 0x49, 0x00},
|
check(d, {0x04, 0x00, 0x24, 0x49, 0x00},
|
||||||
error::invalid_bit_length_repeat);
|
error::invalid_bit_length_repeat);
|
||||||
check({0x04, 0x00, 0x24, 0xe9, 0xff, 0xff},
|
check(d, {0x04, 0x00, 0x24, 0xe9, 0xff, 0xff},
|
||||||
error::invalid_bit_length_repeat);
|
error::invalid_bit_length_repeat);
|
||||||
check({0x04, 0x00, 0x24, 0xe9, 0xff, 0x6d},
|
check(d, {0x04, 0x00, 0x24, 0xe9, 0xff, 0x6d},
|
||||||
error::missing_eob);
|
error::missing_eob);
|
||||||
check({0x04, 0x80, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24,
|
check(d, {0x04, 0x80, 0x49, 0x92, 0x24, 0x49, 0x92, 0x24,
|
||||||
0x71, 0xff, 0xff, 0x93, 0x11, 0x00},
|
0x71, 0xff, 0xff, 0x93, 0x11, 0x00},
|
||||||
error::over_subscribed_length);
|
error::over_subscribed_length);
|
||||||
check({0x04, 0x80, 0x49, 0x92, 0x24, 0x0f, 0xb4, 0xff,
|
check(d, {0x04, 0x80, 0x49, 0x92, 0x24, 0x0f, 0xb4, 0xff,
|
||||||
0xff, 0xc3, 0x84},
|
0xff, 0xc3, 0x84},
|
||||||
error::incomplete_length_set);
|
error::incomplete_length_set);
|
||||||
check({0x04, 0xc0, 0x81, 0x08, 0x00, 0x00, 0x00, 0x00,
|
check(d, {0x04, 0xc0, 0x81, 0x08, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x20, 0x7f, 0xeb, 0x0b, 0x00, 0x00},
|
0x20, 0x7f, 0xeb, 0x0b, 0x00, 0x00},
|
||||||
error::invalid_literal_length);
|
error::invalid_literal_length);
|
||||||
check({0x02, 0x7e, 0xff, 0xff},
|
check(d, {0x02, 0x7e, 0xff, 0xff},
|
||||||
error::invalid_distance_code);
|
error::invalid_distance_code);
|
||||||
check({0x0c, 0xc0, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00,
|
check(d, {0x0c, 0xc0, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x90, 0xff, 0x6b, 0x04, 0x00},
|
0x90, 0xff, 0x6b, 0x04, 0x00},
|
||||||
error::invalid_distance);
|
error::invalid_distance);
|
||||||
check({0x05,0xe0, 0x81, 0x91, 0x24, 0xcb, 0xb2, 0x2c,
|
check(d, {0x05,0xe0, 0x81, 0x91, 0x24, 0xcb, 0xb2, 0x2c,
|
||||||
0x49, 0xe2, 0x0f, 0x2e, 0x8b, 0x9a, 0x47, 0x56,
|
0x49, 0xe2, 0x0f, 0x2e, 0x8b, 0x9a, 0x47, 0x56,
|
||||||
0x9f, 0xfb, 0xfe, 0xec, 0xd2, 0xff, 0x1f},
|
0x9f, 0xfb, 0xfe, 0xec, 0xd2, 0xff, 0x1f},
|
||||||
error::end_of_stream);
|
error::end_of_stream);
|
||||||
check({0xed, 0xc0, 0x01, 0x01, 0x00, 0x00, 0x00, 0x40,
|
check(d, {0xed, 0xc0, 0x01, 0x01, 0x00, 0x00, 0x00, 0x40,
|
||||||
0x20, 0xff, 0x57, 0x1b, 0x42, 0x2c, 0x4f},
|
0x20, 0xff, 0x57, 0x1b, 0x42, 0x2c, 0x4f},
|
||||||
error::end_of_stream);
|
error::end_of_stream);
|
||||||
check({0x02, 0x08, 0x20, 0x80, 0x00, 0x03, 0x00},
|
check(d, {0x02, 0x08, 0x20, 0x80, 0x00, 0x03, 0x00},
|
||||||
error::end_of_stream);
|
error::end_of_stream);
|
||||||
// TODO: Excess data (from golang test inflate suite), should this be an error?
|
check(d, {0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x78, 0x9c, 0xff},
|
||||||
check({0x78, 0x9c, 0x03, 0x00, 0x00, 0x00, 0x00, 0x01, 0x78, 0x9c, 0xff},
|
|
||||||
error::invalid_stored_length);
|
error::invalid_stored_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
void testInvalidSettings()
|
void testInvalidSettings(IDecompressor& d)
|
||||||
{
|
{
|
||||||
except<std::domain_error>(
|
except<std::domain_error>(
|
||||||
[]()
|
[&]()
|
||||||
{
|
{
|
||||||
inflate_stream is;
|
d.init(7);
|
||||||
is.reset(7);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void testFixedHuffmanFlushTrees()
|
void testFixedHuffmanFlushTrees(IDecompressor& d)
|
||||||
{
|
{
|
||||||
std::string out(5, 0);
|
std::string out(5, 0);
|
||||||
z_params zs;
|
d.init();
|
||||||
inflate_stream is;
|
|
||||||
is.reset();
|
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
std::initializer_list<std::uint8_t> in = {
|
std::initializer_list<std::uint8_t> in = {
|
||||||
0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00,
|
0xf2, 0x48, 0xcd, 0xc9, 0xc9, 0x07, 0x00, 0x00,
|
||||||
0x00, 0xff, 0xff};
|
0x00, 0xff, 0xff};
|
||||||
zs.next_in = &*in.begin();
|
d.next_in(&*in.begin());
|
||||||
zs.next_out = &out[0];
|
d.next_out(&out[0]);
|
||||||
zs.avail_in = in.size();
|
d.avail_in(in.size());
|
||||||
zs.avail_out = out.size();
|
d.avail_out(out.size());
|
||||||
is.write(zs, Flush::trees, ec);
|
ec = d.write(Flush::trees);
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
is.write(zs, Flush::sync, ec);
|
ec = d.write(Flush::sync);
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
BEAST_EXPECT(zs.avail_out == 0);
|
BEAST_EXPECT(d.avail_out() == 0);
|
||||||
BEAST_EXPECT(out == "Hello");
|
BEAST_EXPECT(out == "Hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
void testUncompressedFlushTrees()
|
void testUncompressedFlushTrees(IDecompressor& d)
|
||||||
{
|
{
|
||||||
std::string out(5, 0);
|
std::string out(5, 0);
|
||||||
z_params zs;
|
d.init();
|
||||||
inflate_stream is;
|
|
||||||
is.reset();
|
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
std::initializer_list<std::uint8_t> in = {
|
std::initializer_list<std::uint8_t> in = {
|
||||||
0x00, 0x05, 0x00, 0xfa, 0xff, 0x48, 0x65, 0x6c,
|
0x00, 0x05, 0x00, 0xfa, 0xff, 0x48, 0x65, 0x6c,
|
||||||
0x6c, 0x6f, 0x00, 0x00};
|
0x6c, 0x6f, 0x00, 0x00};
|
||||||
zs.next_in = &*in.begin();
|
d.next_in(&*in.begin());
|
||||||
zs.next_out = &out[0];
|
d.next_out(&out[0]);
|
||||||
zs.avail_in = in.size();
|
d.avail_in(in.size());
|
||||||
zs.avail_out = out.size();
|
d.avail_out(out.size());
|
||||||
is.write(zs, Flush::trees, ec);
|
ec = d.write(Flush::trees);
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
is.write(zs, Flush::sync, ec);
|
ec = d.write(Flush::sync);
|
||||||
BEAST_EXPECT(!ec);
|
BEAST_EXPECT(!ec);
|
||||||
BEAST_EXPECT(zs.avail_out == 0);
|
BEAST_EXPECT(d.avail_out() == 0);
|
||||||
BEAST_EXPECT(out == "Hello");
|
BEAST_EXPECT(out == "Hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,11 +640,16 @@ public:
|
|||||||
log <<
|
log <<
|
||||||
"sizeof(inflate_stream) == " <<
|
"sizeof(inflate_stream) == " <<
|
||||||
sizeof(inflate_stream) << std::endl;
|
sizeof(inflate_stream) << std::endl;
|
||||||
testInflate();
|
testInflate(zlib_decompressor);
|
||||||
testInflateErrors();
|
testInflate(beast_decompressor);
|
||||||
testInvalidSettings();
|
testInflateErrors(zlib_decompressor);
|
||||||
testFixedHuffmanFlushTrees();
|
testInflateErrors(beast_decompressor);
|
||||||
testUncompressedFlushTrees();
|
testInvalidSettings(zlib_decompressor);
|
||||||
|
testInvalidSettings(beast_decompressor);
|
||||||
|
testFixedHuffmanFlushTrees(zlib_decompressor);
|
||||||
|
testFixedHuffmanFlushTrees(beast_decompressor);
|
||||||
|
testUncompressedFlushTrees(zlib_decompressor);
|
||||||
|
testUncompressedFlushTrees(beast_decompressor);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user