diff --git a/deps.edn b/deps.edn index f11b43b9..5b6fd9a1 100644 --- a/deps.edn +++ b/deps.edn @@ -29,7 +29,21 @@ io.netty/netty-resolver {:mvn/version "4.1.100.Final"}, io.netty/netty-resolver-dns {:mvn/version "4.1.100.Final"}, metosin/malli - {:mvn/version "0.10.4", :exclusions [org.clojure/clojure]}}, + {:mvn/version "0.10.4", :exclusions [org.clojure/clojure]}, + com.aayushatharva.brotli4j/brotli4j {:mvn/version "1.12.0"}, + com.aayushatharva.brotli4j/service {:mvn/version "1.12.0"}, + com.aayushatharva.brotli4j/native-linux-aarch64 + {:mvn/version "1.12.0"}, + com.aayushatharva.brotli4j/native-linux-armv7 + {:mvn/version "1.12.0"}, + com.aayushatharva.brotli4j/native-linux-x86_64 + {:mvn/version "1.12.0"}, + com.aayushatharva.brotli4j/native-osx-aarch64 + {:mvn/version "1.12.0"}, + com.aayushatharva.brotli4j/native-osx-x86_64 {:mvn/version "1.12.0"}, + com.aayushatharva.brotli4j/native-windows-x86_64 + {:mvn/version "1.12.0"}, + com.github.luben/zstd-jni {:mvn/version "1.5.5-7"}}, :aliases {:lein2deps {:deps diff --git a/project.clj b/project.clj index 8c4aa471..641720c6 100644 --- a/project.clj +++ b/project.clj @@ -27,41 +27,41 @@ [io.netty/netty-handler-proxy ~netty-version] [io.netty/netty-resolver ~netty-version] [io.netty/netty-resolver-dns ~netty-version] - [metosin/malli "0.10.4" :exclusions [org.clojure/clojure]]] - :profiles {:dev {:dependencies [[criterium "0.4.6"] - [cheshire "5.10.0"] - [org.slf4j/slf4j-simple "1.7.30"] - [com.cognitect/transit-clj "1.0.324"] - [spootnik/signal "0.2.4"] - ;; This is for dev and testing ONLY, not recommended for prod - [org.bouncycastle/bcprov-jdk18on "1.75"] - [org.bouncycastle/bcpkix-jdk18on "1.75"] - ;;[org.bouncycastle/bctls-jdk18on "1.75"] - [io.netty/netty-tcnative-boringssl-static "2.0.61.Final"] - ;;[com.aayushatharva.brotli4j/all ~brotli-version] - [com.aayushatharva.brotli4j/brotli4j ~brotli-version] - [com.aayushatharva.brotli4j/service ~brotli-version] - [com.aayushatharva.brotli4j/native-linux-aarch64 ~brotli-version] - [com.aayushatharva.brotli4j/native-linux-armv7 ~brotli-version] - [com.aayushatharva.brotli4j/native-linux-x86_64 ~brotli-version] - [com.aayushatharva.brotli4j/native-osx-aarch64 ~brotli-version] - [com.aayushatharva.brotli4j/native-osx-x86_64 ~brotli-version] - [com.aayushatharva.brotli4j/native-windows-x86_64 ~brotli-version] - [com.github.luben/zstd-jni "1.5.5-7"]] - :jvm-opts ["-Dorg.slf4j.simpleLogger.defaultLogLevel=debug" - "-Dorg.slf4j.simpleLogger.showThreadName=false" - "-Dorg.slf4j.simpleLogger.showThreadId=true" - "-Dorg.slf4j.simpleLogger.showLogName=false" - "-Dorg.slf4j.simpleLogger.showShortLogName=true" - "-Dorg.slf4j.simpleLogger.showDateTime=true" - "-Dorg.slf4j.simpleLogger.log.io.netty.util=error" - "-Dorg.slf4j.simpleLogger.log.io.netty.channel=warn"]} - :test {:jvm-opts ["-Dorg.slf4j.simpleLogger.defaultLogLevel=off"]} + [metosin/malli "0.10.4" :exclusions [org.clojure/clojure]] + ;;[com.aayushatharva.brotli4j/all ~brotli-version] + [com.aayushatharva.brotli4j/brotli4j ~brotli-version] + [com.aayushatharva.brotli4j/service ~brotli-version] + [com.aayushatharva.brotli4j/native-linux-aarch64 ~brotli-version] + [com.aayushatharva.brotli4j/native-linux-armv7 ~brotli-version] + [com.aayushatharva.brotli4j/native-linux-x86_64 ~brotli-version] + [com.aayushatharva.brotli4j/native-osx-aarch64 ~brotli-version] + [com.aayushatharva.brotli4j/native-osx-x86_64 ~brotli-version] + [com.aayushatharva.brotli4j/native-windows-x86_64 ~brotli-version] + [com.github.luben/zstd-jni "1.5.5-7"]] + :profiles {:dev {:dependencies [[criterium "0.4.6"] + [cheshire "5.10.0"] + [org.slf4j/slf4j-simple "1.7.30"] + [com.cognitect/transit-clj "1.0.324"] + [spootnik/signal "0.2.4"] + ;; This is for dev and testing ONLY, not recommended for prod + [org.bouncycastle/bcprov-jdk18on "1.75"] + [org.bouncycastle/bcpkix-jdk18on "1.75"] + ;;[org.bouncycastle/bctls-jdk18on "1.75"] + [io.netty/netty-tcnative-boringssl-static "2.0.61.Final"]] + :jvm-opts ["-Dorg.slf4j.simpleLogger.defaultLogLevel=debug" + "-Dorg.slf4j.simpleLogger.showThreadName=false" + "-Dorg.slf4j.simpleLogger.showThreadId=true" + "-Dorg.slf4j.simpleLogger.showLogName=false" + "-Dorg.slf4j.simpleLogger.showShortLogName=true" + "-Dorg.slf4j.simpleLogger.showDateTime=true" + "-Dorg.slf4j.simpleLogger.log.io.netty.util=error" + "-Dorg.slf4j.simpleLogger.log.io.netty.channel=warn"]} + :test {:jvm-opts ["-Dorg.slf4j.simpleLogger.defaultLogLevel=off"]} :leak-level-paranoid {:jvm-opts ["-Dio.netty.leakDetectionLevel=PARANOID"]} - :pedantic {:pedantic? :abort} - :trace {:jvm-opts ["-Dorg.slf4j.simpleLogger.defaultLogLevel=trace"]} - :profile {:dependencies [[com.clojure-goes-fast/clj-async-profiler "1.1.1"]] - :jvm-opts ["-Djdk.attach.allowAttachSelf"]}} + :pedantic {:pedantic? :abort} + :trace {:jvm-opts ["-Dorg.slf4j.simpleLogger.defaultLogLevel=trace"]} + :profile {:dependencies [[com.clojure-goes-fast/clj-async-profiler "1.1.1"]] + :jvm-opts ["-Djdk.attach.allowAttachSelf"]}} :java-source-paths ["src-java"] :test-selectors {:default #(not (some #{:benchmark :stress} diff --git a/src-java/aleph/http/AlephCompressionOptions.java b/src-java/aleph/http/AlephCompressionOptions.java deleted file mode 100644 index a5f2fe5e..00000000 --- a/src-java/aleph/http/AlephCompressionOptions.java +++ /dev/null @@ -1,42 +0,0 @@ -package aleph.http; - -import io.netty.handler.codec.compression.BrotliOptions; -import io.netty.handler.codec.compression.DeflateOptions; -import io.netty.handler.codec.compression.GzipOptions; -import io.netty.handler.codec.compression.SnappyOptions; -import io.netty.handler.codec.compression.StandardCompressionOptions; -import io.netty.handler.codec.compression.ZstdOptions; - -/** - * {@link AlephCompressionOptions} exists because the Clojure compiler cannot - * distinguish between static fields and static methods without reflection. - * - * This is a problem when using Netty's StandardCompressionOptions, because - * reflection triggers a load of all the methods referencing optional classes, - * which may not exist in the classpath, resulting in a ClassNotFoundException. - */ -public class AlephCompressionOptions { - private AlephCompressionOptions() { - // Prevent outside initialization - } - - public static BrotliOptions brotli() { - return StandardCompressionOptions.brotli(); - } - - public static ZstdOptions zstd() { - return StandardCompressionOptions.zstd(); - } - - public static SnappyOptions snappy() { - return StandardCompressionOptions.snappy(); - } - - public static GzipOptions gzip() { - return StandardCompressionOptions.gzip(); - } - - public static DeflateOptions deflate() { - return StandardCompressionOptions.deflate(); - } -} diff --git a/src/aleph/http/compression.clj b/src/aleph/http/compression.clj index 0029ac83..6a465105 100644 --- a/src/aleph/http/compression.clj +++ b/src/aleph/http/compression.clj @@ -1,6 +1,6 @@ (ns ^:no-doc aleph.http.compression - "Currently only for HTTP/2, since Netty offers better support for - compression in HTTP/1 code. + "Currently focused on HTTP/2, since Netty offers better support for + compression in its HTTP/1 code. Best supported compression codecs on the web are Brotli, gzip, and deflate. @@ -8,8 +8,8 @@ open-source databases. It's not on track to be a web standard, but is well-supported by Netty. - Zstd is a Facebook codec that is registered with IANA, but is not yet - widely available. (See https://caniuse.com/zstd). + Zstd is a promising Facebook codec that is registered with IANA, but is not + yet widely available. (See https://caniuse.com/zstd). See https://www.iana.org/assignments/http-parameters/http-parameters.xml#content-coding" (:require @@ -17,15 +17,17 @@ [clj-commons.primitive-math :as p] [clojure.tools.logging :as log]) (:import - (aleph.http AlephCompressionOptions) (io.netty.channel ChannelHandler) (io.netty.handler.codec.compression Brotli - BrotliOptions CompressionOptions + BrotliOptions + CompressionOptions DeflateOptions GzipOptions SnappyOptions - Zstd ZstdOptions) + StandardCompressionOptions + Zstd + ZstdOptions) (io.netty.handler.codec.http HttpHeaderNames) (io.netty.handler.codec.http2 Http2HeadersFrame) (io.netty.util AsciiString) @@ -36,6 +38,10 @@ (def ^:private ^AsciiString head-method (AsciiString. "HEAD")) (def ^:private ^AsciiString connect-method (AsciiString. "CONNECT")) +;; From 0.7.0-rc2 on, Brotli and Zstd should be available by default +(Brotli/ensureAvailability) +(Zstd/ensureAvailability) + (defn- contains-class? "Returns true if the class is in the array" [^"[Lio.netty.handler.codec.compression.CompressionOptions;" a ^Class klazz] @@ -51,11 +57,11 @@ available-compressor-options "A Java array of all available compressor options" (into-array CompressionOptions - (cond-> [(AlephCompressionOptions/deflate) - (AlephCompressionOptions/gzip) - (AlephCompressionOptions/snappy)] - (Brotli/isAvailable) (conj (AlephCompressionOptions/brotli)) - (Zstd/isAvailable) (conj (AlephCompressionOptions/zstd))))) + [(StandardCompressionOptions/brotli) + (StandardCompressionOptions/deflate) + (StandardCompressionOptions/gzip) + (StandardCompressionOptions/zstd) + (StandardCompressionOptions/snappy)])) (defn- qvalue @@ -116,12 +122,10 @@ ;; no named encodings were listed, so we'll apply *'s qval to unset ones (p/> star 0.0) - (cond (and (p/== br -1.0) - (Brotli/isAvailable)) + (cond (p/== br -1.0) "br" - (and (p/== zstd -1.0) - (Zstd/isAvailable)) + (p/== zstd -1.0) "zstd" (p/== snappy -1.0) @@ -215,6 +219,7 @@ (p/== 204 status) (p/== 304 status))) (log/debug "Setting content-encoding to:" @encoding) + ;; TODO: add "vary" header (.set headers HttpHeaderNames/CONTENT_ENCODING chosen-encoding)))))) (.write ctx msg promise))))))