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; 020import javax.servlet.FilterChain; 021import javax.servlet.ServletException; 022import javax.servlet.http.HttpServletRequest; 023import javax.servlet.http.HttpServletResponse; 024 025import org.springframework.http.HttpStatus; 026import org.springframework.util.Assert; 027 028/** 029 * Overrides {@link HttpServletResponse#sendRedirect(String)} and handles it by 030 * setting the HTTP status and "Location" headers, which keeps the Servlet 031 * container from re-writing relative redirect URLs into absolute ones. 032 * Servlet containers are required to do that but against the recommendation of 033 * <a href="https://tools.ietf.org/html/rfc7231#section-7.1.2"> RFC 7231 Section 7.1.2</a>, 034 * and furthermore not necessarily taking into account "X-Forwarded" headers. 035 * 036 * <p><strong>Note:</strong> While relative redirects are recommended in the 037 * RFC, under some configurations with reverse proxies they may not work. 038 * 039 * @author Rob Winch 040 * @author Rossen Stoyanchev 041 * @since 4.3.10 042 */ 043public class RelativeRedirectFilter extends OncePerRequestFilter { 044 045 private HttpStatus redirectStatus = HttpStatus.SEE_OTHER; 046 047 048 /** 049 * Set the default HTTP Status to use for redirects. 050 * <p>By default this is {@link HttpStatus#SEE_OTHER}. 051 * @param status the 3xx redirect status to use 052 */ 053 public void setRedirectStatus(HttpStatus status) { 054 Assert.notNull(status, "Property 'redirectStatus' is required"); 055 Assert.isTrue(status.is3xxRedirection(), "Not a redirect status code"); 056 this.redirectStatus = status; 057 } 058 059 /** 060 * Return the configured redirect status. 061 */ 062 public HttpStatus getRedirectStatus() { 063 return this.redirectStatus; 064 } 065 066 067 @Override 068 protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, 069 FilterChain filterChain) throws ServletException, IOException { 070 071 response = RelativeRedirectResponseWrapper.wrapIfNecessary(response, this.redirectStatus); 072 filterChain.doFilter(request, response); 073 } 074 075}