ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Two Servlet Filters Every Web Application Should Have
Pages: 1, 2, 3

Unfortunately, there is really no good way you can tell if content displayed by your browser was GZIP compressed or not. Part of the process working is that it is unnoticeable if the content was compressed or not. In order to test out the compression, we need to spoof some HTTP requests and see what exactly is returned.



This can be done relatively easily by tossing some code in a JSP; here is such a JSP.

<%@ page import="java.util.*,
                 java.net.*,
                 java.io.*" %>
<%
String url = request.getParameter("url");
if (url != null) {
  URL noCompress = new URL(url);
  HttpURLConnection huc =
   (HttpURLConnection)noCompress.openConnection();
  huc.setRequestProperty("user-agent",
                         "Mozilla(MSIE)");
  huc.connect();
  ByteArrayOutputStream baos =
    new ByteArrayOutputStream();
  InputStream is = huc.getInputStream();
  while(is.read() != -1) {
    baos.write((byte)is.read());
  }
  byte[] b1 = baos.toByteArray();

  URL compress = new URL(url);
  HttpURLConnection hucCompress =
   (HttpURLConnection)noCompress.openConnection();
 hucCompress.setRequestProperty("accept-encoding",
                                 "gzip");
  hucCompress.setRequestProperty("user-agent",
                                 "Mozilla(MSIE)");
  hucCompress.connect();
  ByteArrayOutputStream baosCompress =
    new ByteArrayOutputStream();
  InputStream isCompress =
    hucCompress.getInputStream();
  while(isCompress.read() != -1) {
    baosCompress.write((byte)isCompress.read());
  }
  byte[] b2 = baosCompress.toByteArray();
  request.setAttribute("t1",
                       new Integer(b1.length));
  request.setAttribute("t2",
                       new Integer(b2.length));
}
request.setAttribute("url", url);
%>
<head>
  <title>Cache Test</title>
</head>
<body>
<h1>Cache Test Page</h1>
Enter a URL to test.
<form method="POST">
<input name="url" size="50">
<input type="submit" value="Check URL">
</form>
 <p><b>Testing: ${url}</b></p>
 Request 1: ${t1} bytes<br/>
 Request 2: ${t2} bytes<br/>
 Space saved: ${t1-t2} bytes
   or ${(1-t2/t1)*100}%<br/>
</body>
</html>

Save the above JSP in the same web application, and browse to the page. You will see an HTML form that requests a URL; it will resemble the following:

Figure 2
Figure 2. Blank compression test page

The JSP works by taking a URL and spoofing two HTTP requests to that URL. One request spoofs an HTTP request that doesn't accept GZIP content. The other request spoofs an HTTP request that does accept GZIP-compressed content. Compression is quantified by counting the number of bytes each request returned. If the given URL (i.e., web app) provides support for GZIP compression, the second request should be smaller. Try out the JSP by filling in the form; any URL will do, but something you know has GZIP support is ideal, say http://www.jspbook.com. Here are the results for supplying http://www.jspbook.com as the URL.

Figure 3
Figure 3. Compression test page, using the news page of http://www.jspbook.com

The compression saved just over 60%. That means the compressed content was sent roughly 60% faster to my web browser, allowing it to start rendering the page 60% sooner. The end result is that a user would probably see this page about twice as fast as a non-GZIP-compressed page. However, the benefit is not only on the user's end. The web application sending this page is sitting on a server(s) and that server(s) only has so much bandwidth to work with. Reducing the number of bytes you need to transmit per page also means you can have one server sending out more pages using the same amount of bandwidth. The tradeoff is processing power (running the compression algorithm) versus the number of bytes you need to send to a user. In almost every case, your server will have a far faster processor than a network card, and it is well worth always trying to compress content -- especially if you also cache compressed content (we'll see how to do this a little later).

Compression Filtering Tips

You should almost always try to compress content. Compression is good for the bandwidth of both the end user and your server. However, like most things, it pays to not blindly compress everything your web application produces. Compression works by eliminating redundancies in content. Text content (basically anything a JSP produces) can usually be compressed quite well, but already compressed content (e.g., a JPG image) or randomized content (e.g., anything encrypted) cannot be so easily compressed. In the latter case of already compressed or randomized content, it often does not pay to attempt to apply something such as a GZIP filter. You will spend a noticeable amount of processing power to achieve an unnoticeable amount of compression. For general use, only apply a compression filter to any resources in the web application that are text-producing, namely all JSP and HTML pages. Using the code deploying compression presented by this article is as easy as putting jspbook.jar in a web application's WEB-INF/lib directory and adding the following lines to web.xml.

  <filter>
    <filter-name>Compress</filter-name>
    <filter-class>com.jspbook.GZIPFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>Compress</filter-name>
    <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
  <filter-mapping>
    <filter-name>Compress</filter-name>
    <url-pattern>*.html</url-pattern>
  </filter-mapping>

Not bad at all! Especially considering you can add the given compression filter to just about any web application you have ever made and you will reap the rewards of compression instantly. Note: the given code is completely free for use both commercially and non-commercially, and you need not give any credit or reference to where you got the code. However, if you like how it works, hopefully you will pick up a copy of Servlets and JSP; the J2EE Web Tier and encourage more code like it to be made.

Another point to always remember about compression filters, especially GZIP, is that not all web browsers are able to understand the format. Be sure to always explicitly check, as the above code did, before sending back compressed content. While this may seem intuitive, it is really easy to forget this point when working with more than one filter. For example, next, a cache filter is introduced that keeps a copy of a response so that it can be reused for other users that later request the same resource. If you were to place the cache filter before the compression filter, then you might cache a GZIP-compressed response. Next time someone requested the same resource. the cached copy would be returned by the cache filter -- without performing a check to see if the user supports GZIP compression. Trouble would ensue if the cache filter ended up returning GZIP-compressed content to a browser that didn't understand the GZIP format.

The take-home message is that a GZIP compression filter (or any compression filter, for that matter) is a powerful tool that is easy to use and that you should almost always use. By compressing content, you can optimize the amount of bytes that need be sent across the World Wide Web, resulting in benefits for both your server and the user.

Pages: 1, 2, 3

Next Pagearrow