cpp_client_telemetry/lib/compression/HttpDeflateCompression.cpp

91 строка
3.2 KiB
C++

// Copyright (c) Microsoft. All rights reserved.
#include "mat/config.h"
#include "HttpDeflateCompression.hpp"
#include "utils/Utils.hpp"
#ifdef HAVE_MAT_ZLIB
#define ZLIB_CONST
#include <zlib.h>
#endif
namespace ARIASDK_NS_BEGIN {
HttpDeflateCompression::HttpDeflateCompression(IRuntimeConfig& runtimeConfig)
: m_config(runtimeConfig)
{
}
HttpDeflateCompression::~HttpDeflateCompression()
{
}
bool HttpDeflateCompression::handleCompress(EventsUploadContextPtr const& ctx)
{
UNREFERENCED_PARAMETER(ctx);
#ifdef HAVE_MAT_ZLIB
if (!m_config.IsHttpRequestCompressionEnabled()) {
return true;
}
// Using a slightly adapted in-place compression technique as suggested
// by Mark Adler himself: http://stackoverflow.com/a/12412863/3543211
z_stream stream;
memset(&stream, 0, sizeof(stream));
// All values are defaults as would be used by a plain deflate(), except
// for the negative -MAX_WBITS argument which makes zlib use "raw deflate"
// without zlib header, as required by IIS.
int result = deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS, 8 /*DEF_MEM_LEVEL*/, Z_DEFAULT_STRATEGY);
if (result != Z_OK) {
LOG_WARN("HTTP request compressing failed, error=%u/%u (%s)", 1, result, stream.msg);
compressionFailed(ctx);
return false;
}
stream.avail_in = static_cast<uInt>(ctx->body.size());
ctx->body.resize(deflateBound(&stream, stream.avail_in));
stream.next_in = ctx->body.data();
std::vector<uint8_t> temp(32);
stream.next_out = temp.data();
stream.avail_out = static_cast<uInt>(temp.size());
result = deflate(&stream, Z_FINISH);
if (result == Z_OK || result == Z_STREAM_END) {
std::copy(temp.cbegin(), temp.cbegin() + stream.total_out, ctx->body.begin());
stream.next_out = ctx->body.data() + stream.total_out;
stream.avail_out = static_cast<uInt>(ctx->body.size()) - static_cast<uInt>(stream.total_out);
}
if (result == Z_OK) {
result = deflate(&stream, Z_FINISH);
if (result == Z_OK) {
// The output shall never catch up with the input. Mark says in the
// Stack Overflow reference above that this should happen only for
// incompressible data longer than 20 MB, i.e. virtually never for
// telemetry events in Bond. But better make it 100% safe here.
temp.assign(ctx->body.cbegin() + stream.total_in, ctx->body.cbegin() + stream.total_in + stream.avail_in);
stream.next_in = temp.data();
stream.avail_in = static_cast<uInt>(temp.size());
result = deflate(&stream, Z_FINISH);
}
}
deflateEnd(&stream);
if (result != Z_STREAM_END) {
LOG_WARN("HTTP request compressing failed, error=%u/%u (%s)", 2, result, stream.msg);
compressionFailed(ctx);
return false;
}
ctx->body.resize(stream.total_out);
ctx->compressed = true;
#endif
return true;
}
} ARIASDK_NS_END