Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions xbmc/filesystem/ZipFile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -525,3 +525,40 @@ bool CZipFile::DecompressGzip(const std::string& in, std::string& out)
inflateEnd(&strm);
return true;
}

bool CZipFile::CompressGZip(const std::string& in, std::string& out, int compressionLevel)
{
const int windowBits = MAX_WBITS + 16;

z_stream strm;
memset(&strm, 0, sizeof(strm));

int err = deflateInit2(&strm, compressionLevel, Z_DEFLATED, windowBits, 8, Z_DEFAULT_STRATEGY);
if (err != Z_OK)
{
CLog::Log(LOGERROR, "FileZip: zlib compress error %d", err);
return false;
}

strm.avail_in = static_cast<unsigned int>(in.size());
strm.next_in = reinterpret_cast<unsigned char*>(const_cast<char*>(in.c_str()));

char outbuffer[32768];
do
{
strm.next_out = reinterpret_cast<Bytef*>(outbuffer);
strm.avail_out = sizeof(outbuffer);
err = deflate(&strm, Z_FINISH);
if (out.size() < strm.total_out)
out.append(outbuffer, strm.total_out - out.size());
} while (err == Z_OK);

deflateEnd(&strm);

if (err != Z_STREAM_END)
{
CLog::Log(LOGERROR, "FileZip: failed to compress. zlib error %d", err);
return false;
}
return true;
}
2 changes: 2 additions & 0 deletions xbmc/filesystem/ZipFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ namespace XFILE

/*! Decompress gzip encoded buffer in-memory */
static bool DecompressGzip(const std::string& in, std::string& out);
/*! Compress to gzip encoded buffer in-memory */
static bool CompressGZip(const std::string& in, std::string& out, int compressionLevel);

private:
bool InitDecompress();
Expand Down
4 changes: 4 additions & 0 deletions xbmc/network/WebServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,10 @@ int CWebServer::FinalizeRequest(const std::shared_ptr<IHTTPRequestHandler>& hand
if (!responseDetails.contentType.empty())
handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_TYPE, responseDetails.contentType);

// if the request handler has set a content encoding and it hasn't been set as a header, add it
if (!responseDetails.contentEncoding.empty())
handler->AddResponseHeader(MHD_HTTP_HEADER_CONTENT_ENCODING, responseDetails.contentEncoding);

// if the request handler has set a last modified date and it hasn't been set as a header, add it
CDateTime lastModified;
if (handler->GetLastModifiedDate(lastModified) && lastModified.IsValid())
Expand Down
27 changes: 27 additions & 0 deletions xbmc/network/httprequesthandler/HTTPJsonRpcHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@

#include "URL.h"
#include "filesystem/File.h"
#include "filesystem/ZipFile.h"
#include "interfaces/json-rpc/JSONRPC.h"
#include "interfaces/json-rpc/JSONServiceDescription.h"
#include "interfaces/json-rpc/JSONUtils.h"
#include "network/WebServer.h"
#include "network/httprequesthandler/HTTPRequestHandlerUtils.h"
#include "settings/AdvancedSettings.h"
#include "settings/SettingsComponent.h"
#include "utils/JSONVariantWriter.h"
#include "utils/Variant.h"
#include "utils/log.h"
Expand Down Expand Up @@ -99,6 +102,30 @@ int CHTTPJsonRpcHandler::HandleRequest()
return MHD_YES;
}

std::string acceptEncoding = HTTPRequestHandlerUtils::GetRequestHeaderValue(
m_request.connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT_ENCODING);
if (isRequest && acceptEncoding.find("gzip") != std::string::npos)
{
int compressionLevel =
CServiceBroker::GetSettingsComponent()->GetAdvancedSettings()->m_jsonCompressionLevel;
if (compressionLevel != 0)
{
unsigned int time = XbmcThreads::SystemClockMillis();
std::string gzipAnswer;
auto uncompressedSize = m_responseData.size();
if (XFILE::CZipFile::CompressGZip(m_responseData, gzipAnswer, compressionLevel))
{
m_responseData = std::move(gzipAnswer);
m_response.contentEncoding = "gzip";
unsigned int duration = XbmcThreads::SystemClockMillis() - time;
if (duration > 1)
CLog::Log(LOGINFO, "{0} - Compress time {1}ms [{2} -> {3} R{5}:{4:.2f}]", __FUNCTION__,
duration, uncompressedSize, m_responseData.size(),
static_cast<float>(uncompressedSize) / m_responseData.size(), compressionLevel);
}
}
}

m_requestData.clear();

m_responseRange.SetData(m_responseData.c_str(), m_responseData.size());
Expand Down
1 change: 1 addition & 0 deletions xbmc/network/httprequesthandler/IHTTPRequestHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ typedef struct HTTPResponseDetails {
std::multimap<std::string, std::string> headers;
std::string contentType;
uint64_t totalLength;
std::string contentEncoding;
} HTTPResponseDetails;

class IHTTPRequestHandler
Expand Down
2 changes: 2 additions & 0 deletions xbmc/settings/AdvancedSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ void CAdvancedSettings::Initialize()

m_jsonOutputCompact = true;
m_jsonTcpPort = 9090;
m_jsonCompressionLevel = 4;

m_enableMultimediaKeys = false;

Expand Down Expand Up @@ -834,6 +835,7 @@ void CAdvancedSettings::ParseSettingsFile(const std::string &file)
{
XMLUtils::GetBoolean(pElement, "compactoutput", m_jsonOutputCompact);
XMLUtils::GetUInt(pElement, "tcpport", m_jsonTcpPort);
XMLUtils::GetInt(pElement, "compressionlevel", m_jsonCompressionLevel);
}

pElement = pRootElement->FirstChildElement("samba");
Expand Down
1 change: 1 addition & 0 deletions xbmc/settings/AdvancedSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ class CAdvancedSettings : public ISettingCallback, public ISettingsHandler

bool m_jsonOutputCompact;
unsigned int m_jsonTcpPort;
int m_jsonCompressionLevel; /*!< @brief zLib compression level from -1 to 9. (0 disable compression support) */

bool m_enableMultimediaKeys;
std::vector<std::string> m_settingsFiles;
Expand Down