diff --git a/src/core/core.pri b/src/core/core.pri index f3a5311fd..f91d7f059 100644 --- a/src/core/core.pri +++ b/src/core/core.pri @@ -37,6 +37,7 @@ HEADERS += \ $$PWD/bittorrent/private/filterparserthread.h \ $$PWD/bittorrent/private/statistics.h \ $$PWD/utils/fs.h \ + $$PWD/utils/gzip.h \ $$PWD/utils/misc.h \ $$PWD/utils/string.h \ $$PWD/unicodestrings.h \ @@ -76,6 +77,7 @@ SOURCES += \ $$PWD/bittorrent/private/filterparserthread.cpp \ $$PWD/bittorrent/private/statistics.cpp \ $$PWD/utils/fs.cpp \ + $$PWD/utils/gzip.cpp \ $$PWD/utils/misc.cpp \ $$PWD/utils/string.cpp \ $$PWD/torrentfilter.cpp \ diff --git a/src/core/http/responsegenerator.cpp b/src/core/http/responsegenerator.cpp index f6aad3afa..4ec7f0178 100644 --- a/src/core/http/responsegenerator.cpp +++ b/src/core/http/responsegenerator.cpp @@ -29,11 +29,9 @@ * Contact : chris@qbittorrent.org */ -#include +#include "core/utils/gzip.h" #include "responsegenerator.h" -bool gCompress(QByteArray data, QByteArray& dest_buffer); - using namespace Http; QByteArray ResponseGenerator::generate(Response response) @@ -44,7 +42,7 @@ QByteArray ResponseGenerator::generate(Response response) // So we only benefit from gzip if the message is bigger than 23+26 = 49 // If the message is smaller than 49 bytes we actually send MORE data if we gzip QByteArray dest_buf; - if ((response.content.size() > 49) && (gCompress(response.content, dest_buf))) + if ((response.content.size() > 49) && (Utils::Gzip::compress(response.content, dest_buf))) response.content = dest_buf; else response.headers.remove(HEADER_CONTENT_ENCODING); @@ -67,58 +65,3 @@ QByteArray ResponseGenerator::generate(Response response) return ret.toUtf8() + response.content; } - -bool gCompress(QByteArray data, QByteArray& dest_buffer) -{ - static const int BUFSIZE = 128 * 1024; - char tmp_buf[BUFSIZE]; - int ret; - - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.next_in = reinterpret_cast(data.data()); - strm.avail_in = data.length(); - strm.next_out = reinterpret_cast(tmp_buf); - 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); - - if (ret != Z_OK) - return false; - - while (strm.avail_in != 0) { - ret = deflate(&strm, Z_NO_FLUSH); - if (ret != Z_OK) - return false; - - if (strm.avail_out == 0) { - dest_buffer.append(tmp_buf, BUFSIZE); - strm.next_out = reinterpret_cast(tmp_buf); - strm.avail_out = BUFSIZE; - } - } - - int deflate_res = Z_OK; - while (deflate_res == Z_OK) { - if (strm.avail_out == 0) { - dest_buffer.append(tmp_buf, BUFSIZE); - strm.next_out = reinterpret_cast(tmp_buf); - strm.avail_out = BUFSIZE; - } - - deflate_res = deflate(&strm, Z_FINISH); - } - - if (deflate_res != Z_STREAM_END) - return false; - - dest_buffer.append(tmp_buf, BUFSIZE - strm.avail_out); - deflateEnd(&strm); - - return true; -} diff --git a/src/core/net/downloadhandler.cpp b/src/core/net/downloadhandler.cpp index f642c8b55..4a91af4c8 100644 --- a/src/core/net/downloadhandler.cpp +++ b/src/core/net/downloadhandler.cpp @@ -36,15 +36,13 @@ #include #include -#include - #include "core/utils/fs.h" +#include "core/utils/gzip.h" #include "core/utils/misc.h" #include "downloadmanager.h" #include "downloadhandler.h" static QString errorCodeToString(QNetworkReply::NetworkError status); -static QByteArray gUncompress(Bytef *inData, uInt len); using namespace Net; @@ -143,7 +141,7 @@ bool DownloadHandler::saveToFile(QString &filePath) QByteArray replyData = m_reply->readAll(); if (m_reply->rawHeader("Content-Encoding") == "gzip") { // uncompress gzip reply - replyData = gUncompress(reinterpret_cast(replyData.data()), static_cast(replyData.length())); + Utils::Gzip::uncompress(replyData, replyData); } tmpfile->write(replyData); tmpfile->close(); @@ -236,55 +234,3 @@ QString errorCodeToString(QNetworkReply::NetworkError status) return QObject::tr("Unknown error"); } } - -QByteArray gUncompress(Bytef *inData, uInt len) -{ - if (len <= 4) { - qWarning("gUncompress: Input data is truncated"); - return QByteArray(); - } - - QByteArray result; - - z_stream strm; - static const int CHUNK_SIZE = 1024; - char out[CHUNK_SIZE]; - - /* allocate inflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = len; - strm.next_in = inData; - - const int windowBits = 15; - const int ENABLE_ZLIB_GZIP = 32; - - int ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP); // gzip decoding - if (ret != Z_OK) - return QByteArray(); - - // run inflate() - do { - strm.avail_out = CHUNK_SIZE; - strm.next_out = reinterpret_cast(out); - - ret = inflate(&strm, Z_NO_FLUSH); - Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered - - switch (ret) { - case Z_NEED_DICT: - case Z_DATA_ERROR: - case Z_MEM_ERROR: - (void) inflateEnd(&strm); - return QByteArray(); - } - - result.append(out, CHUNK_SIZE - strm.avail_out); - } - while (!strm.avail_out); - - // clean up and return - inflateEnd(&strm); - return result; -} diff --git a/src/core/utils/gzip.cpp b/src/core/utils/gzip.cpp new file mode 100644 index 000000000..89dc16500 --- /dev/null +++ b/src/core/utils/gzip.cpp @@ -0,0 +1,142 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015 Vladimir Golovnev + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#include +#include + +#include "gzip.h" + +bool Utils::Gzip::compress(QByteArray src, QByteArray &dest) +{ + static const int BUFSIZE = 128 * 1024; + char tmpBuf[BUFSIZE]; + int ret; + + dest.clear(); + + 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.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); + + if (ret != Z_OK) + return false; + + while (strm.avail_in != 0) { + ret = deflate(&strm, Z_NO_FLUSH); + if (ret != Z_OK) + return false; + + if (strm.avail_out == 0) { + dest.append(tmpBuf, BUFSIZE); + 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; + } + + deflateRes = deflate(&strm, Z_FINISH); + } + + if (deflateRes != Z_STREAM_END) + return false; + + dest.append(tmpBuf, BUFSIZE - strm.avail_out); + deflateEnd(&strm); + + return true; +} + +bool Utils::Gzip::uncompress(QByteArray src, QByteArray &dest) +{ + dest.clear(); + + if (src.size() <= 4) { + qWarning("uncompress: Input data is truncated"); + return false; + } + + z_stream strm; + static const int CHUNK_SIZE = 1024; + char out[CHUNK_SIZE]; + + /* allocate inflate state */ + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = static_cast(src.size()); + strm.next_in = reinterpret_cast(src.data()); + + const int windowBits = 15; + const int ENABLE_ZLIB_GZIP = 32; + + int ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP); // gzip decoding + if (ret != Z_OK) + return false; + + // run inflate() + do { + strm.avail_out = CHUNK_SIZE; + strm.next_out = reinterpret_cast(out); + + ret = inflate(&strm, Z_NO_FLUSH); + Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered + + switch (ret) { + case Z_NEED_DICT: + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&strm); + return false; + } + + dest.append(out, CHUNK_SIZE - strm.avail_out); + } + while (!strm.avail_out); + + // clean up and return + inflateEnd(&strm); + return true; +} diff --git a/src/core/utils/gzip.h b/src/core/utils/gzip.h new file mode 100644 index 000000000..29dee59c6 --- /dev/null +++ b/src/core/utils/gzip.h @@ -0,0 +1,44 @@ +/* + * Bittorrent Client using Qt and libtorrent. + * Copyright (C) 2015 Vladimir Golovnev + * Copyright (C) 2006 Christophe Dumez + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give permission to + * link this program with the OpenSSL project's "OpenSSL" library (or with + * modified versions of it that use the same license as the "OpenSSL" library), + * and distribute the linked executables. You must obey the GNU General Public + * License in all respects for all of the code used other than "OpenSSL". If you + * modify file(s), you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete this + * exception statement from your version. + */ + +#ifndef UTILS_GZIP_H +#define UTILS_GZIP_H + +class QByteArray; + +namespace Utils +{ + namespace Gzip + { + bool compress(QByteArray src, QByteArray &dest); + bool uncompress(QByteArray src, QByteArray &dest); + } +} + +#endif // UTILS_GZIP_H