You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by cz...@apache.org on 2016/08/23 19:28:52 UTC

svn commit: r1757420 - in /felix/trunk/http/sslfilter/src: main/java/org/apache/felix/http/sslfilter/internal/ main/resources/OSGI-INF/metatype/ test/java/org/apache/felix/http/sslfilter/internal/

Author: cziegeler
Date: Tue Aug 23 19:28:52 2016
New Revision: 1757420

URL: http://svn.apache.org/viewvc?rev=1757420&view=rev
Log:
FELIX-5309 : SslFilter: sendRedirect does not support deliberate protocol changes on the current host

Modified:
    felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java
    felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java
    felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties
    felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml
    felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterJettyTest.java
    felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java

Modified: felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java?rev=1757420&r1=1757419&r2=1757420&view=diff
==============================================================================
--- felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java (original)
+++ felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilter.java Tue Aug 23 19:28:52 2016
@@ -45,23 +45,30 @@ public class SslFilter implements Filter
     private static final String DEFAULT_SSL_HEADER = HDR_X_FORWARDED_SSL;
     private static final String DEFAULT_SSL_VALUE = "on";
     private static final String DEFAULT_CERT_HEADER = HDR_X_FORWARDED_SSL_CERTIFICATE;
+    private static final boolean DEFAULT_REWRITE_ABSOLUTE_URLS = false;
 
     private static final String PROP_SSL_HEADER = "ssl-forward.header";
     private static final String PROP_SSL_VALUE = "ssl-forward.value";
     private static final String PROP_SSL_CERT_KEY = "ssl-forward-cert.header";
+    private static final String PROP_REWRITE_ABSOLUTE_URLS = "rewrite.absolute.urls";
 
     private volatile ConfigHolder config;
 
     SslFilter()
     {
-        this.config = new ConfigHolder(DEFAULT_SSL_HEADER, DEFAULT_SSL_VALUE, DEFAULT_CERT_HEADER);
+        this.config = new ConfigHolder(DEFAULT_SSL_HEADER,
+                DEFAULT_SSL_VALUE,
+                DEFAULT_CERT_HEADER,
+                DEFAULT_REWRITE_ABSOLUTE_URLS);
     }
 
+    @Override
     public void destroy()
     {
         // No explicit destroy needed...
     }
 
+    @Override
     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException
     {
         final ConfigHolder cfg = this.config;
@@ -97,6 +104,7 @@ public class SslFilter implements Filter
         }
     }
 
+    @Override
     public void init(FilterConfig config)
     {
         // make sure there is some configuration
@@ -107,20 +115,42 @@ public class SslFilter implements Filter
         String certHeader = DEFAULT_CERT_HEADER;
         String sslHeader = DEFAULT_SSL_HEADER;
         String sslValue = DEFAULT_SSL_VALUE;
+        boolean rewriteUrls = DEFAULT_REWRITE_ABSOLUTE_URLS;
 
         if (properties != null)
         {
             certHeader = getOptionalString(properties, PROP_SSL_CERT_KEY);
             sslHeader = getMandatoryString(properties, PROP_SSL_HEADER);
             sslValue = getMandatoryString(properties, PROP_SSL_VALUE);
+            rewriteUrls = getOptionalBoolean(properties, PROP_REWRITE_ABSOLUTE_URLS, rewriteUrls);
         }
 
-        this.config = new ConfigHolder(sslHeader, sslValue, certHeader);
+        this.config = new ConfigHolder(sslHeader, sslValue, certHeader, rewriteUrls);
 
         SystemLogger.log(LogService.LOG_INFO, "SSL filter (re)configured with: " + "SSL forward header = '" + sslHeader + "'; SSL forward value = '" + sslValue + "'; SSL certificate header = '"
             + certHeader + "'.");
     }
 
