diff --git a/.gitmodules b/.gitmodules index 40b89e748..0948533d2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -32,3 +32,6 @@ branch = post-3.2.1-transmission path = third-party/utfcpp url = https://github.com/transmission/utfcpp +[submodule "third-party/libdeflate"] + path = third-party/libdeflate + url = https://github.com/transmission/libdeflate diff --git a/CMakeLists.txt b/CMakeLists.txt index 5e4304384..7ae7d1a8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,6 +35,7 @@ tr_auto_option(ENABLE_MAC "Build Mac client" AUTO) option(INSTALL_LIB "Install the library" OFF) tr_auto_option(RUN_CLANG_TIDY "Run clang-tidy on the code" AUTO) tr_auto_option(USE_SYSTEM_EVENT2 "Use system event2 library" AUTO) +tr_auto_option(USE_SYSTEM_DEFLATE "Use system deflate library" AUTO) tr_auto_option(USE_SYSTEM_DHT "Use system dht library" AUTO) tr_auto_option(USE_SYSTEM_MINIUPNPC "Use system miniupnpc library" AUTO) tr_auto_option(USE_SYSTEM_NATPMP "Use system natpmp library" AUTO) @@ -109,16 +110,17 @@ string(SUBSTRING "${TR_VCS_REVISION}" 0 10 TR_VCS_REVISION) set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CURL_MINIMUM 7.28.0) -set(EVENT2_MINIMUM 2.0.10) -set(OPENSSL_MINIMUM 0.9.7) set(CYASSL_MINIMUM 3.0) -set(POLARSSL_MINIMUM 1.2) -set(ZLIB_MINIMUM 1.2.3) -set(GTK_MINIMUM 3.24.0) -set(GLIB_MINIMUM 2.50.1) +set(DEFLATE_MINIMUM 1.9) +set(EVENT2_MINIMUM 2.0.10) set(GIO_MINIMUM 2.26.0) +set(GLIB_MINIMUM 2.50.1) +set(GTK_MINIMUM 3.24.0) set(LIBAPPINDICATOR_MINIMUM 0.4.90) +set(OPENSSL_MINIMUM 0.9.7) +set(POLARSSL_MINIMUM 1.2) set(QT_MINIMUM 5.6) +set(ZLIB_MINIMUM 1.2.3) if(WIN32) foreach(L C CXX) @@ -319,6 +321,11 @@ endif() set(THIRD_PARTY_DIR ${CMAKE_SOURCE_DIR}/third-party) +tr_add_external_auto_library(DEFLATE libdeflate deflate) +if(NOT USE_SYSTEM_DEFLATE) + set(DEFLATE_VERSION 1.9) +endif() + tr_add_external_auto_library(EVENT2 libevent event CMAKE_ARGS -DEVENT__DISABLE_OPENSSL:BOOL=ON diff --git a/Transmission.xcodeproj/project.pbxproj b/Transmission.xcodeproj/project.pbxproj index 8f32c284b..383f0167b 100644 --- a/Transmission.xcodeproj/project.pbxproj +++ b/Transmission.xcodeproj/project.pbxproj @@ -359,6 +359,47 @@ C1FEE5791C3223CC00D62832 /* watchdir-kqueue.cc in Sources */ = {isa = PBXBuildFile; fileRef = C1FEE5741C3223CC00D62832 /* watchdir-kqueue.cc */; }; C1FEE57A1C3223CC00D62832 /* watchdir.cc in Sources */ = {isa = PBXBuildFile; fileRef = C1FEE5751C3223CC00D62832 /* watchdir.cc */; }; C1FEE57B1C3223CC00D62832 /* watchdir.h in Headers */ = {isa = PBXBuildFile; fileRef = C1FEE5761C3223CC00D62832 /* watchdir.h */; }; + C31DB6D72794A4430050ABC9 /* libdeflate.h in Headers */ = {isa = PBXBuildFile; fileRef = C31DB6D62794A4430050ABC9 /* libdeflate.h */; }; + C3CEBBC327949F8400683BE0 /* deflate_decompress.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBAB27949F8300683BE0 /* deflate_decompress.c */; }; + C3CEBBC427949F8400683BE0 /* gzip_compress.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBAC27949F8300683BE0 /* gzip_compress.c */; }; + C3CEBBC527949F8400683BE0 /* adler32.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBAD27949F8300683BE0 /* adler32.c */; }; + C3CEBBC627949F8400683BE0 /* gzip_decompress.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBAE27949F8300683BE0 /* gzip_decompress.c */; }; + C3CEBBC727949F8400683BE0 /* hc_matchfinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBAF27949F8300683BE0 /* hc_matchfinder.h */; }; + C3CEBBC827949F8400683BE0 /* lib_common.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBB027949F8300683BE0 /* lib_common.h */; }; + C3CEBBC927949F8400683BE0 /* ht_matchfinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBB127949F8300683BE0 /* ht_matchfinder.h */; }; + C3CEBBCA27949F8400683BE0 /* gzip_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBB227949F8400683BE0 /* gzip_constants.h */; }; + C3CEBBCB27949F8400683BE0 /* matchfinder_common.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBB327949F8400683BE0 /* matchfinder_common.h */; }; + C3CEBBCC27949F8400683BE0 /* bt_matchfinder.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBB427949F8400683BE0 /* bt_matchfinder.h */; }; + C3CEBBCD27949F8400683BE0 /* crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBB527949F8400683BE0 /* crc32.c */; }; + C3CEBBCE27949F8400683BE0 /* crc32_table.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBB627949F8400683BE0 /* crc32_table.h */; }; + C3CEBBCF27949F8400683BE0 /* deflate_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBB727949F8400683BE0 /* deflate_constants.h */; }; + C3CEBBD027949F8400683BE0 /* unaligned.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBB827949F8400683BE0 /* unaligned.h */; }; + C3CEBBD127949F8400683BE0 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBB927949F8400683BE0 /* utils.c */; }; + C3CEBBD227949F8400683BE0 /* zlib_compress.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBBA27949F8400683BE0 /* zlib_compress.c */; }; + C3CEBBD327949F8400683BE0 /* zlib_decompress.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBBB27949F8400683BE0 /* zlib_decompress.c */; }; + C3CEBBD427949F8400683BE0 /* deflate_compress.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBBC27949F8400683BE0 /* deflate_compress.c */; }; + C3CEBBD527949F8400683BE0 /* cpu_features_common.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBBD27949F8400683BE0 /* cpu_features_common.h */; }; + C3CEBBD627949F8400683BE0 /* adler32_vec_template.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBBE27949F8400683BE0 /* adler32_vec_template.h */; }; + C3CEBBD727949F8400683BE0 /* crc32_vec_template.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBBF27949F8400683BE0 /* crc32_vec_template.h */; }; + C3CEBBD827949F8400683BE0 /* zlib_constants.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBC027949F8400683BE0 /* zlib_constants.h */; }; + C3CEBBD927949F8400683BE0 /* deflate_compress.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBC127949F8400683BE0 /* deflate_compress.h */; }; + C3CEBBDA27949F8400683BE0 /* decompress_template.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBC227949F8400683BE0 /* decompress_template.h */; }; + C3CEBBE22794A03700683BE0 /* adler32_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBDD2794A03700683BE0 /* adler32_impl.h */; }; + C3CEBBE32794A03700683BE0 /* crc32_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBDE2794A03700683BE0 /* crc32_impl.h */; }; + C3CEBBE42794A03700683BE0 /* matchfinder_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBDF2794A03700683BE0 /* matchfinder_impl.h */; }; + C3CEBBE52794A03700683BE0 /* cpu_features.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBE02794A03700683BE0 /* cpu_features.h */; }; + C3CEBBE62794A03700683BE0 /* cpu_features.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBE12794A03700683BE0 /* cpu_features.c */; }; + C3CEBBEE2794A07900683BE0 /* cpu_features.c in Sources */ = {isa = PBXBuildFile; fileRef = C3CEBBE72794A07800683BE0 /* cpu_features.c */; }; + C3CEBBEF2794A07900683BE0 /* decompress_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBE82794A07900683BE0 /* decompress_impl.h */; }; + C3CEBBF02794A07900683BE0 /* crc32_pclmul_template.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBE92794A07900683BE0 /* crc32_pclmul_template.h */; }; + C3CEBBF12794A07900683BE0 /* crc32_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBEA2794A07900683BE0 /* crc32_impl.h */; }; + C3CEBBF22794A07900683BE0 /* cpu_features.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBEB2794A07900683BE0 /* cpu_features.h */; }; + C3CEBBF32794A07900683BE0 /* matchfinder_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBEC2794A07900683BE0 /* matchfinder_impl.h */; }; + C3CEBBF42794A07900683BE0 /* adler32_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBED2794A07900683BE0 /* adler32_impl.h */; }; + C3CEBBF92794A0D200683BE0 /* common_defs.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBF62794A0D200683BE0 /* common_defs.h */; }; + C3CEBBFA2794A0D200683BE0 /* compiler_gcc.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBF72794A0D200683BE0 /* compiler_gcc.h */; }; + C3CEBBFB2794A0D200683BE0 /* compiler_msc.h in Headers */ = {isa = PBXBuildFile; fileRef = C3CEBBF82794A0D200683BE0 /* compiler_msc.h */; }; + C3CEBBFC2794A12200683BE0 /* libdeflate.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C3CEBBA927949CA000683BE0 /* libdeflate.a */; }; CAB35C64252F6F5E00552A55 /* mime-types.h in Headers */ = {isa = PBXBuildFile; fileRef = CAB35C62252F6F5E00552A55 /* mime-types.h */; }; E138A9780C04D88F00C5426C /* ProgressGradients.mm in Sources */ = {isa = PBXBuildFile; fileRef = E138A9760C04D88F00C5426C /* ProgressGradients.mm */; }; ED8A163F2735A8AA000D61F9 /* peer-mgr-active-requests.h in Headers */ = {isa = PBXBuildFile; fileRef = ED8A163B2735A8AA000D61F9 /* peer-mgr-active-requests.h */; }; @@ -463,6 +504,13 @@ remoteGlobalIDString = C1A7516326ED03140038B90A; remoteInfo = arc4; }; + C33E46A12794B3CC0090F2AA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = C3CEBB9F27949CA000683BE0; + remoteInfo = deflate; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -1022,6 +1070,47 @@ C1FEE5741C3223CC00D62832 /* watchdir-kqueue.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "watchdir-kqueue.cc"; sourceTree = ""; }; C1FEE5751C3223CC00D62832 /* watchdir.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = watchdir.cc; sourceTree = ""; }; C1FEE5761C3223CC00D62832 /* watchdir.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = watchdir.h; sourceTree = ""; }; + C31DB6D62794A4430050ABC9 /* libdeflate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libdeflate.h; sourceTree = ""; }; + C3CEBBA927949CA000683BE0 /* libdeflate.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libdeflate.a; sourceTree = BUILT_PRODUCTS_DIR; }; + C3CEBBAB27949F8300683BE0 /* deflate_decompress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = deflate_decompress.c; path = lib/deflate_decompress.c; sourceTree = ""; }; + C3CEBBAC27949F8300683BE0 /* gzip_compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gzip_compress.c; path = lib/gzip_compress.c; sourceTree = ""; }; + C3CEBBAD27949F8300683BE0 /* adler32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = adler32.c; path = lib/adler32.c; sourceTree = ""; }; + C3CEBBAE27949F8300683BE0 /* gzip_decompress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = gzip_decompress.c; path = lib/gzip_decompress.c; sourceTree = ""; }; + C3CEBBAF27949F8300683BE0 /* hc_matchfinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hc_matchfinder.h; path = lib/hc_matchfinder.h; sourceTree = ""; }; + C3CEBBB027949F8300683BE0 /* lib_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = lib_common.h; path = lib/lib_common.h; sourceTree = ""; }; + C3CEBBB127949F8300683BE0 /* ht_matchfinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ht_matchfinder.h; path = lib/ht_matchfinder.h; sourceTree = ""; }; + C3CEBBB227949F8400683BE0 /* gzip_constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = gzip_constants.h; path = lib/gzip_constants.h; sourceTree = ""; }; + C3CEBBB327949F8400683BE0 /* matchfinder_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = matchfinder_common.h; path = lib/matchfinder_common.h; sourceTree = ""; }; + C3CEBBB427949F8400683BE0 /* bt_matchfinder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bt_matchfinder.h; path = lib/bt_matchfinder.h; sourceTree = ""; }; + C3CEBBB527949F8400683BE0 /* crc32.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = crc32.c; path = lib/crc32.c; sourceTree = ""; }; + C3CEBBB627949F8400683BE0 /* crc32_table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crc32_table.h; path = lib/crc32_table.h; sourceTree = ""; }; + C3CEBBB727949F8400683BE0 /* deflate_constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = deflate_constants.h; path = lib/deflate_constants.h; sourceTree = ""; }; + C3CEBBB827949F8400683BE0 /* unaligned.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = unaligned.h; path = lib/unaligned.h; sourceTree = ""; }; + C3CEBBB927949F8400683BE0 /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = utils.c; path = lib/utils.c; sourceTree = ""; }; + C3CEBBBA27949F8400683BE0 /* zlib_compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zlib_compress.c; path = lib/zlib_compress.c; sourceTree = ""; }; + C3CEBBBB27949F8400683BE0 /* zlib_decompress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = zlib_decompress.c; path = lib/zlib_decompress.c; sourceTree = ""; }; + C3CEBBBC27949F8400683BE0 /* deflate_compress.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = deflate_compress.c; path = lib/deflate_compress.c; sourceTree = ""; }; + C3CEBBBD27949F8400683BE0 /* cpu_features_common.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpu_features_common.h; path = lib/cpu_features_common.h; sourceTree = ""; }; + C3CEBBBE27949F8400683BE0 /* adler32_vec_template.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = adler32_vec_template.h; path = lib/adler32_vec_template.h; sourceTree = ""; }; + C3CEBBBF27949F8400683BE0 /* crc32_vec_template.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crc32_vec_template.h; path = lib/crc32_vec_template.h; sourceTree = ""; }; + C3CEBBC027949F8400683BE0 /* zlib_constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = zlib_constants.h; path = lib/zlib_constants.h; sourceTree = ""; }; + C3CEBBC127949F8400683BE0 /* deflate_compress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = deflate_compress.h; path = lib/deflate_compress.h; sourceTree = ""; }; + C3CEBBC227949F8400683BE0 /* decompress_template.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = decompress_template.h; path = lib/decompress_template.h; sourceTree = ""; }; + C3CEBBDD2794A03700683BE0 /* adler32_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = adler32_impl.h; path = lib/arm/adler32_impl.h; sourceTree = ""; }; + C3CEBBDE2794A03700683BE0 /* crc32_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crc32_impl.h; path = lib/arm/crc32_impl.h; sourceTree = ""; }; + C3CEBBDF2794A03700683BE0 /* matchfinder_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = matchfinder_impl.h; path = lib/arm/matchfinder_impl.h; sourceTree = ""; }; + C3CEBBE02794A03700683BE0 /* cpu_features.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpu_features.h; path = lib/arm/cpu_features.h; sourceTree = ""; }; + C3CEBBE12794A03700683BE0 /* cpu_features.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cpu_features.c; path = lib/arm/cpu_features.c; sourceTree = ""; }; + C3CEBBE72794A07800683BE0 /* cpu_features.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = cpu_features.c; path = lib/x86/cpu_features.c; sourceTree = ""; }; + C3CEBBE82794A07900683BE0 /* decompress_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = decompress_impl.h; path = lib/x86/decompress_impl.h; sourceTree = ""; }; + C3CEBBE92794A07900683BE0 /* crc32_pclmul_template.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crc32_pclmul_template.h; path = lib/x86/crc32_pclmul_template.h; sourceTree = ""; }; + C3CEBBEA2794A07900683BE0 /* crc32_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = crc32_impl.h; path = lib/x86/crc32_impl.h; sourceTree = ""; }; + C3CEBBEB2794A07900683BE0 /* cpu_features.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = cpu_features.h; path = lib/x86/cpu_features.h; sourceTree = ""; }; + C3CEBBEC2794A07900683BE0 /* matchfinder_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = matchfinder_impl.h; path = lib/x86/matchfinder_impl.h; sourceTree = ""; }; + C3CEBBED2794A07900683BE0 /* adler32_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = adler32_impl.h; path = lib/x86/adler32_impl.h; sourceTree = ""; }; + C3CEBBF62794A0D200683BE0 /* common_defs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = common_defs.h; path = common/common_defs.h; sourceTree = ""; }; + C3CEBBF72794A0D200683BE0 /* compiler_gcc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = compiler_gcc.h; path = common/compiler_gcc.h; sourceTree = ""; }; + C3CEBBF82794A0D200683BE0 /* compiler_msc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = compiler_msc.h; path = common/compiler_msc.h; sourceTree = ""; }; CAB35C62252F6F5E00552A55 /* mime-types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "mime-types.h"; sourceTree = ""; }; E138A9750C04D88F00C5426C /* ProgressGradients.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ProgressGradients.h; sourceTree = ""; }; E138A9760C04D88F00C5426C /* ProgressGradients.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ProgressGradients.mm; sourceTree = ""; }; @@ -1117,6 +1206,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + C3CEBBFC2794A12200683BE0 /* libdeflate.a in Frameworks */, C1A7517526ED048C0038B90A /* libarc4.a in Frameworks */, C1639A741A55F4E000E42033 /* libb64.a in Frameworks */, A22CFCCB0FC24FDA0009BD3E /* libdht.a in Frameworks */, @@ -1165,6 +1255,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C3CEBBA427949CA000683BE0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -1275,6 +1372,7 @@ A2F35BB915C5A0A100EBF632 /* QuickLookPlugin.qlgenerator */, C1639A6F1A55F4D600E42033 /* libb64.a */, C1A7516426ED03140038B90A /* libarc4.a */, + C3CEBBA927949CA000683BE0 /* libdeflate.a */, ); name = Products; sourceTree = ""; @@ -1291,6 +1389,7 @@ C15E58AC219A37C600AB292F /* utils */, C1A7518626ED04EC0038B90A /* arc4 */, A22CFCB50FC24F630009BD3E /* dht */, + C3CEBB9E27949A3900683BE0 /* libdeflate */, A2E384BF130DFA49001F501B /* libutp */, BE75C3570C72A0D600DBEFE0 /* libevent */, BE1183410CE15DF00002D0F3 /* libminiupnp */, @@ -1755,6 +1854,78 @@ path = arc4; sourceTree = ""; }; + C3CEBB9E27949A3900683BE0 /* libdeflate */ = { + isa = PBXGroup; + children = ( + C31DB6D62794A4430050ABC9 /* libdeflate.h */, + C3CEBBF52794A09500683BE0 /* common */, + C3CEBBDB27949FA400683BE0 /* arm */, + C3CEBBDC27949FB400683BE0 /* x86 */, + C3CEBBBE27949F8400683BE0 /* adler32_vec_template.h */, + C3CEBBAD27949F8300683BE0 /* adler32.c */, + C3CEBBB427949F8400683BE0 /* bt_matchfinder.h */, + C3CEBBBD27949F8400683BE0 /* cpu_features_common.h */, + C3CEBBB627949F8400683BE0 /* crc32_table.h */, + C3CEBBBF27949F8400683BE0 /* crc32_vec_template.h */, + C3CEBBB527949F8400683BE0 /* crc32.c */, + C3CEBBC227949F8400683BE0 /* decompress_template.h */, + C3CEBBBC27949F8400683BE0 /* deflate_compress.c */, + C3CEBBC127949F8400683BE0 /* deflate_compress.h */, + C3CEBBB727949F8400683BE0 /* deflate_constants.h */, + C3CEBBAB27949F8300683BE0 /* deflate_decompress.c */, + C3CEBBAC27949F8300683BE0 /* gzip_compress.c */, + C3CEBBB227949F8400683BE0 /* gzip_constants.h */, + C3CEBBAE27949F8300683BE0 /* gzip_decompress.c */, + C3CEBBAF27949F8300683BE0 /* hc_matchfinder.h */, + C3CEBBB127949F8300683BE0 /* ht_matchfinder.h */, + C3CEBBB027949F8300683BE0 /* lib_common.h */, + C3CEBBB327949F8400683BE0 /* matchfinder_common.h */, + C3CEBBB827949F8400683BE0 /* unaligned.h */, + C3CEBBB927949F8400683BE0 /* utils.c */, + C3CEBBBA27949F8400683BE0 /* zlib_compress.c */, + C3CEBBC027949F8400683BE0 /* zlib_constants.h */, + C3CEBBBB27949F8400683BE0 /* zlib_decompress.c */, + ); + name = libdeflate; + path = "third-party/libdeflate"; + sourceTree = ""; + }; + C3CEBBDB27949FA400683BE0 /* arm */ = { + isa = PBXGroup; + children = ( + C3CEBBDD2794A03700683BE0 /* adler32_impl.h */, + C3CEBBE12794A03700683BE0 /* cpu_features.c */, + C3CEBBE02794A03700683BE0 /* cpu_features.h */, + C3CEBBDE2794A03700683BE0 /* crc32_impl.h */, + C3CEBBDF2794A03700683BE0 /* matchfinder_impl.h */, + ); + name = arm; + sourceTree = ""; + }; + C3CEBBDC27949FB400683BE0 /* x86 */ = { + isa = PBXGroup; + children = ( + C3CEBBED2794A07900683BE0 /* adler32_impl.h */, + C3CEBBE72794A07800683BE0 /* cpu_features.c */, + C3CEBBEB2794A07900683BE0 /* cpu_features.h */, + C3CEBBEA2794A07900683BE0 /* crc32_impl.h */, + C3CEBBE92794A07900683BE0 /* crc32_pclmul_template.h */, + C3CEBBE82794A07900683BE0 /* decompress_impl.h */, + C3CEBBEC2794A07900683BE0 /* matchfinder_impl.h */, + ); + name = x86; + sourceTree = ""; + }; + C3CEBBF52794A09500683BE0 /* common */ = { + isa = PBXGroup; + children = ( + C3CEBBF62794A0D200683BE0 /* common_defs.h */, + C3CEBBF72794A0D200683BE0 /* compiler_gcc.h */, + C3CEBBF82794A0D200683BE0 /* compiler_msc.h */, + ); + name = common; + sourceTree = ""; + }; E1B6FBF80C0D719B0015FE4D /* Info Window */ = { isa = PBXGroup; children = ( @@ -1973,6 +2144,42 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C3CEBBA027949CA000683BE0 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + C3CEBBEF2794A07900683BE0 /* decompress_impl.h in Headers */, + C3CEBBF22794A07900683BE0 /* cpu_features.h in Headers */, + C3CEBBE42794A03700683BE0 /* matchfinder_impl.h in Headers */, + C3CEBBE52794A03700683BE0 /* cpu_features.h in Headers */, + C3CEBBCB27949F8400683BE0 /* matchfinder_common.h in Headers */, + C3CEBBE32794A03700683BE0 /* crc32_impl.h in Headers */, + C3CEBBD527949F8400683BE0 /* cpu_features_common.h in Headers */, + C3CEBBE22794A03700683BE0 /* adler32_impl.h in Headers */, + C3CEBBCA27949F8400683BE0 /* gzip_constants.h in Headers */, + C3CEBBF32794A07900683BE0 /* matchfinder_impl.h in Headers */, + C3CEBBFB2794A0D200683BE0 /* compiler_msc.h in Headers */, + C3CEBBF12794A07900683BE0 /* crc32_impl.h in Headers */, + C3CEBBF42794A07900683BE0 /* adler32_impl.h in Headers */, + C3CEBBC827949F8400683BE0 /* lib_common.h in Headers */, + C3CEBBD027949F8400683BE0 /* unaligned.h in Headers */, + C3CEBBD727949F8400683BE0 /* crc32_vec_template.h in Headers */, + C3CEBBCF27949F8400683BE0 /* deflate_constants.h in Headers */, + C31DB6D72794A4430050ABC9 /* libdeflate.h in Headers */, + C3CEBBF92794A0D200683BE0 /* common_defs.h in Headers */, + C3CEBBD927949F8400683BE0 /* deflate_compress.h in Headers */, + C3CEBBCC27949F8400683BE0 /* bt_matchfinder.h in Headers */, + C3CEBBF02794A07900683BE0 /* crc32_pclmul_template.h in Headers */, + C3CEBBD827949F8400683BE0 /* zlib_constants.h in Headers */, + C3CEBBDA27949F8400683BE0 /* decompress_template.h in Headers */, + C3CEBBC927949F8400683BE0 /* ht_matchfinder.h in Headers */, + C3CEBBD627949F8400683BE0 /* adler32_vec_template.h in Headers */, + C3CEBBC727949F8400683BE0 /* hc_matchfinder.h in Headers */, + C3CEBBCE27949F8400683BE0 /* crc32_table.h in Headers */, + C3CEBBFA2794A0D200683BE0 /* compiler_gcc.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ @@ -2005,6 +2212,7 @@ buildRules = ( ); dependencies = ( + C33E46A22794B3CC0090F2AA /* PBXTargetDependency */, C1A751C826ED06390038B90A /* PBXTargetDependency */, A226FDB10D0CDF6E005A7F71 /* PBXTargetDependency */, BE1183760CE161040002D0F3 /* PBXTargetDependency */, @@ -2216,6 +2424,23 @@ productReference = C1A7516426ED03140038B90A /* libarc4.a */; productType = "com.apple.product-type.library.static"; }; + C3CEBB9F27949CA000683BE0 /* deflate */ = { + isa = PBXNativeTarget; + buildConfigurationList = C3CEBBA527949CA000683BE0 /* Build configuration list for PBXNativeTarget "deflate" */; + buildPhases = ( + C3CEBBA027949CA000683BE0 /* Headers */, + C3CEBBA227949CA000683BE0 /* Sources */, + C3CEBBA427949CA000683BE0 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = deflate; + productName = deflate; + productReference = C3CEBBA927949CA000683BE0 /* libdeflate.a */; + productType = "com.apple.product-type.library.static"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -2271,6 +2496,7 @@ 3C7A118C0D0B2EB800B5701F /* natpmp */, C1639A6E1A55F4D600E42033 /* b64 */, C1A7516326ED03140038B90A /* arc4 */, + C3CEBB9F27949CA000683BE0 /* deflate */, ); }; /* End PBXProject section */ @@ -2694,6 +2920,24 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + C3CEBBA227949CA000683BE0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + C3CEBBE62794A03700683BE0 /* cpu_features.c in Sources */, + C3CEBBEE2794A07900683BE0 /* cpu_features.c in Sources */, + C3CEBBC327949F8400683BE0 /* deflate_decompress.c in Sources */, + C3CEBBD327949F8400683BE0 /* zlib_decompress.c in Sources */, + C3CEBBD127949F8400683BE0 /* utils.c in Sources */, + C3CEBBD427949F8400683BE0 /* deflate_compress.c in Sources */, + C3CEBBC427949F8400683BE0 /* gzip_compress.c in Sources */, + C3CEBBD227949F8400683BE0 /* zlib_compress.c in Sources */, + C3CEBBCD27949F8400683BE0 /* crc32.c in Sources */, + C3CEBBC527949F8400683BE0 /* adler32.c in Sources */, + C3CEBBC627949F8400683BE0 /* gzip_decompress.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ @@ -2762,6 +3006,11 @@ target = C1A7516326ED03140038B90A /* arc4 */; targetProxy = C1A751C726ED06390038B90A /* PBXContainerItemProxy */; }; + C33E46A22794B3CC0090F2AA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = C3CEBB9F27949CA000683BE0 /* deflate */; + targetProxy = C33E46A12794B3CC0090F2AA /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -3021,6 +3270,7 @@ "third-party/libevent/include", "third-party/libutp", "third-party/utfcpp/source", + "third-party/libdeflate", ); OTHER_CFLAGS = ( "$(inherited)", @@ -3215,6 +3465,7 @@ "third-party/libevent/include", "third-party/libutp", "third-party/utfcpp/source", + "third-party/libdeflate", ); OTHER_CFLAGS = ( "$(inherited)", @@ -3466,6 +3717,7 @@ "third-party/libevent/include", "third-party/libutp", "third-party/utfcpp/source", + "third-party/libdeflate", ); OTHER_CFLAGS = ( "$(inherited)", @@ -3736,6 +3988,33 @@ }; name = Release; }; + C3CEBBA627949CA000683BE0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = NO; + HEADER_SEARCH_PATHS = "third-party/libdeflate"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + C3CEBBA727949CA000683BE0 /* Release - Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = NO; + HEADER_SEARCH_PATHS = "third-party/libdeflate"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = "Release - Debug"; + }; + C3CEBBA827949CA000683BE0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = NO; + HEADER_SEARCH_PATHS = "third-party/libdeflate"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -3879,6 +4158,16 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Debug; }; + C3CEBBA527949CA000683BE0 /* Build configuration list for PBXNativeTarget "deflate" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C3CEBBA627949CA000683BE0 /* Debug */, + C3CEBBA727949CA000683BE0 /* Release - Debug */, + C3CEBBA827949CA000683BE0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; /* End XCConfigurationList section */ }; rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; diff --git a/cmake/FindDEFLATE.cmake b/cmake/FindDEFLATE.cmake new file mode 100644 index 000000000..4d2988c56 --- /dev/null +++ b/cmake/FindDEFLATE.cmake @@ -0,0 +1,37 @@ +if(DEFLATE_PREFER_STATIC_LIB) + set(DEFLATE_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(WIN32) + set(CMAKE_FIND_LIBRARY_SUFFIXES .a .lib ${CMAKE_FIND_LIBRARY_SUFFIXES}) + else() + set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) + endif() +endif() + +if(UNIX) + find_package(PkgConfig QUIET) + # cmake supported added in libdeflate v1.9 + pkg_check_modules(_DEFLATE libdeflate>=${DEFLATE_MINIMUM}) +endif() + +find_path(DEFLATE_INCLUDE_DIR NAMES libdeflate.h HINTS ${_DEFLATE_INCLUDEDIR}) +find_library(DEFLATE_LIBRARY NAMES deflate HINTS ${_DEFLATE_LIBDIR}) + +set(DEFLATE_INCLUDE_DIRS ${DEFLATE_INCLUDE_DIR}) +set(DEFLATE_LIBRARIES ${DEFLATE_LIBRARY}) +set(DEFLATE_VERSION ${_DEFLATE_VERSION}) + +include(FindPackageHandleStandardArgs) + +find_package_handle_standard_args(DEFLATE + REQUIRED_VARS + DEFLATE_INCLUDE_DIR + DEFLATE_LIBRARY + DEFLATE_VERSION +) + +mark_as_advanced(DEFLATE_INCLUDE_DIR DEFLATE_LIBRARY) + +if(DEFLATE_PREFER_STATIC_LIB) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${DEFLATE_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) + unset(DEFLATE_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES) +endif() diff --git a/libtransmission/CMakeLists.txt b/libtransmission/CMakeLists.txt index 5ed3c15d1..b4cc2a968 100644 --- a/libtransmission/CMakeLists.txt +++ b/libtransmission/CMakeLists.txt @@ -245,7 +245,7 @@ include_directories( include_directories( SYSTEM ${UTFCPP_INCLUDE_DIRS} - ${ZLIB_INCLUDE_DIRS} + ${DEFLATE_INCLUDE_DIRS} ${CRYPTO_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${EVENT2_INCLUDE_DIRS} @@ -274,6 +274,7 @@ foreach(UT ${EVENT2_UPSTREAM_TARGET} ${NATPMP_UPSTREAM_TARGET} ${MINIUPNPC_UPSTREAM_TARGET} ${DHT_UPSTREAM_TARGET} + ${DEFLATE_UPSTREAM_TARGET} ${UTP_UPSTREAM_TARGET} ${B64_UPSTREAM_TARGET}) add_dependencies(${TR_NAME} ${UT}) @@ -281,7 +282,7 @@ endforeach() target_link_libraries(${TR_NAME} ${CMAKE_THREAD_LIBS_INIT} - ${ZLIB_LIBRARIES} + ${DEFLATE_LIBRARIES} ${CRYPTO_LIBRARIES} ${CURL_LIBRARIES} ${EVENT2_LIBRARIES} diff --git a/libtransmission/rpc-server.cc b/libtransmission/rpc-server.cc index cc874dcfc..9e2bd6862 100644 --- a/libtransmission/rpc-server.cc +++ b/libtransmission/rpc-server.cc @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include @@ -57,6 +57,8 @@ using namespace std::literals; #define dbgmsg(...) tr_logAddDeepNamed(MY_NAME, __VA_ARGS__) +static int constexpr DeflateLevel = 6; // medium / default + /*** **** ***/ @@ -269,65 +271,31 @@ static void add_response(struct evhttp_request* req, tr_rpc_server* server, stru } else { - struct evbuffer_iovec iovec[1]; - void* content_ptr = evbuffer_pullup(content, -1); + auto const* const content_ptr = evbuffer_pullup(content, -1); size_t const content_len = evbuffer_get_length(content); + auto const max_compressed_len = libdeflate_deflate_compress_bound(server->compressor.get(), content_len); - if (!server->isStreamInitialized) + struct evbuffer_iovec iovec[1]; + evbuffer_reserve_space(out, std::max(content_len, max_compressed_len), iovec, 1); + + auto const compressed_len = libdeflate_zlib_compress( + server->compressor.get(), + content_ptr, + content_len, + iovec[0].iov_base, + iovec[0].iov_len); + if (0 < compressed_len && compressed_len < content_len) { - server->isStreamInitialized = true; - server->stream.zalloc = (alloc_func)Z_NULL; - server->stream.zfree = (free_func)Z_NULL; - server->stream.opaque = (voidpf)Z_NULL; - - /* zlib's manual says: "Add 16 to windowBits to write a simple gzip header - * and trailer around the compressed data instead of a zlib wrapper." */ -#ifdef TR_LIGHTWEIGHT - int const compressionLevel = Z_DEFAULT_COMPRESSION; -#else - int const compressionLevel = Z_BEST_COMPRESSION; -#endif - // "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." - if (Z_OK != deflateInit2(&server->stream, compressionLevel, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY)) - { - tr_logAddNamedDbg(MY_NAME, "deflateInit2 failed: %s", server->stream.msg); - } - } - - server->stream.next_in = static_cast(content_ptr); - server->stream.avail_in = content_len; - - /* allocate space for the raw data and call deflate() just once -- - * we won't use the deflated data if it's longer than the raw data, - * so it's okay to let deflate() run out of output buffer space */ - evbuffer_reserve_space(out, content_len, iovec, 1); - server->stream.next_out = static_cast(iovec[0].iov_base); - server->stream.avail_out = iovec[0].iov_len; - auto const state = deflate(&server->stream, Z_FINISH); - - if (state == Z_STREAM_END) - { - iovec[0].iov_len -= server->stream.avail_out; - -#if 0 - - fprintf(stderr, "compressed response is %.2f of original (raw==%zu bytes; compressed==%zu)\n", - (double)evbuffer_get_length(out) / content_len, content_len, evbuffer_get_length(out)); - -#endif - + iovec[0].iov_len = compressed_len; evhttp_add_header(req->output_headers, "Content-Encoding", "gzip"); } else { - memcpy(iovec[0].iov_base, content_ptr, content_len); + std::copy_n(content_ptr, content_len, static_cast(iovec[0].iov_base)); iovec[0].iov_len = content_len; } evbuffer_commit_space(out, iovec, 1); - deflateReset(&server->stream); } } @@ -1031,7 +999,8 @@ static void missing_settings_key(tr_quark const q) } tr_rpc_server::tr_rpc_server(tr_session* session_in, tr_variant* settings) - : session{ session_in } + : compressor{ libdeflate_alloc_compressor(DeflateLevel), libdeflate_free_compressor } + , session{ session_in } { auto address = tr_address{}; auto boolVal = bool{}; @@ -1233,9 +1202,4 @@ tr_rpc_server::~tr_rpc_server() TR_ASSERT(tr_amInEventThread(this->session)); stopServer(this); - - if (this->isStreamInitialized) - { - deflateEnd(&this->stream); - } } diff --git a/libtransmission/rpc-server.h b/libtransmission/rpc-server.h index f8551ca1b..5096d9c64 100644 --- a/libtransmission/rpc-server.h +++ b/libtransmission/rpc-server.h @@ -13,21 +13,18 @@ #endif #include +#include #include #include -#include - -#include -#include -#include -#include /* TODO: eventually remove this */ - #include "transmission.h" #include "net.h" +struct event; +struct evhttp; struct tr_variant; +struct libdeflate_compressor; class tr_rpc_server { @@ -40,7 +37,7 @@ public: tr_rpc_server& operator=(tr_rpc_server&) = delete; tr_rpc_server& operator=(tr_rpc_server&&) = delete; - z_stream stream = {}; + std::shared_ptr compressor; std::list hostWhitelist; std::list whitelist; @@ -65,7 +62,6 @@ public: bool isEnabled = false; bool isHostWhitelistEnabled = false; bool isPasswordEnabled = false; - bool isStreamInitialized = false; bool isWhitelistEnabled = false; }; diff --git a/libtransmission/rpcimpl.cc b/libtransmission/rpcimpl.cc index 0e535bf9b..3b7fa04fe 100644 --- a/libtransmission/rpcimpl.cc +++ b/libtransmission/rpcimpl.cc @@ -15,10 +15,7 @@ #include #include -#ifndef ZLIB_CONST -#define ZLIB_CONST -#endif -#include +#include #include "transmission.h" @@ -1390,99 +1387,63 @@ static void gotNewBlocklist( if (response_code != 200) { + // we failed to download the blocklist... tr_snprintf( result, sizeof(result), "gotNewBlocklist: http error %ld: %s", response_code, tr_webGetResponseStr(response_code)); + tr_idle_function_done(data, result); + return; } - else /* successfully fetched the blocklist... */ + + // see if we need to decompress the content + auto content = std::vector{}; + content.resize(1024 * 128); + for (;;) { - auto stream = z_stream{}; - char const* configDir = tr_sessionGetConfigDir(session); - size_t const buflen = 1024 * 128; /* 128 KiB buffer */ - auto* const buf = static_cast(tr_malloc(buflen)); - tr_error* error = nullptr; - - /* this is an odd Magic Number required by zlib to enable gz support. - See zlib's inflateInit2() documentation for a full description */ - int const windowBits = 15 + 32; - - stream.zalloc = (alloc_func)Z_NULL; - stream.zfree = (free_func)Z_NULL; - stream.opaque = (voidpf)Z_NULL; - stream.next_in = reinterpret_cast(std::data(response)); - stream.avail_in = std::size(response); - if (inflateInit2(&stream, windowBits) != Z_OK) + auto decompressor = std::shared_ptr{ libdeflate_alloc_decompressor(), + libdeflate_free_decompressor }; + auto actual_size = size_t{}; + auto const decompress_result = libdeflate_gzip_decompress( + decompressor.get(), + std::data(response), + std::size(response), + std::data(content), + std::size(content), + &actual_size); + if (decompress_result == LIBDEFLATE_INSUFFICIENT_SPACE) { - // If stream init fails, log an error but keep going forward - // since the file may be uncompressed anyway. - tr_logAddError("inflateInit2 failed: %s", stream.msg ? stream.msg : "unknown"); + // need a bigger buffer + content.resize(content.size() * 2); + continue; } - - auto filename = tr_strvPath(configDir, "blocklist.tmp.XXXXXX"); - tr_sys_file_t const fd = tr_sys_file_open_temp(std::data(filename), &error); - - if (fd == TR_BAD_SYS_FILE) + if (decompress_result == LIBDEFLATE_BAD_DATA) { - tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename.c_str(), error->message); - tr_error_clear(&error); + // couldn't decompress it; maybe we downloaded an uncompressed file + content.assign(std::begin(response), std::end(response)); } - - auto err = int{}; - for (;;) - { - stream.next_out = static_cast(buf); - stream.avail_out = buflen; - err = inflate(&stream, Z_NO_FLUSH); - - if ((stream.avail_out < buflen) && (!tr_sys_file_write(fd, buf, buflen - stream.avail_out, nullptr, &error))) - { - tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename.c_str(), error->message); - tr_error_clear(&error); - break; - } - - if (err != Z_OK) - { - if (err != Z_STREAM_END && err != Z_DATA_ERROR) - { - tr_snprintf(result, sizeof(result), _("Error uncompressing blocklist: %s (%d)"), zError(err), err); - } - - break; - } - } - - inflateEnd(&stream); - - if ((err == Z_DATA_ERROR) && // couldn't inflate it... it's probably already uncompressed - !tr_sys_file_write(fd, std::data(response), std::size(response), nullptr, &error)) - { - tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename.c_str(), error->message); - tr_error_clear(&error); - } - - tr_sys_file_close(fd, nullptr); - - if (!tr_str_is_empty(result)) - { - tr_logAddError("%s", result); - } - else - { - /* feed it to the session and give the client a response */ - int const rule_count = tr_blocklistSetContent(session, filename.c_str()); - tr_variantDictAddInt(data->args_out, TR_KEY_blocklist_size, rule_count); - tr_snprintf(result, sizeof(result), "success"); - } - - tr_sys_path_remove(filename.c_str(), nullptr); - tr_free(buf); + break; } - tr_idle_function_done(data, result); + // tr_blocklistSetContent needs a source file, + // so save content into a tmpfile + auto const filename = tr_strvJoin(tr_sessionGetConfigDir(session), "blocklist.tmp"); + tr_error* error = nullptr; + if (!tr_saveFile(filename, std::string_view{ std::data(content), std::size(content) }, &error)) + { + tr_snprintf(result, sizeof(result), _("Couldn't save file \"%1$s\": %2$s"), filename.c_str(), error->message); + tr_error_clear(&error); + tr_idle_function_done(data, result); + return; + } + + // feed it to the session and give the client a response + int const rule_count = tr_blocklistSetContent(session, filename.c_str()); + tr_variantDictAddInt(data->args_out, TR_KEY_blocklist_size, rule_count); + tr_sys_path_remove(filename.c_str(), nullptr); + tr_idle_function_done(data, "success"); } static char const* blocklistUpdate( diff --git a/third-party/libdeflate b/third-party/libdeflate new file mode 160000 index 000000000..0b8349a7e --- /dev/null +++ b/third-party/libdeflate @@ -0,0 +1 @@ +Subproject commit 0b8349a7ee3c5d6cb0def3c668a9079ce82af9b5