001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.filter; 018 019import java.io.IOException; 020 021import javax.servlet.FilterChain; 022import javax.servlet.ServletException; 023import javax.servlet.http.HttpServletRequest; 024import javax.servlet.http.HttpServletResponse; 025 026import org.springframework.http.HttpStatus; 027import org.springframework.util.Assert; 028 029/** 030 * Overrides {@link HttpServletResponse#sendRedirect(String)} and handles it by 031 * setting the HTTP status and "Location" headers, which keeps the Servlet 032 * container from re-writing relative redirect URLs into absolute ones. 033 * Servlet containers are required to do that but against the recommendation of 034 * <a href="https://tools.ietf.org/html/rfc7231#section-7.1.2"> RFC 7231 Section 7.1.2</a>, 035 * and furthermore not necessarily taking into account "X-Forwarded" headers. 036 * 037 * <p><strong>Note:</strong> While relative redirects are recommended in the 038 * RFC, under some configurations with reverse proxies they may not work. 039 * 040 * @author Rob Winch 041 * @author Rossen Stoyanchev 042 * @since 4.3.10 043 */ 044public class RelativeRedirectFilter extends OncePerRequestFilter { 045 046 private HttpStatus redirectStatus = HttpStatus.SEE_OTHER; 047 048 049 /** 050 * Set the default HTTP Status to use for redirects. 051 * <p>By default this is {@link HttpStatus#SEE_OTHER}. 052 * @param status the 3xx redirect status to use 053 */ 054 public void setRedirectStatus(HttpStatus status) { 055 Assert.notNull(status, "Property 'redirectStatus' is required"); 056 Assert.isTrue(status.is3xxRedirection(), "Not a redirect status code"); 057 this.redirectStatus = status; 058 } 059 060 /** 061 * Return the configured redirect status. 062 */ 063 public HttpStatus getRedirectStatus() { 064 return this.redirectStatus; 065 } 066 067 068 @Override 069 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, 070 FilterChain filterChain) throws ServletException, IOException { 071 072 response = RelativeRedirectResponseWrapper.wrapIfNecessary(response, this.redirectStatus); 073 filterChain.doFilter(request, response); 074 } 075 076}