+    private boolean getOptionalBoolean(Dictionary properties,
+            String key,
+            boolean defaultValue) throws ConfigurationException
+    {
+        Object raw = properties.get(key);
+        if (raw == null)
+        {
+            return defaultValue;
+        }
+        if ( raw instanceof Boolean )
+        {
+            return (Boolean)raw;
+        }
+        if (!(raw instanceof String))
+        {
+            throw new ConfigurationException(key, "invalid value");
+        }
+        return Boolean.valueOf((String)raw);
+    }
+
     private String getOptionalString(Dictionary properties, String key) throws ConfigurationException
     {
         Object raw = properties.get(key);
@@ -150,12 +180,15 @@ public class SslFilter implements Filter
         final String certHeader;
         final String sslHeader;
         final String sslValue;
+        final boolean rewriteAbsoluteUrls;
 
-        public ConfigHolder(String sslHeader, String sslValue, String certHeader)
+        public ConfigHolder(String sslHeader, String sslValue, String certHeader,
+                boolean rewriteAbsoluteUrls)
         {
             this.sslHeader = sslHeader;
             this.sslValue = sslValue;
             this.certHeader = certHeader;
+            this.rewriteAbsoluteUrls = rewriteAbsoluteUrls;
         }
     }
 }

Modified: felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java?rev=1757420&r1=1757419&r2=1757420&view=diff
==============================================================================
--- felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java (original)
+++ felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java Tue Aug 23 19:28:52 2016
@@ -51,6 +51,8 @@ class SslFilterResponse extends HttpServ
     private final String clientProto;
     private final int clientPort;
 
+    private final boolean rewriteAbsoluteUrls;
+
     public SslFilterResponse(HttpServletResponse response, HttpServletRequest request, ConfigHolder config) throws MalformedURLException
     {
         super(response);
@@ -62,7 +64,7 @@ class SslFilterResponse extends HttpServ
         this.serverPort = request.getServerPort();
 
         String value = request.getHeader(config.sslHeader);
-        
+
         if ((HDR_X_FORWARDED_PROTO.equalsIgnoreCase(config.sslHeader) && HTTP.equalsIgnoreCase(value)) ||
                 (HDR_X_FORWARDED_SSL.equalsIgnoreCase(config.sslHeader) && !config.sslValue.equalsIgnoreCase(value)))
         {
@@ -96,6 +98,7 @@ class SslFilterResponse extends HttpServ
         }
 
         this.clientPort = port;
+        this.rewriteAbsoluteUrls = config.rewriteAbsoluteUrls;
     }
 
     @Override
