tjg184 / urlrewritefilter

Automatically exported from code.google.com/p/urlrewritefilter
Other
0 stars 0 forks source link

Relative URI in to-clause leads to currupt Location field, when type="permanent-redirect" or type="temporary-redirect" #163

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
What steps will reproduce the problem?

1.
    <rule>
        <from>/</from>
        <to type="permanent-redirect">/index</to>
    </rule>

2. $ curl -I http://localhost:8080/

What is the expected output? What do you see instead?

=Expected=

Like the implementation of mod_rewrite and the implementation of 
UrlRewriteFilter’s type="redirect", I expected the Location field to be an 
absolute URI (according to 
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.30), even if the 
to-part of the rule is a relative URI.

This is what type="redirect" does:

Rule:

    <rule>
        <from>/</from>
        <to type="redirect">/index</to>
    </rule>

Request+Response:

$ curl -I http://localhost:8080/
HTTP/1.1 302 Found
Server: Apache-Coyote/1.1
Location: http://localhost:8080/index
Content-Length: 0
Date: Fri, 20 Jun 2014 10:21:24 GMT

=Actual behavior=

Actually the permanent-redirect (same for type="temporary-redirect") behaves 
different to mod_rewrite and UrlRewriteFilter’s type="redirect". The Location 
field is simply filled with the content of the to-clause, which leads to an 
illegal response. Some clients, like most browsers, will handle those corrupt 
Location fields like HTML-links, depending on the request url, but there is no 
guarantee.

$ curl -I http://localhost:8080/
HTTP/1.1 301 Moved Permanently
Server: Apache-Coyote/1.1
Location: /index
Content-Length: 0
Date: Fri, 20 Jun 2014 10:26:19 GMT

What version of the product are you using? On what operating system?

UrlRewriteFilter:  3.2, 4.0.3
OS:                Linux (CentOS, Ubuntu)
Servlet-Container: Tomcat 6, Tomcat 7

Please provide any additional information below.

The reason why type="redirect" performs as expected is: the implementation just 
calls hsResponse.sendRedirect(target). HttpServletRespone.sendRedirect() 
composes the Location field correctly (testet with multiple versions of Tomcat).

In case of type="permanent-redirect" or type="temporary-redirect", the response 
is manually crafted as follows:

  hsResponse.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); // respectively SC_MOVED_TEMPORARILY
  hsResponse.setHeader("Location", target);

For UrlRewriteFilter 3.2 (probably adaptable to 4.0.x) I wrote a patch, which 
solves the problem for me:

Index: src/java/org/tuckey/web/filters/urlrewrite/NormalRewrittenUrl.java
===================================================================
--- 
src/java/org/tuckey/web/filters/urlrewrite/NormalRewrittenUrl.java  (revision 
325)
+++ src/java/org/tuckey/web/filters/urlrewrite/NormalRewrittenUrl.java  (working 
copy)
@@ -44,6 +44,7 @@
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
+import java.util.regex.Pattern;

 /**
@@ -53,6 +54,7 @@
  * @version $Revision: 1 $ $Date: 2006-08-01 21:40:28 +1200 (Tue, 01 Aug 2006) $
  */
 public class NormalRewrittenUrl implements RewrittenUrl {
+   private static final Pattern ABSOLUTE_URL_PATTERN = 
Pattern.compile("^[^:]+://[^/]+/.*$");

     private static Log log = Log.getLog(RewrittenUrl.class);

@@ -251,6 +253,7 @@
                     target = hsResponse.encodeRedirectURL(target);
                 }
                 hsResponse.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+                target = handleRelativeUrl(hsRequest, target);
                 hsResponse.setHeader("Location", target);
                 if (log.isTraceEnabled()) log.trace("temporarily redirected to " + target);
             }
@@ -265,6 +268,7 @@
                     target = hsResponse.encodeRedirectURL(target);
                 }
                 hsResponse.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
+                target = handleRelativeUrl(hsRequest, target);
                 hsResponse.setHeader("Location", target);
                 if (log.isTraceEnabled()) log.trace("permanently redirected to " + target);
             }
@@ -315,6 +319,23 @@
     public void setNoSubstitution(boolean noSubstitution) {
         this.noSubstitution = noSubstitution;
     }
-
+    
+    private static String handleRelativeUrl(HttpServletRequest request, String 
targetUrl){
+       StringBuffer requestUrlBuffer = request.getRequestURL();
+       return 
convertToAbsoluteUrl(null==requestUrlBuffer?"":requestUrlBuffer.toString(), 
targetUrl);
+    }

+    private static String convertToAbsoluteUrl(String contextUrl, String 
targetUrl){
+       if (ABSOLUTE_URL_PATTERN.matcher(contextUrl).matches()) {
+           if (targetUrl.startsWith("/")) {
+               int right = contextUrl.indexOf('/', contextUrl.indexOf("://") + 3);
+               targetUrl = contextUrl.substring(0, right) + targetUrl;
+           } else if (!targetUrl.contains("://")) {
+               int right = contextUrl.lastIndexOf('/') + 1;
+               targetUrl = contextUrl.substring(0, right) + targetUrl;
+           }
+       }
+       
+       return targetUrl;
+    }
 }

Original issue reported on code.google.com by stefan.m...@googlemail.com on 20 Jun 2014 at 11:11