CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-eclipse-jetty--jetty-server

Core server component of Eclipse Jetty web server providing HTTP server functionality, request handling, and connection management

Pending
Overview
Eval results
Files

request-response.mddocs/

Request and Response APIs

The request and response APIs provide the core interfaces for handling HTTP requests and generating responses, including content processing, header management, and lifecycle callbacks.

Request Interface

The Request interface represents an HTTP request with content, headers, and context.

public interface Request extends Attributes, Content.Source {
    // Request identification and metadata
    String getId();
    Components getComponents();
    ConnectionMetaData getConnectionMetaData();
    
    // HTTP method and URI
    String getMethod();
    HttpURI getHttpURI();
    
    // Request context
    Context getContext();
    
    // Headers and cookies
    HttpFields getHeaders();
    List<HttpCookie> getCookies();
    
    // Session management
    Session getSession(boolean create);
    
    // Content handling (from Content.Source)
    Content.Chunk read();
    void demand(Runnable demandCallback);
    void fail(Throwable failure);
    
    // Nested interfaces
    interface Handler {
        boolean handle(Request request, Response response, Callback callback) throws Exception;
    }
    
    interface Wrapper extends Request {
        Request getWrapped();
    }
}

Response Interface

The Response interface represents an HTTP response with status, headers, and content writing capabilities.

public interface Response extends Content.Sink {
    // Request association
    Request getRequest();
    
    // Status management
    int getStatus();
    void setStatus(int code);
    
    // Header management  
    HttpFields.Mutable getHeaders();
    
    // Content writing (from Content.Sink)
    void write(boolean last, ByteBuffer byteBuffer, Callback callback);
    
    // Error handling
    Runnable writeError(Request request, Response response, Callback callback, 
                       int code, String message);
    
    // Response state
    boolean isCommitted();
    boolean isCompleted();
    long getBytesWritten();
    
    // Nested classes
    class Wrapper implements Response {
        public Response getWrapped();
    }
}

Usage Examples

Basic Request Handling

public class SimpleHandler extends Handler.Abstract {
    @Override
    public boolean handle(Request request, Response response, Callback callback) 
            throws Exception {
        // Get request information
        String method = request.getMethod();
        String path = request.getHttpURI().getPath();
        String userAgent = request.getHeaders().get("User-Agent");
        
        System.out.println("Request: " + method + " " + path);
        System.out.println("User-Agent: " + userAgent);
        
        // Set response
        response.setStatus(200);
        response.getHeaders().put("Content-Type", "text/html");
        
        String html = "<html><body><h1>Hello from Jetty!</h1>" +
                     "<p>Method: " + method + "</p>" +
                     "<p>Path: " + path + "</p></body></html>";
        
        response.write(true, ByteBuffer.wrap(html.getBytes()), callback);
        return true;
    }
}

Reading Request Content

public class ContentHandler extends Handler.Abstract {
    @Override
    public boolean handle(Request request, Response response, Callback callback) 
            throws Exception {
        
        // Check if request has content
        String contentType = request.getHeaders().get("Content-Type");
        if (contentType != null && contentType.startsWith("application/json")) {
            readJsonContent(request, response, callback);
        } else {
            handleNoContent(response, callback);
        }
        
        return true;
    }
    
    private void readJsonContent(Request request, Response response, Callback callback) {
        StringBuilder content = new StringBuilder();
        
        // Read content chunks asynchronously
        request.demand(() -> {
            Content.Chunk chunk;
            while ((chunk = request.read()) != null) {
                if (chunk.hasRemaining()) {
                    // Process content chunk
                    ByteBuffer buffer = chunk.getByteBuffer();
                    byte[] bytes = new byte[buffer.remaining()];
                    buffer.get(bytes);
                    content.append(new String(bytes, StandardCharsets.UTF_8));
                }
                
                chunk.release();
                
                if (chunk.isLast()) {
                    // All content read, process and respond
                    processJsonAndRespond(content.toString(), response, callback);
                    return;
                }
            }
            
            // Need more content, demand again
            request.demand(() -> readJsonContent(request, response, callback));
        });
    }
    
    private void processJsonAndRespond(String json, Response response, Callback callback) {
        response.setStatus(200);
        response.getHeaders().put("Content-Type", "application/json");
        
        String responseJson = "{\"received\": " + json + ", \"status\": \"processed\"}";
        response.write(true, ByteBuffer.wrap(responseJson.getBytes()), callback);
    }
    
