|
|
|
@ -18,8 +18,12 @@ package org.springframework.boot.web.servlet.support; |
|
|
|
|
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
import java.io.IOException; |
|
|
|
import java.io.PrintWriter; |
|
|
|
import java.io.PrintWriter; |
|
|
|
|
|
|
|
import java.util.Collection; |
|
|
|
|
|
|
|
import java.util.Collections; |
|
|
|
import java.util.HashMap; |
|
|
|
import java.util.HashMap; |
|
|
|
|
|
|
|
import java.util.HashSet; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
import java.util.Set; |
|
|
|
|
|
|
|
|
|
|
|
import javax.servlet.Filter; |
|
|
|
import javax.servlet.Filter; |
|
|
|
import javax.servlet.FilterChain; |
|
|
|
import javax.servlet.FilterChain; |
|
|
|
@ -40,6 +44,7 @@ import org.springframework.boot.web.server.ErrorPageRegistrar; |
|
|
|
import org.springframework.boot.web.server.ErrorPageRegistry; |
|
|
|
import org.springframework.boot.web.server.ErrorPageRegistry; |
|
|
|
import org.springframework.core.Ordered; |
|
|
|
import org.springframework.core.Ordered; |
|
|
|
import org.springframework.core.annotation.Order; |
|
|
|
import org.springframework.core.annotation.Order; |
|
|
|
|
|
|
|
import org.springframework.util.ClassUtils; |
|
|
|
import org.springframework.web.filter.OncePerRequestFilter; |
|
|
|
import org.springframework.web.filter.OncePerRequestFilter; |
|
|
|
import org.springframework.web.util.NestedServletException; |
|
|
|
import org.springframework.web.util.NestedServletException; |
|
|
|
|
|
|
|
|
|
|
|
@ -77,6 +82,14 @@ public class ErrorPageFilter implements Filter, ErrorPageRegistry { |
|
|
|
|
|
|
|
|
|
|
|
private static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code"; |
|
|
|
private static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static final Set<Class<?>> CLIENT_ABORT_EXCEPTIONS; |
|
|
|
|
|
|
|
static { |
|
|
|
|
|
|
|
Set<Class<?>> clientAbortExceptions = new HashSet<>(); |
|
|
|
|
|
|
|
addClassIfPresent(clientAbortExceptions, |
|
|
|
|
|
|
|
"org.apache.catalina.connector.ClientAbortException"); |
|
|
|
|
|
|
|
CLIENT_ABORT_EXCEPTIONS = Collections.unmodifiableSet(clientAbortExceptions); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String global; |
|
|
|
private String global; |
|
|
|
|
|
|
|
|
|
|
|
private final Map<Integer, String> statuses = new HashMap<>(); |
|
|
|
private final Map<Integer, String> statuses = new HashMap<>(); |
|
|
|
@ -164,7 +177,6 @@ public class ErrorPageFilter implements Filter, ErrorPageRegistry { |
|
|
|
handleCommittedResponse(request, ex); |
|
|
|
handleCommittedResponse(request, ex); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
forwardToErrorPage(errorPath, request, wrapped, ex); |
|
|
|
forwardToErrorPage(errorPath, request, wrapped, ex); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -200,6 +212,9 @@ public class ErrorPageFilter implements Filter, ErrorPageRegistry { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void handleCommittedResponse(HttpServletRequest request, Throwable ex) { |
|
|
|
private void handleCommittedResponse(HttpServletRequest request, Throwable ex) { |
|
|
|
|
|
|
|
if (isClientAbortException(ex)) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
String message = "Cannot forward to error page for request " |
|
|
|
String message = "Cannot forward to error page for request " |
|
|
|
+ getDescription(request) + " as the response has already been" |
|
|
|
+ getDescription(request) + " as the response has already been" |
|
|
|
+ " committed. As a result, the response may have the wrong status" |
|
|
|
+ " committed. As a result, the response may have the wrong status" |
|
|
|
@ -216,6 +231,18 @@ public class ErrorPageFilter implements Filter, ErrorPageRegistry { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private boolean isClientAbortException(Throwable ex) { |
|
|
|
|
|
|
|
if (ex == null) { |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (Class<?> candidate : CLIENT_ABORT_EXCEPTIONS) { |
|
|
|
|
|
|
|
if (candidate.isInstance(ex)) { |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return isClientAbortException(ex.getCause()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String getErrorPath(Map<Integer, String> map, Integer status) { |
|
|
|
private String getErrorPath(Map<Integer, String> map, Integer status) { |
|
|
|
if (map.containsKey(status)) { |
|
|
|
if (map.containsKey(status)) { |
|
|
|
return map.get(status); |
|
|
|
return map.get(status); |
|
|
|
@ -276,6 +303,15 @@ public class ErrorPageFilter implements Filter, ErrorPageRegistry { |
|
|
|
public void destroy() { |
|
|
|
public void destroy() { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static void addClassIfPresent(Collection<Class<?>> collection, |
|
|
|
|
|
|
|
String className) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
collection.add(ClassUtils.forName(className, null)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (Throwable ex) { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static class ErrorWrapperResponse extends HttpServletResponseWrapper { |
|
|
|
private static class ErrorWrapperResponse extends HttpServletResponseWrapper { |
|
|
|
|
|
|
|
|
|
|
|
private int status; |
|
|
|
private int status; |
|
|
|
|