Merge branch '1.5.x' into 2.0.x
This commit is contained in:
		
						commit
						2c6465abdc
					
				| 
						 | 
				
			
			@ -18,8 +18,12 @@ package org.springframework.boot.web.servlet.support;
 | 
			
		|||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.io.PrintWriter;
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.HashSet;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
 | 
			
		||||
import javax.servlet.Filter;
 | 
			
		||||
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.core.Ordered;
 | 
			
		||||
import org.springframework.core.annotation.Order;
 | 
			
		||||
import org.springframework.util.ClassUtils;
 | 
			
		||||
import org.springframework.web.filter.OncePerRequestFilter;
 | 
			
		||||
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 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 final Map<Integer, String> statuses = new HashMap<>();
 | 
			
		||||
| 
						 | 
				
			
			@ -164,7 +177,6 @@ public class ErrorPageFilter implements Filter, ErrorPageRegistry {
 | 
			
		|||
			handleCommittedResponse(request, ex);
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		forwardToErrorPage(errorPath, request, wrapped, ex);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -200,6 +212,9 @@ public class ErrorPageFilter implements Filter, ErrorPageRegistry {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	private void handleCommittedResponse(HttpServletRequest request, Throwable ex) {
 | 
			
		||||
		if (isClientAbortException(ex)) {
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		String message = "Cannot forward to error page for request "
 | 
			
		||||
				+ getDescription(request) + " as the response has already been"
 | 
			
		||||
				+ " 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) {
 | 
			
		||||
		if (map.containsKey(status)) {
 | 
			
		||||
			return map.get(status);
 | 
			
		||||
| 
						 | 
				
			
			@ -276,6 +303,15 @@ public class ErrorPageFilter implements Filter, ErrorPageRegistry {
 | 
			
		|||
	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 int status;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,7 @@ import javax.servlet.http.HttpServletRequest;
 | 
			
		|||
import javax.servlet.http.HttpServletResponse;
 | 
			
		||||
import javax.servlet.http.HttpServletResponseWrapper;
 | 
			
		||||
 | 
			
		||||
import org.apache.catalina.connector.ClientAbortException;
 | 
			
		||||
import org.junit.Rule;
 | 
			
		||||
import org.junit.Test;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -131,6 +132,19 @@ public class ErrorPageFilterTests {
 | 
			
		|||
		assertThat(this.response.isCommitted()).isTrue();
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void responseCommittedWhenFromClientAbortException() throws Exception {
 | 
			
		||||
		this.filter.addErrorPages(new ErrorPage("/error"));
 | 
			
		||||
		this.response.setCommitted(true);
 | 
			
		||||
		this.chain = new TestFilterChain((request, response, chain) -> {
 | 
			
		||||
			chain.call();
 | 
			
		||||
			throw new ClientAbortException();
 | 
			
		||||
		});
 | 
			
		||||
		this.filter.doFilter(this.request, this.response, this.chain);
 | 
			
		||||
		assertThat(this.response.isCommitted()).isTrue();
 | 
			
		||||
		assertThat(this.output.toString()).doesNotContain("Cannot forward");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void responseUncommittedWithoutErrorPage() throws Exception {
 | 
			
		||||
		this.chain = new TestFilterChain(
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue