From d00705286218a5f501ab18bc8a50ec22f043b8b7 Mon Sep 17 00:00:00 2001
From: rsanchez <rsanchez@curisit.net>
Date: Thu, 08 Jun 2017 17:15:11 +0000
Subject: [PATCH] #0 enh - Gzipping main bundle on the fly

---
 securis/src/main/java/net/curisit/securis/utils/GZipServletResponseWrapper.java |  139 ++++++++++++++++++++++++++++++++++++++++++++++
 securis/src/main/java/net/curisit/securis/GzipFilter.java                       |   29 +++++++--
 securis/src/main/webapp/WEB-INF/web.xml                                         |    2 
 securis/src/main/webapp/index.jsp                                               |    2 
 4 files changed, 163 insertions(+), 9 deletions(-)

diff --git a/securis/src/main/java/net/curisit/securis/GzipFilter.java b/securis/src/main/java/net/curisit/securis/GzipFilter.java
index 6e448d9..4c0682c 100644
--- a/securis/src/main/java/net/curisit/securis/GzipFilter.java
+++ b/securis/src/main/java/net/curisit/securis/GzipFilter.java
@@ -10,13 +10,16 @@
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.annotation.WebFilter;
+import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import net.curisit.securis.utils.GZipServletResponseWrapper;
+
 @ApplicationScoped
-@WebFilter(urlPatterns = "*.gz")
+@WebFilter(urlPatterns = "*.js")
 public class GzipFilter implements Filter {
 
 	@SuppressWarnings("unused")
@@ -27,12 +30,24 @@
 	}
 
 	@Override
