|
|
|
|
@@ -27,21 +27,39 @@ import javax.servlet.http.HttpServletResponse;
|
|
|
|
|
|
|
|
|
|
import org.springframework.web.context.request.async.WebAsyncManager;
|
|
|
|
|
import org.springframework.web.context.request.async.WebAsyncUtils;
|
|
|
|
|
import org.springframework.web.util.WebUtils;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Filter base class that guarantees to be just executed once per request,
|
|
|
|
|
* on any servlet container. It provides a {@link #doFilterInternal}
|
|
|
|
|
* Filter base class that aims to guarantee a single execution per request
|
|
|
|
|
* dispatch, on any servlet container. It provides a {@link #doFilterInternal}
|
|
|
|
|
* method with HttpServletRequest and HttpServletResponse arguments.
|
|
|
|
|
*
|
|
|
|
|
* <p>In an async scenario a filter may be invoked again in additional threads
|
|
|
|
|
* as part of an {@linkplain javax.servlet.DispatcherType.ASYNC ASYNC} dispatch.
|
|
|
|
|
* Sub-classes may decide whether to be invoked once per request or once per
|
|
|
|
|
* request thread for as long as the same request is being processed.
|
|
|
|
|
* See {@link #shouldNotFilterAsyncDispatch()}.
|
|
|
|
|
* <p>As of Servlet 3.0, a filter may be invoked as part of a
|
|
|
|
|
* {@link javax.servlet.DispatcherType.REQUEST REQUEST} or
|
|
|
|
|
* {@link javax.servlet.DispatcherType.ASYNC ASYNC} dispatches that occur in
|
|
|
|
|
* separate threads. A filter can be configured in {@code web.xml} whether it
|
|
|
|
|
* should be involved in async dispatches. However, in some cases servlet
|
|
|
|
|
* containers assume different default configuration. Therefore sub-classes can
|
|
|
|
|
* override the method {@link #shouldNotFilterAsyncDispatch()} to declare
|
|
|
|
|
* statically if they shouuld indeed be invoked, <em>once</em>, during both types
|
|
|
|
|
* of dispatches in order to provide thread initialization, logging, security,
|
|
|
|
|
* and so on. This mechanism complements and does not replace the need to
|
|
|
|
|
* configure a filter in {@code web.xml} with dispatcher types.
|
|
|
|
|
*
|
|
|
|
|
* <p>The {@link #getAlreadyFilteredAttributeName} method determines how
|
|
|
|
|
* to identify that a request is already filtered. The default implementation
|
|
|
|
|
* is based on the configured name of the concrete filter instance.
|
|
|
|
|
* <p>Sub-classes may use {@link #isAsyncDispatch(HttpServletRequest)} to
|
|
|
|
|
* determine when a filter is invoked as part of an async dispatch, and
|
|
|
|
|
* use {@link #isAsyncStarted(HttpServletRequest)} to determine when the
|
|
|
|
|
* request has been placed in async mode and therefore the current dispatch
|
|
|
|
|
* won't be the last one.
|
|
|
|
|
*
|
|
|
|
|
* <p>Yet another dispatch type that also occurs in its own thread is
|
|
|
|
|
* {@link javax.servlet.DispatcherType.ERROR ERROR}. Sub-classes can override
|
|
|
|
|
* {@link #shouldNotFilterErrorDispatch()} if they wish to declare statically
|
|
|
|
|
* if they should be invoked <em>once</em> during error dispatches.
|
|
|
|
|
*
|
|
|
|
|
* <p>The {@link #getAlreadyFilteredAttributeName} method determines how to
|
|
|
|
|
* identify that a request is already filtered. The default implementation is
|
|
|
|
|
* based on the configured name of the concrete filter instance.
|
|
|
|
|
*
|
|
|
|
|
* @author Juergen Hoeller
|
|
|
|
|
* @author Rossen Stoyanchev
|
|
|
|
|
@@ -74,13 +92,10 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
|
|
|
|
|
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
|
|
|
|
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
|
|
|
|
|
|
|
|
|
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
|
|
|
|
|
boolean processAsyncDispatch = asyncManager.hasConcurrentResult() && !shouldNotFilterAsyncDispatch();
|
|
|
|
|
|
|
|
|
|
String alreadyFilteredAttributeName = getAlreadyFilteredAttributeName();
|
|
|
|
|
boolean hasAlreadyFilteredAttribute = request.getAttribute(alreadyFilteredAttributeName) != null;
|
|
|
|
|
|
|
|
|
|
if ((hasAlreadyFilteredAttribute && (!processAsyncDispatch)) || shouldNotFilter(httpRequest)) {
|
|
|
|
|
if (hasAlreadyFilteredAttribute || skipDispatch(httpRequest) || shouldNotFilter(httpRequest)) {
|
|
|
|
|
|
|
|
|
|
// Proceed without invoking this filter...
|
|
|
|
|
filterChain.doFilter(request, response);
|
|
|
|
|
@@ -92,14 +107,46 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
|
|
|
|
|
doFilterInternal(httpRequest, httpResponse, filterChain);
|
|
|
|
|
}
|
|
|
|
|
finally {
|
|
|
|
|
if (!asyncManager.isConcurrentHandlingStarted()) {
|
|
|
|
|
// Remove the "already filtered" request attribute for this request.
|
|
|
|
|
request.removeAttribute(alreadyFilteredAttributeName);
|
|
|
|
|
}
|
|
|
|
|
// Remove the "already filtered" request attribute for this request.
|
|
|
|
|
request.removeAttribute(alreadyFilteredAttributeName);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean skipDispatch(HttpServletRequest request) {
|
|
|
|
|
if (isAsyncDispatch(request) && shouldNotFilterAsyncDispatch()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if ((request.getAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE) != null) && shouldNotFilterErrorDispatch()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The dispatcher type {@code javax.servlet.DispatcherType.ASYNC} introduced
|
|
|
|
|
* in Servlet 3.0 means a filter can be invoked in more than one thread over
|
|
|
|
|
* the course of a single request. This method returns {@code true} if the
|
|
|
|
|
* filter is currently executing within an asynchronous dispatch.
|
|
|
|
|
*
|
|
|
|
|
* @param request the current request
|
|
|
|
|
* @see WebAsyncManager#hasConcurrentResult()
|
|
|
|
|
*/
|
|
|
|
|
protected boolean isAsyncDispatch(HttpServletRequest request) {
|
|
|
|
|
return WebAsyncUtils.getAsyncManager(request).hasConcurrentResult();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether request processing is in asynchronous mode meaning that the
|
|
|
|
|
* response will not be committed after the current thread is exited.
|
|
|
|
|
*
|
|
|
|
|
* @param request the current request
|
|
|
|
|
* @see WebAsyncManager#isConcurrentHandlingStarted()
|
|
|
|
|
*/
|
|
|
|
|
protected boolean isAsyncStarted(HttpServletRequest request) {
|
|
|
|
|
return WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the name of the request attribute that identifies that a request
|
|
|
|
|
* is already filtered.
|
|
|
|
|
@@ -130,18 +177,18 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether to filter async dispatches, which occur in a different thread.
|
|
|
|
|
* The dispatcher type {@code javax.servlet.DispatcherType.ASYNC} introduced
|
|
|
|
|
* in Servlet 3.0 means a filter can be invoked in more than one thread (and
|
|
|
|
|
* exited) over the course of a single request. Some filters only need to
|
|
|
|
|
* filter the initial thread (e.g. request wrapping) while others may need
|
|
|
|
|
* in Servlet 3.0 means a filter can be invoked in more than one thread
|
|
|
|
|
* over the course of a single request. Some filters only need to filter
|
|
|
|
|
* the initial thread (e.g. request wrapping) while others may need
|
|
|
|
|
* to be invoked at least once in each additional thread for example for
|
|
|
|
|
* setting up thread locals or to perform final processing at the very end.
|
|
|
|
|
* <p>Note that although a filter can be mapped to handle specific dispatcher
|
|
|
|
|
* types via {@code web.xml} or in Java through the {@code ServletContext},
|
|
|
|
|
* servlet containers may enforce different defaults with regards to
|
|
|
|
|
* dispatcher types. This flag enforces the design intent of the filter.
|
|
|
|
|
* <p>The default setting is "true", which means the filter will not be
|
|
|
|
|
*
|
|
|
|
|
* <p>The default return value is "true", which means the filter will not be
|
|
|
|
|
* invoked during subsequent async dispatches. If "false", the filter will
|
|
|
|
|
* be invoked during async dispatches with the same guarantees of being
|
|
|
|
|
* invoked only once during a request within a single thread.
|
|
|
|
|
@@ -150,6 +197,16 @@ public abstract class OncePerRequestFilter extends GenericFilterBean {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether to filter error dispatches such as when the servlet container
|
|
|
|
|
* processes and error mapped in {@code web.xml}. The default return value
|
|
|
|
|
* is "true", which means the filter will not be invoked in case of an error
|
|
|
|
|
* dispatch.
|
|
|
|
|
*/
|
|
|
|
|
protected boolean shouldNotFilterErrorDispatch() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Same contract as for <code>doFilter</code>, but guaranteed to be
|
|
|
|
|
* just invoked once per request within a single request thread.
|
|
|
|
|
|