From 93d491445a958a47a085eb26705bdc81bd106e2a Mon Sep 17 00:00:00 2001 From: Liam Date: Sun, 2 Jun 2024 10:20:10 +0100 Subject: [PATCH] add html compression --- pom.xml | 5 + .../backend/filter/HtmlCompressionFilter.java | 98 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 src/main/java/cc/fascinated/backend/filter/HtmlCompressionFilter.java diff --git a/pom.xml b/pom.xml index 78ec5f3..852ef52 100644 --- a/pom.xml +++ b/pom.xml @@ -77,6 +77,11 @@ 3.14.0 compile + + com.googlecode.htmlcompressor + htmlcompressor + 1.5.2 + diff --git a/src/main/java/cc/fascinated/backend/filter/HtmlCompressionFilter.java b/src/main/java/cc/fascinated/backend/filter/HtmlCompressionFilter.java new file mode 100644 index 0000000..71ea391 --- /dev/null +++ b/src/main/java/cc/fascinated/backend/filter/HtmlCompressionFilter.java @@ -0,0 +1,98 @@ +package cc.fascinated.backend.filter; + +import com.googlecode.htmlcompressor.compressor.HtmlCompressor; +import jakarta.servlet.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; +import org.springframework.stereotype.Component; + +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.PrintWriter; + +/** + * Filter to compress HTML responses using HtmlCompressor. + * Author: Fascinated (fascinated7) + */ +@Component +public class HtmlCompressionFilter implements Filter { + private final HtmlCompressor htmlCompressor = new HtmlCompressor(); + + /** + * Applies the HTML compression filter. + * + * @param request the ServletRequest + * @param response the ServletResponse + * @param chain the FilterChain + * @throws ServletException if an error occurs during filtering + * @throws IOException if an input or output error occurs + */ + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws ServletException, IOException { + + ServletResponse newResponse = response; + + // Wrap the response to capture the output + if (request instanceof HttpServletRequest) { + newResponse = new CharResponseWrapper((HttpServletResponse) response); + } + + // Pass the request and response along the filter chain + chain.doFilter(request, newResponse); + + // Compress the captured response if it was wrapped + if (newResponse instanceof CharResponseWrapper) { + String responseContent = newResponse.toString(); + if (responseContent != null) { + response.getWriter().write(htmlCompressor.compress(responseContent)); + } + } + } + + /** + * Wrapper for HttpServletResponse to capture the output for compression. + */ + private static class CharResponseWrapper extends HttpServletResponseWrapper { + private final CharArrayWriter charWriter = new CharArrayWriter(); + private PrintWriter writer; + private boolean getOutputStreamCalled; + private boolean getWriterCalled; + + /** + * Constructor to wrap the response. + * @param response the original HttpServletResponse + */ + public CharResponseWrapper(HttpServletResponse response) { + super(response); + } + + @Override + public ServletOutputStream getOutputStream() throws IOException { + if (getWriterCalled) { + throw new IllegalStateException("getWriter already called"); + } + getOutputStreamCalled = true; + return super.getOutputStream(); + } + + @Override + public PrintWriter getWriter() { + if (writer != null) { + return writer; + } + if (getOutputStreamCalled) { + throw new IllegalStateException("getOutputStream already called"); + } + getWriterCalled = true; + writer = new PrintWriter(charWriter); + return writer; + } + + @Override + public String toString() { + return (writer != null) ? charWriter.toString() : null; + } + } +}