From 4b9618ba33382ce9de215f1f9eae31d91a290442 Mon Sep 17 00:00:00 2001 From: Danny Wilson Date: Thu, 11 Jun 2015 16:57:41 +0200 Subject: [PATCH 1/3] Fix reflection warnings --- project.clj | 2 ++ src/ring/middleware/gzip.clj | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/project.clj b/project.clj index 298603f..ed1797e 100644 --- a/project.clj +++ b/project.clj @@ -3,4 +3,6 @@ user-agents." :url "https://github.com/bertrandk/ring-gzip" :license {:name "MIT-style license (see LICENSE for details)."} + :global-vars {*warn-on-reflection* true} + :profiles {:test {:resource-paths ["test"]}} :dependencies [[org.clojure/clojure "1.5.1"]]) diff --git a/src/ring/middleware/gzip.clj b/src/ring/middleware/gzip.clj index e19d819..fe0900f 100644 --- a/src/ring/middleware/gzip.clj +++ b/src/ring/middleware/gzip.clj @@ -56,7 +56,7 @@ (cond (string? body) (> (count body) min-length) (seq? body) (> (count body) min-length) - (instance? File body) (> (.length body) min-length) + (instance? File body) (> (.length ^File body) min-length) :else true))) (defn- supported-response? @@ -77,7 +77,7 @@ (doseq [string body] (io/copy (str string) out)) (io/copy body out))) (when (instance? Closeable body) - (.close body))) + (.close ^Closeable body))) p-in)) (defn- gzip-response From f448ea7bb461cf52255453eaafacfb23d1706732 Mon Sep 17 00:00:00 2001 From: Danny Wilson Date: Thu, 11 Jun 2015 17:10:58 +0200 Subject: [PATCH 2/3] Implement support for pre-compressed static files --- src/ring/middleware/gzip.clj | 43 ++++++++++++++++++++++++++--- test/ring/middleware/gzip_test.clj | 21 ++++++++++++++ test/text.txt | 1 + test/text.txt.gz | Bin 0 -> 41 bytes 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 test/text.txt create mode 100644 test/text.txt.gz diff --git a/src/ring/middleware/gzip.clj b/src/ring/middleware/gzip.clj index fe0900f..42c7a7a 100644 --- a/src/ring/middleware/gzip.clj +++ b/src/ring/middleware/gzip.clj @@ -6,6 +6,7 @@ File PipedInputStream PipedOutputStream) + (java.net URL) (java.util.zip GZIPOutputStream))) (defn- accepts-gzip? @@ -18,18 +19,22 @@ accepts))) ;; Set Vary to make sure proxies don't deliver the wrong content. -(defn- set-response-headers +(defn- set-encoding-headers [headers] (if-let [vary (get headers "vary")] (-> headers (assoc "Vary" (str vary ", Accept-Encoding")) (assoc "Content-Encoding" "gzip") - (dissoc "Content-Length") (dissoc "vary")) (-> headers (assoc "Vary" "Accept-Encoding") - (assoc "Content-Encoding" "gzip") - (dissoc "Content-Length")))) + (assoc "Content-Encoding" "gzip")))) + +(defn- set-response-headers + [headers] + (-> headers + (set-encoding-headers) + (dissoc "Content-Length"))) (def ^:private supported-status? #{200, 201, 202, 203, 204, 205 403, 404}) @@ -86,6 +91,12 @@ (update-in [:headers] set-response-headers) (update-in [:body] compress-body))) +(defn- gzip-static-response + [resp gzfile] + (-> resp + (update-in [:headers] set-encoding-headers) + (assoc :body gzfile))) + (defn wrap-gzip "Middleware that compresses responses with gzip for supported user-agents." [handler] @@ -96,3 +107,27 @@ (gzip-response resp) resp)) (handler req)))) + +(defn wrap-gzip-static + "Middleware that returns pre-compressed files (if available) for supported user-agents. + + Inspired by the NGiNX module: http://nginx.org/en/docs/http/ngx_http_gzip_static_module.html + + Given a resource or File body + and the same file with .gz appended exists + it will return the .gz one instead." + [handler] + (fn [req] + (let [{body :body :as resp} (handler req) + ^File file (if (instance? File body) + body + (if (instance? URL body) + (try (io/file body) (catch IllegalArgumentException e))))] + (if (and file (accepts-gzip? req)) + (let [gzfile (File. (str file ".gz"))] + (if (.exists gzfile) + (gzip-static-response resp gzfile) + ;else + resp)) + ;else + resp)))) diff --git a/test/ring/middleware/gzip_test.clj b/test/ring/middleware/gzip_test.clj index 14bc4ce..b141b4b 100644 --- a/test/ring/middleware/gzip_test.clj +++ b/test/ring/middleware/gzip_test.clj @@ -140,3 +140,24 @@ resp ((wrap-gzip handler) req)]] (is (= (get-in resp [:headers "Content-Encoding"]) "gzip"))))) + +(deftest test-wrap-gzip-static + (testing "Precompressed static resource file response" + (let [handler (constantly {:status 200 + :headers {} + :body (io/resource "text.txt")}) + req (req :headers {"accept-encoding" "gzip"}) + resp ((wrap-gzip-static handler) req)] + (is (= (get-in resp [:headers "Content-Encoding"]) + "gzip")) + (is (= (.toURI (:body resp)) (.toURI (io/resource "text.txt.gz")))))) + + (testing "Precompressed static file response" + (let [handler (constantly {:status 200 + :headers {} + :body (io/file "test/text.txt")}) + req (req :headers {"accept-encoding" "gzip"}) + resp ((wrap-gzip-static handler) req)] + (is (= (get-in resp [:headers "Content-Encoding"]) + "gzip")) + (is (= (:body resp) (io/file "test/text.txt.gz")))))) \ No newline at end of file diff --git a/test/text.txt b/test/text.txt new file mode 100644 index 0000000..dbb193b --- /dev/null +++ b/test/text.txt @@ -0,0 +1 @@ +Testing 123 diff --git a/test/text.txt.gz b/test/text.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..317761eaf22e25a583508efee6f551ddf1607bfa GIT binary patch literal 41 wcmb2|=HOtQTp7y1T#{N*qE}K;!ocmRt9SB@cesIx(K9B7fBgsZco-NM00C4Cp8x;= literal 0 HcmV?d00001 From 20125d64ea969440aed040bc4ce0b85a850be2f2 Mon Sep 17 00:00:00 2001 From: Danny Wilson Date: Fri, 12 Jun 2015 14:39:42 +0200 Subject: [PATCH 3/3] Allow clients to send multiple Accept headers. (Google pagespeed happens to be such a client.) Fixes: java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to java.lang.CharSequence at clojure.core$re_matcher.invoke (core.clj:4475) clojure.core$re_seq.invoke (core.clj:4500) ring.middleware.gzip$accepts_gzip_QMARK_.invoke (gzip.clj:17) --- src/ring/middleware/gzip.clj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ring/middleware/gzip.clj b/src/ring/middleware/gzip.clj index 42c7a7a..be5182b 100644 --- a/src/ring/middleware/gzip.clj +++ b/src/ring/middleware/gzip.clj @@ -16,7 +16,7 @@ ;; proxies, av software, buggy browsers, etc...) (re-seq #"(gzip\s*,?\s*(gzip|deflate)?|X{4,13}|~{4,13}|\-{4,13})" - accepts))) + (str accepts)))) ;; Set Vary to make sure proxies don't deliver the wrong content. (defn- set-encoding-headers