From 21b457266106b546119eac503bcf5741f7065cf7 Mon Sep 17 00:00:00 2001 From: Jacob Rosenberg Date: Thu, 13 Dec 2012 17:33:29 -0800 Subject: [PATCH 1/3] add gzip support for press files when requested - add Gzip class for compression of strings and inputstreams - modify controller to use gzip when accept-encoding header requests it --- app/controllers/press/Press.java | 19 +++++++++++++++++ app/press/io/Gzip.java | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 app/press/io/Gzip.java diff --git a/app/controllers/press/Press.java b/app/controllers/press/Press.java index dbfaf11..75c1133 100644 --- a/app/controllers/press/Press.java +++ b/app/controllers/press/Press.java @@ -1,6 +1,7 @@ package controllers.press; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; @@ -9,8 +10,10 @@ import org.joda.time.format.DateTimeFormat; import org.joda.time.format.DateTimeFormatter; +import play.Logger; import play.exceptions.UnexpectedException; import play.mvc.Controller; +import play.mvc.Http.Header; import press.CachingStrategy; import press.PluginConfig; import press.ScriptCompressedFileManager; @@ -21,6 +24,7 @@ import press.StyleRequestHandler; import press.io.CompressedFile; import press.io.FileIO; +import press.io.Gzip; public class Press extends Controller { public static final DateTimeFormatter httpDateTimeFormatter = DateTimeFormat @@ -80,6 +84,21 @@ private static void renderCompressedFile(CompressedFile compressedFile, String t } } + // attempt gzip if the client requests it. + // + Header encodings = request.headers.get("accept-encoding"); + + if ((encodings != null) && (encodings.value().indexOf("gzip") != -1)) { + try { + ByteArrayOutputStream gzip = Gzip.gzip(inputStream); + response.setHeader("Content-Encoding", "gzip"); + response.setHeader("Content-Length", gzip.size() + ""); + renderBinary(new ByteArrayInputStream(gzip.toByteArray()), compressedFile.name()); + } catch (IOException e) { + Logger.error(e, "Unable to compress output: %s", e.getMessage()); + } + } + renderBinary(inputStream, compressedFile.name()); } diff --git a/app/press/io/Gzip.java b/app/press/io/Gzip.java new file mode 100644 index 0000000..35f8144 --- /dev/null +++ b/app/press/io/Gzip.java @@ -0,0 +1,36 @@ +package press.io; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import java.util.zip.GZIPOutputStream; + +public class Gzip { + + public static ByteArrayOutputStream gzip(final InputStream inputStream) + throws IOException + { + final ByteArrayOutputStream stringOutputStream = new ByteArrayOutputStream(); + final OutputStream gzipOutputStream = new GZIPOutputStream(stringOutputStream); + + final byte[] buf = new byte[5000]; + int len; + while ((len = inputStream.read(buf)) > 0) { + gzipOutputStream.write(buf, 0, len); + } + + inputStream.close(); + gzipOutputStream.close(); + + return stringOutputStream; + + } + + public static ByteArrayOutputStream gzip(final String input) + throws IOException { + return gzip(new ByteArrayInputStream(input.getBytes())); + } +} From 3c68ab55ca40511c7bd448e48f196058adc6d861 Mon Sep 17 00:00:00 2001 From: Jacob Rosenberg Date: Thu, 13 Dec 2012 17:46:27 -0800 Subject: [PATCH 2/3] add config variable to control gzip (default off) --- app/controllers/press/Press.java | 4 +++- app/press/PluginConfig.java | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/controllers/press/Press.java b/app/controllers/press/Press.java index 75c1133..e6c9c9b 100644 --- a/app/controllers/press/Press.java +++ b/app/controllers/press/Press.java @@ -88,7 +88,9 @@ private static void renderCompressedFile(CompressedFile compressedFile, String t // Header encodings = request.headers.get("accept-encoding"); - if ((encodings != null) && (encodings.value().indexOf("gzip") != -1)) { + if (PluginConfig.gzipEnabled && + (encodings != null) && + (encodings.value().indexOf("gzip") != -1)) { try { ByteArrayOutputStream gzip = Gzip.gzip(inputStream); response.setHeader("Content-Encoding", "gzip"); diff --git a/app/press/PluginConfig.java b/app/press/PluginConfig.java index 80c4967..cb4b56f 100644 --- a/app/press/PluginConfig.java +++ b/app/press/PluginConfig.java @@ -48,6 +48,9 @@ public static class DefaultConfig { // compiled, they will be output raw. public static final boolean outputRawLess = false; + // If enabled, turns on gzip when the client supports it + public static final boolean gzipEnabled = false; + public static class js { // The directory where source javascript files are read from public static final String srcDir = "/public/javascripts/"; @@ -85,6 +88,7 @@ public static class css { public static String contentHostingDomain; public static String p3pHeader; public static boolean outputRawLess; + public static boolean gzipEnabled; public static class js { public static String srcDir = DefaultConfig.js.srcDir; @@ -134,6 +138,7 @@ public static void readConfig() { DefaultConfig.contentHostingDomain); p3pHeader = ConfigHelper.getString("press.p3pHeader", DefaultConfig.p3pHeader); outputRawLess = ConfigHelper.getBoolean("press.outputRawLess", DefaultConfig.outputRawLess); + gzipEnabled = ConfigHelper.getBoolean("press.gzipEnabled", DefaultConfig.gzipEnabled); css.srcDir = ConfigHelper.getString("press.css.sourceDir", DefaultConfig.css.srcDir); css.compressedDir = ConfigHelper.getString("press.css.outputDir", From 5156bb52b60f384c259e9c333741825946c6eb07 Mon Sep 17 00:00:00 2001 From: Jacob Rosenberg Date: Thu, 27 Jun 2013 15:44:48 -0700 Subject: [PATCH 3/3] adds vary on accept encoding for gzip --- app/controllers/press/Press.java | 8 ++++++++ commands.pyc | Bin 1055 -> 1071 bytes 2 files changed, 8 insertions(+) diff --git a/app/controllers/press/Press.java b/app/controllers/press/Press.java index e6c9c9b..a55e2e5 100644 --- a/app/controllers/press/Press.java +++ b/app/controllers/press/Press.java @@ -84,6 +84,14 @@ private static void renderCompressedFile(CompressedFile compressedFile, String t } } + /* + * google wants this: "Instructs proxy servers to cache two versions + * of the resource: one compressed, and one uncompressed. This helps + * avoid issues with public proxies that do not detect the presence + * of a Content-Encoding header properly." + */ + response.headers.put("Vary", new Header("Vary", "Accept-Encoding")); + // attempt gzip if the client requests it. // Header encodings = request.headers.get("accept-encoding"); diff --git a/commands.pyc b/commands.pyc index 13759ef257bcb4aab4b0941ebf6eef1ce91d805b..789604221dab1c4071b83763269cedbdab6822c1 100644 GIT binary patch literal 1071 zcmcIiOHaZ;5S~6jUdD?@V?6dEy&GdNVkAKd*~*1mVV4>nE$J4~1ik35^Y8cvoEd0H zgcHOzGdr`pGy8orWBnYL&ZFII7?S2t%@U=xE@#%&vzkm|eu7R-lqQOPLbU`K@e`j0yc?No0=Z`9TI^bxYqM*^ z5+UVaY(mljnTLl)#E^aG2orlL=|Mc529ZoHw1e3!wP{U4%^NCu`3q80(8ooC06SC* zz8I?1A>>SMO!0!w1ThhmT2NjGWu^2bT5eaXM7yIT)+*|&By{WXBAUd3)GimuU4zrr z*&BmZuWB$)RS|=Ag_0R3tKX~`+tsV#g+r=`&Gng;x04JLB+`6GP;YnM!~MNUQ_{W~ z#)&#bOBX2Dn)5c_HXa_rcQY+b$OeS~?4-|akJN%^K>TwVD19(YRdR;LR_DFd=n>Rb zyWV}gPpM9K?N;m7tNVfmR?v=!sQ zfEwYV#5OZKv%53<-pstd7xR1jZ`BUWKY?o*#gtGffEH>2JpnBN%7Pc%u|U~u*q|IX z98ei(cv%cdGpOQ38)FI!>)=KYhY>$Prxr>T#ayA90`&QbX9165;aWhhwQy~A?S<>G z>%bHtW#HC=$OWOYa9#-o8h}tXFm;fU?nI+eJ5;HSb~}z!ht{NLcteMipD+ytJ?&Nq zvPae6i#?rsgq`UPC|=T;BrcLtOUmn^%#