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;
+ }
+ }
+}