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
Original issue reported on code.google.com by
stefan.m...@googlemail.com
on 20 Jun 2014 at 11:11