FELIX-5027 : SSL Filter URL Decoding Issues

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1702383 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java b/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java
index 535f937..aa35627 100644
--- a/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java
+++ b/http/sslfilter/src/main/java/org/apache/felix/http/sslfilter/internal/SslFilterResponse.java
@@ -67,7 +67,7 @@
         }
         else
         {
-            // Client is talking HTTPS to proxy, so we should rewrite all HTTP-based URLs... 
+            // Client is talking HTTPS to proxy, so we should rewrite all HTTP-based URLs...
             this.clientProto = HTTPS;
             this.serverProto = HTTP;
         }
@@ -98,7 +98,7 @@
     {
         if (HDR_LOCATION.equalsIgnoreCase(name))
         {
-        	URL rewritten = null;
+        	String rewritten = null;
         	try {
         		rewritten = rewriteUrlIfNeeded(value);
         	} catch (URISyntaxException e) {
@@ -107,7 +107,7 @@
             // Trying to set a redirect location to the original client-side URL, which should be https...
             if (rewritten != null)
             {
-                value = rewritten.toExternalForm();
+                value = rewritten;
             }
         }
         super.setHeader(name, value);
@@ -116,7 +116,7 @@
     @Override
     public void sendRedirect(String location) throws IOException
     {
-    	URL rewritten = null;
+    	String rewritten = null;
     	try {
     		rewritten = rewriteUrlIfNeeded(location);
     	} catch (URISyntaxException e) {
@@ -124,7 +124,7 @@
     	}
         if (rewritten != null)
         {
-            location = rewritten.toExternalForm();
+            location = rewritten;
         }
         super.sendRedirect(location);
     }
@@ -142,7 +142,7 @@
         return HTTP_PORT;
     }
 
-    private URL rewriteUrlIfNeeded(String value) throws URISyntaxException
+    private String rewriteUrlIfNeeded(String value) throws URISyntaxException
     {
         if (value == null)
         {
@@ -154,7 +154,7 @@
             URI uri;
             if (value.startsWith(this.serverProto.concat("://")))
             {
-  
+
                 uri = new URI (value);
             }
             else
@@ -165,7 +165,7 @@
 
             String actualProto = uri.getScheme();
 
-            
+
             if (!this.serverProto.equalsIgnoreCase(actualProto))
             {
                 // protocol is already correct
@@ -184,15 +184,37 @@
                 return null;
             }
 
-         
-            return new URI(this.clientProto,null, this.serverName, this.clientPort, uri.getPath(),uri.getQuery(),uri.getFragment()).toURL();
+            final StringBuilder sb = new StringBuilder();
+            sb.append(this.clientProto);
+            sb.append("://");
+            sb.append(this.serverName);
+            if ( this.clientPort != -1 )
+            {
+                sb.append(':');
+                sb.append(this.clientPort);
+            }
+            if ( uri.getPath() != null )
+            {
+                sb.append(uri.getPath());
+            }
+            if ( uri.getRawQuery() != null )
+            {
+                sb.append('?');
+                sb.append(uri.getRawQuery());
+            }
+            if ( uri.getRawFragment() != null )
+            {
+                sb.append('#');
+                sb.append(uri.getRawFragment());
+            }
+            return sb.toString();
         }
         catch (MalformedURLException e)
         {
             return null;
         }
     }
-    
-    
-    
+
+
+
 }
diff --git a/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java b/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java
index af5740a..8daf77b 100644
--- a/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java
+++ b/http/sslfilter/src/test/java/org/apache/felix/http/sslfilter/internal/SslFilterResponseTest.java
@@ -26,6 +26,7 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.net.URI;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -36,6 +37,7 @@
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+
 import org.junit.Test;
 
 public class SslFilterResponseTest
@@ -100,26 +102,26 @@
 
         assertEquals(expected, resp.getHeader(LOCATION));
     }
-    
-    
+
+
     @Test
     public void testSetHttpLocationHeaderToOriginalRequestURIWithFragment() throws Exception
     {
         String location, expected;
-        
+
         TestHttpServletResponse resp = createServletResponse();
         HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
-        
+
         SslFilterResponse sresp = new SslFilterResponse(resp, req);
-        
+
         location = HTTP + "://" + BACKEND_SERVER + "/foo#abc";
         expected = HTTPS + "://" + BACKEND_SERVER + "/foo#abc";
-        
+
         sresp.setHeader(LOCATION, location);
-        
+
         assertEquals(expected, resp.getHeader(LOCATION));
     }
-    
+
 
     @Test
     public void testSetHttpLocationHeaderToOriginalRequestWithExplicitPort() throws Exception
@@ -191,6 +193,23 @@
         assertEquals(expected, resp.getHeader(LOCATION));
     }
 
+    @Test
+    public void testQueryString() throws Exception
+    {
+        TestHttpServletResponse response = createServletResponse();
+        HttpServletRequest req = createServletRequest(BACKEND_SERVER, PATH);
+
+        SslFilterResponse sresp = new SslFilterResponse(response, req);
+
+        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));
+    }
+
     private HttpServletRequest createServletRequest(String serverName, String requestURL)
     {
         return createServletRequest(serverName, DEFAULT_HTTP_PORT, HTTPS, DEFAULT_HTTPS_PORT, requestURL);
@@ -218,186 +237,223 @@
         private int status = -1;
         private boolean committed = false;
 
+        @Override
         public void setLocale(Locale loc)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void setContentType(String type)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void setContentLength(int len)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void setContentLengthLong(long len)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void setCharacterEncoding(String charset)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void setBufferSize(int size)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void resetBuffer()
         {
         }
 
+        @Override
         public void reset()
         {
         }
 
+        @Override
         public boolean isCommitted()
         {
             return this.committed;
         }
 
+        @Override
         public PrintWriter getWriter() throws IOException
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public ServletOutputStream getOutputStream() throws IOException
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public Locale getLocale()
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public String getContentType()
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public String getCharacterEncoding()
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public int getBufferSize()
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void flushBuffer() throws IOException
         {
             committed = true;
         }
 
+        @Override
         public void setStatus(int sc, String sm)
         {
             status = sc;
             committed = true;
         }
 
+        @Override
         public void setStatus(int sc)
         {
             status = sc;
             committed = true;
         }
 
+        @Override
         public void setIntHeader(String name, int value)
         {
             headers.put(name, Integer.toString(value));
         }
 
+        @Override
         public void setHeader(String name, String value)
         {
             headers.put(name, value);
         }
 
+        @Override
         public void setDateHeader(String name, long date)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void sendRedirect(String location) throws IOException
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void sendError(int sc, String msg) throws IOException
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void sendError(int sc) throws IOException
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public int getStatus()
         {
             return status;
         }
 
+        @Override
         public Collection<String> getHeaders(String name)
         {
             return Collections.singleton(headers.get(name));
         }
 
+        @Override
         public Collection<String> getHeaderNames()
         {
             return headers.keySet();
         }
 
+        @Override
         public String getHeader(String name)
         {
             return headers.get(name);
         }
 
+        @Override
         public String encodeUrl(String url)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public String encodeURL(String url)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public String encodeRedirectUrl(String url)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public String encodeRedirectURL(String url)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public boolean containsHeader(String name)
         {
             return headers.containsKey(name);
         }
 
+        @Override
         public void addIntHeader(String name, int value)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void addHeader(String name, String value)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void addDateHeader(String name, long date)
         {
             throw new UnsupportedOperationException();
         }
 
+        @Override
         public void addCookie(Cookie cookie)
         {
             throw new UnsupportedOperationException();