4
votes

I use Jetty9 and I want to test if compressing text files will increase performance. At first I'm interested in serving off-line compressed files just like it is described at: http://marianoguerra.org/posts/201205enable-gzip-compression-in-jetty.html

My code looks like:

static private void set_jetty_handlers(Server server)
    {
    // gzip: I have added it to to serve off-line compressed JavaScript, CSS etc.
    // as described at: http://marianoguerra.org/posts/201205enable-gzip-compression-in-jetty.html
    ServletHolder servletHolder = new ServletHolder(new DefaultServlet());
    servletHolder.setInitParameter("gzip", "true");
    ServletContextHandler s_context_handler = new ServletContextHandler();
    s_context_handler.addServlet(servletHolder,"/*");

    ResourceHandler resource_handler = new ResourceHandler();
    resource_handler.setDirectoriesListed(false);
    resource_handler.setWelcomeFiles(new String[] {"index.html"});
    resource_handler.setResourceBase("");
    resource_handler.setCacheControl(MAX_AGE);

    // gzip: I have added it to to serve offline compressed JavaScript, CSS etc.
    resource_handler.setHandler(s_context_handler);

    // I want to work with aliases (links and symbolic links)
    ContextHandler context_handler = new ContextHandler();
    context_handler.addAliasCheck(new ContextHandler.ApproveAliases());

    HandlerList handlers = new HandlerList();
    handlers.setHandlers(new Handler[] { new my_jetty_handler(), resource_handler, new DefaultHandler() });
    context_handler.setHandler(handlers);

    server.setHandler(context_handler);
    configureThreadPool(server);
    } // set_jetty_handlers

But when I compressed test.html into test.html.gz then I got HTTP ERROR: 404. Lines I added to enable gzip compression are tagged with gzip: in comment.

I have also found that older version of Jetty had ResourceHandler.setMinGzipLength(). It is not available in current Jetty version but from documentation it does what I want.

How to enable gzip compression? At first I want to test static files compression, but after those tests I want to apply GzipFilter in my my_jetty_handler() that serves dynamic content and is also unclear how to do it from Java code.

2

2 Answers

5
votes

I can add gzip compression for my handlers by:

GzipHandler gzipHandlerRES = new GzipHandler();
gzipHandlerRES.setMimeTypes("text/html,text/plain,text/xml,text/css,application/javascript,text/javascript");
gzipHandlerRES.setHandler(resource_handler);

It cannot work with offline compressed files (request for test.html should serve test.html.gz).

1
votes

You have a mix of behavior, and a broken understanding of how contexts work.

First, the example:

package jetty;

import java.util.EnumSet;

import javax.servlet.DispatcherType;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlets.GzipFilter;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jetty.util.thread.ThreadPool;

public class GzipExample
{
    public static void main(String[] args)
    {
        ThreadPool threadPool = new QueuedThreadPool();
        Server server = new Server(threadPool);
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(8080);
        server.addConnector(connector);

        ServletContextHandler context = new ServletContextHandler();
        context.setContextPath("/");
        // Welcome files are part of the context
        context.setWelcomeFiles(new String[] { "index.html" });
        // Add alias check logic to context
        context.addAliasCheck(new ContextHandler.ApproveAliases());
        server.setHandler(context);

        // Add dynamic Gzip compression, as a servlet filter
        FilterHolder gzipHolder = context.addFilter(GzipFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
        gzipHolder.setInitParameter("methods","GET,POST");
        // response bytes required before gzip kicks in 
        gzipHolder.setInitParameter("minGzipSize", "256");
        // mime-types to compress (seen as response type)
        gzipHolder.setInitParameter("mimeTypes", "text/plain,text/css,text/html,text/javascript");

        // Add your own servlets here
        context.addServlet(HelloServlet.class,"/hello/*");

        // Lastly, the default servlet for resource base content (serves static files)
        // It is important that this is last.
        ServletHolder defHolder = new ServletHolder("default", DefaultServlet.class);
        // Cannot be null or empty, must be declared, must be a directory, can be a URL to some jar content
        defHolder.setInitParameter("resourceBase","./resource-base/");
        defHolder.setInitParameter("dirAllowed","true");
        defHolder.setInitParameter("gzip", "true");
        defHolder.setInitParameter("otherGzipFileExtensions", ".svgz");
        defHolder.setInitParameter("cacheControl","private, max-age=0, no-cache");
        context.addServlet(defHolder,"/");
    }
}

What's important:

  • ThreadPool is setup and provided to the Server instance, not configured after the fact.
  • ServletContextHandler is your context, it holds the welcome files list, the name of your context path, the alias check, all of your filters and servlets.
  • GzipFilter is the way currently (this is changing in Jetty 9.3.x to a more fundamental gzip handling mechanism that is more resilient to http/2 + async i/o realities) to setup dynamic gzip compression.
  • GzipFilter has configuration for the gzip behavior, including minimum byte threshold for compression, mime-types, etc ...
  • DefaultServlet is the component that serves your static files, including support to serve optionally pre-compressed static files. (eg: client requests /main.css, indicating it is capable of receiving gzip compressed, the default servlet finds /main.css.gz in your resource base and serves it back as-is, to the client requesting /main.css)
  • resourceBase is required for all of this to work, define it.
  • ResourceHandler is super basic, and isn't meant for advanced concepts like gzip, caching, resume, partial/range request, etc...
  • You cannot use Jetty Handlers with gzip compression, that's only implemented as part of the servlet layer. (this will change with the final Jetty 9.3.0 release)