From b008c97c831cbb4bedc8d811bea5c22e5cc77313 Mon Sep 17 00:00:00 2001 From: Benjamin Sergeant Date: Fri, 29 May 2020 16:49:29 -0700 Subject: [PATCH] (http server) support gzip compression --- docs/CHANGELOG.md | 4 +++ ixwebsocket/IXHttpServer.cpp | 48 ++++++++++++++++++++++++++++++++ ixwebsocket/IXWebSocketVersion.h | 2 +- makefile | 2 +- ws/ws_http_client.cpp | 7 +++-- 5 files changed, 59 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 8e68f393..eee2f3d3 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All changes to this project will be documented in this file. +## [9.6.5] - 2020-05-29 + +(http server) support gzip compression + ## [9.6.4] - 2020-05-20 (compiler fix) support clang 5 and earlier (contributed by @LunarWatcher) diff --git a/ixwebsocket/IXHttpServer.cpp b/ixwebsocket/IXHttpServer.cpp index d4cf951f..bda1e5c4 100644 --- a/ixwebsocket/IXHttpServer.cpp +++ b/ixwebsocket/IXHttpServer.cpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace { @@ -38,6 +39,47 @@ namespace auto vec = res.second; return std::make_pair(res.first, std::string(vec.begin(), vec.end())); } + + std::string gzipCompress(const std::string& str) + { + z_stream zs; // z_stream is zlib's control structure + memset(&zs, 0, sizeof(zs)); + + // deflateInit2 configure the file format: request gzip instead of deflate + const int windowBits = 15; + const int GZIP_ENCODING = 16; + + deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, + windowBits | GZIP_ENCODING, 8, + Z_DEFAULT_STRATEGY); + + zs.next_in = (Bytef*) str.data(); + zs.avail_in = (uInt) str.size(); // set the z_stream's input + + int ret; + char outbuffer[32768]; + std::string outstring; + + // retrieve the compressed bytes blockwise + do + { + zs.next_out = reinterpret_cast(outbuffer); + zs.avail_out = sizeof(outbuffer); + + ret = deflate(&zs, Z_FINISH); + + if(outstring.size() < zs.total_out) + { + // append the block to the output string + outstring.append(outbuffer, + zs.total_out - outstring.size()); + } + } while(ret == Z_OK); + + deflateEnd(&zs); + + return outstring; + } } // namespace namespace ix @@ -120,6 +162,12 @@ namespace ix std::string content = res.second; + std::string acceptEncoding = request->headers["Accept-encoding"]; + if (acceptEncoding == "gzip" or acceptEncoding == "*") + { + content = gzipCompress(content); + } + // Log request std::stringstream ss; ss << request->method << " " << request->headers["User-Agent"] << " " diff --git a/ixwebsocket/IXWebSocketVersion.h b/ixwebsocket/IXWebSocketVersion.h index b62686b2..aca86d7e 100644 --- a/ixwebsocket/IXWebSocketVersion.h +++ b/ixwebsocket/IXWebSocketVersion.h @@ -6,4 +6,4 @@ #pragma once -#define IX_WEBSOCKET_VERSION "9.6.4" +#define IX_WEBSOCKET_VERSION "9.6.5" diff --git a/makefile b/makefile index 7a5e23dc..7df547c4 100644 --- a/makefile +++ b/makefile @@ -29,7 +29,7 @@ ws_mbedtls_install: mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 -DUSE_MBED_TLS=1 .. ; ninja install) ws: - mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j 4) + mkdir -p build && (cd build ; cmake -GNinja -DCMAKE_BUILD_TYPE=Debug -DUSE_TLS=1 -DUSE_WS=1 .. ; ninja install) ws_install: mkdir -p build && (cd build ; cmake -DCMAKE_BUILD_TYPE=MinSizeRel -DUSE_TLS=1 -DUSE_WS=1 .. ; make -j 4 install) diff --git a/ws/ws_http_client.cpp b/ws/ws_http_client.cpp index 1804010d..c5e57dba 100644 --- a/ws/ws_http_client.cpp +++ b/ws/ws_http_client.cpp @@ -109,8 +109,11 @@ namespace ix args->verbose = verbose; args->compress = compress; args->logger = [](const std::string& msg) { spdlog::info(msg); }; - args->onProgressCallback = [](int current, int total) -> bool { - spdlog::info("Downloaded {} bytes out of {}", current, total); + args->onProgressCallback = [verbose](int current, int total) -> bool { + if (verbose) + { + spdlog::info("Downloaded {} bytes out of {}", current, total); + } return true; };