    private void handleNoContent(Response response, Callback callback) {
        response.setStatus(400);
        response.getHeaders().put("Content-Type", "text/plain");
        response.write(true, ByteBuffer.wrap("No content provided".getBytes()), callback);
    }
}

Cookie and Session Handling

public class SessionHandler extends Handler.Abstract {
    @Override
    public boolean handle(Request request, Response response, Callback callback) 
            throws Exception {
        
        // Get or create session
        Session session = request.getSession(true);
        String sessionId = session.getId();
        
        // Read session data
        Integer visitCount = (Integer) session.getAttribute("visitCount");
        if (visitCount == null) {
            visitCount = 0;
        }
        visitCount++;
        session.setAttribute("visitCount", visitCount);
        
        // Read cookies
        List<HttpCookie> cookies = request.getCookies();
        String preferredLang = null;
        for (HttpCookie cookie : cookies) {
            if ("lang".equals(cookie.getName())) {
                preferredLang = cookie.getValue();
                break;
            }
        }
        
        // Set response cookie
        if (preferredLang == null) {
            preferredLang = "en";
            HttpCookie langCookie = HttpCookie.build("lang", preferredLang)
                .path("/")
                .maxAge(Duration.ofDays(30))
                .httpOnly(true)
                .build();
            response.getHeaders().addCookie(langCookie);
        }
        
        // Generate response
        response.setStatus(200);
        response.getHeaders().put("Content-Type", "text/html");
        
        String html = String.format(
            "<html><body>" +
            "<h1>Session Demo</h1>" +
            "<p>Session ID: %s</p>" +
            "<p>Visit count: %d</p>" +
            "<p>Language: %s</p>" +
            "</body></html>", 
            sessionId, visitCount, preferredLang);
        
        response.write(true, ByteBuffer.wrap(html.getBytes()), callback);
        return true;
    }
}

Content Processing

FormFields

Parse form data from request content.

public class FormFields extends ContentSourceCompletableFuture<Fields> {
    public static CompletableFuture<Fields> from(Request request);
    public static CompletableFuture<Fields> from(Request request, Charset charset, int maxFields, int maxLength);
}

Usage:

public class FormHandler extends Handler.Abstract {
    @Override
    public boolean handle(Request request, Response response, Callback callback) 
            throws Exception {
        
        String contentType = request.getHeaders().get("Content-Type");
        if ("application/x-www-form-urlencoded".equals(contentType)) {
            
            FormFields.from(request).thenAccept(fields -> {
                // Process form fields
                String name = fields.getValue("name");
                String email = fields.getValue("email");
                
                // Generate response
                response.setStatus(200);
                response.getHeaders().put("Content-Type", "text/plain");
                String responseText = "Received: name=" + name + ", email=" + email;
                response.write(true, ByteBuffer.wrap(responseText.getBytes()), callback);
                
            }).exceptionally(throwable -> {
                // Handle parsing error
                response.setStatus(400);
                response.getHeaders().put("Content-Type", "text/plain");
                response.write(true, ByteBuffer.wrap("Invalid form data".getBytes()), callback);
                return null;
            });
            
            return true;
        }
        
        return false; // Not handled
    }
}

HTTP URI Processing

HttpURI Interface

public interface HttpURI {
    String getScheme();
    String getHost();
    int getPort();
    String getPath();
    String getQuery();
    String getFragment();
    String getParam(String key);
    Map<String, List<String>> getQueryParameters();
    boolean isAbsolute();
}

Usage:

public boolean handle(Request request, Response response, Callback callback) throws Exception {
    HttpURI uri = request.getHttpURI();
    
    String scheme = uri.getScheme();  // "http" or "https"
    String host = uri.getHost();      // "localhost"
    int port = uri.getPort();         // 8080
    String path = uri.getPath();      // "/api/users"
    String query = uri.getQuery();    // "page=1&size=10"
    
    // Parse query parameters
    Map<String, List<String>> queryParams = uri.getQueryParameters();
    String page = queryParams.containsKey("page") ? 
        queryParams.get("page").get(0) : "1";
    String size = queryParams.containsKey("size") ? 
        queryParams.get("size").get(0) : "20";
    
    // Generate response based on parameters
    response.setStatus(200);
    response.getHeaders().put("Content-Type", "application/json");
    
    String json = String.format(
        "{\"path\": \"%s\", \"page\": %s, \"size\": %s}", 
        path, page, size);
    
    response.write(true, ByteBuffer.wrap(json.getBytes()), callback);
    return true;
}