-	public void doFilter(ServletRequest sreq, ServletResponse sres, FilterChain fc) throws IOException, ServletException {
-		//HttpServletRequest req = (HttpServletRequest) sreq;
-		HttpServletResponse res = (HttpServletResponse) sres;
-		res.addHeader("Content-Encoding", "gzip");
-		// LOG.info("Content served as gzip: {}", req.getRequestURI());
-		fc.doFilter(sreq, sres);
+	public void doFilter(ServletRequest sreq, ServletResponse sres, FilterChain chain) throws IOException, ServletException {
+		HttpServletRequest httpRequest = (HttpServletRequest) sreq;
+		HttpServletResponse httpResponse = (HttpServletResponse) sres;
+
+		if (acceptsGZipEncoding(httpRequest)) {
+			httpResponse.addHeader("Content-Encoding", "gzip");
+			GZipServletResponseWrapper gzipResponse = new GZipServletResponseWrapper(httpResponse);
+			chain.doFilter(sreq, gzipResponse);
+			gzipResponse.close();
+		} else {
+			chain.doFilter(sreq, sres);
+		}
+	}
+
+	private boolean acceptsGZipEncoding(HttpServletRequest httpRequest) {
+		String acceptEncoding = httpRequest.getHeader("Accept-Encoding");
+
+		return acceptEncoding != null && acceptEncoding.indexOf("gzip") != -1;
 	}
 
 	@Override
diff --git a/securis/src/main/java/net/curisit/securis/utils/GZipServletResponseWrapper.java b/securis/src/main/java/net/curisit/securis/utils/GZipServletResponseWrapper.java
new file mode 100644
index 0000000..331165c
--- /dev/null
+++ b/securis/src/main/java/net/curisit/securis/utils/GZipServletResponseWrapper.java
@@ -0,0 +1,139 @@
+package net.curisit.securis.utils;
+
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.util.zip.GZIPOutputStream;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.WriteListener;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+public class GZipServletResponseWrapper extends HttpServletResponseWrapper {
+
+	private GZIPServletOutputStream gzipOutputStream = null;
+	private PrintWriter printWriter = null;
+
+	public GZipServletResponseWrapper(HttpServletResponse response) throws IOException {
+		super(response);
+	}
+
+	public void close() throws IOException {
+
+		//PrintWriter.close does not throw exceptions.
+		//Hence no try-catch block.
+		if (this.printWriter != null) {
+			this.printWriter.close();
+		}
+
+		if (this.gzipOutputStream != null) {
+			this.gzipOutputStream.close();
+		}
+	}
+
+	/**
+	 * Flush OutputStream or PrintWriter
+	 *
+	 * @throws IOException
+	 */
+
+	@Override
+	public void flushBuffer() throws IOException {
+
+		//PrintWriter.flush() does not throw exception
+		if (this.printWriter != null) {
+			this.printWriter.flush();
+		}
+
+		IOException exception1 = null;
+		try {
+			if (this.gzipOutputStream != null) {
+				this.gzipOutputStream.flush();
+			}
+		} catch (IOException e) {
+			exception1 = e;
+		}
+
+		IOException exception2 = null;
+		try {
+			super.flushBuffer();
+		} catch (IOException e) {
+			exception2 = e;
+		}
+
+		if (exception1 != null)
+			throw exception1;
+		if (exception2 != null)
+			throw exception2;
+	}
+
+	@Override
+	public ServletOutputStream getOutputStream() throws IOException {
+		if (this.printWriter != null) {
+			throw new IllegalStateException("PrintWriter obtained already - cannot get OutputStream");
+		}
+		if (this.gzipOutputStream == null) {
+			this.gzipOutputStream = new GZIPServletOutputStream(getResponse().getOutputStream());
+		}
+		return this.gzipOutputStream;
+	}
+
+	@Override
+	public PrintWriter getWriter() throws IOException {
+		if (this.printWriter == null && this.gzipOutputStream != null) {
+			throw new IllegalStateException("OutputStream obtained already - cannot get PrintWriter");
+		}
+		if (this.printWriter == null) {
+			this.gzipOutputStream = new GZIPServletOutputStream(getResponse().getOutputStream());
+			this.printWriter = new PrintWriter(new OutputStreamWriter(this.gzipOutputStream, getResponse().getCharacterEncoding()));
+		}
+		return this.printWriter;
+	}
+
+	@Override
+	public void setContentLength(int len) {
+		//ignore, since content length of zipped content
+		//does not match content length of unzipped content.
+	}
+
+	private static class GZIPServletOutputStream extends ServletOutputStream {
+		private final ServletOutputStream servletOutputStream;
+		private final GZIPOutputStream gzipStream;
+
+		public GZIPServletOutputStream(ServletOutputStream servletOutputStream) throws IOException {
+			this.servletOutputStream = servletOutputStream;
+			this.gzipStream = new GZIPOutputStream(servletOutputStream);
+		}
+
+		@Override
+		public boolean isReady() {
+			return this.servletOutputStream.isReady();
+		}
+
+		@Override
+		public void setWriteListener(WriteListener writeListener) {
+			this.servletOutputStream.setWriteListener(writeListener);
+		}
+
+		@Override
+		public void write(int b) throws IOException {
+			this.gzipStream.write(b);
+		}
+
+		@Override
+		public void close() throws IOException {
+			this.gzipStream.close();
+		}
+
+		@Override
+		public void flush() throws IOException {
+			this.gzipStream.flush();
+		}
+
+		public void finish() throws IOException {
+			this.gzipStream.finish();
+		}
+	}
+
+}
diff --git a/securis/src/main/webapp/WEB-INF/web.xml b/securis/src/main/webapp/WEB-INF/web.xml
index 1c1c0f5..9e90a78 100644
--- a/securis/src/main/webapp/WEB-INF/web.xml
+++ b/securis/src/main/webapp/WEB-INF/web.xml
@@ -60,7 +60,7 @@
     </filter>    
     <filter-mapping>
         <filter-name>GzipFilter</filter-name>
-        <url-pattern>*.gz</url-pattern>
+        <url-pattern>/main-bundle.js</url-pattern>
     </filter-mapping>
 
 	<filter>
diff --git a/securis/src/main/webapp/index.jsp b/securis/src/main/webapp/index.jsp
index d740a0c..4578432 100644
--- a/securis/src/main/webapp/index.jsp
+++ b/securis/src/main/webapp/index.jsp
@@ -11,7 +11,7 @@
 
     <script src="jspm.browser.js"></script>
     <script src="jspm.config.js"></script>
-    <script src="main-bundle.js.gz"></script>
+    <script src="main-bundle.js"></script>
     <script>
       System.import('src/main.js').catch(function(err){ console.error(err); });
     </script>

--
Gitblit v1.3.2