Author: jawi
Date: Mon May 26 10:32:31 2014
New Revision: 1597554

URL: http://svn.apache.org/r1597554
Log:
FELIX-4420 - Implement sendRedirect:

- rewrite redirects if the redirect-URL is at the same host as the rewritten 
URLs;
- added some tests in order to verify the correctness.


Added:
    
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterConstants.java
   (with props)
    
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java
   (with props)
    
felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java
   (with props)
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/SslFilterRequest.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=1597554&r1=1597553&r2=1597554&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
 Mon May 26 10:32:31 2014
@@ -18,6 +18,9 @@
  */
 package org.apache.felix.http.sslfilter.internal;
 
+import static 
org.apache.felix.http.sslfilter.internal.SslFilterConstants.HDR_X_FORWARDED_SSL;
+import static 
org.apache.felix.http.sslfilter.internal.SslFilterConstants.HDR_X_FORWARDED_SSL_CERTIFICATE;
+
 import java.io.IOException;
 import java.security.cert.CertificateException;
 import java.util.Dictionary;
@@ -29,17 +32,19 @@ import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.log.LogService;
 
+@SuppressWarnings("rawtypes")
 public class SslFilter implements Filter
 {
     public static final String PID = 
"org.apache.felix.http.sslfilter.SslFilter";
 
-    private static final String DEFAULT_SSL_HEADER = "X-Forwarded-SSL";
+    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 = 
"X-Forwarded-SSL-Certificate";
+    private static final String DEFAULT_CERT_HEADER = 
HDR_X_FORWARDED_SSL_CERTIFICATE;
 
     private static final String PROP_SSL_HEADER = "ssl-forward.header";
     private static final String PROP_SSL_VALUE = "ssl-forward.value";
@@ -62,12 +67,14 @@ public class SslFilter implements Filter
         final ConfigHolder cfg = this.config;
 
         HttpServletRequest httpReq = (HttpServletRequest) req;
+        HttpServletResponse httpResp = (HttpServletResponse) res;
+
         if (cfg.sslValue.equalsIgnoreCase(httpReq.getHeader(cfg.sslHeader)))
         {
             try
             {
-                // In case this fails, we fall back to the original HTTP
-                // request, which is better than nothing...
+                httpResp = new SslFilterResponse(httpResp, httpReq);
+                // In case this fails, we fall back to the original HTTP 
request, which is better than nothing...
                 httpReq = new SslFilterRequest(httpReq, 
httpReq.getHeader(cfg.certHeader));
             }
             catch (CertificateException e)
@@ -76,11 +83,10 @@ public class SslFilter implements Filter
             }
         }
 
-        // forward the request making sure any certificate is removed
-        // again after the request processing gets back here
+        // forward the request making sure any certificate is removed again 
after the request processing gets back here
         try
         {
-            chain.doFilter(httpReq, res);
+            chain.doFilter(httpReq, httpResp);
         }
         finally
         {
@@ -96,7 +102,7 @@ public class SslFilter implements Filter
         // make sure there is some configuration
     }
 
-    void configure(@SuppressWarnings("rawtypes") final Dictionary properties) 
throws ConfigurationException
+    void configure(Dictionary properties) throws ConfigurationException
     {
         String certHeader = DEFAULT_CERT_HEADER;
         String sslHeader = DEFAULT_SSL_HEADER;
@@ -115,7 +121,7 @@ public class SslFilter implements Filter
             + certHeader + "'.");
     }
 
-    private String getOptionalString(@SuppressWarnings("rawtypes") Dictionary 
properties, String key) throws ConfigurationException
+    private String getOptionalString(Dictionary properties, String key) throws 
ConfigurationException
     {
         Object raw = properties.get(key);
         if (raw == null || "".equals(((String) raw).trim()))
@@ -129,7 +135,7 @@ public class SslFilter implements Filter
         return ((String) raw).trim();
     }
 
