diff --git a/CMakeLists.txt b/CMakeLists.txt
index 876409b6..b8450a98 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -60,6 +60,12 @@ find_package(Qt5LinguistTools REQUIRED)
find_package(Qt5Concurrent REQUIRED)
find_package(Qt5Multimedia REQUIRED)
+find_package(ZLIB)
+
+if (ZLIB_FOUND)
+ include_directories(${ZLIB_INCLUDE_DIRS})
+endif()
+
if (APPLE)
find_package(Qt5MacExtras REQUIRED)
endif(APPLE)
@@ -321,7 +327,7 @@ add_subdirectory(libs/matrix-structs)
include_directories(${matrix_structs_SOURCE_DIR}/include)
include_directories(${matrix_structs_SOURCE_DIR}/deps)
-set(COMMON_LIBS matrix_structs Qt5::Widgets Qt5::Network Qt5::Concurrent)
+set(COMMON_LIBS matrix_structs Qt5::Widgets Qt5::Network Qt5::Concurrent ${ZLIB_LIBRARIES})
if(APPVEYOR_BUILD)
set(NHEKO_LIBS ${COMMON_LIBS} lmdb)
diff --git a/include/MatrixClient.h b/include/MatrixClient.h
index 826b4e18..6847ab22 100644
--- a/include/MatrixClient.h
+++ b/include/MatrixClient.h
@@ -142,6 +142,7 @@ signals:
private:
QNetworkReply *makeUploadRequest(QSharedPointer<QIODevice> iodev);
+ QByteArray uncompress(const QByteArray &data);
// Client API prefix.
QString clientApiUrl_;
diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc
index 70a9bbf5..44257172 100644
--- a/src/MatrixClient.cc
+++ b/src/MatrixClient.cc
@@ -28,6 +28,8 @@
#include <QSettings>
#include <QUrlQuery>
+#include <zlib.h>
+
#include "Login.h"
#include "MatrixClient.h"
#include "Register.h"
@@ -252,6 +254,7 @@ MatrixClient::sync() noexcept
endpoint.setQuery(query);
QNetworkRequest request(QString(endpoint.toEncoded()));
+ request.setRawHeader(QByteArray("Accept-Encoding"), QByteArray("gzip, deflate"));
auto reply = get(request);
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
@@ -264,8 +267,13 @@ MatrixClient::sync() noexcept
return;
}
+ auto data = reply->readAll();
+
+ if (reply->hasRawHeader(QByteArray("Content-Encoding")))
+ data = uncompress(data);
+
try {
- mtx::responses::Sync response = nlohmann::json::parse(reply->readAll());
+ mtx::responses::Sync response = nlohmann::json::parse(data);
emit syncCompleted(response);
} catch (std::exception &e) {
qWarning() << "Sync malformed response: " << e.what();
@@ -374,6 +382,7 @@ MatrixClient::initialSync() noexcept
endpoint.setQuery(query);
QNetworkRequest request(QString(endpoint.toEncoded()));
+ request.setRawHeader(QByteArray("Accept-Encoding"), QByteArray("gzip, deflate"));
auto reply = get(request);
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
@@ -386,8 +395,13 @@ MatrixClient::initialSync() noexcept
return;
}
+ auto data = reply->readAll();
+
+ if (reply->hasRawHeader(QByteArray("Content-Encoding")))
+ data = uncompress(data);
+
try {
- mtx::responses::Sync response = nlohmann::json::parse(reply->readAll());
+ mtx::responses::Sync response = nlohmann::json::parse(data);
emit initialSyncCompleted(response);
} catch (std::exception &e) {
qWarning() << "Sync malformed response" << e.what();
@@ -1268,3 +1282,59 @@ MatrixClient::makeUploadRequest(QSharedPointer<QIODevice> iodev)
return reply;
}
+
+QByteArray
+MatrixClient::uncompress(const QByteArray &data)
+{
+ /*
+ * https://stackoverflow.com/questions/2690328/qt-quncompress-gzip-data/7351507#7351507
+ */
+
+ if (data.size() <= 4) {
+ qWarning("uncompress: Input data is truncated");
+ return QByteArray();
+ }
+
+ QByteArray result;
+
+ int ret;
+ 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 = data.size();
+ strm.next_in = (Bytef *)(data.data());
+
+ ret = inflateInit2(&strm, 15 + 32); // gzip decoding
+ if (ret != Z_OK)
+ return QByteArray();
+
+ // run inflate()
+ do {
+ strm.avail_out = CHUNK_SIZE;
+ strm.next_out = (Bytef *)(out);
+
+ ret = inflate(&strm, Z_NO_FLUSH);
+ Q_ASSERT(ret != Z_STREAM_ERROR); // state not clobbered
+
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ // fall through
+ 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 == 0);
+
+ // clean up and return
+ inflateEnd(&strm);
+ return result;
+}
|