Core server component of Eclipse Jetty web server providing HTTP server functionality, request handling, and connection management
—
Context and resource handling provides servlet-like contexts for organizing handlers, virtual host support, resource serving, and static content management.
The ContextHandler provides a servlet-like context for organizing request handling with path mapping, virtual hosts, and resource management.
public class ContextHandler extends Handler.Wrapper implements Attributes, AliasCheck {
// Constructors
public ContextHandler();
public ContextHandler(String contextPath);
public ContextHandler(Handler handler, String contextPath);
// Context path configuration
public String getContextPath();
public void setContextPath(String contextPath);
public String getPathInContext(String canonicallyEncodedPath);
// Resource management
public Resource getBaseResource();
public void setBaseResource(Resource resource);
public void setResourceBase(String resourceBase);
public String getResourceBase();
// Virtual host support
public List<String> getVirtualHosts();
public void setVirtualHosts(String... vhosts);
public void addVirtualHosts(String... virtualHosts);
// Class loading
public ClassLoader getClassLoader();
public void setClassLoader(ClassLoader classLoader);
// MIME types
public MimeTypes getMimeTypes();
public void setMimeTypes(MimeTypes mimeTypes);
// Temporary directory
public File getTempDirectory();
public void setTempDirectory(File temp);
// Context initialization
public Map<String, String> getInitParams();
public String getInitParameter(String name);
public void setInitParameter(String name, String value);
// Display name
public String getDisplayName();
public void setDisplayName(String servletContextName);
// Alias checking
public boolean checkAlias(String pathInContext, Resource resource);
public void addAliasCheck(AliasCheck check);
public List<AliasCheck> getAliasChecks();
// Context availability
public boolean isAvailable();
public void setAvailable(boolean available);
public String getUnavailableException();
}// Create server
Server server = new Server(8080);
// Create context handler for /api
ContextHandler apiContext = new ContextHandler("/api");
apiContext.setHandler(new ApiHandler());
// Create context handler for /web
ContextHandler webContext = new ContextHandler("/web");
webContext.setResourceBase("src/main/webapp");
webContext.setHandler(new DefaultServlet()); // For static files
// Create context collection to route requests
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[]{apiContext, webContext});
server.setHandler(contexts);public class AdvancedContextSetup {
public void setupContexts(Server server) {
// Main application context
ContextHandler mainContext = createMainContext();
// Admin interface context
ContextHandler adminContext = createAdminContext();
// Static resources context
ContextHandler staticContext = createStaticContext();
// Combine contexts
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[]{
mainContext, adminContext, staticContext
});
server.setHandler(contexts);
}
private ContextHandler createMainContext() {
ContextHandler context = new ContextHandler("/app");
// Set display name
context.setDisplayName("Main Application");
// Configure resources
context.setResourceBase("src/main/webapp");
// Set initialization parameters
context.setInitParameter("debug", "true");
context.setInitParameter("environment", "development");
// Configure virtual hosts
context.setVirtualHosts(new String[]{"example.com", "www.example.com"});
// Set custom class loader
URLClassLoader customClassLoader = createCustomClassLoader();
context.setClassLoader(customClassLoader);
// Configure MIME types
MimeTypes mimeTypes = new MimeTypes();
mimeTypes.addMimeMapping("json", "application/json");
context.setMimeTypes(mimeTypes);
// Set temporary directory
context.setTempDirectory(new File("/tmp/jetty-main"));
// Add alias checks for security
context.addAliasCheck(new SymlinkAllowedResourceAliasChecker(context));
context.addAliasCheck(new AllowedResourceAliasChecker(context));
// Set handler
context.setHandler(new MainApplicationHandler());
return context;
}
private ContextHandler createAdminContext() {
ContextHandler context = new ContextHandler("/admin");
context.setDisplayName("Admin Interface");
// Restrict to localhost
context.setVirtualHosts(new String[]{"127.0.0.1", "localhost"});
// Admin-specific configuration
context.setInitParameter("adminMode", "true");
context.setHandler(new AdminHandler());
return context;
}
private ContextHandler createStaticContext() {
ContextHandler context = new ContextHandler("/static");
context.setDisplayName("Static Resources");
context.setResourceBase("static-content/");
// Use resource handler for static files
ResourceHandler resourceHandler = new ResourceHandler();
resourceHandler.setDirectoriesListed(false);
resourceHandler.setWelcomeFiles(new String[]{"index.html"});
context.setHandler(resourceHandler);
return context;
}
private URLClassLoader createCustomClassLoader() {
// Create custom class loader for context
return new URLClassLoader(new URL[]{}, getClass().getClassLoader());
}
}Collection of context handlers with automatic routing based on context paths.
public class ContextHandlerCollection extends Handler.Sequence {
// Context management
public ContextHandler[] getContextHandlers();
public void setContextHandlers(ContextHandler[] contextHandlers);
public void addContextHandler(ContextHandler contextHandler);
public boolean removeContextHandler(ContextHandler contextHandler);
// Context lookup
public ContextHandler getContextHandler(String contextPath);
public Map<String, ContextHandler> getContextHandlerMap();
// Request handling
public boolean handle(Request request, Response response, Callback callback) throws Exception;
}Specialized handler for serving static resources with caching, directory listing, and welcome files.
public class ResourceHandler extends Handler.Wrapper {
// Resource configuration
public Resource getBaseResource();
public void setBaseResource(Resource baseResource);
public void setResourceBase(String resourceBase);
public String getResourceBase();
// Welcome files
public List<String> getWelcomeFiles();
public void setWelcomeFiles(String... welcomeFiles);
public void addWelcomeFiles(String... welcomeFiles);
// Directory listing
public boolean isDirectoriesListed();
public void setDirectoriesListed(boolean directoriesListed);
// Resource serving options
public boolean isAcceptRanges();
public void setAcceptRanges(boolean acceptRanges);
public boolean isEtags();
public void setEtags(boolean etags);
public int getCacheControl();
public void setCacheControl(int cacheControl);
// Resource service
public ResourceService getResourceService();
public void setResourceService(ResourceService resourceService);
// Path mapping
public String[] getPathInfoOnly();
public void setPathInfoOnly(String... pathInfoOnly);
}public class StaticResourceServer {
public void setupStaticResources(Server server) {
// Create resource handler
ResourceHandler resourceHandler = new ResourceHandler();
// Configure base resource directory
resourceHandler.setResourceBase("src/main/webapp");
// Configure welcome files
resourceHandler.setWelcomeFiles(new String[]{
"index.html", "index.htm", "default.html"
});
// Enable directory listings for development
resourceHandler.setDirectoriesListed(true);
// Enable range requests for partial content
resourceHandler.setAcceptRanges(true);
// Enable ETags for caching
resourceHandler.setEtags(true);
// Set cache control (1 hour)
resourceHandler.setCacheControl(3600);
// Create context for static resources
ContextHandler staticContext = new ContextHandler("/static");
staticContext.setHandler(resourceHandler);
server.setHandler(staticContext);
}
}public class AdvancedResourceHandler extends ResourceHandler {
@Override
protected void doStart() throws Exception {
super.doStart();
// Custom resource service configuration
ResourceService service = getResourceService();
// Configure caching
service.setAcceptRanges(true);
service.setDirAllowed(false); // Disable directory access
service.setRedirectWelcome(true); // Redirect to welcome files
service.setGzipEquivalentFileExtensions(Arrays.asList(".gz"));
// Custom welcome file resolution
service.setWelcomeFactory(this::findWelcomeFile);
}
private String findWelcomeFile(String pathInContext) {
// Custom logic to find welcome files
Resource resource = getBaseResource().resolve(pathInContext);
if (resource.isDirectory()) {
// Try different welcome files based on context
if (pathInContext.startsWith("/api")) {
return "api-index.html";
} else if (pathInContext.startsWith("/docs")) {
return "documentation.html";
}
}
return null; // Use default welcome files
}
@Override
public boolean handle(Request request, Response response, Callback callback)
throws Exception {
// Add custom headers for all resources
String path = request.getHttpURI().getPath();
if (path.endsWith(".css")) {
response.getHeaders().add("Content-Type", "text/css; charset=utf-8");
} else if (path.endsWith(".js")) {
response.getHeaders().add("Content-Type", "application/javascript; charset=utf-8");
}
// Add CORS headers for API resources
if (path.startsWith("/api")) {
response.getHeaders().add("Access-Control-Allow-Origin", "*");
}
return super.handle(request, response, callback);
}
}The Resource interface provides abstraction for accessing files, directories, and other resources.
public interface Resource {
// Resource identification
String getName();
URI getURI();
Path getPath();
// Resource state
boolean exists();
boolean isDirectory();
boolean isReadable();
long length();
long lastModified();
// Content access
InputStream newInputStream() throws IOException;
ReadableByteChannel newReadableByteChannel() throws IOException;
// Directory operations
List<Resource> list();
Resource resolve(String subPath);
// Resource creation
static Resource newResource(String resource);
static Resource newResource(URI uri);
static Resource newResource(Path path);
}Context-specific request wrapper providing additional context information.
public class ContextRequest extends Request.Wrapper implements Invocable {
// Context information
public ContextHandler getContextHandler();
public Context getContext();
public String getContextPath();
public String getPathInContext();
// Session management
public HttpSession getSession();
public HttpSession getSession(boolean create);
// Attributes with context scope
public Object getAttribute(String name);
public void setAttribute(String name, Object value);
public void removeAttribute(String name);
public Set<String> getAttributeNameSet();
// Request dispatcher
public RequestDispatcher getRequestDispatcher(String path);
}Context-specific response wrapper.
public class ContextResponse extends Response.Wrapper {
// Response encoding
public void setCharacterEncoding(String encoding);
public String getCharacterEncoding();
public void setContentType(String contentType);
public String getContentType();
// Output handling
public PrintWriter getWriter() throws IOException;
public ServletOutputStream getOutputStream() throws IOException;
}public class VirtualHostExample {
public void setupVirtualHosts(Server server) {
// Context for main site
ContextHandler mainSite = new ContextHandler("/");
mainSite.setVirtualHosts(new String[]{"example.com", "www.example.com"});
mainSite.setHandler(new MainSiteHandler());
// Context for API subdomain
ContextHandler apiSite = new ContextHandler("/");
apiSite.setVirtualHosts(new String[]{"api.example.com"});
apiSite.setHandler(new ApiHandler());
// Context for admin subdomain with IP restriction
ContextHandler adminSite = new ContextHandler("/");
adminSite.setVirtualHosts(new String[]{"admin.example.com", "127.0.0.1:8080"});
adminSite.setHandler(new AdminHandler());
// Context for mobile site
ContextHandler mobileSite = new ContextHandler("/");
mobileSite.setVirtualHosts(new String[]{"m.example.com", "mobile.example.com"});
mobileSite.setHandler(new MobileSiteHandler());
// Combine all contexts
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[]{
mainSite, apiSite, adminSite, mobileSite
});
server.setHandler(contexts);
}
}public interface AliasCheck {
boolean checkAlias(String pathInContext, Resource resource);
}public class AllowedResourceAliasChecker extends AbstractLifeCycle implements AliasCheck {
public AllowedResourceAliasChecker(ContextHandler contextHandler);
public boolean checkAlias(String pathInContext, Resource resource);
protected boolean check(String pathInContext, Resource resource);
}
public class SymlinkAllowedResourceAliasChecker extends AllowedResourceAliasChecker {
public SymlinkAllowedResourceAliasChecker(ContextHandler contextHandler);
}public class SecurityAliasChecker implements AliasCheck {
private final Set<String> allowedExtensions;
private final Set<String> blockedPaths;
public SecurityAliasChecker() {
this.allowedExtensions = Set.of(".html", ".css", ".js", ".png", ".jpg", ".gif");
this.blockedPaths = Set.of("/WEB-INF", "/META-INF", "/.git", "/.svn");
}
@Override
public boolean checkAlias(String pathInContext, Resource resource) {
// Block access to sensitive directories
for (String blockedPath : blockedPaths) {
if (pathInContext.startsWith(blockedPath)) {
return false;
}
}
// Only allow specific file extensions
String fileName = resource.getName();
if (fileName != null) {
for (String ext : allowedExtensions) {
if (fileName.endsWith(ext)) {
return true;
}
}
}
return false; // Deny by default
}
}
// Usage
ContextHandler context = new ContextHandler("/files");
context.addAliasCheck(new SecurityAliasChecker());public class ContextInitializationExample extends ContextHandler {
@Override
protected void doStart() throws Exception {
// Pre-initialization
setupLogging();
loadConfiguration();
super.doStart();
// Post-initialization
initializeServices();
registerMBeans();
}
@Override
protected void doStop() throws Exception {
// Pre-shutdown
unregisterMBeans();
shutdownServices();
super.doStop();
// Post-shutdown
cleanupResources();
}
private void setupLogging() {
// Configure logging for this context
setAttribute("logLevel", "DEBUG");
}
private void loadConfiguration() {
// Load context-specific configuration
Properties config = new Properties();
try (InputStream is = getClass().getResourceAsStream("/context.properties")) {
if (is != null) {
config.load(is);
for (String key : config.stringPropertyNames()) {
setInitParameter(key, config.getProperty(key));
}
}
} catch (IOException e) {
throw new RuntimeException("Failed to load configuration", e);
}
}
private void initializeServices() {
// Initialize context-specific services
Object service = new MyContextService();
setAttribute("contextService", service);
}
private void registerMBeans() {
// Register JMX MBeans for monitoring
}
private void unregisterMBeans() {
// Unregister JMX MBeans
}
private void shutdownServices() {
// Shutdown services gracefully
Object service = getAttribute("contextService");
if (service instanceof MyContextService) {
((MyContextService) service).shutdown();
}
}
private void cleanupResources() {
// Final cleanup
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-eclipse-jetty--jetty-server