@@ -149,7 +152,7 @@ class SslFilterResponse extends HttpServ
 
     private String rewriteUrlIfNeeded(String value) throws URISyntaxException
     {
-        if (value == null)
+        if (value == null || (!this.rewriteAbsoluteUrls && value.contains("://")) )
         {
             return null;
         }

Modified: felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties
URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties?rev=1757420&r1=1757419&r2=1757420&view=diff
==============================================================================
--- felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties (original)
+++ felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.properties Tue Aug 23 19:28:52 2016
@@ -22,3 +22,5 @@ ssl-forward.value.name=SSL forward value
 ssl-forward.value.description=HTTP Request header value that indicates a request is a SSL request terminated at a proxy. The default value is 'on'. Another commonly used value is 'https'.
 ssl-forward-cert.header.name=SSL client header
 ssl-forward-cert.header.description=HTTP Request header name that contains the client certificate forwarded by a proxy. The default value is 'X-Forwarded-SSL-Certificate'. Another commonly used value is 'X-Forwarded-SSL-Client-Cert'.
+rewrite.absolute.urls.name=Rewrite Absolute URLs
+rewrite.absolute.urls.description=If enabled, absolute URLs passed to either sendRedirect or by setting the location header are rewritten as well.

Modified: felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml
URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml?rev=1757420&r1=1757419&r2=1757420&view=diff
==============================================================================
--- felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml (original)
+++ felix/trunk/http/sslfilter/src/main/resources/OSGI-INF/metatype/org.apache.felix.http.sslfilter.SslFilter.xml Tue Aug 23 19:28:52 2016
@@ -7,6 +7,8 @@
         	type="String" default="on" required="true" />
         <AD id="ssl-forward-cert.header" name="%ssl-forward-cert.header.name" description="%ssl-forward-cert.header.description"
         	type="String" default="X-Forwarded-SSL-Certificate" required="false"/>
+        <AD id="rewrite.absolute.urls" name="%rewrite.absolute.urls.name" description="%rewrite.absolute.urls.description"
+            type="Boolean" default="false" required="false"/>
     </OCD>
     <Designate pid="org.apache.felix.http.sslfilter.SslFilter">
         <Object ocdref="org.apache.felix.http.sslfilter.SslFilter"/>

Modified: felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterJettyTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterJettyTest.java?rev=1757420&r1=1757419&r2=1757420&view=diff
==============================================================================
--- felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterJettyTest.java (original)
+++ felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterJettyTest.java Tue Aug 23 19:28:52 2016
@@ -112,7 +112,7 @@ public class SslFilterJettyTest
         assertEquals(302, conn.getResponseCode());
 
         String location = conn.getHeaderField(HDR_LOCATION);
-        assertTrue(location, location.startsWith(HTTPS));
+        assertTrue(location, location.startsWith(HTTP));
     }
 
     @Test

Modified: felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java?rev=1757420&r1=1757419&r2=1757420&view=diff
==============================================================================
--- felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java (original)
+++ felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java Tue Aug 23 19:28:52 2016
@@ -19,6 +19,7 @@
 package org.apache.felix.http.sslfilter.internal;
 
 import static junit.framework.Assert.assertEquals;
+import static org.apache.felix.http.sslfilter.internal.SslFilterConstants.HDR_X_FORWARDED_PROTO;
 import static org.apache.felix.http.sslfilter.internal.SslFilterConstants.HTTP;
 import static org.apache.felix.http.sslfilter.internal.SslFilterConstants.HTTPS;
 import static org.mockito.Mockito.mock;
@@ -26,7 +27,6 @@ import static org.mockito.Mockito.when;
 
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.net.URI;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -37,17 +37,16 @@ import javax.servlet.ServletOutputStream
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
 import org.apache.felix.http.sslfilter.internal.SslFilter.ConfigHolder;
 import org.junit.Test;
 
-import static org.apache.felix.http.sslfilter.internal.SslFilterConstants.HDR_X_FORWARDED_PROTO;
-
 public class SslFilterResponseTest
 {
     private static final String BACKEND_SERVER = "backend.server";
     private static final String OTHER_SERVER = "other.server";
 
-    private static final String PATH = "http://localhost:8080/";
+    private static final String PATH = "http://" + BACKEND_SERVER + "/foo";
 
     private static final String DEFAULT_HTTP_PORT = "80";
     private static final String ALT_HTTP_PORT = "8080";
@@ -61,8 +60,8 @@ public class SslFilterResponseTest
     {
         TestHttpServletResponse resp = createServletResponse();
         HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
+        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+
         SslFilterResponse sresp = new SslFilterResponse(resp, req, cfg);
 
         sresp.setHeader(LOCATION, null);
@@ -77,8 +76,8 @@ public class SslFilterResponseTest
 
         TestHttpServletResponse resp = createServletResponse();
         HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
+        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+
         SslFilterResponse sresp = new SslFilterResponse(resp, req, cfg);
 
         location = HTTPS + "://" + BACKEND_SERVER + "/foo";
@@ -87,6 +86,18 @@ public class SslFilterResponseTest
         sresp.setHeader(LOCATION, location);
 
         assertEquals(expected, resp.getHeader(LOCATION));
+
+        req = createServletRequest(BACKEND_SERVER, PATH);
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+
+        sresp = new SslFilterResponse(resp, req, cfg);
+
+        location = HTTP + "://" + BACKEND_SERVER + "/foo";
+        expected = HTTPS + "://" + BACKEND_SERVER + "/foo";
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, resp.getHeader(LOCATION));
     }
 
     @Test
@@ -97,39 +108,29 @@ public class SslFilterResponseTest
         TestHttpServletResponse resp = createServletResponse();
         HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
 
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
+        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+
         SslFilterResponse sresp = new SslFilterResponse(resp, req, cfg);
 
         location = HTTP + "://" + BACKEND_SERVER + "/foo";
-        expected = HTTPS + "://" + BACKEND_SERVER + "/foo";
+        expected = location;
 
         sresp.setHeader(LOCATION, location);
 
         assertEquals(expected, resp.getHeader(LOCATION));
-    }
 
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
 
-    @Test
-    public void testSetHttpLocationHeaderToOriginalRequestURIWithFragment() throws Exception
-    {
-        String location, expected;
-
-        TestHttpServletResponse resp = createServletResponse();
-        HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
-        SslFilterResponse sresp = new SslFilterResponse(resp, req, cfg);
+        sresp = new SslFilterResponse(resp, req, cfg);
 
-        location = HTTP + "://" + BACKEND_SERVER + "/foo#abc";
-        expected = HTTPS + "://" + BACKEND_SERVER + "/foo#abc";
+        location = HTTP + "://" + BACKEND_SERVER + "/foo";
+        expected = HTTPS + "://" + BACKEND_SERVER + "/foo";
 
         sresp.setHeader(LOCATION, location);
 
         assertEquals(expected, resp.getHeader(LOCATION));
     }
 
-
     @Test
     public void testSetHttpLocationHeaderToOriginalRequestWithExplicitPort() throws Exception
     {
@@ -137,11 +138,24 @@ public class SslFilterResponseTest
 
         TestHttpServletResponse resp = createServletResponse();
         HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
+        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+
         SslFilterResponse sresp = new SslFilterResponse(resp, req, cfg);
 
         location = HTTP + "://" + BACKEND_SERVER + ":" + DEFAULT_HTTP_PORT + "/foo";
+        expected = HTTP + "://" + BACKEND_SERVER + ":" + DEFAULT_HTTP_PORT + "/foo";
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, resp.getHeader(LOCATION));
+
+        resp = createServletResponse();
+        req = createServletRequest(BACKEND_SERVER, PATH);
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+
+        sresp = new SslFilterResponse(resp, req, cfg);
+
+        location = HTTP + "://" + BACKEND_SERVER + ":" + DEFAULT_HTTP_PORT + "/foo";
         expected = HTTPS + "://" + BACKEND_SERVER + "/foo";
 
         sresp.setHeader(LOCATION, location);
@@ -156,11 +170,24 @@ public class SslFilterResponseTest
 
         TestHttpServletResponse resp = createServletResponse();
         HttpServletRequest req = createServletRequest(BACKEND_SERVER, DEFAULT_HTTP_PORT, HTTPS, ALT_HTTPS_PORT, PATH);
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
+        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+
         SslFilterResponse sresp = new SslFilterResponse(resp, req, cfg);
 
         location = HTTP + "://" + BACKEND_SERVER + "/foo";
+        expected = HTTP + "://" + BACKEND_SERVER + "/foo";
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, resp.getHeader(LOCATION));
+
+        resp = createServletResponse();
+        req = createServletRequest(BACKEND_SERVER, DEFAULT_HTTP_PORT, HTTPS, ALT_HTTPS_PORT, PATH);
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+
+        sresp = new SslFilterResponse(resp, req, cfg);
+
+        location = HTTP + "://" + BACKEND_SERVER + "/foo";
         expected = HTTPS + "://" + BACKEND_SERVER + ":" + ALT_HTTPS_PORT + "/foo";
 
         sresp.setHeader(LOCATION, location);
