//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.0 which is available at
// https://www.apache.org/licenses/LICENSE-2.0
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

package org.eclipse.jetty.server.handler;

import java.io.IOException;

import jakarta.servlet.AsyncContext;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;

A handler wrapper that provides the framework to asynchronously delay the handling of a request. While it uses standard servlet API for asynchronous servlets, it adjusts the dispatch type of the request so that it does not appear to be asynchronous during the delayed dispatch.
/** * A handler wrapper that provides the framework to asynchronously * delay the handling of a request. While it uses standard servlet * API for asynchronous servlets, it adjusts the dispatch type of the * request so that it does not appear to be asynchronous during the * delayed dispatch. */
public class AsyncDelayHandler extends HandlerWrapper { public static final String AHW_ATTR = "o.e.j.s.h.AsyncHandlerWrapper"; @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (!isStarted() || _handler == null) return; // Get the dispatcher types DispatcherType ctype = baseRequest.getDispatcherType(); DispatcherType dtype = (DispatcherType)baseRequest.getAttribute(AHW_ATTR); Object asyncContextPath = null; Object asyncPathInfo = null; Object asyncQueryString = null; Object asyncRequestUri = null; Object asyncServletPath = null; Object asyncHttpServletMapping = null; // Is this request a restarted one? boolean restart = false; if (dtype != null) { // fake the dispatch type to the original baseRequest.setAttribute(AHW_ATTR, null); baseRequest.setDispatcherType(dtype); restart = true; asyncContextPath = baseRequest.getAttribute(AsyncContext.ASYNC_CONTEXT_PATH); baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH, null); asyncPathInfo = baseRequest.getAttribute(AsyncContext.ASYNC_PATH_INFO); baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO, null); asyncQueryString = baseRequest.getAttribute(AsyncContext.ASYNC_QUERY_STRING); baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING, null); asyncRequestUri = baseRequest.getAttribute(AsyncContext.ASYNC_REQUEST_URI); baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI, null); asyncServletPath = baseRequest.getAttribute(AsyncContext.ASYNC_SERVLET_PATH); baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH, null); asyncHttpServletMapping = baseRequest.getAttribute(AsyncContext.ASYNC_MAPPING); baseRequest.setAttribute(AsyncContext.ASYNC_MAPPING, null); } // Should we handle this request now? if (!startHandling(baseRequest, restart)) { // No, so go async and remember dispatch type AsyncContext context = baseRequest.startAsync(); baseRequest.setAttribute(AHW_ATTR, ctype); delayHandling(baseRequest, context); return; } // Handle the request try { _handler.handle(target, baseRequest, request, response); } finally { if (restart) { // reset the request baseRequest.setDispatcherType(ctype); baseRequest.setAttribute(AsyncContext.ASYNC_CONTEXT_PATH, asyncContextPath); baseRequest.setAttribute(AsyncContext.ASYNC_PATH_INFO, asyncPathInfo); baseRequest.setAttribute(AsyncContext.ASYNC_QUERY_STRING, asyncQueryString); baseRequest.setAttribute(AsyncContext.ASYNC_REQUEST_URI, asyncRequestUri); baseRequest.setAttribute(AsyncContext.ASYNC_SERVLET_PATH, asyncServletPath); baseRequest.setAttribute(AsyncContext.ASYNC_MAPPING, asyncHttpServletMapping); } // signal the request is leaving the handler endHandling(baseRequest); } }
Called to indicate that a request has been presented for handling
Params:
  • request – The request to handle
  • restart – True if this request is being restarted after a delay
Returns:True if the request should be handled now
/** * Called to indicate that a request has been presented for handling * * @param request The request to handle * @param restart True if this request is being restarted after a delay * @return True if the request should be handled now */
protected boolean startHandling(Request request, boolean restart) { return true; }
Called to indicate that a requests handling is being delayed/ The implementation should arrange for context.dispatch() to be called when the request should be handled. It may also set timeouts on the context.
Params:
  • request – The request to be delayed
  • context – The AsyncContext of the delayed request
/** * Called to indicate that a requests handling is being delayed/ * The implementation should arrange for context.dispatch() to be * called when the request should be handled. It may also set * timeouts on the context. * * @param request The request to be delayed * @param context The AsyncContext of the delayed request */
protected void delayHandling(Request request, AsyncContext context) { context.dispatch(); }
Called to indicated the handling of the request is ending. This is only the end of the current dispatch of the request and if the request is asynchronous, it may be handled again.
Params:
  • request – The request
/** * Called to indicated the handling of the request is ending. * This is only the end of the current dispatch of the request and * if the request is asynchronous, it may be handled again. * * @param request The request */
protected void endHandling(Request request) { } }