-    private String getMandatoryString(@SuppressWarnings("rawtypes") Dictionary 
properties, String key) throws ConfigurationException
+    private String getMandatoryString(Dictionary properties, String key) 
throws ConfigurationException
     {
         String value = getOptionalString(properties, key);
         if (value == null)

Added: 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterConstants.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterConstants.java?rev=1597554&view=auto
==============================================================================
--- 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterConstants.java
 (added)
+++ 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterConstants.java
 Mon May 26 10:32:31 2014
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.http.sslfilter.internal;
+
+/**
+ * Provides constants used in the SSL filter.
+ */
+interface SslFilterConstants
+{
+    /**
+     * If there is an SSL certificate associated with the request, it must be 
exposed by the servlet container to the 
+     * servlet programmer as an array of objects of type 
java.security.cert.X509Certificate and accessible via a 
+     * ServletRequest attribute of 
<tt>javax.servlet.request.X509Certificate</tt>.
+     * <p>
+     * The order of this array is defined as being in ascending order of 
trust. The first certificate in the chain is
+     * the one set by the client, the next is the one used to authenticate the 
first, and so on.
+     */
+    String ATTR_SSL_CERTIFICATE = "javax.servlet.request.X509Certificate";
+
+    /**
+     * De-facto header used to inform what protocol the forwarded client used 
to connect to the proxy, such as "https".
+     */
+    String HDR_X_FORWARDED_PROTO = "X-Forwarded-Proto";
+    /**
+     * De-facto header used to inform what port the forwarded client used to 
connect to the proxy, such as "433".
+     */
+    String HDR_X_FORWARDED_PORT = "X-Forwarded-Port";
+    /**
+     * De-facto header used to inform that the proxy is forwarding a SSL 
request.
+     */
+    String HDR_X_FORWARDED_SSL = "X-Forwarded-SSL";
+    /**
+     * De-facto(?) header used to pass the certificate the client used to 
connect to the proxy, in X.509 format.
+     */
+    String HDR_X_FORWARDED_SSL_CERTIFICATE = "X-Forwarded-SSL-Certificate";
+
+    /**
+     * HTTP header used to explain the client it should redirect to another 
URL.
+     */
+    String HDR_LOCATION = "Location";
+
+    /**
+     * HTTP protocol/scheme.
+     */
+    String HTTP = "http";
+    /**
+     * Default port used for HTTP.
+     */
+    int HTTP_PORT = 80;
+
+    /**
+     * HTTPS protocol/scheme.
+     */
+    String HTTPS = "https";
+    /**
+     * Default port used for HTTPS.
+     */
+    int HTTPS_PORT = 443;
+
+    String UTF_8 = "UTF-8";
+    String X_509 = "X.509";
+}

Propchange: 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterConstants.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterRequest.java
URL: 
http://svn.apache.org/viewvc/felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterRequest.java?rev=1597554&r1=1597553&r2=1597554&view=diff
==============================================================================
--- 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterRequest.java
 (original)
+++ 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterRequest.java
 Mon May 26 10:32:31 2014
@@ -18,6 +18,11 @@
  */
 package org.apache.felix.http.sslfilter.internal;
 
+import static 
org.apache.felix.http.sslfilter.internal.SslFilterConstants.ATTR_SSL_CERTIFICATE;
+import static 
org.apache.felix.http.sslfilter.internal.SslFilterConstants.HTTPS;
+import static 
org.apache.felix.http.sslfilter.internal.SslFilterConstants.UTF_8;
+import static 
org.apache.felix.http.sslfilter.internal.SslFilterConstants.X_509;
+
 import java.io.ByteArrayInputStream;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
@@ -32,45 +37,29 @@ import javax.servlet.http.HttpServletReq
 
 class SslFilterRequest extends HttpServletRequestWrapper
 {
-    // The HTTPS scheme name
-    private static final String HTTPS_SCHEME = "https";
-
     // The HTTP scheme prefix in an URL
     private static final String HTTP_SCHEME_PREFIX = "http://";;
 
     // pattern to convert the header to a PEM certificate for parsing
     // by replacing spaces with line breaks
-    private static Pattern HEADER_TO_CERT = Pattern.compile("(?! 
CERTIFICATE)(?= ) ");
-
-    // character encoding for the client certificate header
-    private static final String UTF_8 = "UTF-8";
-
-    /**
-     * If there is an SSL certificate associated with the request, it must be
-     * exposed by the servlet container to the servlet programmer as an array 
of
-     * objects of type java.security.cert.X509Certificate and accessible via a
-     * ServletRequest attribute of javax.servlet.request.X509Certificate.
-     * <p>
-     * The order of this array is defined as being in ascending order of trust.
-     * The first certificate in the chain is the one set by the client, the 
next
-     * is the one used to authenticate the first, and so on.
-     */
-    protected static final String ATTR_SSL_CERTIFICATE = 
"javax.servlet.request.X509Certificate";
-
-    private String requestURL;
+    private static final Pattern HEADER_TO_CERT = Pattern.compile("(?! 
CERTIFICATE)(?= ) ");
 
     @SuppressWarnings("unchecked")
     SslFilterRequest(HttpServletRequest request, String clientCertHeader) 
throws CertificateException
     {
         super(request);
+        
+        // TODO jawi: perhaps we should make this class a little smarter wrt 
the given request:
+        // it now always assumes it should rewrite its URL, while this might 
not always be the
+        // case...
 
-        if (clientCertHeader != null && clientCertHeader.length() > 0)
+        if (clientCertHeader != null && !"".equals(clientCertHeader.trim()))
         {
             final String clientCert = 
HEADER_TO_CERT.matcher(clientCertHeader).replaceAll("\n");
 
             try
             {
-                CertificateFactory fac = 
CertificateFactory.getInstance("X.509");
+                CertificateFactory fac = CertificateFactory.getInstance(X_509);
 
                 InputStream instream = new 
ByteArrayInputStream(clientCert.getBytes(UTF_8));
 
@@ -92,7 +81,7 @@ class SslFilterRequest extends HttpServl
 
     public String getScheme()
     {
-        return HTTPS_SCHEME;
+        return HTTPS;
     }
 
     public boolean isSecure()
@@ -102,19 +91,13 @@ class SslFilterRequest extends HttpServl
 
     public StringBuffer getRequestURL()
     {
-        if (this.requestURL == null)
+        StringBuffer tmp = new StringBuffer(super.getRequestURL());
+        // In case the request happened over http, simply insert an additional 
's' 
+        // to make the request appear to be done over https...
+        if (tmp.indexOf(HTTP_SCHEME_PREFIX) == 0)
         {
-            StringBuffer tmp = super.getRequestURL();
-            if (tmp.indexOf(HTTP_SCHEME_PREFIX) == 0)
-            {
-                this.requestURL = HTTPS_SCHEME.concat(tmp.substring(4));
-            }
-            else
-            {
-                this.requestURL = tmp.toString();
-            }
+            tmp.insert(4, 's');
         }
-
-        return new StringBuffer(this.requestURL);
+        return tmp;
     }
 }

Added: 
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=1597554&view=auto
==============================================================================
--- 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java
 (added)
+++ 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java
 Mon May 26 10:32:31 2014
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.http.sslfilter.internal;
+
+import static 
org.apache.felix.http.sslfilter.internal.SslFilterConstants.HDR_LOCATION;
+import static 
org.apache.felix.http.sslfilter.internal.SslFilterConstants.HDR_X_FORWARDED_PORT;
+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.apache.felix.http.sslfilter.internal.SslFilterConstants.HTTPS_PORT;
+import static 
org.apache.felix.http.sslfilter.internal.SslFilterConstants.HTTP_PORT;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+
+/**
+ * Provides a custom {@link HttpServletResponse} for use in SSL filter.
+ */
+class SslFilterResponse extends HttpServletResponseWrapper
+{
+    private final String serverName;
+    private final String serverProto;
+    private final int serverPort;
+    private final String clientProto;
+    private final int clientPort;
+
+    public SslFilterResponse(HttpServletResponse response, HttpServletRequest 
request)
+    {
+        super(response);
+
+        // Only rewrite URLs for the host & port the request was sent to...
+        this.serverName = request.getServerName();
+        this.serverPort = request.getServerPort();
+
+        String proto = request.getHeader(HDR_X_FORWARDED_PROTO);
+        if (HTTP.equalsIgnoreCase(proto))
+        {
+            // Not really a useful scenario: client is talking HTTP to proxy, 
and we should rewrite all HTTPS-based URLs...
+            this.clientProto = HTTP;
+            this.serverProto = HTTPS;
+        }
+        else
+        {
+            // Client is talking HTTPS to proxy, so we should rewrite all 
HTTP-based URLs... 
+            this.clientProto = HTTPS;
+            this.serverProto = HTTP;
+        }
+
+        int port;
+        try
+        {
+            String fwdPort = request.getHeader(HDR_X_FORWARDED_PORT);
+            port = Integer.valueOf(fwdPort);
+        }
+        catch (Exception e)
+        {
+            // Use default port for the used protocol...
+            port = -1;
+        }
+        // Normalize the protocol port...
+        if ((port > 0) && ((HTTPS.equals(this.clientProto) && (port == 
HTTPS_PORT)) || (HTTP.equals(this.clientProto) && (port == HTTP_PORT))))
+        {
+            // Port is the default one, do not use it...
+            port = -1;
+        }
+
+        this.clientPort = port;
+    }
+
+    @Override
+    public void setHeader(String name, String value)
+    {
+        if (HDR_LOCATION.equalsIgnoreCase(name))
+        {
+            URL rewritten = rewriteUrlIfNeeded(value);
+            // Trying to set a redirect location to the original client-side 
URL, which should be https...
+            if (rewritten != null)
+            {
+                value = rewritten.toExternalForm();
+            }
+        }
+        super.setHeader(name, value);
+    }
+
+    private int normalizePort(String protocol, int port)
+    {
+        if (port > 0)
+        {
+            return port;
+        }
+        if (HTTPS.equalsIgnoreCase(protocol))
+        {
+            return HTTPS_PORT;
+        }
+        return HTTP_PORT;
+    }
+
+    private URL rewriteUrlIfNeeded(String value)
+    {
+        try
+        {
+            URL url = new URL(value);
+
+            String actualProto = url.getProtocol();
+
+            if (!this.serverProto.equalsIgnoreCase(actualProto))
+            {
+                return null;
+            }
+
+            if (!this.serverName.equals(url.getHost()))
+            {
+                return null;
+            }
+
+            if (normalizePort(this.serverProto, this.serverPort) != 
normalizePort(actualProto, url.getPort()))
+            {
+                return null;
+            }
+
+            return new URL(this.clientProto, this.serverName, this.clientPort, 
url.getFile());
+        }
+        catch (MalformedURLException e)
+        {
+            return null;
+        }
+    }
+}

Propchange: 
felix/trunk/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
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=1597554&view=auto
==============================================================================
--- 
felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java
 (added)
+++ 
felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java
 Mon May 26 10:32:31 2014
@@ -0,0 +1,378 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.http.sslfilter.internal;
+
+import static junit.framework.Assert.assertEquals;
+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;
+import static org.mockito.Mockito.when;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.junit.Test;
+
+public class SslFilterResponseTest
+{
+    private static final String BACKEND_SERVER = "backend.server";
+    private static final String OTHER_SERVER = "other.server";
+
+    private static final String DEFAULT_HTTP_PORT = "80";
+    private static final String ALT_HTTP_PORT = "8080";
+    private static final String DEFAULT_HTTPS_PORT = "443";
+    private static final String ALT_HTTPS_PORT = "8443";
+
+    private static final String LOCATION = "Location";
+
+    @Test
+    public void testSetHttpLocationHeaderToNullValue() throws Exception
+    {
+        HttpServletResponse resp = createServletResponse();
+        HttpServletRequest req = createServletRequest(BACKEND_SERVER);
+
+        SslFilterResponse sresp = new SslFilterResponse(resp, req);
+
+        sresp.setHeader(LOCATION, null);
+
+        assertEquals(null, sresp.getHeader(LOCATION));
+    }
+
+    @Test
+    public void testSetHttpsLocationHeaderToOriginalRequestURI() throws 
Exception
+    {
+        String location, expected;
+
+        HttpServletResponse resp = createServletResponse();
+        HttpServletRequest req = createServletRequest(BACKEND_SERVER);
+
+        SslFilterResponse sresp = new SslFilterResponse(resp, req);
+
+        location = HTTPS + "://" + BACKEND_SERVER + "/foo";
+        expected = location;
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, sresp.getHeader(LOCATION));
+    }
+
+    @Test
+    public void testSetHttpLocationHeaderToOriginalRequestURI() throws 
Exception
+    {
+        String location, expected;
+
+        HttpServletResponse resp = createServletResponse();
+        HttpServletRequest req = createServletRequest(BACKEND_SERVER);
+
+        SslFilterResponse sresp = new SslFilterResponse(resp, req);
+
+        location = HTTP + "://" + BACKEND_SERVER + "/foo";
+        expected = HTTPS + "://" + BACKEND_SERVER + "/foo";
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, sresp.getHeader(LOCATION));
+    }
+
+    @Test
+    public void testSetHttpLocationHeaderToOriginalRequestWithExplicitPort() 
throws Exception
+    {
+        String location, expected;
+
+        HttpServletResponse resp = createServletResponse();
+        HttpServletRequest req = createServletRequest(BACKEND_SERVER);
+
+        SslFilterResponse sresp = new SslFilterResponse(resp, req);
+
+        location = HTTP + "://" + BACKEND_SERVER + ":" + DEFAULT_HTTP_PORT + 
"/foo";
+        expected = HTTPS + "://" + BACKEND_SERVER + "/foo";
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, sresp.getHeader(LOCATION));
+    }
+
+    @Test
+    public void testSetHttpLocationHeaderToOriginalRequestWithForwardedPort() 
throws Exception
+    {
+        String location, expected;
+
+        HttpServletResponse resp = createServletResponse();
+        HttpServletRequest req = createServletRequest(BACKEND_SERVER, 
DEFAULT_HTTP_PORT, HTTPS, ALT_HTTPS_PORT);
+
+        SslFilterResponse sresp = new SslFilterResponse(resp, req);
+
+        location = HTTP + "://" + BACKEND_SERVER + "/foo";
+        expected = HTTPS + "://" + BACKEND_SERVER + ":" + ALT_HTTPS_PORT + 
"/foo";
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, sresp.getHeader(LOCATION));
+    }
+
+    @Test
+    public void testSetHttpLocationHeaderToOriginalRequestWithDifferentPort() 
throws Exception
+    {
+        String location, expected;
+
+        HttpServletResponse resp = createServletResponse();
+        HttpServletRequest req = createServletRequest(BACKEND_SERVER);
+
+        SslFilterResponse sresp = new SslFilterResponse(resp, req);
+
+        location = HTTP + "://" + BACKEND_SERVER + ":" + ALT_HTTP_PORT + 
"/foo";
+        expected = location;
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, sresp.getHeader(LOCATION));
+    }
+
+    @Test
+    public void testSetHttpLocationHeaderToOtherRequestURI() throws Exception
+    {
+        HttpServletResponse resp = createServletResponse();
+        HttpServletRequest req = createServletRequest(BACKEND_SERVER);
+
+        SslFilterResponse sresp = new SslFilterResponse(resp, req);
+
+        String location = HTTP + "://" + OTHER_SERVER + "/foo";
+        String expected = location;
+
+        sresp.setHeader(LOCATION, location);
+
+        assertEquals(expected, sresp.getHeader(LOCATION));
+    }
+
+    private HttpServletRequest createServletRequest(String serverName)
+    {
+        return createServletRequest(serverName, DEFAULT_HTTP_PORT, HTTPS, 
DEFAULT_HTTPS_PORT);
+    }
+
+    private HttpServletRequest createServletRequest(String serverName, String 
serverPort, String forwardedProto, String forwardedPort)
+    {
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        when(req.getServerName()).thenReturn(serverName);
+        when(req.getServerPort()).thenReturn(Integer.parseInt(serverPort));
+        when(req.getHeader("X-Forwarded-Proto")).thenReturn(forwardedProto);
+        when(req.getHeader("X-Forwarded-Port")).thenReturn(forwardedPort);
+        return req;
+    }
+
+    private HttpServletResponse createServletResponse()
+    {
+        HttpServletResponse resp = new HttpServletResponse()
+        {
+            private final Map<String, String> headers = new HashMap<String, 
String>();
+            private int status = -1;
+            private boolean committed = false;
+
+            public void setLocale(Locale loc)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void setContentType(String type)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void setContentLength(int len)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void setCharacterEncoding(String charset)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void setBufferSize(int size)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void resetBuffer()
+            {
+            }
+
+            public void reset()
+            {
+            }
+
+            public boolean isCommitted()
+            {
+                return this.committed;
+            }
+
+            public PrintWriter getWriter() throws IOException
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public ServletOutputStream getOutputStream() throws IOException
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public Locale getLocale()
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public String getContentType()
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public String getCharacterEncoding()
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public int getBufferSize()
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void flushBuffer() throws IOException
+            {
+                committed = true;
+            }
+
+            public void setStatus(int sc, String sm)
+            {
+                status = sc;
+                committed = true;
+            }
+
+            public void setStatus(int sc)
+            {
+                status = sc;
+                committed = true;
+            }
+
+            public void setIntHeader(String name, int value)
+            {
+                headers.put(name, Integer.toString(value));
+            }
+
+            public void setHeader(String name, String value)
+            {
+                headers.put(name, value);
+            }
+
+            public void setDateHeader(String name, long date)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void sendRedirect(String location) throws IOException
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void sendError(int sc, String msg) throws IOException
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void sendError(int sc) throws IOException
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public int getStatus()
+            {
+                return status;
+            }
+
+            public Collection<String> getHeaders(String name)
+            {
+                return Collections.singleton(headers.get(name));
+            }
+
+            public Collection<String> getHeaderNames()
+            {
+                return headers.keySet();
+            }
+
+            public String getHeader(String name)
+            {
+                return headers.get(name);
+            }
+
+            public String encodeUrl(String url)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public String encodeURL(String url)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public String encodeRedirectUrl(String url)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public String encodeRedirectURL(String url)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public boolean containsHeader(String name)
+            {
+                return headers.containsKey(name);
+            }
+
+            public void addIntHeader(String name, int value)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void addHeader(String name, String value)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void addDateHeader(String name, long date)
+            {
+                throw new UnsupportedOperationException();
+            }
+
+            public void addCookie(Cookie cookie)
+            {
+                throw new UnsupportedOperationException();
+            }
+        };
+        return resp;
+    }
+}

Propchange: 
felix/trunk/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to