Header Management

HttpFields Interface

public interface HttpFields extends Iterable<HttpField> {
    // Field access
    HttpField getField(String name);
    String get(String name);
    List<String> getValuesList(String name);
    int size();
    boolean contains(String name);
    boolean contains(String name, String value);
    
    // Iteration
    Iterator<HttpField> iterator();
    Stream<HttpField> stream();
    
    // Mutable version for responses
    interface Mutable extends HttpFields {
        HttpField put(String name, String value);
        HttpField add(String name, String value);
        boolean remove(String name);
        void clear();
        void addCookie(HttpCookie cookie);
    }
}

Connection Metadata

ConnectionMetaData Interface

public interface ConnectionMetaData extends Attributes {
    String getId();
    HttpConfiguration getHttpConfiguration();
    String getProtocol();
    SocketAddress getLocalSocketAddress();
    SocketAddress getRemoteSocketAddress();
    boolean isSecure();
    X509Certificate[] getPeerCertificates();
}

Usage:

public boolean handle(Request request, Response response, Callback callback) throws Exception {
    ConnectionMetaData connMeta = request.getConnectionMetaData();
    
    String protocol = connMeta.getProtocol();  // "HTTP/1.1", "HTTP/2", etc.
    boolean isSecure = connMeta.isSecure();    // true for HTTPS
    SocketAddress remoteAddr = connMeta.getRemoteSocketAddress();
    
    // Client certificate info for mutual TLS
    X509Certificate[] clientCerts = connMeta.getPeerCertificates();
    String clientDN = null;
    if (clientCerts != null && clientCerts.length > 0) {
        clientDN = clientCerts[0].getSubjectX500Principal().getName();
    }
    
    // Generate response with connection info
    response.setStatus(200);
    response.getHeaders().put("Content-Type", "application/json");
    
    String json = String.format(
        "{\"protocol\": \"%s\", \"secure\": %b, \"remote\": \"%s\", \"clientDN\": \"%s\"}", 
        protocol, isSecure, remoteAddr, clientDN);
    
    response.write(true, ByteBuffer.wrap(json.getBytes()), callback);
    return true;
}

Request Wrappers

Request.Wrapper

Base class for wrapping and modifying requests.

public static class Request.Wrapper implements Request {
    public Request getWrapped();
    
    // All Request methods delegate to wrapped instance
    // Override specific methods to modify behavior
}

Usage:

public class TimingRequestWrapper extends Request.Wrapper {
    private final long startTime;
    
    public TimingRequestWrapper(Request wrapped) {
        super(wrapped);
        this.startTime = System.nanoTime();
    }
    
    public long getProcessingTime() {
        return System.nanoTime() - startTime;
    }
}

// In handler
TimingRequestWrapper timedRequest = new TimingRequestWrapper(request);
// Process request...
long processingTime = timedRequest.getProcessingTime();

Response Wrappers

Response.Wrapper

Base class for wrapping and modifying responses.

public static class Response.Wrapper implements Response {
    public Response getWrapped();
    
    // Override methods to intercept/modify response behavior
}

Usage:

public class CompressingResponseWrapper extends Response.Wrapper {
    private final GZIPOutputStream gzipOut;
    
    public CompressingResponseWrapper(Response wrapped) throws IOException {
        super(wrapped);
        this.gzipOut = new GZIPOutputStream(new ResponseOutputStream(wrapped));
    }
    
    @Override
    public void write(boolean last, ByteBuffer content, Callback callback) {
        try {
            // Compress content before writing
            byte[] bytes = new byte[content.remaining()];
            content.get(bytes);
            gzipOut.write(bytes);
            
            if (last) {
                gzipOut.close();
            }
            
            callback.succeeded();
        } catch (IOException e) {
            callback.failed(e);
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-org-eclipse-jetty--jetty-server

docs

configuration.md

connection-management.md

context-resources.md

handlers.md

index.md

request-logging.md

request-response.md

security-ssl.md

server-core.md

session-management.md

utility-handlers.md

tile.json