@@ -175,8 +202,8 @@ public class SslFilterResponseTest
 
         TestHttpServletResponse resp = createServletResponse();
         HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
+        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+
         SslFilterResponse sresp = new SslFilterResponse(resp, req, cfg);
 
         location = HTTP + "://" + BACKEND_SERVER + ":" + ALT_HTTP_PORT + "/foo";
@@ -185,6 +212,19 @@ public class SslFilterResponseTest
         sresp.setHeader(LOCATION, location);
 
         assertEquals(expected, resp.getHeader(LOCATION));
+
+        resp = createServletResponse();
+        req = createServletRequest(BACKEND_SERVER, PATH);
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+
+        sresp = new SslFilterResponse(resp, req, cfg);
+
+        location = HTTP + "://" + BACKEND_SERVER + ":" + ALT_HTTP_PORT + "/foo";
+        expected = location;
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, resp.getHeader(LOCATION));
     }
 
     @Test
@@ -192,8 +232,8 @@ public class SslFilterResponseTest
     {
         TestHttpServletResponse resp = createServletResponse();
         HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
+        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+
         SslFilterResponse sresp = new SslFilterResponse(resp, req,cfg);
 
         String location = HTTP + "://" + OTHER_SERVER + "/foo";
@@ -202,39 +242,125 @@ public class SslFilterResponseTest
         sresp.setHeader(LOCATION, location);
 
         assertEquals(expected, resp.getHeader(LOCATION));
+
+        resp = createServletResponse();
+        req = createServletRequest(BACKEND_SERVER, PATH);
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+
+        sresp = new SslFilterResponse(resp, req,cfg);
+
+        location = HTTP + "://" + OTHER_SERVER + "/foo";
+        expected = location;
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, resp.getHeader(LOCATION));
     }
 
     @Test
-    public void testQueryString() throws Exception
+    public void testFragment() throws Exception
     {
-        TestHttpServletResponse response = createServletResponse();
-        HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
-        SslFilterResponse sresp = new SslFilterResponse(response, req, cfg);
+        test("/foo#abc");
+    }
 
+    @Test
+    public void testQueryString() throws Exception
+    {
         final String queryString = "?resource=%2Fen.html%3FpbOpen%3Dtrue&$$login$$=%24%24login%24%24&j_reason=errors.login.account.not.found";
-        final String setUrl = "http://" + BACKEND_SERVER + "/" + queryString;
-        final URI u = new URI(setUrl);
-        final String expectedUrl = "https://" + BACKEND_SERVER + "/" + queryString;
-        sresp.setHeader(SslFilterConstants.HDR_LOCATION, setUrl);
-
-        assertEquals(expectedUrl, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+        test("/" + queryString);
     }
 
     @Test
     public void testPathEncoding() throws Exception
     {
+        test("/apps/test/content/%E4%B8%83%E6%9C%88%E5%8F%B7.redirect");
+    }
+
+
+    private void test(final String path) throws Exception
+    {
         TestHttpServletResponse response = createServletResponse();
         HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
-        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null);
-        
+
+        // test - don't rewrite absolute urls / absolute http url / sendRedirect
+        // expected: no rewrite
+        ConfigHolder cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
         SslFilterResponse sresp = new SslFilterResponse(response, req, cfg);
 
-        final String setUrl = "http://" + BACKEND_SERVER + "/apps/test/content/%E4%B8%83%E6%9C%88%E5%8F%B7.redirect";
-        sresp.setHeader(SslFilterConstants.HDR_LOCATION, setUrl);
+        sresp.sendRedirect("http://" + BACKEND_SERVER + path);
+        assertEquals("http://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
 
-        assertEquals("https://" + BACKEND_SERVER + "/apps/test/content/%E4%B8%83%E6%9C%88%E5%8F%B7.redirect", sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+        // test - don't rewrite absolute urls / absolute http url / setHeader
+        // expected: no rewrite
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+        sresp = new SslFilterResponse(response, req, cfg);
+
+        sresp.setHeader(SslFilterConstants.HDR_LOCATION, "http://" + BACKEND_SERVER + path);
+        assertEquals("http://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+
+        // test - don't rewrite absolute urls / absolute https url / sendRedirect
+        // expected: no rewrite
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+        sresp = new SslFilterResponse(response, req, cfg);
+
+        sresp.sendRedirect("https://" + BACKEND_SERVER + path);
+        assertEquals("https://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+
+        // test - don't rewrite absolute urls / absolute https url / setHeader
+        // expected: no rewrite
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+        sresp = new SslFilterResponse(response, req, cfg);
+
+        sresp.setHeader(SslFilterConstants.HDR_LOCATION, "https://" + BACKEND_SERVER + path);
+        assertEquals("https://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+
+        // test - rewrite absolute urls / absolute http url / sendRedirect
+        // expected: rewrite
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+        sresp = new SslFilterResponse(response, req, cfg);
+
+        sresp.sendRedirect("http://" + BACKEND_SERVER + path);
+        assertEquals("https://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+
+        // test - rewrite absolute urls / absolute http url / setHeader
+        // expected: rewrite
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+        sresp = new SslFilterResponse(response, req, cfg);
+
+        sresp.setHeader(SslFilterConstants.HDR_LOCATION, "http://" + BACKEND_SERVER + path);
+        assertEquals("https://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+
+        // test - rewrite absolute urls / absolute https url / sendRedirect
+        // expected: no rewrite
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+        sresp = new SslFilterResponse(response, req, cfg);
+
+        sresp.sendRedirect("https://" + BACKEND_SERVER + path);
+        assertEquals("https://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+
+        // test - rewrite absolute urls / absolute https url / setHeader
+        // expected: no rewrite
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+        sresp = new SslFilterResponse(response, req, cfg);
+
+        sresp.setHeader(SslFilterConstants.HDR_LOCATION, "https://" + BACKEND_SERVER + path);
+        assertEquals("https://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+
+        // test - don't rewrite absolute urls / relative path / setHeader
+        // expected: rewrite
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, false);
+        sresp = new SslFilterResponse(response, req, cfg);
+
+        sresp.sendRedirect(path);
+        assertEquals("https://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
+
+        // test - rewrite absolute urls / relative path / sendRedirect
+        // expected: rewrite
+        cfg = new ConfigHolder(HDR_X_FORWARDED_PROTO, "https", null, true);
+        sresp = new SslFilterResponse(response, req, cfg);
+
+        sresp.setHeader(SslFilterConstants.HDR_LOCATION, path);
+        assertEquals("https://" + BACKEND_SERVER + path, sresp.getHeader(SslFilterConstants.HDR_LOCATION));
     }
 
     private HttpServletRequest createServletRequest(String serverName, String requestURL)
@@ -358,6 +484,7 @@ public class SslFilterResponseTest
             committed = true;
         }
 
+        @SuppressWarnings("deprecation")
         @Override
         public void setStatus(int sc, String sm)
         {
@@ -393,7 +520,7 @@ public class SslFilterResponseTest
         @Override
         public void sendRedirect(String location) throws IOException
         {
-            throw new UnsupportedOperationException();
+            this.setHeader(SslFilterConstants.HDR_LOCATION, location);
         }
 
         @Override
@@ -432,6 +559,7 @@ public class SslFilterResponseTest
             return headers.get(name);
         }
 
+        @SuppressWarnings("deprecation")
         @Override
         public String encodeUrl(String url)
         {
@@ -444,6 +572,7 @@ public class SslFilterResponseTest
             throw new UnsupportedOperationException();
         }
 
+        @SuppressWarnings("deprecation")
         @Override
         public String encodeRedirectUrl(String url)
         {