BACK INDEX EXIT NEXT

The Jetty HTTP Server 

Introduction

This section describes the important concepts in the Jetty HttpServer model.  It should be read by those with an interest in gaining a deeper insight into the Jetty architecture and those considering writing custom handlers.

The Introduction to the HttpServer explained that the server accepts requests and passes them off to handlers for processing but did not elaborate on how this is acheived. This section discusses the server, listener, context and handler entities and the relationships between them.


HttpServer

The org.mortbay.http.HttpServer class provides a linkage between a collection of request listeners and collections of request handlers:
HttpListener n-->1 HttpServer 1-->n HttpContext 1-->n HttpHandler
Diagram: HttpServer relationship model

It is the responsibility of an HttpServer to accept requests received by an HttpListener, and match them to suitable HttpContext(s). It does this by using the host and context path elements from the request. Note that more than one HttpContext might match the request, and in this case, all HttpContexts are tried in the order in which they were registered with the server until the request is marked as having been handled.

The trivial code snippet from the Introduction to the HttpServer can then be represented as:
SocketListener1-->1HttpServer1-->1HttpContext1-->1ResourceHandler
port:8080                        "/"             "./docroot"
Diagram: Trivial file server object relationships

This depicts a single listener on port 8080 passing requests to a single server, which in turn passes them to a single context with a single handler which returns static content from the directory ./docroot .

HttpListener

Implementations of the org.mortbay.http.HttpListener interface are added to a HttpServer and act as sources of requests for the server. The org.mortbay.http.SocketListener is the main implementation. It listens on a standard TCP/IP port for requests, but there are also listener implementations for SSL, Non blocking IO, testing and others.

Multiple listeners may be used to listen on different ports and/or on specific IP addresses. This is most frequently used with SSL or with multi-hosting:
SocketListener -+
port:80         |
                |
JSSEListener   -+> HttpServer --> HttpContext --> ResourceHandler
port:443        |                 "/"             "./docroot"
                |
SocketListener -+
host:1.2.3.4
port: 80           
Diagram:  Multiple listeners with multihosting

Listeners are configured via set methods. Listeners can be created by using the HttpServer as a factory to create a standard type of listener:

HttpServer server=new HttpServer();
HttpListener listener=
    server.addListener(new InetAddrPort("myhost",8080));
Code Example:  Convenience methods for adding standard listeners


However, in order to provide detailed configuration, it is more common to create the listener directly and then add it to the HttpServer:
HttpServer server = new HttpServer();
SocketListener listener = new SocketListener();
listener.setHost("myhost");
listener.setPort(8080);
listener.setMinThreads(5); listener.setMaxThreads(250); server.addListener(listener);
Code Example: Configuring a listener


All HttpListeners are responsible for allocating threads to requests, so most implementations are extensions of the org.mortbay.util.ThreadedServer or org.mortbay.util.ThreadPool. Thus attributes such as min/max threads, min/max idle times etc are also set via the API.

Jetty has several type of HttpListeners including:

 

HttpContext

A org.mortbay.http.HttpContext aggregates org.mortbay.http.HttpHandler implementations. When a request is passsed to a HttpContext it tries each of its HttpHandlers in turn ( in the order in which they were registered) until the request is marked as handled. Note that it is perfectly possible for more than one handler to process the request, but only one handler can mark the request as being finally handled.

Note that in Jetty 3.1 and previous releases, the HttpContext class was called HandlerContext.

A typical a context might have handlers for security, servlets and static resources:
                                              +-> SecurityHandler
                                              |
SocketListener --> HttpServer --> HttpContext +-> ServletHandler
port: 80                          "/"         |
                                              +-> ResourceHandler
Diagram: Single context, multiple handlers

All HttpHandlers within a single HttpContext share the following attributes:


A single HttpServer can have multiple HttpContexts.  This is typically used to serve several applications from the same port(s) using URL mappings:
SocketListener --> HttpServer +-> HttpContext --> HttpHandler(s)
port:80                       |   path:"/alpha/*"
                              |
                              +-> HttpContext --> HttpHandler(s)
                                  path:"/beta/*"
Diagram:  Multiple contexts with URL mapping

Alternatively,  different applications can be served from the same port using virtual hosts:
SocketListener --> HttpServer +-> HttpContext --> HttpHandler(s)
port:80                       |   vhost: www.alpha.com
                              |   path: "/"
                              |
                              +-> HttpContext --> HttpHandler(s)
                                  vhost: www.beta.com
                                  path: "/"
Diagram: Multiple contexts with virtual hosts

If multiple contexts are to be served from the same port, but on different IP addresses, then it is possible to give each context its own HttpServer:
SocketListener --> HttpServer --> HttpContext --> HttpHandler(s)
host:www.alpha.com                path:"/"
port:80

SocketListener --> HttpServer --> HttpContext --> HttpHandler(s)
host:www.beta.com                 path: "/"
port:80
Diagram:  Multiple servers


HttpContexts can be instantiated by the HttpServer as part of a call to addContext() with context args:
HttpContext context = server.addContext("/mydocs/*");
context.setResourceBase("./docroot/");
Code Example:  Implied context creation


