Skip to content

Instantly share code, notes, and snippets.

@suprememoocow
Created January 6, 2012 13:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save suprememoocow/1570654 to your computer and use it in GitHub Desktop.
Save suprememoocow/1570654 to your computer and use it in GitHub Desktop.
PrecompressedStaticServlet: serves pre-compressed resource files from an Http Servlet container if they exist.
<web-app>
<!-- ... -->
<servlet>
<servlet-name>compressionHandlingDefaultServlet</servlet-name>
<servlet-class>com.barclayswealth.fsvoc.presentation.PrecompressedStaticServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>compressionHandlingDefaultServlet</servlet-name>
<url-pattern>/js/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>compressionHandlingDefaultServlet</servlet-name>
<url-pattern>/css/*</url-pattern>
</servlet-mapping>
<!-- ... -->
</web-app>
package me.newdigate.http;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
* Web optimization tools recommend using compression to minimize payloads when sending content over HTTP. A common
* technique employed by Java developers is to install a ServletFilter to compress all outgoing files. While this
* technique may work well for dynamically generated content, it is very CPU-inefficient for static content.
*
* This servlet is designed to serve static resources that have been precompressed during the build process. If you are
* using Maven, the yuicompressor-maven-plugin plugin can gzip javascript files while minifying them. Another option is
* to use ant and the gzip task.
*
* The servlet kicks in when the following criteria are fulfilled:
* <ul>
* <li>The incoming http request is a GET</li>
* <li>The requested file name ends with .js or .css</li>
* <li>The Accept-Encoding header includes 'gzip'</li>
* <li>A file with a matching name and the suffix '.gz' exists in the same directory as the file being requested.</li>
* </ul>
*
* If this is the case, the request is forwarded to the default dispatcher for the '.gz' file. If this is not the case,
* the original request is forwarded to the default dispatcher.
*
* In either case the default servlet container dispatcher transmits the file, ensuring the any optimisations that are
* used for effiecent file transfer are maintained.
*
* @author Andrew Newdigate
*/
public class PrecompressedStaticServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private RequestDispatcher defaultServlet;
@Override
public void init() throws ServletException {
super.init();
defaultServlet = getServletContext().getNamedDispatcher("default");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (requestIsElligibleForCompressedSend(request)) {
String gzPath = getRelativePath(request) + ".gz";
String mimeType = getMimeType(request);
response.setContentType(mimeType);
response.setHeader("Content-Encoding", "gzip");
response.setHeader("Vary", "Accept-Encoding");
request.getRequestDispatcher(gzPath)
.forward(request, responseWrapper(response, "Content-Type", "Content-Encoding", "Vary"));
} else {
defaultServlet.forward(request, response);
}
}
private boolean requestIsElligibleForCompressedSend(HttpServletRequest request) throws MalformedURLException {
if (!matchingExtension(request.getRequestURI())) {
return false;
}
String acceptEncoding = request.getHeader("Accept-Encoding");
if (acceptEncoding == null) {
return false;
}
if (!acceptEncoding.contains("gzip")) {
return false;
}
String gzPath = getRelativePath(request) + ".gz";
URL compressedUrl = getServletContext().getResource(gzPath);
return compressedUrl != null;
}
protected String getMimeType(HttpServletRequest request) {
String mimeType = getServletContext().getMimeType(request.getRequestURI());
return mimeType;
}
protected String getRelativePath(HttpServletRequest request) {
String requestUri = request.getRequestURI();
String contextPath = request.getContextPath();
if (contextPath == null || contextPath.isEmpty()) {
return requestUri;
}
String relativeToContext = requestUri.substring(contextPath.length());
return relativeToContext;
}
protected boolean matchingExtension(String requestUri) {
return requestUri.endsWith(".js") || requestUri.endsWith(".css");
}
protected HttpServletResponse responseWrapper(HttpServletResponse response, final String... headersToIgnore) {
final Set<String> headers = new HashSet<String>(Arrays.asList(headersToIgnore));
return new HttpServletResponseWrapper(response) {
@Override
public void setHeader(String name, String value) {
if (headers.contains(name)) {
return;
}
super.setHeader(name, value);
}
@Override
public void setDateHeader(String name, long date) {
if (headers.contains(name)) {
return;
}
super.setDateHeader(name, date);
}
@Override
public void setIntHeader(String name, int value) {
if (headers.contains(name)) {
return;
}
super.setIntHeader(name, value);
}
@Override
public void addDateHeader(String name, long date) {
if (headers.contains(name)) {
return;
}
super.addDateHeader(name, date);
}
@Override
public void addHeader(String name, String value) {
if (headers.contains(name)) {
return;
}
super.addHeader(name, value);
}
@Override
public void addIntHeader(String name, int value) {
if (headers.contains(name)) {
return;
}
super.addIntHeader(name, value);
}
@Override
public void setContentType(String type) {
if (headers.contains("Content-Type")) {
return;
}
super.setContentType(type);
}
};
}
}
@suprememoocow
Copy link
Author

Web optimization tools recommend using compression to minimize payloads when sending content over HTTP. A common
technique employed by Java developers is to install a ServletFilter to compress all outgoing files. While this
technique may work well for dynamically generated content, it is very CPU-inefficient for static content.

This java http servlet is designed to serve static resources that have been precompressed during the build process. If you are
using Maven, the yuicompressor-maven-plugin can gzip javascript files while minifying them. Another option is
to use ant and the gzip task.

The servlet kicks in when the following criteria are fulfilled:

  • The incoming http request is a GET
  • The requested file name ends with .js or .css
  • The Accept-Encoding header includes 'gzip'
  • A file with a matching name and the suffix '.gz' exists in the same directory as the file being requested.

If this is the case, the request is forwarded to the default dispatcher for the '.gz' file. If this is not the case, the original request is forwarded to the default dispatcher.

In either case the default servlet container dispatcher transmits the file, ensuring the any optimisations that are used for effiecent file transfer are maintained.

@afattahi54
Copy link

Very helpfull !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment