diff --git a/src/base/http/responsegenerator.cpp b/src/base/http/responsegenerator.cpp index 324bfd552..4ac6cba61 100644 --- a/src/base/http/responsegenerator.cpp +++ b/src/base/http/responsegenerator.cpp @@ -93,14 +93,15 @@ void Http::compressContent(Response &response) return; // try compressing - QByteArray buf; - if (!Utils::Gzip::compress(response.content, buf)) + bool ok = false; + const QByteArray compressedData = Utils::Gzip::compress(response.content, 6, &ok); + if (!ok) return; // "Content-Encoding: gzip\r\n" is 24 bytes long - if ((buf.size() + 24) >= contentSize) + if ((compressedData.size() + 24) >= contentSize) return; - response.content = buf; + response.content = compressedData; response.headers[HEADER_CONTENT_ENCODING] = QLatin1String("gzip"); } diff --git a/src/base/utils/gzip.cpp b/src/base/utils/gzip.cpp index 89dc16500..ce26eda2e 100644 --- a/src/base/utils/gzip.cpp +++ b/src/base/utils/gzip.cpp @@ -27,66 +27,71 @@ * exception statement from your version. */ +#include "gzip.h" + #include -#include -#include "gzip.h" +#ifndef ZLIB_CONST +#define ZLIB_CONST // make z_stream.next_in const +#endif +#include -bool Utils::Gzip::compress(QByteArray src, QByteArray &dest) +QByteArray Utils::Gzip::compress(const QByteArray &data, const int level, bool *ok) { - static const int BUFSIZE = 128 * 1024; - char tmpBuf[BUFSIZE]; - int ret; + if (ok) *ok = false; - dest.clear(); + if (data.isEmpty()) + return {}; + + const int BUFSIZE = 128 * 1024; + char tmpBuf[BUFSIZE] = {0}; z_stream strm; strm.zalloc = Z_NULL; strm.zfree = Z_NULL; strm.opaque = Z_NULL; - strm.next_in = reinterpret_cast(src.data()); - strm.avail_in = src.length(); - strm.next_out = reinterpret_cast(tmpBuf); + strm.next_in = reinterpret_cast(data.constData()); + strm.avail_in = uInt(data.size()); + strm.next_out = reinterpret_cast(tmpBuf); strm.avail_out = BUFSIZE; // windowBits = 15 + 16 to enable gzip // From the zlib manual: windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits // to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. - ret = deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); + int result = deflateInit2(&strm, level, Z_DEFLATED, (15 + 16), 9, Z_DEFAULT_STRATEGY); + if (result != Z_OK) + return {}; - if (ret != Z_OK) - return false; + QByteArray output; + output.reserve(deflateBound(&strm, data.size())); - while (strm.avail_in != 0) { - ret = deflate(&strm, Z_NO_FLUSH); - if (ret != Z_OK) - return false; + // feed to deflate + while (strm.avail_in > 0) { + result = deflate(&strm, Z_NO_FLUSH); - if (strm.avail_out == 0) { - dest.append(tmpBuf, BUFSIZE); - strm.next_out = reinterpret_cast(tmpBuf); - strm.avail_out = BUFSIZE; + if (result != Z_OK) { + deflateEnd(&strm); + return {}; } + + output.append(tmpBuf, (BUFSIZE - strm.avail_out)); + strm.next_out = reinterpret_cast(tmpBuf); + strm.avail_out = BUFSIZE; } - int deflateRes = Z_OK; - while (deflateRes == Z_OK) { - if (strm.avail_out == 0) { - dest.append(tmpBuf, BUFSIZE); - strm.next_out = reinterpret_cast(tmpBuf); - strm.avail_out = BUFSIZE; - } + // flush the rest from deflate + while (result != Z_STREAM_END) { + result = deflate(&strm, Z_FINISH); - deflateRes = deflate(&strm, Z_FINISH); + output.append(tmpBuf, (BUFSIZE - strm.avail_out)); + strm.next_out = reinterpret_cast(tmpBuf); + strm.avail_out = BUFSIZE; } - if (deflateRes != Z_STREAM_END) - return false; - - dest.append(tmpBuf, BUFSIZE - strm.avail_out); deflateEnd(&strm); - return true; + if (ok) *ok = true; + return output; } bool Utils::Gzip::uncompress(QByteArray src, QByteArray &dest) diff --git a/src/base/utils/gzip.h b/src/base/utils/gzip.h index 29dee59c6..79b16778c 100644 --- a/src/base/utils/gzip.h +++ b/src/base/utils/gzip.h @@ -36,7 +36,7 @@ namespace Utils { namespace Gzip { - bool compress(QByteArray src, QByteArray &dest); + QByteArray compress(const QByteArray &data, int level = 6, bool *ok = nullptr); bool uncompress(QByteArray src, QByteArray &dest); } }