As addContext() will always create a new context instance, it is possible to accidentally create multiple copies of the same context (by calling addContext() with the same parameters). To avoid this, you can use the getContext() method instead, which will only create a new context if one with the same specification does not already exist:
HttpContext context = server.getContext("myhost","/mydocs/*");
context.setResourceBase("./docroot/");
Code Example:  Lazy context creation


The previous example highlights that it is possible specify a virtual host as well as the context path. A single context may be registered with different virtual hosts. Once context configuration becomes complex, it is best to take explicit control over context creation:
HttpContext context = new HttpContext();
context.setContextPath("/context/*");
context.setVirtualHosts(new String[]{"alpa.com","beta.com"});
context.setResourceBase("./docroot/");
server.addContext(context);
Code Example:  Creating a context with multiple virtual hosts

Developers Note:  Derivations of HttpServer may implement the newHttpContext() method to change the factory method for creating new contexts. This is used, for example, by the org.mortbay.jetty.Server class to return HttpContext derivations that have convenience methods for configuring servlets. The org.mortbay.jetty.servlet.WebApplicationContext class is a specialization of HttpContext that configures the handlers by looking at the standard web application XML files.


HttpHandler

The org.mortbay.http.HttpHandler interface represents Jetty's core unit of content generation or manipulation. Implementations of this interface can be used to modify or handle requests. Typically, handlers are arranged in a list, and a request presented to each handler in turn until (at most) one indicates that the request has been handled. This allows handlers to:

The handlers provided with the org.mortbay.http.handler package are:
ResourceHandler Serve static content from the resource base of the HttpContext (see below).
SecurityHandler Provide BASIC and FORM authentication.
HTAccessHandler Provide apache .htaccess style security.
NotFoundHandler Handles unserviced requests.
DumpHandler A debugging tool that dumps the request and response headers.
ForwardHandler Forward a request to another URL
NullHandler An abstract base implementation of the interface, used for to derive other handlers.
A ServletHandler and WebApplicationHandler are provided by the org.mortbay.jetty.servlet package and is discussed in detail in the Jetty Server section.

HttpHandlers are tried within a context in the order they were added to the HttpContext. The following code creates a context that checks authentication, then tries a servlet mapping before trying static content then finally dropping through to an error page generator if no handler marks the request as handled:

HttpContext context = server.addContext("/");
context.add(new SecurityHandler());
context.add(new ServletHandler());
context.add(new ResourceHandler());
context.add(new NotFoundHandler());
Code Example:  Importance of handler ordering



Resource Handler

One of the most common things for a HttpServer to do is to serve static content from a base directory or URL. The org.mortbay.http.handler.ResourceHandler implementation of HttpHandler is provided for this purpose. Its features include:


The root directory or URL for serving static content is the ResourceBase of the HttpContext. Thus, to serve static content from the directory "./docroot/":
HttpContext context = server.getContext("/context/*");
context.setResourceBase("./docroot/");
ResourceHandler handler = new ResourceHandler();
handler.setDirAllowed(true);
handler.setPutAllowed(false);
handler.setDelAllowed(false);
handler.setAcceptRanges(true);
context.addHandler(handler);
context.addHandler(new NotFoundHandler());
Code Example:  Detailed configuration of a ResourceHandler

The NotFoundHandler is added to generate a 404 for requests for resources that don't exist. The ResourceHandler lets requests that it cannot handle fall through to the next handler.

Developers Note:
HttpHandlers ARE ORDER DEPENDANT!. If in the above example the NotFoundHandler had been added to the context before the ResourceHandler, then all requests would be 404'd and resources would not be served. It is a common mistake to put a ResourceHandler before a ServletHandler with the JSPServlet, so jsp source code is served rather than the dynamic content from the JSPServlet.


Putting It All Together

Finally, here is a fully worked code example to configure a server on port 8181 serving static content and a dump servlet at "/mystuff/" :
   
import java.io.*;
import java.net.*;
import org.mortbay.util.*;
import org.mortbay.http.*;
import org.mortbay.jetty.servlet.*;
import org.mortbay.http.handler.*;
import org.mortbay.servlet.*;     
      
public class SimpleServer
{
  public static void main (String[] args)
    throws Exception
  {
    // Create the server
    HttpServer server=new HttpServer();
      
    // Create a port listener
    SocketListener listener=new SocketListener();
    listener.setPort(8181);
    server.addListener(listener);

    // Create a context 
    HttpContext context = new HttpContext();
    context.setContextPath("/mystuff/*");
    server.addContext(context);
      
    // Create a servlet container
    ServletHandler servlets = new ServletHandler();
    context.addHandler(servlets);

    // Map a servlet onto the container
    servlets.addServlet("Dump","/Dump/*","org.mortbay.servlet.Dump");
      
    // Serve static content from the context
    String home = System.getProperty("jetty.home",".");
    context.setResourceBase(home+"/demo/webapps/jetty/tut/");
    context.addHandler(new ResourceHandler());

    // Start the http server
    server.start ();
  }
}

Code Example: Setting up an HttpServer

BACK INDEX EXIT NEXT