Last active
April 2, 2021 10:31
-
-
Save Crydust/7e4e9228cd95febccdc58f0501c1e327 to your computer and use it in GitHub Desktop.
HTTPServer post-process filter (written as answer to https://stackoverflow.com/q/14592299/11451)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package spike; | |
import com.sun.net.httpserver.Filter; | |
import com.sun.net.httpserver.HttpHandler; | |
import com.sun.net.httpserver.HttpServer; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import java.net.InetSocketAddress; | |
import java.nio.charset.StandardCharsets; | |
import java.util.List; | |
import static java.util.Arrays.asList; | |
public class App { | |
private static final String VERY_LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse at lacinia diam. Donec aliquam risus ut ante consequat venenatis. Mauris tempus nulla vel lorem maximus, sed euismod sapien sollicitudin. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas volutpat sem odio, in eleifend enim finibus nec. Vivamus in velit sapien. Quisque ac mattis lorem. Curabitur at libero nec lectus hendrerit bibendum hendrerit sed dolor. Cras in ex et purus lobortis tempor eget molestie risus. Integer in libero non urna elementum gravida.\n" + | |
"\n" + | |
"Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Phasellus eu gravida sem. Curabitur interdum risus nibh, interdum tempor est lacinia sed. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum euismod pretium tristique. Fusce scelerisque vitae urna eget molestie. Nullam ut diam scelerisque, convallis felis vel, luctus velit. Aenean vestibulum tincidunt erat eget tempor. Suspendisse placerat vulputate diam, id facilisis velit varius vel. Sed viverra porttitor urna non suscipit.\n" + | |
"\n" + | |
"Suspendisse dictum leo ullamcorper tellus fermentum lacinia. Integer bibendum ultrices elit, ut ultricies lacus aliquam id. Sed iaculis metus eget tortor molestie, ac luctus nulla facilisis. Pellentesque eleifend turpis elit, eget scelerisque arcu porta at. Nulla in tempus ipsum. Cras vel dictum sem. Sed mollis massa et tortor dictum, sed volutpat odio fringilla.\n" + | |
"\n" + | |
"Aenean sit amet ex metus. Aliquam erat volutpat. Nunc justo libero, condimentum vel tristique ac, malesuada eu eros. Sed viverra vehicula mi quis egestas. Suspendisse quis consectetur neque. Nulla tortor ipsum, volutpat ut erat non, pretium maximus velit. Etiam finibus volutpat viverra. Integer eget molestie tellus. Cras ut malesuada nisi. In pharetra a sem quis egestas. Nam congue metus sed ultrices dictum. Nullam dignissim lobortis dolor quis fringilla.\n" + | |
"\n" + | |
"Sed vestibulum eros ut mauris elementum rutrum. Nunc ullamcorper tortor vel dolor varius, mollis iaculis quam congue. Vestibulum id urna nec mauris fermentum commodo. Vivamus tellus felis, convallis et eros id, viverra semper nisi. Fusce convallis mattis ante. Nulla pulvinar arcu purus, in tincidunt nibh ullamcorper sed. Nullam aliquet consequat arcu, non maximus nulla tincidunt scelerisque. Pellentesque mollis lacinia purus. Aliquam sodales mi id odio maximus faucibus. Sed non enim eu tortor rutrum aliquam in quis justo. Pellentesque ut magna in turpis eleifend bibendum ut a diam. Suspendisse varius, augue vel pharetra egestas, urna enim condimentum tortor, ultrices facilisis dui enim at nibh. Ut in nisl eu magna rutrum maximus."; | |
public static void main(String[] args) throws IOException, InterruptedException { | |
HttpServer hs = createServer(); | |
Thread.sleep(60_000L); | |
hs.stop(0); | |
} | |
private static HttpServer createServer() throws IOException { | |
List<Filter> filters = asList(new GzipFilter()); | |
HttpServer hs = HttpServer.create(new InetSocketAddress("127.0.0.1", 8080), 0); | |
hs.createContext("/", text(VERY_LONG_TEXT)).getFilters().addAll(filters); | |
hs.start(); | |
return hs; | |
} | |
private static HttpHandler text(String body) { | |
byte[] bodyBytes = body.getBytes(StandardCharsets.UTF_8); | |
int responseLength = bodyBytes.length; | |
return he -> { | |
try { | |
he.getResponseHeaders().add("Content-Type", "text/plain; charset=UTF-8"); | |
he.sendResponseHeaders(200, responseLength); | |
try (OutputStream out = he.getResponseBody()) { | |
out.write(bodyBytes); | |
} | |
} catch (IOException e) { | |
throw new RuntimeException(e); | |
} | |
}; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package spike; | |
import com.sun.net.httpserver.Headers; | |
import com.sun.net.httpserver.HttpContext; | |
import com.sun.net.httpserver.HttpExchange; | |
import com.sun.net.httpserver.HttpPrincipal; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.io.OutputStream; | |
import java.net.InetSocketAddress; | |
import java.net.URI; | |
class ForwardingHttpExchange extends HttpExchange { | |
private final HttpExchange inner; | |
ForwardingHttpExchange(HttpExchange inner) { | |
this.inner = inner; | |
} | |
@Override | |
public Headers getRequestHeaders() { | |
return inner.getRequestHeaders(); | |
} | |
@Override | |
public Headers getResponseHeaders() { | |
return inner.getResponseHeaders(); | |
} | |
@Override | |
public URI getRequestURI() { | |
return inner.getRequestURI(); | |
} | |
@Override | |
public String getRequestMethod() { | |
return inner.getRequestMethod(); | |
} | |
@Override | |
public HttpContext getHttpContext() { | |
return inner.getHttpContext(); | |
} | |
@Override | |
public void close() { | |
inner.close(); | |
} | |
@Override | |
public InputStream getRequestBody() { | |
return inner.getRequestBody(); | |
} | |
@Override | |
public OutputStream getResponseBody() { | |
return inner.getResponseBody(); | |
} | |
@Override | |
public void sendResponseHeaders(int rCode, long responseLength) throws IOException { | |
inner.sendResponseHeaders(rCode, responseLength); | |
} | |
@Override | |
public InetSocketAddress getRemoteAddress() { | |
return inner.getRemoteAddress(); | |
} | |
@Override | |
public int getResponseCode() { | |
return inner.getResponseCode(); | |
} | |
@Override | |
public InetSocketAddress getLocalAddress() { | |
return inner.getLocalAddress(); | |
} | |
@Override | |
public String getProtocol() { | |
return inner.getProtocol(); | |
} | |
@Override | |
public Object getAttribute(String name) { | |
return inner.getAttribute(name); | |
} | |
@Override | |
public void setAttribute(String name, Object value) { | |
inner.setAttribute(name, value); | |
} | |
@Override | |
public void setStreams(InputStream i, OutputStream o) { | |
inner.setStreams(i, o); | |
} | |
@Override | |
public HttpPrincipal getPrincipal() { | |
return inner.getPrincipal(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package spike; | |
import com.sun.net.httpserver.Filter; | |
import com.sun.net.httpserver.HttpExchange; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import java.util.List; | |
import java.util.regex.Pattern; | |
import java.util.zip.GZIPOutputStream; | |
import static java.util.Arrays.asList; | |
import static java.util.Objects.requireNonNullElse; | |
final class GzipFilter extends Filter { | |
private static final Pattern COMMA_PATTERN = Pattern.compile("\\s*,\\s*"); | |
@Override | |
public void doFilter(HttpExchange exchange, Chain chain) throws IOException { | |
final String acceptEncoding = exchange.getRequestHeaders().getFirst("Accept-Encoding"); | |
final List<String> acceptEncodings = asList(COMMA_PATTERN.split(requireNonNullElse(acceptEncoding, ""))); | |
chain.doFilter( | |
acceptEncodings.contains("gzip") | |
? new GzipHttpExchange(exchange) | |
: exchange | |
); | |
} | |
@Override | |
public String description() { | |
return "GzipFilter"; | |
} | |
private static class GzipHttpExchange extends ForwardingHttpExchange { | |
private GZIPOutputStream wrappedResponseBody = null; | |
GzipHttpExchange(HttpExchange inner) { | |
super(inner); | |
} | |
@Override | |
public OutputStream getResponseBody() { | |
return wrappedResponseBody != null | |
? wrappedResponseBody | |
: super.getResponseBody(); | |
} | |
@Override | |
public void sendResponseHeaders(int rCode, long responseLength) throws IOException { | |
getResponseHeaders().add("Vary", "Accept-Encoding"); | |
if (responseLength >= 0) { | |
getResponseHeaders().add("Content-Encoding", "gzip"); | |
super.sendResponseHeaders(rCode, 0); | |
wrappedResponseBody = new GZIPOutputStream(super.getResponseBody()); | |
return; | |
} | |
super.sendResponseHeaders(rCode, responseLength); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment