From b936cba526fe5ae3da4e9a78f2f879cd5ae90b48 Mon Sep 17 00:00:00 2001 From: Paul Tuckey Date: Mon, 3 Jul 2023 10:18:09 +1200 Subject: [PATCH 1/2] progress --- annotation/pom.xml | 246 +- .../ProcessorServiceLoaderCheck.java | 38 +- build.xml | 52 +- src/doc/manual/2.6/doc.css | 146 +- src/doc/manual/2.6/guide.html | 1332 ++++---- src/doc/manual/2.6/index.html | 1904 +++++------ .../2.6/urlrewrite-conf-overview-sample.html | 338 +- src/doc/manual/3.0/annotation.html | 344 +- src/doc/manual/3.0/doc.css | 274 +- src/doc/manual/3.0/guide.html | 1482 ++++---- src/doc/manual/3.0/index.html | 2268 ++++++------- src/doc/manual/3.0/introduction.html | 526 +-- src/doc/manual/3.1/annotation.html | 306 +- src/doc/manual/3.1/doc.css | 274 +- src/doc/manual/3.1/guide.html | 1500 ++++----- src/doc/manual/3.1/index.html | 2630 +++++++-------- src/doc/manual/3.1/introduction.html | 550 +-- src/doc/manual/3.2/annotation.html | 326 +- src/doc/manual/3.2/doc.css | 278 +- src/doc/manual/3.2/guide.html | 1562 ++++----- src/doc/manual/3.2/index.html | 2916 ++++++++-------- src/doc/manual/3.2/introduction.html | 746 ++-- src/doc/manual/4.0/annotation.html | 364 +- src/doc/manual/4.0/doc.css | 206 +- src/doc/manual/4.0/guide.html | 1640 ++++----- src/doc/manual/4.0/index.html | 2986 ++++++++--------- src/doc/manual/4.0/introduction.html | 870 ++--- src/doc/manual/4.0/urlrewrite.xml | 194 +- src/doc/manual/guide.html | 26 +- src/doc/manual/index.html | 26 +- src/doc/maven-request.txt | 26 +- .../tuckey/web/filters/urlrewrite/doc/doc.css | 278 +- .../filters/urlrewrite/json/JsonWriter.java | 438 +-- .../urlrewrite/build.number.properties | 2 +- .../tuckey/web/filters/urlrewrite/doc/doc.css | 92 +- .../filters/urlrewrite/PerformanceTest.java | 236 +- .../filters/urlrewrite/RequestProxyTest.java | 44 +- .../urlrewrite/VariableReplacerTest.java | 196 +- .../functions/CssVarFunctionTest.java | 124 +- .../test/MockRequestParserTest.java | 136 +- .../utils/FunctionReplacerTest.java | 196 +- .../utils/ModRewriteConfLoaderTest.java | 482 +-- .../urlrewrite/conf-test-bad-parse.xml | 26 +- .../filters/urlrewrite/conf-test-no-dtd.xml | 26 +- .../web/filters/urlrewrite/conf-test1.xml | 172 +- .../filters/urlrewrite/conf-test2-incl.xml | 8 +- .../web/filters/urlrewrite/conf-test2.xml | 70 +- .../urlrewrite/utils/htaccess-test1.txt | 16 +- .../test-web-adhoc/WEB-INF/urlrewrite.xml | 42 +- src/test/test-web-adhoc/WEB-INF/web.xml | 44 +- src/test/test-web-adhoc/index.jsp | 10 +- src/test/webapp/WEB-INF/urlrewrite.xml | 404 +-- src/test/webapp/WEB-INF/web.xml | 96 +- src/test/webapp/test-set.jsp | 2 +- 54 files changed, 14758 insertions(+), 14758 deletions(-) diff --git a/annotation/pom.xml b/annotation/pom.xml index 9de2bc70..f4305310 100644 --- a/annotation/pom.xml +++ b/annotation/pom.xml @@ -1,124 +1,124 @@ - - - 4.0.0 - org.tuckey - urlrewritefilter-annotation - jar - 5.0.0 - UrlRewriteFilter Annotation - http://www.tuckey.org/urlrewrite/ - 2006 - - Add-on to urlrewritefilter to support annotations - - - - - UrlRewrite users - urlrewrite@googlegroups.com - urlrewrite+subscribe@googlegroups.com - urlrewrite+unsubscribe@googlegroups.com - https://groups.google.com/d/forum/urlrewrite - - - - - - BSD - http://www.opensource.org/licenses/bsd-license.php - repo - - - - - scm:git:https://github.com/paultuckey/urlrewritefilter.git - scm:git:https://github.com/paultuckey/urlrewritefilter.git - https://github.com/paultuckey/urlrewritefilter - - - - https://github.com/paultuckey/urlrewritefilter/issues - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - 1.5 - 1.5 - -proc:none - - - - - - - - com.sun - tools - 1.6.0 - system - ${java.home}/../lib/tools.jar - - - junit - junit - 4.13.1 - compile - - - javax.servlet - servlet-api - 2.4 - test - - - - - - - org.apache.maven.plugins - maven-surefire-report-plugin - 2.5 - - - org.apache.maven.plugins - maven-shade-plugin - 3.2.2 - - - jakarta - package - - shade - - - jakarta - true - false - - - ${project.groupId}:${project.artifactId} - - - - - javax.servlet - jakarta.servlet - - - javax.annotation - jakarta.annotation - - - - - - - - - + + + 4.0.0 + org.tuckey + urlrewritefilter-annotation + jar + 5.0.0 + UrlRewriteFilter Annotation + http://www.tuckey.org/urlrewrite/ + 2006 + + Add-on to urlrewritefilter to support annotations + + + + + UrlRewrite users + urlrewrite@googlegroups.com + urlrewrite+subscribe@googlegroups.com + urlrewrite+unsubscribe@googlegroups.com + https://groups.google.com/d/forum/urlrewrite + + + + + + BSD + http://www.opensource.org/licenses/bsd-license.php + repo + + + + + scm:git:https://github.com/paultuckey/urlrewritefilter.git + scm:git:https://github.com/paultuckey/urlrewritefilter.git + https://github.com/paultuckey/urlrewritefilter + + + + https://github.com/paultuckey/urlrewritefilter/issues + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + 1.5 + 1.5 + -proc:none + + + + + + + + com.sun + tools + 1.6.0 + system + ${java.home}/../lib/tools.jar + + + junit + junit + 4.13.1 + compile + + + javax.servlet + servlet-api + 2.4 + test + + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.5 + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.2 + + + jakarta + package + + shade + + + jakarta + true + false + + + ${project.groupId}:${project.artifactId} + + + + + javax.servlet + jakarta.servlet + + + javax.annotation + jakarta.annotation + + + + + + + + + \ No newline at end of file diff --git a/annotation/src/main/java/org/tuckey/web/filters/urlrewrite/annotation/ProcessorServiceLoaderCheck.java b/annotation/src/main/java/org/tuckey/web/filters/urlrewrite/annotation/ProcessorServiceLoaderCheck.java index 61d1a1ad..90c594e2 100644 --- a/annotation/src/main/java/org/tuckey/web/filters/urlrewrite/annotation/ProcessorServiceLoaderCheck.java +++ b/annotation/src/main/java/org/tuckey/web/filters/urlrewrite/annotation/ProcessorServiceLoaderCheck.java @@ -1,19 +1,19 @@ -package org.tuckey.web.filters.urlrewrite.annotation; - -import javax.annotation.processing.Processor; -import java.util.ServiceLoader; - -/** - * Quick and dirty class to check that "service" file is loaded in the current classpath. - */ -public class ProcessorServiceLoaderCheck { - - public static void main(String[] args) { - System.out.println("Checking for services..."); - ServiceLoader processorServices = ServiceLoader.load(Processor.class); - for (Object o : processorServices) { - System.out.println(o); - } - System.out.println("Done."); - } -} +package org.tuckey.web.filters.urlrewrite.annotation; + +import javax.annotation.processing.Processor; +import java.util.ServiceLoader; + +/** + * Quick and dirty class to check that "service" file is loaded in the current classpath. + */ +public class ProcessorServiceLoaderCheck { + + public static void main(String[] args) { + System.out.println("Checking for services..."); + ServiceLoader processorServices = ServiceLoader.load(Processor.class); + for (Object o : processorServices) { + System.out.println(o); + } + System.out.println("Done."); + } +} diff --git a/build.xml b/build.xml index 026d66c5..35fa1c1f 100644 --- a/build.xml +++ b/build.xml @@ -1,26 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/doc/manual/2.6/doc.css b/src/doc/manual/2.6/doc.css index e8771fd7..eda12dcc 100644 --- a/src/doc/manual/2.6/doc.css +++ b/src/doc/manual/2.6/doc.css @@ -1,73 +1,73 @@ -body { - background: #ffffff; - font: 13px Geneva, Verdana, Arial, Helvetica, sans-serif; -} - -h1 { - font-family: Arial, Helvetica, sans-serif; - color: #000000; - font-size: medium; - padding: 0px 0px 5px 5px; - margin: 0px; - border-bottom: 2px solid #808080; -} - -h2 { - border-bottom: 1px solid #808080; - padding: 5px; -} - -h3 { - border-bottom: 1px solid #c0c0c0; - margin-top: 2em; - padding: 0.25em 0.25em 0em 0.5em; -} - -p { - padding: 0.25em 0.25em 0em 1.0em; -} - -code, pre { - font-family: 'Courier New', courier, monospace; - font-size: 11px; -} - -pre { - background: #eeeeff; - margin: 0.5em 3em 0.1em 3em; - padding: 0.25em 0.5em 0.5em 0.5em; -} - -table { - border: 1px solid #c0c0c0; - margin-left: 2em; - border-collapse: collapse; - border-spacing: 0; -} - -th, td { - border: 1px solid #eeeeee; - vertical-align: top; - padding: 3px; -} - -th { - background: #eeeeee; -} - -hr { - border: 0px; - background-color: #c0c0c0; -} - -.err { - color: #ff0000; -} - -.outdated { - border: 2px solid red; - background: #eeeeee; - padding: 5px; - font-weight: bold; -} - +body { + background: #ffffff; + font: 13px Geneva, Verdana, Arial, Helvetica, sans-serif; +} + +h1 { + font-family: Arial, Helvetica, sans-serif; + color: #000000; + font-size: medium; + padding: 0px 0px 5px 5px; + margin: 0px; + border-bottom: 2px solid #808080; +} + +h2 { + border-bottom: 1px solid #808080; + padding: 5px; +} + +h3 { + border-bottom: 1px solid #c0c0c0; + margin-top: 2em; + padding: 0.25em 0.25em 0em 0.5em; +} + +p { + padding: 0.25em 0.25em 0em 1.0em; +} + +code, pre { + font-family: 'Courier New', courier, monospace; + font-size: 11px; +} + +pre { + background: #eeeeff; + margin: 0.5em 3em 0.1em 3em; + padding: 0.25em 0.5em 0.5em 0.5em; +} + +table { + border: 1px solid #c0c0c0; + margin-left: 2em; + border-collapse: collapse; + border-spacing: 0; +} + +th, td { + border: 1px solid #eeeeee; + vertical-align: top; + padding: 3px; +} + +th { + background: #eeeeee; +} + +hr { + border: 0px; + background-color: #c0c0c0; +} + +.err { + color: #ff0000; +} + +.outdated { + border: 2px solid red; + background: #eeeeee; + padding: 5px; + font-weight: bold; +} + diff --git a/src/doc/manual/2.6/guide.html b/src/doc/manual/2.6/guide.html index a4450c54..f1635c39 100644 --- a/src/doc/manual/2.6/guide.html +++ b/src/doc/manual/2.6/guide.html @@ -1,666 +1,666 @@ - - - - UrlRewriteFilter - Guide - - - - - - - -

UrlRewriteFilter 2.6 - Examples

- -

- Examples - Manual -
- General Examples - - Method Invocation - - URL Abstraction - - mod_rewrite vs urlrewrite filter - -

- - - -

General Examples

- -

Redirect one url

- -

-    <rule>
-    <from>^/some/old/page\.html$</from>
-    <to type="redirect">/very/new/page.html</to>
-    </rule>
-
- -

Tiny/Freindly url

- -

-    <rule>
-    <from>^/zebra$</from>
-    <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
-    </rule>
-
- -

Default page as another (requests to / will be redirected)

- -

-    <rule>
-    <from>^/$</from>
-    <to type="redirect">/opencms/opencms/index.html</to>
-    </rule>
-
- -

Perform security checks in a centralised place

- -

-    <rule>
-    <condition type="user-in-role" operator="notequal">admin</condition>
-    <condition type="user-in-role" operator="notequal">bigboss</condition>
-    <from>^/admin/(.*)$</from>
-    <to>/go-away-please.html</to>
-    </rule>
-
- - -

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah - will be redirected to http://www.example.com/blah

- -

-    <rule>
-    <name>Domain Name Check</name>
-    <condition name="host" operator="notequal">www.example.com</condition>
-    <from>(.*)</from>
-    <to type="redirect">http://www.example.com/context$1</to>
-    </rule>
-
- - -

Disable access to a directory.

- -

-    <rule>
-    <name>Disable Directory</name>
-    <from>^/notliveyet/.*$</from>
-    <to>null</to>
-    <set type="status">403</set>
-    </rule>
-
- -

Redirect a directory (for moved content)

- -

-    <rule>
-    <from>^/some/olddir/(.*)$</from>
-    <to type="redirect">/very/newdir/$1</to>
-    </rule>
-
- -

Clean a URL

- -

-    <rule>
-    <from>^/products/([0-9]+)$</from>
-    <to>/products/index.jsp?product_id=$1</to>
-    </rule>
-
- -

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 - without the user noticing.

- -

-    <rule>
-    <from>^/world/([a-z]+)/([a-z]+)$</from>
-    <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- -

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork -

- -

Browser detection

- -

-    <rule>
-    <condition name="user-agent">Mozilla/[1-4]</condition>
-    <from>^/some/page\.html$</from>
-    <to>/some/page-for-old-browsers.html</to>
-    </rule>
-
- -

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html - only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, - Mozilla/3 or Mozilla/4.

- - -

Security. Preclude certain types of method from you web application.

- -

-    <rule>
-    <condition type="method" next="or">PROPFIND</condition>
-    <condition type="method">PUT</condition>
-    <from>.*</from>
-    <to type="redirect">/bad-method.html</to>
-    </rule>
-
- - -

Sunday Specials

- -

-    <rule>
-    <condition type="dayofweek">1</condition>
-    <from>^/products/$</from>
-    <to>/products/sunday-specials.html</to>
-    </rule>
-
- - -

Set the "Cache-Control" HTTP response header for all requests

- -

-    <rule>
-    <from>.*</from>
-    <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
-    </rule>
-
- -

Forward a request to a servlet

- -

-    <rule>
-    <from>^/products/purchase$</from>
-    <to>/servlets/ProductsServlet</to>
-    <set name="action">purchase</set>
-    </rule>
-
- -

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and - inside - the servlet request.getAttribute("action") will return purchase.

- -

Hide jsessionid for requests from googlebot.

- -

-    <outbound-rule encodefirst="true">
-    <condition name="user-agent">googlebot.*</condition>
-    <from>^(.*);jsessionid=.*(\?.*)$</from>
-    <to>$1$2</to>
-    </outbound-rule>
-
- - -

Method Invocation

- -

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have - any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

- -

Invoke a servlet directly

- -

-    <rule>
-    <from>^/products/purchase$</from>
-    <run class="com.blah.web.MyServlet" method="doGet" />
-    </rule>
-
- -

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is - matched on a request. (remeber this method needs to be public!)

- -

Use it to delagate cleanly to your methods

- -

-    <rule>
-    <from>^/pref-editor/addresses$</from>
-    <run class="com.blah.web.PrefsServlet" method="runAddresses" />
-    </rule>
-    <rule>
-    <from>^/pref-editor/phone-nums$</from>
-    <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
-    </rule>
-
- -

Browser based delagation to your methods

- -

-    <rule>
-    <condition name="user-agent">Mozilla/[1-4]</condition>
-    <from>^/content/.*$</from>
-    <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
-    </rule>
-    <rule>
-    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-    <from>^/content/.*$</from>
-    <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
-    <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
-    </rule>
-
- -

When the method specified in the "run" is invoked it has full control over the request and response as if it were a - servlet.

- - - - - - -

URL Abstraction

- -

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

- -

-    <rule>
-    <from>^/tidy/page$</from>
-    <to>/old/url/scheme/page.jsp</to>
-    </rule>
-    <outbound-rule>
-    <from>^/old/url/scheme/page.jsp$</from>
-    <to>/tidy/page</to>
-    </outbound-rule>
-
- -

Any incoming requests for /tidy/page will be transparently forwarded to - /old/url/scheme/page.jsp.

- -

If you use JSTL your JSP page would have something like:

-
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
- -

This will be rewritten upon output to:

-
<a href="/tidy/page">some link</a>
- -

Or if you use standard JSP:

-
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
- -

Will generate output like:

-
<a href="/tidy/page">some link</a>
- - - - -

mod_rewrite vs urlrewrite filter

- - -

Examples of mod_rewrite style conf vs urlrewrite filter conf are below, there are all examples copied directly from - Apache 2.0's official rewrite guide.

- -

-
-<rule>
-<name>Canonical URLs</name>
-<note>
-On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
-should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
-of which URL the user supplied with the request he should finally see the canonical one only.
-
-We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
-and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
-fix a missing trailing slash for /u/user.
-
-RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
-RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
-</note>
-<from>^/~([^/]+)/?(.*)</from>
-<to type="redirect">/u/$1/$2</to>
-</rule>
-<rule>
-<from>^/([uge])/([^/]+)$</from>
-<to type="redirect">/$1/$2/</to>
-</rule>
-
-
-<rule>
-<name>Canonical Hostnames</name>
-<note>
-The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
-may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
-example.com, you might use a variant of the following recipe.
-
-RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
-RewriteCond %{HTTP_HOST} !^$
-RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
-</note>
-<condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
-<condition name="host" operator="notequal">^$</condition>
-<from>^/(.*)</from>
-<to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
-</rule>
-
-
-<rule>
-<name>Moved DocumentRoot</name>
-<note>
-Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
-really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
-Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
-because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
-stuff inside this data pool work for subsequent requests.
-
-We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
-Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
-matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
-With mod_rewrite it is really trivial:
-
-RewriteRule ^/$ /e/www/ [R]
-</note>
-<from>^/$</from>
-<to type="redirect">/e/www/</to>
-</rule>
-
-
-<rule>
-<name>Trailing Slash Problem</name>
-<note>
-Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
-If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
-the server searches for a file named foo. And because this file is a directory it complains. Actually it
-tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
-instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
-
-The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
-correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
-we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
-images are included into this page with relative URLs, because the browser would request an in-lined object.
-For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
-external redirect!
-</note>
-<from>^/~quux/foo$</from>
-<to type="redirect">/~quux/foo/</to>
-</rule>
-
-
-<rule>
-<name>Move Homedirs to Different Webserver</name>
-<note>
-Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
-homedirs on a webserver to another webserver. They usually need such things when establishing a newer
-webserver which will replace the old one over time.
-
-The solution is trivial with mod_rewrite (and urlrewrite filter). On the old webserver we just redirect all
-/~user/anypath URLs to http://newserver/~user/anypath.
-
-RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
-</note>
-<from>^/~(.+)</from>
-<to type="redirect" last="true">http://newserver/~$1</to>
-</rule>
-
-
-<rule>
-<name>Structured Homedirs</name>
-<note>
-Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
-subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
-/home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
-
-We use the following ruleset to expand the tilde URLs into exactly the above layout.
-
-RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
-</note>
-<from>^/~(([a-z])[a-z0-9]+)(.*)</from>
-<to>/home/$2/$1/.www$3</to>
-</rule>
-
-
-<rule>
-<name>Redirect Homedirs For Foreigners</name>
-<note>
-We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
-stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
-
-Just a rewrite condition:
-
-RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
-RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
-</note>
-<condition name="host">!^.+\.ourdomain\.com$</condition>
-<from>^(/~.+)</from>
-<to type="redirect" last="true">http://www.somewhere.com/$1</to>
-</rule>
-
-
-<rule>
-<name>Time-Dependent Rewriting</name>
-<note>
-When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
-instance redirects to specialized pages. How can it be done via mod_rewrite?
-
-There are a lot of types in conjunction with operators we can do time-dependent redirects:
-
-RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
-RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
-RewriteRule ^foo\.html$ foo.day.html
-RewriteRule ^foo\.html$ foo.night.html
-</note>
-<condition type="hourofday" operator="greater">7</condition>
-<condition type="hourofday" operator="less">19</condition>
-<from>^foo\.html$</from>
-<to>foo.day.html</to>
-</rule>
-<rule>
-<from>^foo\.html$</from>
-<to>foo.night.html</to>
-</rule>
-
-
-<rule>
-<name></name>
-<note>
-Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
-backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
-renamed.
-
-We rewrite the old URL to the new one internally via the following rule:
-
-RewriteBase /~quux/
-RewriteRule ^foo\.html$ bar.html
-</note>
-<from>^/~quux/foo\.html$</from>
-<to>/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-<name>From Old to New (extern)</name>
-<note>
-Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
-for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
-i.e. their browsers Location field should change, too.
-
-We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
-
-RewriteBase /~quux/
-RewriteRule ^foo\.html$ bar.html [R]
-</note>
-<from>^/~quux/foo\.html$</from>
-<to type="redirect">/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-<name>Browser Dependent Content</name>
-<note>
-At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
-content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
-the Lynx browsers and a average feature version for all others.
-
-We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
-have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
-"User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
-stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
-browsers receive page foo.32.html. This is done by the following ruleset:
-
-RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
-RewriteRule ^foo\.html$ foo.NS.html [L]
-
-RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
-RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
-RewriteRule ^foo\.html$ foo.20.html [L]
-
-RewriteRule ^foo\.html$ foo.32.html [L]
-</note>
-<condition name="user-agent">^Mozilla/3.*</condition>
-<from>^foo\.html$</from>
-<to last="true">foo.NS.html</to>
-</rule>
-<rule>
-<condition name="user-agent" next="or">^Lynx/.*</condition>
-<condition name="user-agent">^Mozilla/[12].*</condition>
-<from>^foo\.html$</from>
-<to last="true">foo.20.html</to>
-</rule>
-<rule>
-<from>^foo\.html$</from>
-<to last="true">foo.32.html</to>
-</rule>
-
-
-<rule>
-<name>From Static to Dynamic</name>
-<note>
-How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
-notice by the browser/user.
-
-We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
-a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
-
-RewriteBase /~quux/
-RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
-</note>
-<from>^/~quux/foo\.html$</from>
-<to>/~quux/foo.jsp</to>
-</rule>
-
-<rule>
-<name>Blocking of Robots</name>
-<note>
-    How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
-    containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
-
-    We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
-    indexed area where the robot traversal would create big server load). We have to make sure that we forbid
-    access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
-    This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
-    information.
-
-    RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
-    RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
-    RewriteRule ^/~quux/foo/arc/.+ - [F]
-</note>
-<condition name="user-agent">^NameOfBadRobot.*</condition>
-<condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
-<from>^/~quux/foo/arc/.+</from>
-<to>null</to>
-<set type="status">403</set>
-</rule>
-
-
-<rule>
-<name>Blocked Inline-Images</name>
-<note>
-Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
-nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
-it adds useless traffic to our server.
-
-While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
-sends a HTTP Referer header.
-
-RewriteCond %{HTTP_REFERER} !^$
-RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
-RewriteRule .*\.gif$ - [F]
-</note>
-<condition name="referer" operator="notequal">^$</condition>
-<condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
-<from>.*\.gif$</from>
-<to>null</to>
-<set type="status">403</set>
-</rule>
-<rule>
-<name>Blocked Inline-Images example 2</name>
-<note>
-RewriteCond %{HTTP_REFERER} !^$
-RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
-RewriteRule ^inlined-in-foo\.gif$ - [F]
-</note>
-<condition name="referer" operator="notequal">^$</condition>
-<condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
-<from>^inlined-in-foo\.gif$</from>
-<to>null</to>
-<set type="status">403</set>
-</rule>
-
-
- - -
-
-
- -

Copyright 2007 Paul Tuckey

- - - + + + + UrlRewriteFilter - Guide + + + + + + + +

UrlRewriteFilter 2.6 - Examples

+ +

+ Examples - Manual +
+ General Examples + - Method Invocation + - URL Abstraction + - mod_rewrite vs urlrewrite filter + +

+ + + +

General Examples

+ +

Redirect one url

+ +

+    <rule>
+    <from>^/some/old/page\.html$</from>
+    <to type="redirect">/very/new/page.html</to>
+    </rule>
+
+ +

Tiny/Freindly url

+ +

+    <rule>
+    <from>^/zebra$</from>
+    <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
+    </rule>
+
+ +

Default page as another (requests to / will be redirected)

+ +

+    <rule>
+    <from>^/$</from>
+    <to type="redirect">/opencms/opencms/index.html</to>
+    </rule>
+
+ +

Perform security checks in a centralised place

+ +

+    <rule>
+    <condition type="user-in-role" operator="notequal">admin</condition>
+    <condition type="user-in-role" operator="notequal">bigboss</condition>
+    <from>^/admin/(.*)$</from>
+    <to>/go-away-please.html</to>
+    </rule>
+
+ + +

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah + will be redirected to http://www.example.com/blah

+ +

+    <rule>
+    <name>Domain Name Check</name>
+    <condition name="host" operator="notequal">www.example.com</condition>
+    <from>(.*)</from>
+    <to type="redirect">http://www.example.com/context$1</to>
+    </rule>
+
+ + +

Disable access to a directory.

+ +

+    <rule>
+    <name>Disable Directory</name>
+    <from>^/notliveyet/.*$</from>
+    <to>null</to>
+    <set type="status">403</set>
+    </rule>
+
+ +

Redirect a directory (for moved content)

+ +

+    <rule>
+    <from>^/some/olddir/(.*)$</from>
+    <to type="redirect">/very/newdir/$1</to>
+    </rule>
+
+ +

Clean a URL

+ +

+    <rule>
+    <from>^/products/([0-9]+)$</from>
+    <to>/products/index.jsp?product_id=$1</to>
+    </rule>
+
+ +

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 + without the user noticing.

+ +

+    <rule>
+    <from>^/world/([a-z]+)/([a-z]+)$</from>
+    <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ +

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork +

+ +

Browser detection

+ +

+    <rule>
+    <condition name="user-agent">Mozilla/[1-4]</condition>
+    <from>^/some/page\.html$</from>
+    <to>/some/page-for-old-browsers.html</to>
+    </rule>
+
+ +

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html + only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, + Mozilla/3 or Mozilla/4.

+ + +

Security. Preclude certain types of method from you web application.

+ +

+    <rule>
+    <condition type="method" next="or">PROPFIND</condition>
+    <condition type="method">PUT</condition>
+    <from>.*</from>
+    <to type="redirect">/bad-method.html</to>
+    </rule>
+
+ + +

Sunday Specials

+ +

+    <rule>
+    <condition type="dayofweek">1</condition>
+    <from>^/products/$</from>
+    <to>/products/sunday-specials.html</to>
+    </rule>
+
+ + +

Set the "Cache-Control" HTTP response header for all requests

+ +

+    <rule>
+    <from>.*</from>
+    <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
+    </rule>
+
+ +

Forward a request to a servlet

+ +

+    <rule>
+    <from>^/products/purchase$</from>
+    <to>/servlets/ProductsServlet</to>
+    <set name="action">purchase</set>
+    </rule>
+
+ +

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and + inside + the servlet request.getAttribute("action") will return purchase.

+ +

Hide jsessionid for requests from googlebot.

+ +

+    <outbound-rule encodefirst="true">
+    <condition name="user-agent">googlebot.*</condition>
+    <from>^(.*);jsessionid=.*(\?.*)$</from>
+    <to>$1$2</to>
+    </outbound-rule>
+
+ + +

Method Invocation

+ +

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have + any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

+ +

Invoke a servlet directly

+ +

+    <rule>
+    <from>^/products/purchase$</from>
+    <run class="com.blah.web.MyServlet" method="doGet" />
+    </rule>
+
+ +

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is + matched on a request. (remeber this method needs to be public!)

+ +

Use it to delagate cleanly to your methods

+ +

+    <rule>
+    <from>^/pref-editor/addresses$</from>
+    <run class="com.blah.web.PrefsServlet" method="runAddresses" />
+    </rule>
+    <rule>
+    <from>^/pref-editor/phone-nums$</from>
+    <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
+    </rule>
+
+ +

Browser based delagation to your methods

+ +

+    <rule>
+    <condition name="user-agent">Mozilla/[1-4]</condition>
+    <from>^/content/.*$</from>
+    <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
+    </rule>
+    <rule>
+    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+    <from>^/content/.*$</from>
+    <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
+    <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
+    </rule>
+
+ +

When the method specified in the "run" is invoked it has full control over the request and response as if it were a + servlet.

+ + + + + + +

URL Abstraction

+ +

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

+ +

+    <rule>
+    <from>^/tidy/page$</from>
+    <to>/old/url/scheme/page.jsp</to>
+    </rule>
+    <outbound-rule>
+    <from>^/old/url/scheme/page.jsp$</from>
+    <to>/tidy/page</to>
+    </outbound-rule>
+
+ +

Any incoming requests for /tidy/page will be transparently forwarded to + /old/url/scheme/page.jsp.

+ +

If you use JSTL your JSP page would have something like:

+
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
+ +

This will be rewritten upon output to:

+
<a href="/tidy/page">some link</a>
+ +

Or if you use standard JSP:

+
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
+ +

Will generate output like:

+
<a href="/tidy/page">some link</a>
+ + + + +

mod_rewrite vs urlrewrite filter

+ + +

Examples of mod_rewrite style conf vs urlrewrite filter conf are below, there are all examples copied directly from + Apache 2.0's official rewrite guide.

+ +

+
+<rule>
+<name>Canonical URLs</name>
+<note>
+On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
+should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
+of which URL the user supplied with the request he should finally see the canonical one only.
+
+We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
+and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
+fix a missing trailing slash for /u/user.
+
+RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
+RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
+</note>
+<from>^/~([^/]+)/?(.*)</from>
+<to type="redirect">/u/$1/$2</to>
+</rule>
+<rule>
+<from>^/([uge])/([^/]+)$</from>
+<to type="redirect">/$1/$2/</to>
+</rule>
+
+
+<rule>
+<name>Canonical Hostnames</name>
+<note>
+The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
+may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
+example.com, you might use a variant of the following recipe.
+
+RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
+RewriteCond %{HTTP_HOST} !^$
+RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
+</note>
+<condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
+<condition name="host" operator="notequal">^$</condition>
+<from>^/(.*)</from>
+<to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
+</rule>
+
+
+<rule>
+<name>Moved DocumentRoot</name>
+<note>
+Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
+really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
+Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
+because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
+stuff inside this data pool work for subsequent requests.
+
+We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
+Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
+matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
+With mod_rewrite it is really trivial:
+
+RewriteRule ^/$ /e/www/ [R]
+</note>
+<from>^/$</from>
+<to type="redirect">/e/www/</to>
+</rule>
+
+
+<rule>
+<name>Trailing Slash Problem</name>
+<note>
+Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
+If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
+the server searches for a file named foo. And because this file is a directory it complains. Actually it
+tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
+instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
+
+The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
+correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
+we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
+images are included into this page with relative URLs, because the browser would request an in-lined object.
+For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
+external redirect!
+</note>
+<from>^/~quux/foo$</from>
+<to type="redirect">/~quux/foo/</to>
+</rule>
+
+
+<rule>
+<name>Move Homedirs to Different Webserver</name>
+<note>
+Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
+homedirs on a webserver to another webserver. They usually need such things when establishing a newer
+webserver which will replace the old one over time.
+
+The solution is trivial with mod_rewrite (and urlrewrite filter). On the old webserver we just redirect all
+/~user/anypath URLs to http://newserver/~user/anypath.
+
+RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
+</note>
+<from>^/~(.+)</from>
+<to type="redirect" last="true">http://newserver/~$1</to>
+</rule>
+
+
+<rule>
+<name>Structured Homedirs</name>
+<note>
+Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
+subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
+/home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
+
+We use the following ruleset to expand the tilde URLs into exactly the above layout.
+
+RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
+</note>
+<from>^/~(([a-z])[a-z0-9]+)(.*)</from>
+<to>/home/$2/$1/.www$3</to>
+</rule>
+
+
+<rule>
+<name>Redirect Homedirs For Foreigners</name>
+<note>
+We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
+stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
+
+Just a rewrite condition:
+
+RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
+RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
+</note>
+<condition name="host">!^.+\.ourdomain\.com$</condition>
+<from>^(/~.+)</from>
+<to type="redirect" last="true">http://www.somewhere.com/$1</to>
+</rule>
+
+
+<rule>
+<name>Time-Dependent Rewriting</name>
+<note>
+When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
+instance redirects to specialized pages. How can it be done via mod_rewrite?
+
+There are a lot of types in conjunction with operators we can do time-dependent redirects:
+
+RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
+RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
+RewriteRule ^foo\.html$ foo.day.html
+RewriteRule ^foo\.html$ foo.night.html
+</note>
+<condition type="hourofday" operator="greater">7</condition>
+<condition type="hourofday" operator="less">19</condition>
+<from>^foo\.html$</from>
+<to>foo.day.html</to>
+</rule>
+<rule>
+<from>^foo\.html$</from>
+<to>foo.night.html</to>
+</rule>
+
+
+<rule>
+<name></name>
+<note>
+Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
+backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
+renamed.
+
+We rewrite the old URL to the new one internally via the following rule:
+
+RewriteBase /~quux/
+RewriteRule ^foo\.html$ bar.html
+</note>
+<from>^/~quux/foo\.html$</from>
+<to>/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+<name>From Old to New (extern)</name>
+<note>
+Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
+for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
+i.e. their browsers Location field should change, too.
+
+We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
+
+RewriteBase /~quux/
+RewriteRule ^foo\.html$ bar.html [R]
+</note>
+<from>^/~quux/foo\.html$</from>
+<to type="redirect">/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+<name>Browser Dependent Content</name>
+<note>
+At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
+content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
+the Lynx browsers and a average feature version for all others.
+
+We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
+have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
+"User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
+stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
+browsers receive page foo.32.html. This is done by the following ruleset:
+
+RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
+RewriteRule ^foo\.html$ foo.NS.html [L]
+
+RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
+RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
+RewriteRule ^foo\.html$ foo.20.html [L]
+
+RewriteRule ^foo\.html$ foo.32.html [L]
+</note>
+<condition name="user-agent">^Mozilla/3.*</condition>
+<from>^foo\.html$</from>
+<to last="true">foo.NS.html</to>
+</rule>
+<rule>
+<condition name="user-agent" next="or">^Lynx/.*</condition>
+<condition name="user-agent">^Mozilla/[12].*</condition>
+<from>^foo\.html$</from>
+<to last="true">foo.20.html</to>
+</rule>
+<rule>
+<from>^foo\.html$</from>
+<to last="true">foo.32.html</to>
+</rule>
+
+
+<rule>
+<name>From Static to Dynamic</name>
+<note>
+How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
+notice by the browser/user.
+
+We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
+a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
+
+RewriteBase /~quux/
+RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
+</note>
+<from>^/~quux/foo\.html$</from>
+<to>/~quux/foo.jsp</to>
+</rule>
+
+<rule>
+<name>Blocking of Robots</name>
+<note>
+    How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
+    containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
+
+    We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
+    indexed area where the robot traversal would create big server load). We have to make sure that we forbid
+    access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
+    This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
+    information.
+
+    RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
+    RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
+    RewriteRule ^/~quux/foo/arc/.+ - [F]
+</note>
+<condition name="user-agent">^NameOfBadRobot.*</condition>
+<condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
+<from>^/~quux/foo/arc/.+</from>
+<to>null</to>
+<set type="status">403</set>
+</rule>
+
+
+<rule>
+<name>Blocked Inline-Images</name>
+<note>
+Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
+nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
+it adds useless traffic to our server.
+
+While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
+sends a HTTP Referer header.
+
+RewriteCond %{HTTP_REFERER} !^$
+RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
+RewriteRule .*\.gif$ - [F]
+</note>
+<condition name="referer" operator="notequal">^$</condition>
+<condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
+<from>.*\.gif$</from>
+<to>null</to>
+<set type="status">403</set>
+</rule>
+<rule>
+<name>Blocked Inline-Images example 2</name>
+<note>
+RewriteCond %{HTTP_REFERER} !^$
+RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
+RewriteRule ^inlined-in-foo\.gif$ - [F]
+</note>
+<condition name="referer" operator="notequal">^$</condition>
+<condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
+<from>^inlined-in-foo\.gif$</from>
+<to>null</to>
+<set type="status">403</set>
+</rule>
+
+
+ + +
+
+
+ +

Copyright 2007 Paul Tuckey

+ + + diff --git a/src/doc/manual/2.6/index.html b/src/doc/manual/2.6/index.html index 373041c1..1ab886b0 100644 --- a/src/doc/manual/2.6/index.html +++ b/src/doc/manual/2.6/index.html @@ -1,952 +1,952 @@ - - - - UrlRewriteFilter - Manual - - - - - -

UrlRewriteFilter 2.6 - Manual

- - - -

- Examples - Manual -
- Install - - Filter Parameters - - Configuration - - Testing - - Performance - - Ant Task - -

- -

Community support is available at UrlRewrite on StackOverflow.

- -

Read examples of usage and a - sample of the ant task report. - If you have feedback, or conf you want to share with the world email me.

- - - -

Install

- -
    -
  1. Download the zip (or tar.gz) and extract it into your - context's directory ie, so that urlrewrite.xml goes into the WEB-INF directory.
  2. -
  3. Add the following to your WEB-INF/web.xml (add it near the top above your - servlet mappings (if you have any)): (see filter - parameters for more options) -
    
    -            <filter>
    -            <filter-name>UrlRewriteFilter</filter-name>
    -            <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    -            </filter>
    -            <filter-mapping>
    -            <filter-name>UrlRewriteFilter</filter-name>
    -            <url-pattern>/*</url-pattern>
    -            </filter-mapping>
    -        
  4. -
  5. Add your own configuration to the WEB-INF/urlrewrite.xml that was created.
  6. -
  7. Restart the context.
  8. -
- -

You can visit http://127.0.0.1:8080/rewrite-status - (or whatever the address of your local webapp and context) - to see output (note: this page is only viewable from localhost).

- - - -

Filter Parameters

- -

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

- -

-    <filter>
-    <filter-name>UrlRewriteFilter</filter-name>
-    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-    <!-- set the amount of seconds the conf file will be checked for reload
-    can be a valid integer (0 denotes check every time,
-          empty/not set denotes no reload check) -->
-    <init-param>
-    <param-name>confReloadCheckInterval</param-name>
-    <param-value>60</param-value>
-    </init-param>
-
-    <!-- sets up log level (will be logged to context log)
-    can be: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL, log4j, commons, sysout:{level} (ie, sysout:DEBUG)
-          if you are having trouble using normal levels use sysout:DEBUG -->
-    <init-param>
-    <param-name>logLevel</param-name>
-    <param-value>DEBUG</param-value>
-    </init-param>
-
-    <!-- you can disable status page if desired
-    can be: true, false (default true) -->
-    <init-param>
-    <param-name>statusEnabled</param-name>
-    <param-value>true</param-value>
-    </init-param>
-
-        <!-- you can change status path so that it does not
-          conflict with your installed apps (note, defaults
-          to /rewrite-status) note, must start with / -->
-    <init-param>
-            <param-name>statusPath</param-name>
-            <param-value>/status</param-value>
-    </init-param>
-
-    </filter>
-    <filter-mapping>
-    <filter-name>UrlRewriteFilter</filter-name>
-    <url-pattern>/*</url-pattern>
-    </filter-mapping>
-
- -

Note, setting logLevel to log4j or commons will cause the built in loging to - call either log4j or - commons-logging as if they were the logging framework, - obviously you will need to have the jar for log4j or commons-logging in your classpath.

- - - - -

Configuration File WEB-INF/urlrewrite.xml

- -

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named - urlrewrite.xml. - It may be helpful to read the UrlRewriteFilter DTD - (Document Type Definition). Please also make sure you look at the examples. A simple - configuration file looks like:

- -

-    <?xml version="1.0" encoding="utf-8"?>
-
-    <!DOCTYPE urlrewrite
-    PUBLIC "-//tuckey.org//DTD UrlRewrite 2.6//EN"
-    "http://www.tuckey.org/res/dtds/urlrewrite2.6.dtd">
-
-    <urlrewrite>
-
-    <rule>
-    <from>^/some/olddir/(.*)$</from>
-    <to type="redirect">/very/newdir/$1</to>
-    </rule>
-
-    </urlrewrite>
-
- - -

The urlrewrite.xml file must have a root element called "urlrewrite" and must contain - at least one "rule" element.

- -

A "rule" must contain a "from" and a "to", and can have zero or more "condition" elements and zero or more and/or - "set" elements.

- -

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then - the "from" will be applied to the request URL and the final URL generated by applying the - "to" to the "from" pattern. So long as the rule has matched then the "set" will be run.

- -

Traps for young players:

- -
    -
  • when you want to put an "&" in a rule you must enter it as the XML entity "&amp;"
  • -
  • for simplicity you might want to start all from's with a ^ and end them with a $. -
    In regular expressions ^ specifies the start of - the string and $ specifies the end. -
    ie, a request for /my/url/path will NOT match - <from>^/url/$</from> but it will match <from>/url/</from> -
    -
  • If using <outbound-rule> remember all urls in your code must be encoded e.g. - <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • -
  • Regular expressions are complex and a bit trick at times. read - Regular expression syntax for - Java. -
  • -
- -

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

- -

-    Pattern.compile(<from> element);
-    pattern.matcher(request url);
-    matcher.replaceAll(<to> element);
-    if ( <condition> elements match && matcher.find() ) {
-        handle <set> elements (if any)
-        execute <run> elements (if any)
-        perform <to> element (if any)
-    }
-
- - -

<rule> element

- -

Zero or more. The basis of a rule.

- - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
- -

In the following example requests for /world/usa/nyc will be transparently forwarded to - /world.jsp?country=usa&city=nyc

- -

-    <rule enabled="true">
-       <from>^/world/([a-z]+)/([a-z]+)$</from>
-       <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- - -

<outbound-rule> element

- -

Zero or more. This is very similar to a normal rule but it is used for rewriting urls that go through - response.encodeURL().

- - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
trueRun encodeURL() before running this outbound rule.
false (default)Run encodeURL() after running this outbound rule.
- -

May contain "run", "from", "to" and "set" element(s) also. Example:

- -

-    <outbound-rule>
-    <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
-    <to>/world/$1/$2</to>
-    </outbound-rule>
-
- -

Using the example above JSP's with the code -
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") %>">nyc</a> -
will output -
<a href="/world/usa/nyc">nyc</a> -

- -

Note, If you are using JSTL (ie, <c:url) this will work also.

- -

<name> element

- -

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. - See ant task.

- -

-    <rule>
-    <name>World Rule</name>
-    <from>^/world/([a-z]+)/([a-z]+)$</from>
-    <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- - -

<note> element

- -

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. - See ant task.

- -

-    <rule>
-    <name>World Rule</name>
-    <note>
-        Cleanly redirect world requests to JSP,
-        a country and city must be specified.
-        </note>
-    <from>^/world/([a-z]+)/([a-z]+)$</from>
-    <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- - -

<condition> element

- -

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run - (unless "next" is set to "or" obvoiusly).

- -

Value can be any Regular Expression (Perl5 style).

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD etc.
portThe port that the web application server is running on.
time - Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC otherwise known as unix - time). -
i.e. (new Date()).getTime() -
This can be used for making sure content goes live only at a time you set. -
year - Current year at the server. -
i.e. (Calendar.getInstance()).get(Calendar.YEAR) -
month - Month at the server. January is 0 -
i.e. (Calendar.getInstance()).get(Calendar.MONTH) -
dayofmonth - Day of the month at the server. March first is 1 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) -
dayofweek - Day of the week at the server. Saturday is 1, Sunday is 7 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) -
ampm - AM or PM time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) -
hourofday - The hour of the day (24 hour clock) at the server. 10pm is 22 -
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) -
minute - The minute field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) -
second - The second field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.SECOND) -
millisecond - The millisecond field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) -
attribute - Will check the value of a request attribute (don't confuse this with parameter!), name must be set when - using this type. -
i.e. request.getAttribute([name]) - -
auth-type - Will check the value of a request attribute (don't confuse this with parameter!) -
i.e. request.getAuthType() - -
character-encoding - The character encoding of the imcoming request. -
i.e. request.getCharacterEncoding() - -
content-length - The length of the imcoming request (can be useful if you want to deny large requests). -
i.e. request.getContentLength() - -
content-type - The type of the imcoming request. (this is probably not that useful) -
i.e. request.getContentType() - -
context-path - The context path of the imcoming request. -
i.e. request.getContextPath() - -
cookie - The value of a cookie, note, name must be specified to use this -
i.e. request.getCookies() - the find we the one with [name] specified and check the value. -
parameter - A tidier way of checking request parameters than looking for them in the query string. This will check for the - parameter in GET or POST, note, name must be specified. -
i.e. request.getParameter([name]) - -
path-info - i.e. request.getPathInfo() - -
path-translated - i.e. request.getPathTranslated() - -
protocolThe protocol used to make the request, e.g. HTTP/1.1 -
i.e. request.getProtocol() - -
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob -
i.e. request.getQueryString() - -
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 -
i.e. request.getRemoteAddr() - -
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, - this will only work if your app server is configured to lookup host names, most aren't). -
i.e. request.getRemoteHost() - -
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt -
i.e. request.getRemoteUser() - -
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 -
i.e. request.getRequestedSessionId() - -
request-uriReturns the part of this request's URL from the protocol name up to the query - string in the first line of the HTTP request -
i.e. request.getRequestURI() - -
request-urlReconstructs the URL the client used to make the request. The returned URL - contains a protocol, server name, port number, and server path, but it does not include query string parameters. -
i.e. request.getRequestURL() - -
session-attribute - (note, name must be set) -
i.e. session.getAttribute([name]) - -
session-isnew - Weather the session is new or not. -
i.e. session.isNew() - -
server-name - The host name of the server to which the request was sent (from the host header not the machine name). -
i.e. request.getServerName() - -
scheme - The scheme used for the request, e.g. http or https -
i.e. request.getScheme() - -
user-in-role - (Note, the value for this cannot be a regular expression) -
i.e. request.isUserInRole([value]) - -
name
(optional)
(can be anything)If type is header, this specifies the name of the HTTP header used to run the value - against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator to be used when the condition is run.
notequalNot equal to. (i.e. request value != condition value). Note, this operator only work with - numeric rule types.
greaterGreater than. (i.e. request value > condition value). Note, this operator only work with - numeric - rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only work with numeric - rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator - only - work with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only - work with numeric rule types.
- -

Examples:

- -

-    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-
-    <condition type="user-in-role" operator="notequal">bigboss</condition>
-
-    <condition name="host" operator="notequal">www.example.com</condition>
-
-    <condition type="method" next="or">PROPFIND</condition>
-    <condition type="method">PUT</condition>
-
- - -

<from> element

- -

You must always have exactly one from for each rule or outbound-rule. Value can be a regular expression in the - Perl5 style. Note, from url's are relative to the context.

- - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using case insentitive match. ie, "/WellingtoN" will match "/wellington". -
trueThis value will be matched using case sentitive match. ie, "/aAa" will NOT match "/aaa". -
- -

Example:

- -

-    <from>^/world/([a-z]+)$</from>
-
- - -

<to> element

- -

Value can be a regular replacement expression in the Perl5 style.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally - forwarded - to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as - UrlRewriteFilter. This is the same as doing: -
RequestDispatcher rq = request.getRequestDispatcher([to value]); -
rq.forward(request, response);
-
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. - This is the same a doing: -
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_PERMANENTLY is HTTP status code 301)
temporary-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) - will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) - will NOT be called.
- -

Note, "to" can be null ie, <to>null</to>, this will mean that the request will go no - further if the rule is matched (ie, this filter will not call chain.doFilter).

- -

-    <to>/world.jsp?country=$1</to>
-
- -

To elements can contain backreferences and variables.

- - -

Backreferences

- -

-    %N
-
- -

Provides access to the grouped parts (parentheses!) of the pattern from the last matched Condition in the current rule. - N must be less than 10 and greater than 0.

- - -

Variables

- -

-    %{VARIABLE-NAME}
-
- -

Any valid condition type can be used as a variable name. ie, - '%{port}' will be translated to '80', - '%{year}' to '2005', - '%{cookie:myCookie}' would be translated to - 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

- -

Valid types are and condition type, see condition for a full description.

- - -

<set> element

- -

Allows you to set varous things if the rule is matched.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], - [value]) - (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], - [value]) - (note, name must be set).
response-headerThe same as response.setHeader([name], - [value]) - (note, name must be set).
cookie - Value can be in the format "[value][:domain[:lifetime[:path]]]". - This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain - field is the domain of the cookie, such as '.apache.org',the optional lifetime is the lifetime of the cookie - in seconds, and the optional path is the path of the cookie (note, name must be set). -
statusThe same as response.setStatus([value]) -
content-typeThe same as response.setContentType([value]) -
charsetThe same as response.setCharacterEncoding([value]) -
localeThe same as response.setLocale([value]) - - specify the Locale in the format - (valid - locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). -
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
- -

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be - fetched in a servlet or - JSP using request.getAttribute("client").

- -

-    <rule>
-    <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
-    <from>.*</from>
-    <set name="client">AvantGo</set>
-    </rule>
-    <rule>
-    <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
-    <from>.*</from>
-    <set name="client">Samsung SCH-6100</set>
-    </rule>
-
- -

It is also possible to use regular replacement expressions as part of the - value similar to their usage in <to> elements:

- -

-    <rule>
-        <from>/products/(.*)/(.*)/index.html</from>
-        <set name="urlrewrite.product.slug">$1</set>
-        <set name="urlrewrite.product.id">$2</set>
-        <to>/products?slug=$1&id=$2</to>
-    </rule>
-
- -

<run> element

- -

Allows you to run a method on an object when a rule and it's conditions are matched.

- - - - - - - - - - - - - - - - - - -
AttributeExplanation
class (default)The class you want to run a method on. Must be a fully qualified name.
method (optional, default run)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) - e.g. run(HttpServletRequest request, HttpServletResponse response) -
Note, if init(ServletConfig) or destroy() is found they will be run at when - creating - or destroying an instance. -
neweachtime (optional, default false)If you want new instance of the class to be created before running each time set to true.
- -

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, - HttpServletResponse) - will be invoked, the request will then be forwarded to /world-presentation.jsp.

- -

-    <rule>
-    <from>^/world/[a-z]+/[a-z]+$</from>
-    <run class="com.blah.web.WorldServlet" method="doGet" />
-    <to>/world-presentation.jsp</to>
-    </rule>
-
- -

Note, you can specify init-param's the same way you would for a servlet.

- -

-    <run class="com.blah.web.MyServlet" method="doGet">
-    <init-param>
-    <param-name>someParamName</param-name>
-    <param-value>10</param-value>
-    </init-param>
-    </run>
-
- -

If the method being called throws an Exception the original exception will be re-thrown as if it were the original - if it extends RuntimeException (eg, NullPointer), other exceptions are wrapped in a ServletException and thrown - so your container can handle them.

- - - - -

Testing

- -

Test cases have been written for most of the code. You can find them in the source distribution. UrlRewriteFilter - has been tested using Cactus on the following web application - servers:

- - - -

If you have run the test cases on another application server please let me know.

- - - - -

Performance

- -

UrlRewriteFilter has been written for maximum performance. Testing has indicated - that it should only slow down a request by 0.0005 of a second under normal circumstances - (depending on hardware and configuration etc.). Take a look at the source in the class - UrlRewriterTest.testLoadsOfRules() for more information.

- - - - -

Ant Task

- -

An Ant task has been written to allow validate the conf file and generation - of documentation. You can view a sample.

- -

Paste the following into your build.xml file, then change the dest - and conf to point to the correct places. Note, the urlrewrite jar - file will need to be in your classpath.

- -

-    <target name="urlrewrite-doc" depends="compile"
-    description="UrlRewriteFilter validation and documenting">
-
-    <taskdef
-    name="urlrewritedoc"
-    classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
-    <urlrewritedoc
-    conf="${build.home}/WEB-INF/urlrewrite.xml"
-    dest="urlrewrite-conf-overview.html" />
-    </target>
-
- - -
-
-
- -

Copyright 2007 Paul Tuckey

- - - - + + + + UrlRewriteFilter - Manual + + + + + +

UrlRewriteFilter 2.6 - Manual

+ + + +

+ Examples - Manual +
+ Install + - Filter Parameters + - Configuration + - Testing + - Performance + - Ant Task + +

+ +

Community support is available at UrlRewrite on StackOverflow.

+ +

Read examples of usage and a + sample of the ant task report. + If you have feedback, or conf you want to share with the world email me.

+ + + +

Install

+ +
    +
  1. Download the zip (or tar.gz) and extract it into your + context's directory ie, so that urlrewrite.xml goes into the WEB-INF directory.
  2. +
  3. Add the following to your WEB-INF/web.xml (add it near the top above your + servlet mappings (if you have any)): (see filter + parameters for more options) +
    
    +            <filter>
    +            <filter-name>UrlRewriteFilter</filter-name>
    +            <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    +            </filter>
    +            <filter-mapping>
    +            <filter-name>UrlRewriteFilter</filter-name>
    +            <url-pattern>/*</url-pattern>
    +            </filter-mapping>
    +        
  4. +
  5. Add your own configuration to the WEB-INF/urlrewrite.xml that was created.
  6. +
  7. Restart the context.
  8. +
+ +

You can visit http://127.0.0.1:8080/rewrite-status + (or whatever the address of your local webapp and context) + to see output (note: this page is only viewable from localhost).

+ + + +

Filter Parameters

+ +

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

+ +

+    <filter>
+    <filter-name>UrlRewriteFilter</filter-name>
+    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+    <!-- set the amount of seconds the conf file will be checked for reload
+    can be a valid integer (0 denotes check every time,
+          empty/not set denotes no reload check) -->
+    <init-param>
+    <param-name>confReloadCheckInterval</param-name>
+    <param-value>60</param-value>
+    </init-param>
+
+    <!-- sets up log level (will be logged to context log)
+    can be: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL, log4j, commons, sysout:{level} (ie, sysout:DEBUG)
+          if you are having trouble using normal levels use sysout:DEBUG -->
+    <init-param>
+    <param-name>logLevel</param-name>
+    <param-value>DEBUG</param-value>
+    </init-param>
+
+    <!-- you can disable status page if desired
+    can be: true, false (default true) -->
+    <init-param>
+    <param-name>statusEnabled</param-name>
+    <param-value>true</param-value>
+    </init-param>
+
+        <!-- you can change status path so that it does not
+          conflict with your installed apps (note, defaults
+          to /rewrite-status) note, must start with / -->
+    <init-param>
+            <param-name>statusPath</param-name>
+            <param-value>/status</param-value>
+    </init-param>
+
+    </filter>
+    <filter-mapping>
+    <filter-name>UrlRewriteFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+ +

Note, setting logLevel to log4j or commons will cause the built in loging to + call either log4j or + commons-logging as if they were the logging framework, + obviously you will need to have the jar for log4j or commons-logging in your classpath.

+ + + + +

Configuration File WEB-INF/urlrewrite.xml

+ +

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named + urlrewrite.xml. + It may be helpful to read the UrlRewriteFilter DTD + (Document Type Definition). Please also make sure you look at the examples. A simple + configuration file looks like:

+ +

+    <?xml version="1.0" encoding="utf-8"?>
+
+    <!DOCTYPE urlrewrite
+    PUBLIC "-//tuckey.org//DTD UrlRewrite 2.6//EN"
+    "http://www.tuckey.org/res/dtds/urlrewrite2.6.dtd">
+
+    <urlrewrite>
+
+    <rule>
+    <from>^/some/olddir/(.*)$</from>
+    <to type="redirect">/very/newdir/$1</to>
+    </rule>
+
+    </urlrewrite>
+
+ + +

The urlrewrite.xml file must have a root element called "urlrewrite" and must contain + at least one "rule" element.

+ +

A "rule" must contain a "from" and a "to", and can have zero or more "condition" elements and zero or more and/or + "set" elements.

+ +

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then + the "from" will be applied to the request URL and the final URL generated by applying the + "to" to the "from" pattern. So long as the rule has matched then the "set" will be run.

+ +

Traps for young players:

+ +
    +
  • when you want to put an "&" in a rule you must enter it as the XML entity "&amp;"
  • +
  • for simplicity you might want to start all from's with a ^ and end them with a $. +
    In regular expressions ^ specifies the start of + the string and $ specifies the end. +
    ie, a request for /my/url/path will NOT match + <from>^/url/$</from> but it will match <from>/url/</from> +
    +
  • If using <outbound-rule> remember all urls in your code must be encoded e.g. + <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • +
  • Regular expressions are complex and a bit trick at times. read + Regular expression syntax for + Java. +
  • +
+ +

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

+ +

+    Pattern.compile(<from> element);
+    pattern.matcher(request url);
+    matcher.replaceAll(<to> element);
+    if ( <condition> elements match && matcher.find() ) {
+        handle <set> elements (if any)
+        execute <run> elements (if any)
+        perform <to> element (if any)
+    }
+
+ + +

<rule> element

+ +

Zero or more. The basis of a rule.

+ + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
+ +

In the following example requests for /world/usa/nyc will be transparently forwarded to + /world.jsp?country=usa&city=nyc

+ +

+    <rule enabled="true">
+       <from>^/world/([a-z]+)/([a-z]+)$</from>
+       <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ + +

<outbound-rule> element

+ +

Zero or more. This is very similar to a normal rule but it is used for rewriting urls that go through + response.encodeURL().

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
trueRun encodeURL() before running this outbound rule.
false (default)Run encodeURL() after running this outbound rule.
+ +

May contain "run", "from", "to" and "set" element(s) also. Example:

+ +

+    <outbound-rule>
+    <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
+    <to>/world/$1/$2</to>
+    </outbound-rule>
+
+ +

Using the example above JSP's with the code +
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") %>">nyc</a> +
will output +
<a href="/world/usa/nyc">nyc</a> +

+ +

Note, If you are using JSTL (ie, <c:url) this will work also.

+ +

<name> element

+ +

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +

+    <rule>
+    <name>World Rule</name>
+    <from>^/world/([a-z]+)/([a-z]+)$</from>
+    <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ + +

<note> element

+ +

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +

+    <rule>
+    <name>World Rule</name>
+    <note>
+        Cleanly redirect world requests to JSP,
+        a country and city must be specified.
+        </note>
+    <from>^/world/([a-z]+)/([a-z]+)$</from>
+    <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ + +

<condition> element

+ +

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run + (unless "next" is set to "or" obvoiusly).

+ +

Value can be any Regular Expression (Perl5 style).

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD etc.
portThe port that the web application server is running on.
time + Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC otherwise known as unix + time). +
i.e. (new Date()).getTime() +
This can be used for making sure content goes live only at a time you set. +
year + Current year at the server. +
i.e. (Calendar.getInstance()).get(Calendar.YEAR) +
month + Month at the server. January is 0 +
i.e. (Calendar.getInstance()).get(Calendar.MONTH) +
dayofmonth + Day of the month at the server. March first is 1 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) +
dayofweek + Day of the week at the server. Saturday is 1, Sunday is 7 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) +
ampm + AM or PM time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) +
hourofday + The hour of the day (24 hour clock) at the server. 10pm is 22 +
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) +
minute + The minute field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) +
second + The second field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.SECOND) +
millisecond + The millisecond field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) +
attribute + Will check the value of a request attribute (don't confuse this with parameter!), name must be set when + using this type. +
i.e. request.getAttribute([name]) + +
auth-type + Will check the value of a request attribute (don't confuse this with parameter!) +
i.e. request.getAuthType() + +
character-encoding + The character encoding of the imcoming request. +
i.e. request.getCharacterEncoding() + +
content-length + The length of the imcoming request (can be useful if you want to deny large requests). +
i.e. request.getContentLength() + +
content-type + The type of the imcoming request. (this is probably not that useful) +
i.e. request.getContentType() + +
context-path + The context path of the imcoming request. +
i.e. request.getContextPath() + +
cookie + The value of a cookie, note, name must be specified to use this +
i.e. request.getCookies() + the find we the one with [name] specified and check the value. +
parameter + A tidier way of checking request parameters than looking for them in the query string. This will check for the + parameter in GET or POST, note, name must be specified. +
i.e. request.getParameter([name]) + +
path-info + i.e. request.getPathInfo() + +
path-translated + i.e. request.getPathTranslated() + +
protocolThe protocol used to make the request, e.g. HTTP/1.1 +
i.e. request.getProtocol() + +
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob +
i.e. request.getQueryString() + +
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 +
i.e. request.getRemoteAddr() + +
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, + this will only work if your app server is configured to lookup host names, most aren't). +
i.e. request.getRemoteHost() + +
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt +
i.e. request.getRemoteUser() + +
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 +
i.e. request.getRequestedSessionId() + +
request-uriReturns the part of this request's URL from the protocol name up to the query + string in the first line of the HTTP request +
i.e. request.getRequestURI() + +
request-urlReconstructs the URL the client used to make the request. The returned URL + contains a protocol, server name, port number, and server path, but it does not include query string parameters. +
i.e. request.getRequestURL() + +
session-attribute + (note, name must be set) +
i.e. session.getAttribute([name]) + +
session-isnew + Weather the session is new or not. +
i.e. session.isNew() + +
server-name + The host name of the server to which the request was sent (from the host header not the machine name). +
i.e. request.getServerName() + +
scheme + The scheme used for the request, e.g. http or https +
i.e. request.getScheme() + +
user-in-role + (Note, the value for this cannot be a regular expression) +
i.e. request.isUserInRole([value]) + +
name
(optional)
(can be anything)If type is header, this specifies the name of the HTTP header used to run the value + against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator to be used when the condition is run.
notequalNot equal to. (i.e. request value != condition value). Note, this operator only work with + numeric rule types.
greaterGreater than. (i.e. request value > condition value). Note, this operator only work with + numeric + rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only work with numeric + rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator + only + work with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only + work with numeric rule types.
+ +

Examples:

+ +

+    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+
+    <condition type="user-in-role" operator="notequal">bigboss</condition>
+
+    <condition name="host" operator="notequal">www.example.com</condition>
+
+    <condition type="method" next="or">PROPFIND</condition>
+    <condition type="method">PUT</condition>
+
+ + +

<from> element

+ +

You must always have exactly one from for each rule or outbound-rule. Value can be a regular expression in the + Perl5 style. Note, from url's are relative to the context.

+ + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using case insentitive match. ie, "/WellingtoN" will match "/wellington". +
trueThis value will be matched using case sentitive match. ie, "/aAa" will NOT match "/aaa". +
+ +

Example:

+ +

+    <from>^/world/([a-z]+)$</from>
+
+ + +

<to> element

+ +

Value can be a regular replacement expression in the Perl5 style.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally + forwarded + to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as + UrlRewriteFilter. This is the same as doing: +
RequestDispatcher rq = request.getRequestDispatcher([to value]); +
rq.forward(request, response);
+
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. + This is the same a doing: +
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_PERMANENTLY is HTTP status code 301)
temporary-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) + will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) + will NOT be called.
+ +

Note, "to" can be null ie, <to>null</to>, this will mean that the request will go no + further if the rule is matched (ie, this filter will not call chain.doFilter).

+ +

+    <to>/world.jsp?country=$1</to>
+
+ +

To elements can contain backreferences and variables.

+ + +

Backreferences

+ +

+    %N
+
+ +

Provides access to the grouped parts (parentheses!) of the pattern from the last matched Condition in the current rule. + N must be less than 10 and greater than 0.

+ + +

Variables

+ +

+    %{VARIABLE-NAME}
+
+ +

Any valid condition type can be used as a variable name. ie, + '%{port}' will be translated to '80', + '%{year}' to '2005', + '%{cookie:myCookie}' would be translated to + 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

+ +

Valid types are and condition type, see condition for a full description.

+ + +

<set> element

+ +

Allows you to set varous things if the rule is matched.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], + [value]) + (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], + [value]) + (note, name must be set).
response-headerThe same as response.setHeader([name], + [value]) + (note, name must be set).
cookie + Value can be in the format "[value][:domain[:lifetime[:path]]]". + This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain + field is the domain of the cookie, such as '.apache.org',the optional lifetime is the lifetime of the cookie + in seconds, and the optional path is the path of the cookie (note, name must be set). +
statusThe same as response.setStatus([value]) +
content-typeThe same as response.setContentType([value]) +
charsetThe same as response.setCharacterEncoding([value]) +
localeThe same as response.setLocale([value]) + + specify the Locale in the format + (valid + locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). +
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
+ +

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be + fetched in a servlet or + JSP using request.getAttribute("client").

+ +

+    <rule>
+    <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
+    <from>.*</from>
+    <set name="client">AvantGo</set>
+    </rule>
+    <rule>
+    <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
+    <from>.*</from>
+    <set name="client">Samsung SCH-6100</set>
+    </rule>
+
+ +

It is also possible to use regular replacement expressions as part of the + value similar to their usage in <to> elements:

+ +

+    <rule>
+        <from>/products/(.*)/(.*)/index.html</from>
+        <set name="urlrewrite.product.slug">$1</set>
+        <set name="urlrewrite.product.id">$2</set>
+        <to>/products?slug=$1&id=$2</to>
+    </rule>
+
+ +

<run> element

+ +

Allows you to run a method on an object when a rule and it's conditions are matched.

+ + + + + + + + + + + + + + + + + + +
AttributeExplanation
class (default)The class you want to run a method on. Must be a fully qualified name.
method (optional, default run)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) + e.g. run(HttpServletRequest request, HttpServletResponse response) +
Note, if init(ServletConfig) or destroy() is found they will be run at when + creating + or destroying an instance. +
neweachtime (optional, default false)If you want new instance of the class to be created before running each time set to true.
+ +

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, + HttpServletResponse) + will be invoked, the request will then be forwarded to /world-presentation.jsp.

+ +

+    <rule>
+    <from>^/world/[a-z]+/[a-z]+$</from>
+    <run class="com.blah.web.WorldServlet" method="doGet" />
+    <to>/world-presentation.jsp</to>
+    </rule>
+
+ +

Note, you can specify init-param's the same way you would for a servlet.

+ +

+    <run class="com.blah.web.MyServlet" method="doGet">
+    <init-param>
+    <param-name>someParamName</param-name>
+    <param-value>10</param-value>
+    </init-param>
+    </run>
+
+ +

If the method being called throws an Exception the original exception will be re-thrown as if it were the original + if it extends RuntimeException (eg, NullPointer), other exceptions are wrapped in a ServletException and thrown + so your container can handle them.

+ + + + +

Testing

+ +

Test cases have been written for most of the code. You can find them in the source distribution. UrlRewriteFilter + has been tested using Cactus on the following web application + servers:

+ + + +

If you have run the test cases on another application server please let me know.

+ + + + +

Performance

+ +

UrlRewriteFilter has been written for maximum performance. Testing has indicated + that it should only slow down a request by 0.0005 of a second under normal circumstances + (depending on hardware and configuration etc.). Take a look at the source in the class + UrlRewriterTest.testLoadsOfRules() for more information.

+ + + + +

Ant Task

+ +

An Ant task has been written to allow validate the conf file and generation + of documentation. You can view a sample.

+ +

Paste the following into your build.xml file, then change the dest + and conf to point to the correct places. Note, the urlrewrite jar + file will need to be in your classpath.

+ +

+    <target name="urlrewrite-doc" depends="compile"
+    description="UrlRewriteFilter validation and documenting">
+
+    <taskdef
+    name="urlrewritedoc"
+    classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
+    <urlrewritedoc
+    conf="${build.home}/WEB-INF/urlrewrite.xml"
+    dest="urlrewrite-conf-overview.html" />
+    </target>
+
+ + +
+
+
+ +

Copyright 2007 Paul Tuckey

+ + + + diff --git a/src/doc/manual/2.6/urlrewrite-conf-overview-sample.html b/src/doc/manual/2.6/urlrewrite-conf-overview-sample.html index b7eac4e3..de7c4092 100644 --- a/src/doc/manual/2.6/urlrewrite-conf-overview-sample.html +++ b/src/doc/manual/2.6/urlrewrite-conf-overview-sample.html @@ -1,170 +1,170 @@ -UrlRewriteFilter configuration overview for build/WEB-INF/urlrewrite.xml - - - -

UrlRewriteFilter 2.6.0 build 5728 configuration overview (generated 7/12/05 23:37)

-
-

Summary of build/WEB-INF/urlrewrite.xml

-

In total there are 12 rules, 2 outbound rules and 10 conditions in the configuration file.

-

Test Rule1 (rule 0)

-

A test rule to show a simple redirect.

-

URL's matching /test/status/ will be redirected to /rewrite-status.

-

-

Bild redirect test (rule 1)

-

URL's matching logo.gif will permanent-redirect to http://127.0.0.1:8080/urlrewrite/artifact_type.gif.

-

-

Products (rule 2)

-

Allows users to type product id's into urls.
ID's published in magazine.

-

URL's matching /products/*/*/ will be forwarded to /products.jsp.

-

This rule will set:

    -
  1. -An attribute on the request object called categoryId to the value null -
  2. -
  3. -An attribute on the request object called usingFilter to the value yes -
  4. -
-

-

Rule 3

-

URL's matching /chairs/*/ will be forwarded to /products/chairs.jsp.

-

This rule will set:

    -
  1. -An attribute on the session object called chairShopper to the value true -
  2. -
-

-

Test Rule disabled (rule 4) **DISABLED**

-

URL's matching /test/disabled/ will be redirected to /rewrite-status.

-

Given that the following conditions are met.

    -
  1. -The user-agent HTTP header does NOT match the value mac -and -
  2. -
  3. -dayofmonth is equal to the value 14 -and -
  4. -
  5. -The charset HTTP header matches the value utf -and -
  6. -
  7. -user-in-role is equal to the value admin -
  8. -
-

-

Test Rule with sets (rule 5)

-

URL's matching /test/disabled/.

-

Given that the following condition is met.

    -
  1. -The user-agent HTTP header does NOT match the value mac -
  2. -
-

This rule will set:

    -
  1. -An attribute on the request object called blah to the value ass -
  2. -
  3. -The cache-control HTTP response header to ass -
  4. -
-

Note, other rules will be proessed after this rule.

-

-

Rule 6

-

URL's matching /test-set/([0-9]+) will be forwarded to /test-set.jsp.

-

Given that the following condition is met.

    -
  1. -The user-agent HTTP header does NOT match the value mac -
  2. -
-

This rule will set:

    -
  1. -An attribute on the request object called num to the value num -
  2. -
-

This rule will run:

    -
  1. - run(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj -
  2. -
  3. - run(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj -
  4. -
  5. - nonDefaultRun(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj -
  6. -
  7. - nonDefaultRun(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj - (a new instance will be created for each rule match) -
  8. -
  9. - nonDefaultRun(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj - (a new instance will be created for each rule match) -
  10. -
-Note, if init(ServletConfig) or destroy() is found on the above objects they will be run at when creating or destroying an instance. -

-

Rule 7

-

URL's matching /content/([a-zA-Z]+).

-

This rule will set:

    -
  1. -An attribute on the request object called contentItem to the value $1 -
  2. -
-

This rule will run:

    -
  1. - doGet(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestServlet -
  2. -
-Note, if init(ServletConfig) or destroy() is found on the above object they will be run at when creating or destroying an instance. -

Note, other rules will be proessed after this rule.

-

-

Rule 8

-

URL's matching /pref/([a-zA-Z]+).

-

Given that the following condition is met.

    -
  1. -method is equal to the value POST -
  2. -
-

This rule will run:

    -
  1. - doPost(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestServlet -
  2. -
-Note, if init(ServletConfig) or destroy() is found on the above object they will be run at when creating or destroying an instance. -

Note, other rules will be proessed after this rule.

-

-

Rule 9

-

URL's matching /test-redirect-301 will permanent-redirect to /is-this-301.

-

-

Rule 10

-

URL's matching /test-redirect-302 will temporary-redirect to is-this-302.

-

-

Rule 11

-

URL's matching /test-redirect-302 will temporary-redirect to is-this-302.

-

Given that the following condition is met.

    -
  1. -user-in-role is equal to the value devil -
  2. -
-

-

Out test 1 (outbound rule 0)

-

Outbound URL's matching /page-not-for-devils(0-9)? will be rewritten to /devils-page, after response.encodeURL() has been called.

-

Given that the following condition is met.

    -
  1. -user-in-role is equal to the value devil -
  2. -
-

-

Outbound Rule 1

-

Outbound URL's matching ^(.*);jsessionid=.*$ will be rewritten to $1.

-

Given that the following condition is met.

    -
  1. -The user-agent HTTP header matches the value googlebot.* -
  2. -
-

-
-


- +UrlRewriteFilter configuration overview for build/WEB-INF/urlrewrite.xml + + + +

UrlRewriteFilter 2.6.0 build 5728 configuration overview (generated 7/12/05 23:37)

+
+

Summary of build/WEB-INF/urlrewrite.xml

+

In total there are 12 rules, 2 outbound rules and 10 conditions in the configuration file.

+

Test Rule1 (rule 0)

+

A test rule to show a simple redirect.

+

URL's matching /test/status/ will be redirected to /rewrite-status.

+

+

Bild redirect test (rule 1)

+

URL's matching logo.gif will permanent-redirect to http://127.0.0.1:8080/urlrewrite/artifact_type.gif.

+

+

Products (rule 2)

+

Allows users to type product id's into urls.
ID's published in magazine.

+

URL's matching /products/*/*/ will be forwarded to /products.jsp.

+

This rule will set:

    +
  1. +An attribute on the request object called categoryId to the value null +
  2. +
  3. +An attribute on the request object called usingFilter to the value yes +
  4. +
+

+

Rule 3

+

URL's matching /chairs/*/ will be forwarded to /products/chairs.jsp.

+

This rule will set:

    +
  1. +An attribute on the session object called chairShopper to the value true +
  2. +
+

+

Test Rule disabled (rule 4) **DISABLED**

+

URL's matching /test/disabled/ will be redirected to /rewrite-status.

+

Given that the following conditions are met.

    +
  1. +The user-agent HTTP header does NOT match the value mac +and +
  2. +
  3. +dayofmonth is equal to the value 14 +and +
  4. +
  5. +The charset HTTP header matches the value utf +and +
  6. +
  7. +user-in-role is equal to the value admin +
  8. +
+

+

Test Rule with sets (rule 5)

+

URL's matching /test/disabled/.

+

Given that the following condition is met.

    +
  1. +The user-agent HTTP header does NOT match the value mac +
  2. +
+

This rule will set:

    +
  1. +An attribute on the request object called blah to the value ass +
  2. +
  3. +The cache-control HTTP response header to ass +
  4. +
+

Note, other rules will be proessed after this rule.

+

+

Rule 6

+

URL's matching /test-set/([0-9]+) will be forwarded to /test-set.jsp.

+

Given that the following condition is met.

    +
  1. +The user-agent HTTP header does NOT match the value mac +
  2. +
+

This rule will set:

    +
  1. +An attribute on the request object called num to the value num +
  2. +
+

This rule will run:

    +
  1. + run(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj +
  2. +
  3. + run(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj +
  4. +
  5. + nonDefaultRun(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj +
  6. +
  7. + nonDefaultRun(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj + (a new instance will be created for each rule match) +
  8. +
  9. + nonDefaultRun(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestRunObj + (a new instance will be created for each rule match) +
  10. +
+Note, if init(ServletConfig) or destroy() is found on the above objects they will be run at when creating or destroying an instance. +

+

Rule 7

+

URL's matching /content/([a-zA-Z]+).

+

This rule will set:

    +
  1. +An attribute on the request object called contentItem to the value $1 +
  2. +
+

This rule will run:

    +
  1. + doGet(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestServlet +
  2. +
+Note, if init(ServletConfig) or destroy() is found on the above object they will be run at when creating or destroying an instance. +

Note, other rules will be proessed after this rule.

+

+

Rule 8

+

URL's matching /pref/([a-zA-Z]+).

+

Given that the following condition is met.

    +
  1. +method is equal to the value POST +
  2. +
+

This rule will run:

    +
  1. + doPost(HttpServletRequest, HttpServletResponse) on an instance of org.tuckey.web.filters.urlrewrite.TestServlet +
  2. +
+Note, if init(ServletConfig) or destroy() is found on the above object they will be run at when creating or destroying an instance. +

Note, other rules will be proessed after this rule.

+

+

Rule 9

+

URL's matching /test-redirect-301 will permanent-redirect to /is-this-301.

+

+

Rule 10

+

URL's matching /test-redirect-302 will temporary-redirect to is-this-302.

+

+

Rule 11

+

URL's matching /test-redirect-302 will temporary-redirect to is-this-302.

+

Given that the following condition is met.

    +
  1. +user-in-role is equal to the value devil +
  2. +
+

+

Out test 1 (outbound rule 0)

+

Outbound URL's matching /page-not-for-devils(0-9)? will be rewritten to /devils-page, after response.encodeURL() has been called.

+

Given that the following condition is met.

    +
  1. +user-in-role is equal to the value devil +
  2. +
+

+

Outbound Rule 1

+

Outbound URL's matching ^(.*);jsessionid=.*$ will be rewritten to $1.

+

Given that the following condition is met.

    +
  1. +The user-agent HTTP header matches the value googlebot.* +
  2. +
+

+
+


+ \ No newline at end of file diff --git a/src/doc/manual/3.0/annotation.html b/src/doc/manual/3.0/annotation.html index c27e287f..1e174f39 100644 --- a/src/doc/manual/3.0/annotation.html +++ b/src/doc/manual/3.0/annotation.html @@ -1,172 +1,172 @@ - - - - UrlRewriteFilter - Annotation - - - - - - - - - -
- - - -

URL Matching Annotations

- - - -

EXPIREMENTAL support for annotations has been added as part of 3.0 development. - You must be using JDK 1.5 for this to work.

- -

The intention of annotations in UrlRewriteFilter is purely for conf file generation. The is NO runtime - dependency on the annotations.

- -

Annotations

- -

@HttpUrl

- -

Set the method up to be used when the url is Matched, matched groups are assigned to method paramters (if any).

- -

-        @HttpUrl("^/do-something/([0-9]+)$")
-        void doSomething(Long id)
-    
- -

When a request for /do-something/1234, doSomething is called with id set to 1234.

- -

@HttpParam

- -

Sets the parameter from request.getParameter (handles type conversion as necessary)

- -

-        void doSomething(@HttpParam String name, @HttpParam long id, @HttpParam("uid") Long userId)
-    
- -

The above example will: -
name = request.getParameter("name"); -
id = convertTolongDefault0(request.getParameter("id")); -
userId = convertToLongDefaultNull(request.getParameter("uid")); -
An exception will never be thown during type conversion -

- - - - -

Conf Generation

- -

Add a post-compile step to your build script.

- -

-        <target name="compile-urlrewrite-conf">
-            <path id="annotation-classpath">
-                <path refid="compile.classpath"/>
-                <path refid="compiled.classpath"/>
-                <fileset file="${jdk.home}/lib/tools.jar"/>
-            </path>
-            <fileset id="sources" dir="." includes="src/**/actions/**/*.java"/>
-            <pathconvert pathsep=" " property="sourcefiles" refid="sources"/>
-            <!-- helpful for debugging classpath issues
-                <property name="prop-annotation-classpath" refid="annotation-classpath"/>
-                <echo>
-                CLASSPATH ${prop-annotation-classpath}
-                SOURCES: ${sourcefiles}
-                </echo> -->
-            <exec executable="apt">
-                <arg value="-classpath"/>
-                <arg pathref="annotation-classpath"/>
-                <arg value="-nocompile"/>
-                <arg value="-factory"/>
-                <arg value="org.tuckey.web.filters.urlrewrite.annotation.HttpUrlAPTFactory"/>
-                <arg value="-AsaveRulesTo=build/web/WEB-INF/urlrewrite-generated.xml"/>
-                <arg line="${sourcefiles}"/>
-            </exec>
-        </target>
-    
- -

This will generate to the file specified. Any errors will be output to stdout using the standard APT method. - Read the generated conf file and check it for errors.

- - -

Include the compiled conf file in your normal conf.

- -

-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
-        "http://www.tuckey.org/res/dtds/urlrewrite3.0.dtd"
-[
-    <!ENTITY included SYSTEM "urlrewrite-generated.xml">
-]>
-<!--
-
-    Configuration file for UrlRewriteFilter
-    http://www.tuckey.org/urlrewrite/
-
--->
-<urlrewrite>
-
-    <!--
-        other rules...
-    -->
-
-    &included;
-
-
-</urlrewrite>
-
- - -

Check your /rewrite-status for errors if things start going strange.

- -
- - - - - - + + + + UrlRewriteFilter - Annotation + + + + + + + + + +
+ + + +

URL Matching Annotations

+ + + +

EXPIREMENTAL support for annotations has been added as part of 3.0 development. + You must be using JDK 1.5 for this to work.

+ +

The intention of annotations in UrlRewriteFilter is purely for conf file generation. The is NO runtime + dependency on the annotations.

+ +

Annotations

+ +

@HttpUrl

+ +

Set the method up to be used when the url is Matched, matched groups are assigned to method paramters (if any).

+ +

+        @HttpUrl("^/do-something/([0-9]+)$")
+        void doSomething(Long id)
+    
+ +

When a request for /do-something/1234, doSomething is called with id set to 1234.

+ +

@HttpParam

+ +

Sets the parameter from request.getParameter (handles type conversion as necessary)

+ +

+        void doSomething(@HttpParam String name, @HttpParam long id, @HttpParam("uid") Long userId)
+    
+ +

The above example will: +
name = request.getParameter("name"); +
id = convertTolongDefault0(request.getParameter("id")); +
userId = convertToLongDefaultNull(request.getParameter("uid")); +
An exception will never be thown during type conversion +

+ + + + +

Conf Generation

+ +

Add a post-compile step to your build script.

+ +

+        <target name="compile-urlrewrite-conf">
+            <path id="annotation-classpath">
+                <path refid="compile.classpath"/>
+                <path refid="compiled.classpath"/>
+                <fileset file="${jdk.home}/lib/tools.jar"/>
+            </path>
+            <fileset id="sources" dir="." includes="src/**/actions/**/*.java"/>
+            <pathconvert pathsep=" " property="sourcefiles" refid="sources"/>
+            <!-- helpful for debugging classpath issues
+                <property name="prop-annotation-classpath" refid="annotation-classpath"/>
+                <echo>
+                CLASSPATH ${prop-annotation-classpath}
+                SOURCES: ${sourcefiles}
+                </echo> -->
+            <exec executable="apt">
+                <arg value="-classpath"/>
+                <arg pathref="annotation-classpath"/>
+                <arg value="-nocompile"/>
+                <arg value="-factory"/>
+                <arg value="org.tuckey.web.filters.urlrewrite.annotation.HttpUrlAPTFactory"/>
+                <arg value="-AsaveRulesTo=build/web/WEB-INF/urlrewrite-generated.xml"/>
+                <arg line="${sourcefiles}"/>
+            </exec>
+        </target>
+    
+ +

This will generate to the file specified. Any errors will be output to stdout using the standard APT method. + Read the generated conf file and check it for errors.

+ + +

Include the compiled conf file in your normal conf.

+ +

+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
+        "http://www.tuckey.org/res/dtds/urlrewrite3.0.dtd"
+[
+    <!ENTITY included SYSTEM "urlrewrite-generated.xml">
+]>
+<!--
+
+    Configuration file for UrlRewriteFilter
+    http://www.tuckey.org/urlrewrite/
+
+-->
+<urlrewrite>
+
+    <!--
+        other rules...
+    -->
+
+    &included;
+
+
+</urlrewrite>
+
+ + +

Check your /rewrite-status for errors if things start going strange.

+ +
+ + + + + + diff --git a/src/doc/manual/3.0/doc.css b/src/doc/manual/3.0/doc.css index 28b31294..e66217f2 100644 --- a/src/doc/manual/3.0/doc.css +++ b/src/doc/manual/3.0/doc.css @@ -1,137 +1,137 @@ -body { - background: #c0c0c0; - font: 13px arial, helvetica, sans-serif; -} - -h1 { - color: #000000; - font-size: 2.5em; - padding: 0px 0px 0px 5px; - margin: 0px; - font-family: georgia, times, serif; -} - -#masthead { - font-family: georgia, times, serif; - font-size: 3.5em; - background-color: #efefef; - -moz-border-radius-topright: 20px; - margin-top: 5px; - padding: 5px; - padding-left: 15px; - width: 650px; -} - -#masthead a { - text-decoration: none; - color: black; -} -#masthead img { - vertical-align: 15%; -} - -h2 { - font-family: georgia, times, serif; - border-bottom: 1px solid #808080; - padding: 5px; -} - -h3 { - font-family: georgia, times, serif; - border-bottom: 1px solid #c0c0c0; - margin-top: 2em; - padding: 0.25em 0.25em 0em 0.5em; -} - -p { - padding: 0.25em 0.25em 0em 1.0em; -} - -code, pre { - font-family: 'Courier New', courier, monospace; - font-size: 11px; -} - -pre { - background: #eeeeff; - margin: 0.5em 3em 0.1em 3em; - padding: 0.25em 0.5em 0.5em 0.5em; -} - -table { - border: 1px solid #c0c0c0; - margin-left: 2em; - border-collapse: collapse; - border-spacing: 0; -} - -th, td { - border: 1px solid #eeeeee; - vertical-align: top; - padding: 3px; -} - -th { - background: #eeeeee; -} - -hr { - border: 0px; - background-color: #c0c0c0; -} - -.err { - color: #ff0000; -} - -#menu { - float:left; - width:160px; - background: #efefef; - Zmargin-top: 2px; - padding-bottom: 10px; - padding-left: 10px; - -moz-border-radius-bottomleft: 20px; -} - -#menu ul { - list-style-type: none; - margin-left: .5em; - padding-left: .5em; - margin-top: 7px; -} -#menu li { - margin-bottom: 7px; -} - -#main { - background: white; - border-left: 1px solid #c0c0c0; - border-top: 1px solid #c0c0c0; - border-right: 1px solid #808080; - border-bottom: 1px solid #808080; - margin-left: 170px; - padding: 15px; - -moz-border-radius-bottomleft: 20px; - min-height: 400px; -} - -#footer { - margin-top: 40px; - text-align: center; - font-size: small; - color: black; - text-transform: lowercase; -} - -#footer a { - text-decoration: none; -} - -.outdated { - border: 2px solid red; - background: #eeeeee; - padding: 5px; - font-weight: bold; -} - +body { + background: #c0c0c0; + font: 13px arial, helvetica, sans-serif; +} + +h1 { + color: #000000; + font-size: 2.5em; + padding: 0px 0px 0px 5px; + margin: 0px; + font-family: georgia, times, serif; +} + +#masthead { + font-family: georgia, times, serif; + font-size: 3.5em; + background-color: #efefef; + -moz-border-radius-topright: 20px; + margin-top: 5px; + padding: 5px; + padding-left: 15px; + width: 650px; +} + +#masthead a { + text-decoration: none; + color: black; +} +#masthead img { + vertical-align: 15%; +} + +h2 { + font-family: georgia, times, serif; + border-bottom: 1px solid #808080; + padding: 5px; +} + +h3 { + font-family: georgia, times, serif; + border-bottom: 1px solid #c0c0c0; + margin-top: 2em; + padding: 0.25em 0.25em 0em 0.5em; +} + +p { + padding: 0.25em 0.25em 0em 1.0em; +} + +code, pre { + font-family: 'Courier New', courier, monospace; + font-size: 11px; +} + +pre { + background: #eeeeff; + margin: 0.5em 3em 0.1em 3em; + padding: 0.25em 0.5em 0.5em 0.5em; +} + +table { + border: 1px solid #c0c0c0; + margin-left: 2em; + border-collapse: collapse; + border-spacing: 0; +} + +th, td { + border: 1px solid #eeeeee; + vertical-align: top; + padding: 3px; +} + +th { + background: #eeeeee; +} + +hr { + border: 0px; + background-color: #c0c0c0; +} + +.err { + color: #ff0000; +} + +#menu { + float:left; + width:160px; + background: #efefef; + Zmargin-top: 2px; + padding-bottom: 10px; + padding-left: 10px; + -moz-border-radius-bottomleft: 20px; +} + +#menu ul { + list-style-type: none; + margin-left: .5em; + padding-left: .5em; + margin-top: 7px; +} +#menu li { + margin-bottom: 7px; +} + +#main { + background: white; + border-left: 1px solid #c0c0c0; + border-top: 1px solid #c0c0c0; + border-right: 1px solid #808080; + border-bottom: 1px solid #808080; + margin-left: 170px; + padding: 15px; + -moz-border-radius-bottomleft: 20px; + min-height: 400px; +} + +#footer { + margin-top: 40px; + text-align: center; + font-size: small; + color: black; + text-transform: lowercase; +} + +#footer a { + text-decoration: none; +} + +.outdated { + border: 2px solid red; + background: #eeeeee; + padding: 5px; + font-weight: bold; +} + diff --git a/src/doc/manual/3.0/guide.html b/src/doc/manual/3.0/guide.html index 26a98f4e..b6157f51 100644 --- a/src/doc/manual/3.0/guide.html +++ b/src/doc/manual/3.0/guide.html @@ -1,741 +1,741 @@ - - - - UrlRewriteFilter - Examples - - - - - - - - - -
- - - -

Examples

- -

Redirect one url

- -

-    <rule>
-        <from>^/some/old/page\.html$</from>
-        <to type="redirect">/very/new/page.html</to>
-    </rule>
-
- -

-    <rule match-type="wildcard">
-        <from>/some/old/page.html</from>
-        <to type="redirect">/very/new/page.html</to>
-    </rule>
-
- -

Redirect docs in a directory to another using wildcard engine.

- -

-    <urlrewrite default-match-type="wildcard">
-
-    <rule>
-        <from>/some/old/*.doc</from>
-        <to type="redirect">/very/new/$1.doc</to>
-    </rule>
-
-    </urlrewrite>
-
- -

Tiny/Freindly url

- -

-    <rule>
-        <from>^/zebra$</from>
-        <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
-    </rule>
-
- -

Default page as another (requests to / will be redirected)

- -

-    <rule>
-        <from>^/$</from>
-        <to type="redirect">/opencms/opencms/index.html</to>
-    </rule>
-
- -

Perform security checks in a centralised place

- -

-    <rule>
-        <condition type="user-in-role" operator="notequal">admin</condition>
-        <condition type="user-in-role" operator="notequal">bigboss</condition>
-        <from>^/admin/(.*)$</from>
-        <to>/go-away-please.html</to>
-    </rule>
-
- - -

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah - will be redirected to http://www.example.com/blah

- -

-    <rule>
-        <name>Domain Name Check</name>
-        <condition name="host" operator="notequal">www.example.com</condition>
-        <from>(.*)</from>
-        <to type="redirect">http://www.example.com/context$1</to>
-    </rule>
-
- - -

Disable access to a directory.

- -

-    <rule>
-        <name>Disable Directory</name>
-        <from>^/notliveyet/.*$</from>
-        <set type="status">403</set>
-        <to>null</to>
-    </rule>
-
- -

Redirect a directory (for moved content)

- -

-    <rule>
-        <from>^/some/olddir/(.*)$</from>
-        <to type="redirect">/very/newdir/$1</to>
-    </rule>
-
- -

Clean a URL

- -

-    <rule>
-        <from>^/products/([0-9]+)$</from>
-        <to>/products/index.jsp?product_id=$1</to>
-    </rule>
-
- -

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 - without the user noticing.

- -

-    <rule>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- -

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork -

- -

Browser detection

- -

-    <rule>
-        <condition name="user-agent">Mozilla/[1-4]</condition>
-        <from>^/some/page\.html$</from>
-        <to>/some/page-for-old-browsers.html</to>
-    </rule>
-
- -

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html - only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, - Mozilla/3 or Mozilla/4.

- - -

Security. Preclude certain types of method from you web application.

- -

-    <rule>
-        <condition type="method" next="or">PROPFIND</condition>
-        <condition type="method">PUT</condition>
-        <from>.*</from>
-        <to type="redirect">/bad-method.html</to>
-    </rule>
-
- - -

Sunday Specials

- -

-    <rule>
-        <condition type="dayofweek">1</condition>
-        <from>^/products/$</from>
-        <to>/products/sunday-specials.html</to>
-    </rule>
-
- - -

Set the "Cache-Control" HTTP response header for all requests

- -

-    <rule>
-        <from>.*</from>
-        <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
-    </rule>
-
- -

Forward a request to a servlet

- -

-    <rule>
-        <from>^/products/purchase$</from>
-        <to>/servlets/ProductsServlet</to>
-        <set name="action">purchase</set>
-    </rule>
-
- -

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and - inside - the servlet request.getAttribute("action") will return purchase.

- -

Hide jsessionid for requests from googlebot.

- -

-  <outbound-rule>
-       <name>Strip URL Session ID's</name>
-       <note>
-           Strip ;jsession=XXX from urls passed through
-response.encodeURL().
-           The characters ? and # are the only things we can use to
-find out where the jsessionid ends.
-           The expression in 'from' below contains three capture
-groups, the last two being optional.
-               1, everything before ;jesessionid
-               2, everything after ;jesessionid=XXX starting with a ?
-(to get the query string) up to #
-               3, everything ;jesessionid=XXX and optionally ?XXX
-starting with a # (to get the target)
-           eg,
-           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
-           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
-           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
-index.jsp#dfds
-           from u.jsp;jsessionid=wert.hg - u.jsp
-           from /;jsessionid=tyu - /
-       </note>
-       <condition name="user-agent">googlebot</condition>
-       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
-       <to>$1$2$3</to>
-   </outbound-rule<
-
- - - -

Method Invocation

- -

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have - any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

- -

Invoke a servlet directly

- -

-    <rule>
-    <from>^/products/purchase$</from>
-    <run class="com.blah.web.MyServlet" method="doGet" />
-    </rule>
-
- -

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is - matched on a request. (remeber this method needs to be public!)

- -

Use it to delagate cleanly to your methods

- -

-    <rule>
-        <from>^/pref-editor/addresses$</from>
-        <run class="com.blah.web.PrefsServlet" method="runAddresses" />
-    </rule>
-    <rule>
-        <from>^/pref-editor/phone-nums$</from>
-        <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
-    </rule>
-
- -

Browser based delagation to your methods

- -

-    <rule>
-        <condition name="user-agent">Mozilla/[1-4]</condition>
-        <from>^/content/.*$</from>
-        <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
-    </rule>
-    <rule>
-        <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-        <from>^/content/.*$</from>
-        <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
-        <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
-    </rule>
-
- -

When the method specified in the "run" is invoked it has full control over the request and response as if it were a - servlet.

- - - - - - - -

URL Abstraction

- -

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

- -

-    <rule>
-        <from>^/tidy/page$</from>
-        <to>/old/url/scheme/page.jsp</to>
-    </rule>
-    <outbound-rule>
-        <from>^/old/url/scheme/page.jsp$</from>
-        <to>/tidy/page</to>
-    </outbound-rule>
-
- -

Any incoming requests for /tidy/page will be transparently forwarded to - /old/url/scheme/page.jsp.

- -

If you use JSTL your JSP page would have something like:

-
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
- -

This will be rewritten upon output to:

-
<a href="/tidy/page">some link</a>
- -

Or if you use standard JSP:

-
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
- -

Will generate output like:

-
<a href="/tidy/page">some link</a>
- - - - -

mod_rewrite vs urlrewrite filter

- - -

Examples of mod_rewrite style conf vs urlrewrite filter conf are below, there are all examples copied directly from - Apache 2.0's official rewrite guide.

- -

-
-<rule>
-    <name>Canonical URLs</name>
-    <note>
-        On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
-        should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
-        of which URL the user supplied with the request he should finally see the canonical one only.
-
-        We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
-        and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
-        fix a missing trailing slash for /u/user.
-
-        RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
-        RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
-    </note>
-    <from>^/~([^/]+)/?(.*)</from>
-    <to type="redirect">/u/$1/$2</to>
-</rule>
-<rule>
-    <from>^/([uge])/([^/]+)$</from>
-    <to type="redirect">/$1/$2/</to>
-</rule>
-
-
-<rule>
-    <name>Canonical Hostnames</name>
-    <note>
-        The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
-        may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
-        example.com, you might use a variant of the following recipe.
-
-        RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
-        RewriteCond %{HTTP_HOST} !^$
-        RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
-    </note>
-    <condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
-    <condition name="host" operator="notequal">^$</condition>
-    <from>^/(.*)</from>
-    <to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
-</rule>
-
-
-<rule>
-    <name>Moved DocumentRoot</name>
-    <note>
-        Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
-        really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
-        Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
-        because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
-        stuff inside this data pool work for subsequent requests.
-
-        We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
-        Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
-        matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
-        With mod_rewrite it is really trivial:
-
-        RewriteRule ^/$ /e/www/ [R]
-    </note>
-    <from>^/$</from>
-    <to type="redirect">/e/www/</to>
-</rule>
-
-
-<rule>
-    <name>Trailing Slash Problem</name>
-    <note>
-        Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
-        If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
-        the server searches for a file named foo. And because this file is a directory it complains. Actually it
-        tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
-        instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
-
-        The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
-        correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
-        we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
-        images are included into this page with relative URLs, because the browser would request an in-lined object.
-        For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
-        external redirect!
-    </note>
-    <from>^/~quux/foo$</from>
-    <to type="redirect">/~quux/foo/</to>
-</rule>
-
-
-<rule>
-    <name>Move Homedirs to Different Webserver</name>
-    <note>
-        Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
-        homedirs on a webserver to another webserver. They usually need such things when establishing a newer
-        webserver which will replace the old one over time.
-
-        The solution is trivial with mod_rewrite (and urlrewrite filter). On the old webserver we just redirect all
-        /~user/anypath URLs to http://newserver/~user/anypath.
-
-        RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
-    </note>
-    <from>^/~(.+)</from>
-    <to type="redirect" last="true">http://newserver/~$1</to>
-</rule>
-
-
-<rule>
-    <name>Structured Homedirs</name>
-    <note>
-        Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
-        subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
-        /home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
-
-        We use the following ruleset to expand the tilde URLs into exactly the above layout.
-
-        RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
-    </note>
-    <from>^/~(([a-z])[a-z0-9]+)(.*)</from>
-    <to>/home/$2/$1/.www$3</to>
-</rule>
-
-
-<rule>
-    <name>Redirect Homedirs For Foreigners</name>
-    <note>
-        We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
-        stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
-
-        Just a rewrite condition:
-
-        RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
-        RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
-    </note>
-    <condition name="host">!^.+\.ourdomain\.com$</condition>
-    <from>^(/~.+)</from>
-    <to type="redirect" last="true">http://www.somewhere.com/$1</to>
-</rule>
-
-
-<rule>
-    <name>Time-Dependent Rewriting</name>
-    <note>
-        When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
-        instance redirects to specialized pages. How can it be done via mod_rewrite?
-
-        There are a lot of types in conjunction with operators we can do time-dependent redirects:
-
-        RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
-        RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
-        RewriteRule ^foo\.html$ foo.day.html
-        RewriteRule ^foo\.html$ foo.night.html
-    </note>
-    <condition type="hourofday" operator="greater">7</condition>
-    <condition type="hourofday" operator="less">19</condition>
-    <from>^foo\.html$</from>
-    <to>foo.day.html</to>
-</rule>
-<rule>
-    <from>^foo\.html$</from>
-    <to>foo.night.html</to>
-</rule>
-
-
-<rule>
-    <name></name>
-    <note>
-        Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
-        backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
-        renamed.
-
-        We rewrite the old URL to the new one internally via the following rule:
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ bar.html
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to>/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-    <name>From Old to New (extern)</name>
-    <note>
-        Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
-        for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
-        i.e. their browsers Location field should change, too.
-
-        We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ bar.html [R]
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to type="redirect">/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-    <name>Browser Dependent Content</name>
-    <note>
-        At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
-        content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
-        the Lynx browsers and a average feature version for all others.
-
-        We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
-        have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
-        "User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
-        stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
-        browsers receive page foo.32.html. This is done by the following ruleset:
-
-        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
-        RewriteRule ^foo\.html$ foo.NS.html [L]
-
-        RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
-        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
-        RewriteRule ^foo\.html$ foo.20.html [L]
-
-        RewriteRule ^foo\.html$ foo.32.html [L]
-    </note>
-    <condition name="user-agent">^Mozilla/3.*</condition>
-    <from>^foo\.html$</from>
-    <to last="true">foo.NS.html</to>
-</rule>
-<rule>
-    <condition name="user-agent" next="or">^Lynx/.*</condition>
-    <condition name="user-agent">^Mozilla/[12].*</condition>
-    <from>^foo\.html$</from>
-    <to last="true">foo.20.html</to>
-</rule>
-<rule>
-    <from>^foo\.html$</from>
-    <to last="true">foo.32.html</to>
-</rule>
-
-
-<rule>
-    <name>From Static to Dynamic</name>
-    <note>
-        How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
-        notice by the browser/user.
-
-        We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
-        a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to>/~quux/foo.jsp</to>
-</rule>
-
-<rule>
-    <name>Blocking of Robots</name>
-    <note>
-        How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
-        containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
-
-        We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
-        indexed area where the robot traversal would create big server load). We have to make sure that we forbid
-        access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
-        This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
-        information.
-
-        RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
-        RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
-        RewriteRule ^/~quux/foo/arc/.+ - [F]
-    </note>
-    <condition name="user-agent">^NameOfBadRobot.*</condition>
-    <condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
-    <from>^/~quux/foo/arc/.+</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-
-<rule>
-    <name>Blocked Inline-Images</name>
-    <note>
-        Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
-        nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
-        it adds useless traffic to our server.
-
-        While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
-        sends a HTTP Referer header.
-
-        RewriteCond %{HTTP_REFERER} !^$
-        RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
-        RewriteRule .*\.gif$ - [F]
-    </note>
-    <condition name="referer" operator="notequal">^$</condition>
-    <condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
-    <from>.*\.gif$</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-<rule>
-    <name>Blocked Inline-Images example 2</name>
-    <note>
-        RewriteCond %{HTTP_REFERER} !^$
-        RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
-        RewriteRule ^inlined-in-foo\.gif$ - [F]
-    </note>
-    <condition name="referer" operator="notequal">^$</condition>
-    <condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
-    <from>^inlined-in-foo\.gif$</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-
- - - -
- - - - - - + + + + UrlRewriteFilter - Examples + + + + + + + + + +
+ + + +

Examples

+ +

Redirect one url

+ +

+    <rule>
+        <from>^/some/old/page\.html$</from>
+        <to type="redirect">/very/new/page.html</to>
+    </rule>
+
+ +

+    <rule match-type="wildcard">
+        <from>/some/old/page.html</from>
+        <to type="redirect">/very/new/page.html</to>
+    </rule>
+
+ +

Redirect docs in a directory to another using wildcard engine.

+ +

+    <urlrewrite default-match-type="wildcard">
+
+    <rule>
+        <from>/some/old/*.doc</from>
+        <to type="redirect">/very/new/$1.doc</to>
+    </rule>
+
+    </urlrewrite>
+
+ +

Tiny/Freindly url

+ +

+    <rule>
+        <from>^/zebra$</from>
+        <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
+    </rule>
+
+ +

Default page as another (requests to / will be redirected)

+ +

+    <rule>
+        <from>^/$</from>
+        <to type="redirect">/opencms/opencms/index.html</to>
+    </rule>
+
+ +

Perform security checks in a centralised place

+ +

+    <rule>
+        <condition type="user-in-role" operator="notequal">admin</condition>
+        <condition type="user-in-role" operator="notequal">bigboss</condition>
+        <from>^/admin/(.*)$</from>
+        <to>/go-away-please.html</to>
+    </rule>
+
+ + +

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah + will be redirected to http://www.example.com/blah

+ +

+    <rule>
+        <name>Domain Name Check</name>
+        <condition name="host" operator="notequal">www.example.com</condition>
+        <from>(.*)</from>
+        <to type="redirect">http://www.example.com/context$1</to>
+    </rule>
+
+ + +

Disable access to a directory.

+ +

+    <rule>
+        <name>Disable Directory</name>
+        <from>^/notliveyet/.*$</from>
+        <set type="status">403</set>
+        <to>null</to>
+    </rule>
+
+ +

Redirect a directory (for moved content)

+ +

+    <rule>
+        <from>^/some/olddir/(.*)$</from>
+        <to type="redirect">/very/newdir/$1</to>
+    </rule>
+
+ +

Clean a URL

+ +

+    <rule>
+        <from>^/products/([0-9]+)$</from>
+        <to>/products/index.jsp?product_id=$1</to>
+    </rule>
+
+ +

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 + without the user noticing.

+ +

+    <rule>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ +

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork +

+ +

Browser detection

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/[1-4]</condition>
+        <from>^/some/page\.html$</from>
+        <to>/some/page-for-old-browsers.html</to>
+    </rule>
+
+ +

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html + only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, + Mozilla/3 or Mozilla/4.

+ + +

Security. Preclude certain types of method from you web application.

+ +

+    <rule>
+        <condition type="method" next="or">PROPFIND</condition>
+        <condition type="method">PUT</condition>
+        <from>.*</from>
+        <to type="redirect">/bad-method.html</to>
+    </rule>
+
+ + +

Sunday Specials

+ +

+    <rule>
+        <condition type="dayofweek">1</condition>
+        <from>^/products/$</from>
+        <to>/products/sunday-specials.html</to>
+    </rule>
+
+ + +

Set the "Cache-Control" HTTP response header for all requests

+ +

+    <rule>
+        <from>.*</from>
+        <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
+    </rule>
+
+ +

Forward a request to a servlet

+ +

+    <rule>
+        <from>^/products/purchase$</from>
+        <to>/servlets/ProductsServlet</to>
+        <set name="action">purchase</set>
+    </rule>
+
+ +

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and + inside + the servlet request.getAttribute("action") will return purchase.

+ +

Hide jsessionid for requests from googlebot.

+ +

+  <outbound-rule>
+       <name>Strip URL Session ID's</name>
+       <note>
+           Strip ;jsession=XXX from urls passed through
+response.encodeURL().
+           The characters ? and # are the only things we can use to
+find out where the jsessionid ends.
+           The expression in 'from' below contains three capture
+groups, the last two being optional.
+               1, everything before ;jesessionid
+               2, everything after ;jesessionid=XXX starting with a ?
+(to get the query string) up to #
+               3, everything ;jesessionid=XXX and optionally ?XXX
+starting with a # (to get the target)
+           eg,
+           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
+           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
+           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
+index.jsp#dfds
+           from u.jsp;jsessionid=wert.hg - u.jsp
+           from /;jsessionid=tyu - /
+       </note>
+       <condition name="user-agent">googlebot</condition>
+       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
+       <to>$1$2$3</to>
+   </outbound-rule<
+
+ + + +

Method Invocation

+ +

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have + any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

+ +

Invoke a servlet directly

+ +

+    <rule>
+    <from>^/products/purchase$</from>
+    <run class="com.blah.web.MyServlet" method="doGet" />
+    </rule>
+
+ +

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is + matched on a request. (remeber this method needs to be public!)

+ +

Use it to delagate cleanly to your methods

+ +

+    <rule>
+        <from>^/pref-editor/addresses$</from>
+        <run class="com.blah.web.PrefsServlet" method="runAddresses" />
+    </rule>
+    <rule>
+        <from>^/pref-editor/phone-nums$</from>
+        <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
+    </rule>
+
+ +

Browser based delagation to your methods

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/[1-4]</condition>
+        <from>^/content/.*$</from>
+        <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
+    </rule>
+    <rule>
+        <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+        <from>^/content/.*$</from>
+        <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
+        <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
+    </rule>
+
+ +

When the method specified in the "run" is invoked it has full control over the request and response as if it were a + servlet.

+ + + + + + + +

URL Abstraction

+ +

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

+ +

+    <rule>
+        <from>^/tidy/page$</from>
+        <to>/old/url/scheme/page.jsp</to>
+    </rule>
+    <outbound-rule>
+        <from>^/old/url/scheme/page.jsp$</from>
+        <to>/tidy/page</to>
+    </outbound-rule>
+
+ +

Any incoming requests for /tidy/page will be transparently forwarded to + /old/url/scheme/page.jsp.

+ +

If you use JSTL your JSP page would have something like:

+
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
+ +

This will be rewritten upon output to:

+
<a href="/tidy/page">some link</a>
+ +

Or if you use standard JSP:

+
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
+ +

Will generate output like:

+
<a href="/tidy/page">some link</a>
+ + + + +

mod_rewrite vs urlrewrite filter

+ + +

Examples of mod_rewrite style conf vs urlrewrite filter conf are below, there are all examples copied directly from + Apache 2.0's official rewrite guide.

+ +

+
+<rule>
+    <name>Canonical URLs</name>
+    <note>
+        On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
+        should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
+        of which URL the user supplied with the request he should finally see the canonical one only.
+
+        We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
+        and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
+        fix a missing trailing slash for /u/user.
+
+        RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
+        RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
+    </note>
+    <from>^/~([^/]+)/?(.*)</from>
+    <to type="redirect">/u/$1/$2</to>
+</rule>
+<rule>
+    <from>^/([uge])/([^/]+)$</from>
+    <to type="redirect">/$1/$2/</to>
+</rule>
+
+
+<rule>
+    <name>Canonical Hostnames</name>
+    <note>
+        The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
+        may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
+        example.com, you might use a variant of the following recipe.
+
+        RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
+        RewriteCond %{HTTP_HOST} !^$
+        RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
+    </note>
+    <condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
+    <condition name="host" operator="notequal">^$</condition>
+    <from>^/(.*)</from>
+    <to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
+</rule>
+
+
+<rule>
+    <name>Moved DocumentRoot</name>
+    <note>
+        Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
+        really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
+        Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
+        because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
+        stuff inside this data pool work for subsequent requests.
+
+        We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
+        Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
+        matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
+        With mod_rewrite it is really trivial:
+
+        RewriteRule ^/$ /e/www/ [R]
+    </note>
+    <from>^/$</from>
+    <to type="redirect">/e/www/</to>
+</rule>
+
+
+<rule>
+    <name>Trailing Slash Problem</name>
+    <note>
+        Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
+        If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
+        the server searches for a file named foo. And because this file is a directory it complains. Actually it
+        tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
+        instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
+
+        The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
+        correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
+        we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
+        images are included into this page with relative URLs, because the browser would request an in-lined object.
+        For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
+        external redirect!
+    </note>
+    <from>^/~quux/foo$</from>
+    <to type="redirect">/~quux/foo/</to>
+</rule>
+
+
+<rule>
+    <name>Move Homedirs to Different Webserver</name>
+    <note>
+        Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
+        homedirs on a webserver to another webserver. They usually need such things when establishing a newer
+        webserver which will replace the old one over time.
+
+        The solution is trivial with mod_rewrite (and urlrewrite filter). On the old webserver we just redirect all
+        /~user/anypath URLs to http://newserver/~user/anypath.
+
+        RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
+    </note>
+    <from>^/~(.+)</from>
+    <to type="redirect" last="true">http://newserver/~$1</to>
+</rule>
+
+
+<rule>
+    <name>Structured Homedirs</name>
+    <note>
+        Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
+        subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
+        /home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
+
+        We use the following ruleset to expand the tilde URLs into exactly the above layout.
+
+        RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
+    </note>
+    <from>^/~(([a-z])[a-z0-9]+)(.*)</from>
+    <to>/home/$2/$1/.www$3</to>
+</rule>
+
+
+<rule>
+    <name>Redirect Homedirs For Foreigners</name>
+    <note>
+        We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
+        stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
+
+        Just a rewrite condition:
+
+        RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
+        RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
+    </note>
+    <condition name="host">!^.+\.ourdomain\.com$</condition>
+    <from>^(/~.+)</from>
+    <to type="redirect" last="true">http://www.somewhere.com/$1</to>
+</rule>
+
+
+<rule>
+    <name>Time-Dependent Rewriting</name>
+    <note>
+        When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
+        instance redirects to specialized pages. How can it be done via mod_rewrite?
+
+        There are a lot of types in conjunction with operators we can do time-dependent redirects:
+
+        RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
+        RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
+        RewriteRule ^foo\.html$ foo.day.html
+        RewriteRule ^foo\.html$ foo.night.html
+    </note>
+    <condition type="hourofday" operator="greater">7</condition>
+    <condition type="hourofday" operator="less">19</condition>
+    <from>^foo\.html$</from>
+    <to>foo.day.html</to>
+</rule>
+<rule>
+    <from>^foo\.html$</from>
+    <to>foo.night.html</to>
+</rule>
+
+
+<rule>
+    <name></name>
+    <note>
+        Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
+        backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
+        renamed.
+
+        We rewrite the old URL to the new one internally via the following rule:
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ bar.html
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to>/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+    <name>From Old to New (extern)</name>
+    <note>
+        Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
+        for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
+        i.e. their browsers Location field should change, too.
+
+        We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ bar.html [R]
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to type="redirect">/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+    <name>Browser Dependent Content</name>
+    <note>
+        At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
+        content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
+        the Lynx browsers and a average feature version for all others.
+
+        We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
+        have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
+        "User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
+        stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
+        browsers receive page foo.32.html. This is done by the following ruleset:
+
+        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
+        RewriteRule ^foo\.html$ foo.NS.html [L]
+
+        RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
+        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
+        RewriteRule ^foo\.html$ foo.20.html [L]
+
+        RewriteRule ^foo\.html$ foo.32.html [L]
+    </note>
+    <condition name="user-agent">^Mozilla/3.*</condition>
+    <from>^foo\.html$</from>
+    <to last="true">foo.NS.html</to>
+</rule>
+<rule>
+    <condition name="user-agent" next="or">^Lynx/.*</condition>
+    <condition name="user-agent">^Mozilla/[12].*</condition>
+    <from>^foo\.html$</from>
+    <to last="true">foo.20.html</to>
+</rule>
+<rule>
+    <from>^foo\.html$</from>
+    <to last="true">foo.32.html</to>
+</rule>
+
+
+<rule>
+    <name>From Static to Dynamic</name>
+    <note>
+        How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
+        notice by the browser/user.
+
+        We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
+        a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to>/~quux/foo.jsp</to>
+</rule>
+
+<rule>
+    <name>Blocking of Robots</name>
+    <note>
+        How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
+        containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
+
+        We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
+        indexed area where the robot traversal would create big server load). We have to make sure that we forbid
+        access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
+        This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
+        information.
+
+        RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
+        RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
+        RewriteRule ^/~quux/foo/arc/.+ - [F]
+    </note>
+    <condition name="user-agent">^NameOfBadRobot.*</condition>
+    <condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
+    <from>^/~quux/foo/arc/.+</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+
+<rule>
+    <name>Blocked Inline-Images</name>
+    <note>
+        Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
+        nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
+        it adds useless traffic to our server.
+
+        While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
+        sends a HTTP Referer header.
+
+        RewriteCond %{HTTP_REFERER} !^$
+        RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
+        RewriteRule .*\.gif$ - [F]
+    </note>
+    <condition name="referer" operator="notequal">^$</condition>
+    <condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
+    <from>.*\.gif$</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+<rule>
+    <name>Blocked Inline-Images example 2</name>
+    <note>
+        RewriteCond %{HTTP_REFERER} !^$
+        RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
+        RewriteRule ^inlined-in-foo\.gif$ - [F]
+    </note>
+    <condition name="referer" operator="notequal">^$</condition>
+    <condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
+    <from>^inlined-in-foo\.gif$</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+
+ + + +
+ + + + + + diff --git a/src/doc/manual/3.0/index.html b/src/doc/manual/3.0/index.html index ed98d390..d8a9538c 100644 --- a/src/doc/manual/3.0/index.html +++ b/src/doc/manual/3.0/index.html @@ -1,1134 +1,1134 @@ - - - - UrlRewriteFilter - Manual - - - - - - - - - -
- - - -

Manual

- - -

Community support is available at UrlRewrite on StackOverflow.

- -

Read examples of usage and a - sample of the ant task report. - If you have feedback, or conf you want to share with the world email me. - If you have any suggestions/examples for this manual please post them to the - group.

- - - -

Install

- -
    -
  1. Download the zip (or tar.gz) and extract it into your - context's directory ie, so that urlrewrite.xml goes into the WEB-INF directory.
  2. -
  3. Add the following to your WEB-INF/web.xml (add it near the top above your - servlet mappings (if you have any)): (see filter - parameters for more options) -
    
    -    <filter>
    -       <filter-name>UrlRewriteFilter</filter-name>
    -       <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    -    </filter>
    -    <filter-mapping>
    -       <filter-name>UrlRewriteFilter</filter-name>
    -       <url-pattern>/*</url-pattern>
    -    </filter-mapping>
    -        
  4. -
  5. Add your own configuration to the WEB-INF/urlrewrite.xml that was created.
  6. -
  7. Restart the context.
  8. -
- -

You can visit http://127.0.0.1:8080/rewrite-status - (or whatever the address of your local webapp and context) - to see output (note: this page is only viewable from localhost).

- - - -

Filter Parameters

- -

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

- -

-    <filter>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-        <!-- set the amount of seconds the conf file will be checked for reload
-        can be a valid integer (0 denotes check every time,
-        -1 denotes no reload check, default -1) -->
-        <init-param>
-            <param-name>confReloadCheckInterval</param-name>
-            <param-value>60</param-value>
-        </init-param>
-
-        <!-- if you need to the conf file path can be changed
-        it is specified as a path relative to the root of your context
-        (default /WEB-INF/urlrewrite.xml) -->
-        <init-param>
-            <param-name>confPath</param-name>
-            <param-value>/WEB-INF/urlrewrite.xml</param-value>
-        </init-param>
-
-        <!-- sets up log level (will be logged to context log)
-        can be: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL, log4j, commons,
-        sysout:{level} (ie, sysout:DEBUG)
-        if you are having trouble using normal levels use sysout:DEBUG
-        (default WARN) -->
-        <init-param>
-            <param-name>logLevel</param-name>
-            <param-value>DEBUG</param-value>
-        </init-param>
-
-        <!-- you can change status path so that it does not
-        conflict with your installed apps (note, defaults
-        to /rewrite-status) note, must start with / -->
-        <init-param>
-            <param-name>statusPath</param-name>
-            <param-value>/status</param-value>
-        </init-param>
-
-        <!-- you can disable status page if desired
-        can be: true, false (default true) -->
-        <init-param>
-            <param-name>statusEnabled</param-name>
-            <param-value>true</param-value>
-        </init-param>
-
-        <!-- you may want to allow more hosts to look at the status page
-        statusEnabledOnHosts is a comma delimited list of hosts, * can
-        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
-        <init-param>
-            <param-name>statusEnabledOnHosts</param-name>
-            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
-        </init-param>
-
-    </filter>
-
-    <filter-mapping>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <url-pattern>/*</url-pattern>
-    </filter-mapping>
-
- -

Note, setting logLevel to log4j or commons will cause the built in loging to - call either log4j or - commons-logging as if they were the logging framework, - obviously you will need to have the jar for log4j or commons-logging in your classpath.

- - - - -

Configuration File WEB-INF/urlrewrite.xml

- -

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named - urlrewrite.xml. - It may be helpful to read the UrlRewriteFilter DTD - (Document Type Definition). Please also make sure you look at the examples. A simple - configuration file looks like:

- -

-    <?xml version="1.0" encoding="utf-8"?>
-
-    <!DOCTYPE urlrewrite
-        PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
-        "http://www.tuckey.org/res/dtds/urlrewrite3.0.dtd">
-
-    <urlrewrite>
-
-        <rule>
-           <from>^/some/olddir/(.*)$</from>
-           <to type="redirect">/very/newdir/$1</to>
-        </rule>
-
-        <rule match-type="wildcard">
-           <from>/blog/archive/**</from>
-           <to type="redirect">/roller/history/$1</to>
-        </rule>
-
-    </urlrewrite>
-
- - -

The urlrewrite.xml file must have a root element called "urlrewrite" and must contain - at least one "rule" element.

- -

A "rule" must contain a "from" and a "to", and can have zero or more "condition" elements and zero or more and/or - "set" elements.

- -

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then - the "from" will be applied to the request URL and the final URL generated by applying the - "to" to the "from" pattern. So long as the rule has matched then the "set" will be run.

- - - -

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

- -

-     Pattern.compile(<from> element);
-     pattern.matcher(request url);
-     matcher.replaceAll(<to> element);
-     if ( <condition> elements match && matcher.find() ) {
-         handle <set> elements (if any)
-         execute <run> elements (if any)
-         perform <to> element (if any)
-     }
- 
- - -

<urlrewrite> element

- -

The top level element.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
default-match-type
(optional)
regex (default)All rules and thier conditions will be processed using the Java Regular Expression engine (unless - match-type is specified on a rule).
wildcardAll rules and thier conditions will be processed using the Wildcard Expression - engine - (unless match-type is specified on a rule).
decode-using
(optional)
utf8 (default)When URL is decoded UTF-8 will be used.
nullDo not decode.
[encoding]Any string representing a supported character encoding eg, ISO-8859-1. - See Java Charset Object - for more info. -
use-query-string
(optional)
false (default)The query string will not be appended to the url that the "from" element matches against.
trueThe query string will be appended to the url that the "from" element matches against.
use-context
(optional)
false (default)The context path will not be added to the url that the "from" element matches against.
trueThe context path will be added to the url that the "from" element matches against.
- - -

<rule> element

- -

Zero or more. The basis of a rule.

- - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
match-type
(optional)
regex (default)This rule and it's conditions will be processed using the Java Regular Expression engine.
wildcardThis rule and it's conditions will be processed using the Wildcard Expression engine. -
- -

In the following example requests for /world/usa/nyc will be transparently forwarded to - /world.jsp

- -

-    <rule match-type="regex">
-       <from>^/world/([a-z]+)/([a-z]+)$</from>
-       <to>/world.jsp</to>
-    </rule>
-
- -

-    <rule match-type="wildcard">
-       <from>/world/*/*</from>
-       <to>/world.jsp</to>
-    </rule>
-
- - -

<outbound-rule> element

- -

Zero or more. This is very similar to a normal rule but it is used for rewriting urls that go through - response.encodeURL().

- - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
false (default)Run encodeURL() after running this outbound rule.
trueRun encodeURL() before running this outbound rule.
- -

May contain "run", "from", "to" and "set" element(s) also. Example:

- -

-    <outbound-rule>
-        <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
-        <to>/world/$1/$2</to>
-    </outbound-rule>
-
- -

Using the example above JSP's with the code -
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") - %>">nyc</a> -
will output -
<a href="/world/usa/nyc">nyc</a> -

- -

Or JSTL -
<a href="<c:url value="/world.jsp?country=${country}&amp;city=${city}" - />">nyc</a> -
will output -
<a href="/world/usa/nyc">nyc</a> -

- -

Note, If you are using JSTL (ie, <c:url) this will work also.

- -

<name> element

- -

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. - See ant task.

- -

-    <rule>
-        <name>World Rule</name>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- - -

<note> element

- -

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. - See ant task.

- -

-    <rule>
-        <name>World Rule</name>
-        <note>
-            Cleanly redirect world requests to JSP,
-            a country and city must be specified.
-            </note>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp</to>
-    </rule>
-
- - - -

<condition> element

- -

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run - (unless "next" is set to "or" obvoiusly).

- -

Value can be any Regular Expression.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD etc.
portThe port that the web application server is running on.
time - Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC otherwise known as unix - time). -
i.e. (new Date()).getTime() -
This can be used for making sure content goes live only at a time you set. -
year - Current year at the server. -
i.e. (Calendar.getInstance()).get(Calendar.YEAR) -
month - Month at the server. January is 0 -
i.e. (Calendar.getInstance()).get(Calendar.MONTH) -
dayofmonth - Day of the month at the server. March first is 1 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) -
dayofweek - Day of the week at the server. Saturday is 1, Sunday is 7 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) -
ampm - AM or PM time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) -
hourofday - The hour of the day (24 hour clock) at the server. 10pm is 22 -
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) -
minute - The minute field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) -
second - The second field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.SECOND) -
millisecond - The millisecond field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) -
attribute - Will check the value of a request attribute (don't confuse this with parameter!), name must be set when - using this type. -
i.e. request.getAttribute([name]) - -
auth-type - Will check the value of a request attribute (don't confuse this with parameter!) -
i.e. request.getAuthType() - -
character-encoding - The character encoding of the imcoming request. -
i.e. request.getCharacterEncoding() - -
content-length - The length of the imcoming request (can be useful if you want to deny large requests). -
i.e. request.getContentLength() - -
content-type - The type of the imcoming request. (this is probably not that useful) -
i.e. request.getContentType() - -
context-path - The context path of the imcoming request. -
i.e. request.getContextPath() - -
cookie - The value of a cookie, note, name must be specified to use this -
i.e. request.getCookies() - the find we the one with [name] specified and check the value. -
parameter - A tidier way of checking request parameters than looking for them in the query string. This will check for the - parameter in GET or POST, note, name must be specified. -
i.e. request.getParameter([name]) - -
path-info - i.e. request.getPathInfo() - -
path-translated - i.e. request.getPathTranslated() - -
protocolThe protocol used to make the request, e.g. HTTP/1.1 -
i.e. request.getProtocol() - -
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob -
i.e. request.getQueryString() - -
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 -
i.e. request.getRemoteAddr() - -
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, - this will only work if your app server is configured to lookup host names, most aren't). -
i.e. request.getRemoteHost() - -
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt -
i.e. request.getRemoteUser() - -
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 -
i.e. request.getRequestedSessionId() - -
request-uriReturns the part of this request's URL from the protocol name up to the query - string in the first line of the HTTP request -
i.e. request.getRequestURI() - -
request-urlReconstructs the URL the client used to make the request. The returned URL - contains a protocol, server name, port number, and server path, but it does not include query string parameters. -
i.e. request.getRequestURL() - -
session-attribute - (note, name must be set) -
i.e. session.getAttribute([name]) - -
session-isnew - Weather the session is new or not. -
i.e. session.isNew() - -
server-name - The host name of the server to which the request was sent (from the host header not the machine name). -
i.e. request.getServerName() - -
scheme - The scheme used for the request, e.g. http or https -
i.e. request.getScheme() - -
user-in-role - (Note, the value for this cannot be a regular expression) -
i.e. request.isUserInRole([value]) - -
name
(optional)
(can be anything)If type is header, this specifies the name of the HTTP header used to run the value - against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator to be used when the condition is run, the regular expression matches or the values are - equal.
notequalNot equal to. (i.e. request value != condition value). Note, this operator only work with - numeric rule types.
greaterGreater than. (i.e. request value > condition value). Note, this operator only work with - numeric - rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only work with numeric - rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator - only - work with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only - work with numeric rule types.
- -

Examples:

- -

-    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-
-    <condition type="user-in-role" operator="notequal">bigboss</condition>
-
-    <condition name="host" operator="notequal">www.example.com</condition>
-
-    <condition type="method" next="or">PROPFIND</condition>
-    <condition type="method">PUT</condition>
-
- - -

<from> element

- -

You must always have exactly one from for each rule or outbound-rule. Value can be a regular expression in the - Perl5 style. Note, from url's are relative to the context.

- - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using case insentitive match. ie, "/WellingtoN" will match "/wellington". -
trueThis value will be matched using case sentitive match. ie, "/aAa" will NOT match "/aaa". -
- -

Example:

- -

-    <from>^/world/([a-z]+)$</from>
-
- - -

<to> element

- -

Value can be a regular replacement expression in the Perl5 style.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally - forwarded - to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as - UrlRewriteFilter. This is the same as doing: -
RequestDispatcher rq = request.getRequestDispatcher([to value]); -
rq.forward(request, response);
-
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. - This is the same a doing: -
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_PERMANENTLY is HTTP status code 301)
temporary-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
pre-include
post-include
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) - will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) - will NOT be called.
- -

Note, "to" can be null ie, <to>null</to>, this will mean that the request will go no - further if the rule is matched (ie, this filter will not call chain.doFilter).

- -

-    <to>/world.jsp?country=$1</to>
-
- -

To elements can contain backreferences and variables.

- - -

Backreferences

- -

-    %N
-
- -

Provides access to the grouped parts (parentheses) of the pattern from the last matched Condition - in the current rule. - N must be less than 10 and greater than 0 (i.e. %1, %2, %3 etc).

- - -

Variables

- -

-    %{VARIABLE-NAME}
-
- -

Any valid condition type can be used as a variable name. ie, - '%{port}' will be translated to '80', - '%{year}' to '2005', - '%{cookie:myCookie}' would be translated to - 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

- -

Valid types are condition types, see condition for a full description.

- - -

<set> element

- -

Allows you to set varous things if the rule is matched.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], - [value]) - (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], - [value]) - (note, name must be set).
response-headerThe same as response.setHeader([name], - [value]) - (note, name must be set).
cookie - Value can be in the format "[value][:domain[:lifetime[:path]]]". - This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain - field is the domain of the cookie, such as '.apache.org',the optional lifetime is the lifetime of the cookie - in seconds, and the optional path is the path of the cookie (note, name must be set). -
statusThe same as response.setStatus([value]) -
content-typeThe same as response.setContentType([value]) -
charsetThe same as response.setCharacterEncoding([value]) -
localeThe same as response.setLocale([value]) - - specify the Locale in the format - (valid - locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). -
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
- -

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be - fetched in a servlet or - JSP using request.getAttribute("client").

- -

-    <rule>
-        <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
-        <from>.*</from>
-        <set name="client">AvantGo</set>
-    </rule>
-    <rule>
-        <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
-        <from>.*</from>
-        <set name="client">Samsung SCH-6100</set>
-    </rule>
-
- -

It is also possible to use regular replacement expressions as part of the - value similar to their usage in <to> elements:

- -

-    <rule>
-        <from>/products/(.*)/(.*)/index.html</from>
-        <set name="urlrewrite.product.slug">$1</set>
-        <set name="urlrewrite.product.id">$2</set>
-        <to>/products?slug=$1&id=$2</to>
-    </rule>
-
- - -

<run> element

- -

Allows you to run a method on an object when a rule and it's conditions are matched.

- - - - - - - - - - - - - - - - - - -
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default run)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) - e.g. run(HttpServletRequest request, HttpServletResponse response) -
Note, if init(ServletConfig) or destroy() is found they will be run at when - creating - or destroying an instance. -
neweachtime (optional, default false)If you want new instance of the class to be created before running each time set to true.
- -

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, - HttpServletResponse) - will be invoked, the request will then be forwarded to /world-presentation.jsp.

- -

-    <rule>
-        <from>^/world/[a-z]+/[a-z]+$</from>
-        <run class="com.blah.web.WorldServlet" method="doGet" />
-        <to>/world-presentation.jsp</to>
-    </rule>
-
- -

Note, you can specify init-param's the same way you would for a servlet.

- -

-    <run class="com.blah.web.MyServlet" method="doGet">
-        <init-param>
-            <param-name>someParamName</param-name>
-            <param-value>10</param-value>
-        </init-param>
-    </run>
-
- -

If the method being called throws an Exception the original exception will be re-thrown as if it were the original - if it extends RuntimeException (eg, NullPointer), other exceptions are wrapped in a ServletException and thrown - so your container can handle them.

- - -

<class-rule> element

- -

Allows you to run a method every time a request come in for 100% dynamic rules. See the org.tuckey.web.filters.urlrewrite.sample package for an example.

- - - - - - - - - - - - - - - - - - -
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default matches)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) - e.g. run(HttpServletRequest request, HttpServletResponse response) -
Note, if init(ServletConfig) or destroy() is found they will be run at when - creating or destroying an instance. -
last (optional, default trueIf false more rules will be processed following this rule even if it is matched (so that a better match may be found).
- -

Example:

- -

-    <class-rule class="com.blah.web.MyRuleClass" />
-
- - - - -

Tips

- -
    -
  • When you want to put an "&" in a rule you must enter it as the XML entity "&amp;"
  • -
  • For simplicity you might want to start all from's with a ^ and end them with a $. -
    In regular expressions ^ specifies the start of - the string and $ specifies the end. -
    ie, a request for /my/url/path will NOT match - <from>^/url/$</from> but it will match <from>/url/</from> -
    -
  • If using <outbound-rule> remember all urls in your code must be encoded e.g. - <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • -
  • Regular expressions are complex and a bit tricky at times, read - regular expression syntax for - Java. -
  • -
  • If you find regular expressions difficult use Wildcards.
  • -
  • "Context" is important. If you have an app with the context "/myapp" and you request the url - "/myapp/somefolder/somepage.jsp", the container tells UrlRewriteFilter that the url is "/somefolder/somepage.jsp". - This can be confusing, but basically your rules and conditions should not contain the context path - (it will be handled by the container).
  • -
- - - - - - -

Wildcard Matching Engine

- -

The wildcard matching engine can be used instead of regex. It is supported in conditions and rules - where match-type is set to wildcard (or default-match-type is set on the - urlrewrite element

- -

e.g. /big/url/* will match /big/url/abc.html but will NOT - match /big/url/abc/dir/ or /big/url/abc/. - -

/big/url/** will match /big/url/abc.html, /big/url/abc/dir/ and - /big/url/abc/. - -

You can also use Regular expression style variable replacement, each match of a * will - be available for use in to and set elements using simple $1 - $2 variables.

- -

e.g. /my/big/url/* will match /my/big/url/abc.html and $1 - will be set to abc.html.

- -

Added in 3.0

- - - - -

Ant Task

- -

An Ant task has been written to allow validate the conf file and generation - of documentation. You can view a sample.

- -

Paste the following into your build.xml file, then change the dest - and conf to point to the correct places. Note, the urlrewrite jar - file will need to be in your classpath.

- -

-    <target name="urlrewrite-doc" depends="compile"
-        description="UrlRewriteFilter validation and documenting">
-
-    <taskdef
-        name="urlrewritedoc"
-        classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
-    <urlrewritedoc
-        conf="${build.home}/WEB-INF/urlrewrite.xml"
-        dest="urlrewrite-conf-overview.html" />
-    </target>
-
- -
- - - - - - + + + + UrlRewriteFilter - Manual + + + + + + + + + +
+ + + +

Manual

+ + +

Community support is available at UrlRewrite on StackOverflow.

+ +

Read examples of usage and a + sample of the ant task report. + If you have feedback, or conf you want to share with the world email me. + If you have any suggestions/examples for this manual please post them to the + group.

+ + + +

Install

+ +
    +
  1. Download the zip (or tar.gz) and extract it into your + context's directory ie, so that urlrewrite.xml goes into the WEB-INF directory.
  2. +
  3. Add the following to your WEB-INF/web.xml (add it near the top above your + servlet mappings (if you have any)): (see filter + parameters for more options) +
    
    +    <filter>
    +       <filter-name>UrlRewriteFilter</filter-name>
    +       <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    +    </filter>
    +    <filter-mapping>
    +       <filter-name>UrlRewriteFilter</filter-name>
    +       <url-pattern>/*</url-pattern>
    +    </filter-mapping>
    +        
  4. +
  5. Add your own configuration to the WEB-INF/urlrewrite.xml that was created.
  6. +
  7. Restart the context.
  8. +
+ +

You can visit http://127.0.0.1:8080/rewrite-status + (or whatever the address of your local webapp and context) + to see output (note: this page is only viewable from localhost).

+ + + +

Filter Parameters

+ +

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

+ +

+    <filter>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+        <!-- set the amount of seconds the conf file will be checked for reload
+        can be a valid integer (0 denotes check every time,
+        -1 denotes no reload check, default -1) -->
+        <init-param>
+            <param-name>confReloadCheckInterval</param-name>
+            <param-value>60</param-value>
+        </init-param>
+
+        <!-- if you need to the conf file path can be changed
+        it is specified as a path relative to the root of your context
+        (default /WEB-INF/urlrewrite.xml) -->
+        <init-param>
+            <param-name>confPath</param-name>
+            <param-value>/WEB-INF/urlrewrite.xml</param-value>
+        </init-param>
+
+        <!-- sets up log level (will be logged to context log)
+        can be: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL, log4j, commons,
+        sysout:{level} (ie, sysout:DEBUG)
+        if you are having trouble using normal levels use sysout:DEBUG
+        (default WARN) -->
+        <init-param>
+            <param-name>logLevel</param-name>
+            <param-value>DEBUG</param-value>
+        </init-param>
+
+        <!-- you can change status path so that it does not
+        conflict with your installed apps (note, defaults
+        to /rewrite-status) note, must start with / -->
+        <init-param>
+            <param-name>statusPath</param-name>
+            <param-value>/status</param-value>
+        </init-param>
+
+        <!-- you can disable status page if desired
+        can be: true, false (default true) -->
+        <init-param>
+            <param-name>statusEnabled</param-name>
+            <param-value>true</param-value>
+        </init-param>
+
+        <!-- you may want to allow more hosts to look at the status page
+        statusEnabledOnHosts is a comma delimited list of hosts, * can
+        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
+        <init-param>
+            <param-name>statusEnabledOnHosts</param-name>
+            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
+        </init-param>
+
+    </filter>
+
+    <filter-mapping>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+ +

Note, setting logLevel to log4j or commons will cause the built in loging to + call either log4j or + commons-logging as if they were the logging framework, + obviously you will need to have the jar for log4j or commons-logging in your classpath.

+ + + + +

Configuration File WEB-INF/urlrewrite.xml

+ +

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named + urlrewrite.xml. + It may be helpful to read the UrlRewriteFilter DTD + (Document Type Definition). Please also make sure you look at the examples. A simple + configuration file looks like:

+ +

+    <?xml version="1.0" encoding="utf-8"?>
+
+    <!DOCTYPE urlrewrite
+        PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
+        "http://www.tuckey.org/res/dtds/urlrewrite3.0.dtd">
+
+    <urlrewrite>
+
+        <rule>
+           <from>^/some/olddir/(.*)$</from>
+           <to type="redirect">/very/newdir/$1</to>
+        </rule>
+
+        <rule match-type="wildcard">
+           <from>/blog/archive/**</from>
+           <to type="redirect">/roller/history/$1</to>
+        </rule>
+
+    </urlrewrite>
+
+ + +

The urlrewrite.xml file must have a root element called "urlrewrite" and must contain + at least one "rule" element.

+ +

A "rule" must contain a "from" and a "to", and can have zero or more "condition" elements and zero or more and/or + "set" elements.

+ +

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then + the "from" will be applied to the request URL and the final URL generated by applying the + "to" to the "from" pattern. So long as the rule has matched then the "set" will be run.

+ + + +

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

+ +

+     Pattern.compile(<from> element);
+     pattern.matcher(request url);
+     matcher.replaceAll(<to> element);
+     if ( <condition> elements match && matcher.find() ) {
+         handle <set> elements (if any)
+         execute <run> elements (if any)
+         perform <to> element (if any)
+     }
+ 
+ + +

<urlrewrite> element

+ +

The top level element.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
default-match-type
(optional)
regex (default)All rules and thier conditions will be processed using the Java Regular Expression engine (unless + match-type is specified on a rule).
wildcardAll rules and thier conditions will be processed using the Wildcard Expression + engine + (unless match-type is specified on a rule).
decode-using
(optional)
utf8 (default)When URL is decoded UTF-8 will be used.
nullDo not decode.
[encoding]Any string representing a supported character encoding eg, ISO-8859-1. + See Java Charset Object + for more info. +
use-query-string
(optional)
false (default)The query string will not be appended to the url that the "from" element matches against.
trueThe query string will be appended to the url that the "from" element matches against.
use-context
(optional)
false (default)The context path will not be added to the url that the "from" element matches against.
trueThe context path will be added to the url that the "from" element matches against.
+ + +

<rule> element

+ +

Zero or more. The basis of a rule.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
match-type
(optional)
regex (default)This rule and it's conditions will be processed using the Java Regular Expression engine.
wildcardThis rule and it's conditions will be processed using the Wildcard Expression engine. +
+ +

In the following example requests for /world/usa/nyc will be transparently forwarded to + /world.jsp

+ +

+    <rule match-type="regex">
+       <from>^/world/([a-z]+)/([a-z]+)$</from>
+       <to>/world.jsp</to>
+    </rule>
+
+ +

+    <rule match-type="wildcard">
+       <from>/world/*/*</from>
+       <to>/world.jsp</to>
+    </rule>
+
+ + +

<outbound-rule> element

+ +

Zero or more. This is very similar to a normal rule but it is used for rewriting urls that go through + response.encodeURL().

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
false (default)Run encodeURL() after running this outbound rule.
trueRun encodeURL() before running this outbound rule.
+ +

May contain "run", "from", "to" and "set" element(s) also. Example:

+ +

+    <outbound-rule>
+        <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
+        <to>/world/$1/$2</to>
+    </outbound-rule>
+
+ +

Using the example above JSP's with the code +
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") + %>">nyc</a> +
will output +
<a href="/world/usa/nyc">nyc</a> +

+ +

Or JSTL +
<a href="<c:url value="/world.jsp?country=${country}&amp;city=${city}" + />">nyc</a> +
will output +
<a href="/world/usa/nyc">nyc</a> +

+ +

Note, If you are using JSTL (ie, <c:url) this will work also.

+ +

<name> element

+ +

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +

+    <rule>
+        <name>World Rule</name>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ + +

<note> element

+ +

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +

+    <rule>
+        <name>World Rule</name>
+        <note>
+            Cleanly redirect world requests to JSP,
+            a country and city must be specified.
+            </note>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp</to>
+    </rule>
+
+ + + +

<condition> element

+ +

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run + (unless "next" is set to "or" obvoiusly).

+ +

Value can be any Regular Expression.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD etc.
portThe port that the web application server is running on.
time + Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC otherwise known as unix + time). +
i.e. (new Date()).getTime() +
This can be used for making sure content goes live only at a time you set. +
year + Current year at the server. +
i.e. (Calendar.getInstance()).get(Calendar.YEAR) +
month + Month at the server. January is 0 +
i.e. (Calendar.getInstance()).get(Calendar.MONTH) +
dayofmonth + Day of the month at the server. March first is 1 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) +
dayofweek + Day of the week at the server. Saturday is 1, Sunday is 7 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) +
ampm + AM or PM time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) +
hourofday + The hour of the day (24 hour clock) at the server. 10pm is 22 +
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) +
minute + The minute field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) +
second + The second field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.SECOND) +
millisecond + The millisecond field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) +
attribute + Will check the value of a request attribute (don't confuse this with parameter!), name must be set when + using this type. +
i.e. request.getAttribute([name]) + +
auth-type + Will check the value of a request attribute (don't confuse this with parameter!) +
i.e. request.getAuthType() + +
character-encoding + The character encoding of the imcoming request. +
i.e. request.getCharacterEncoding() + +
content-length + The length of the imcoming request (can be useful if you want to deny large requests). +
i.e. request.getContentLength() + +
content-type + The type of the imcoming request. (this is probably not that useful) +
i.e. request.getContentType() + +
context-path + The context path of the imcoming request. +
i.e. request.getContextPath() + +
cookie + The value of a cookie, note, name must be specified to use this +
i.e. request.getCookies() + the find we the one with [name] specified and check the value. +
parameter + A tidier way of checking request parameters than looking for them in the query string. This will check for the + parameter in GET or POST, note, name must be specified. +
i.e. request.getParameter([name]) + +
path-info + i.e. request.getPathInfo() + +
path-translated + i.e. request.getPathTranslated() + +
protocolThe protocol used to make the request, e.g. HTTP/1.1 +
i.e. request.getProtocol() + +
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob +
i.e. request.getQueryString() + +
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 +
i.e. request.getRemoteAddr() + +
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, + this will only work if your app server is configured to lookup host names, most aren't). +
i.e. request.getRemoteHost() + +
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt +
i.e. request.getRemoteUser() + +
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 +
i.e. request.getRequestedSessionId() + +
request-uriReturns the part of this request's URL from the protocol name up to the query + string in the first line of the HTTP request +
i.e. request.getRequestURI() + +
request-urlReconstructs the URL the client used to make the request. The returned URL + contains a protocol, server name, port number, and server path, but it does not include query string parameters. +
i.e. request.getRequestURL() + +
session-attribute + (note, name must be set) +
i.e. session.getAttribute([name]) + +
session-isnew + Weather the session is new or not. +
i.e. session.isNew() + +
server-name + The host name of the server to which the request was sent (from the host header not the machine name). +
i.e. request.getServerName() + +
scheme + The scheme used for the request, e.g. http or https +
i.e. request.getScheme() + +
user-in-role + (Note, the value for this cannot be a regular expression) +
i.e. request.isUserInRole([value]) + +
name
(optional)
(can be anything)If type is header, this specifies the name of the HTTP header used to run the value + against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator to be used when the condition is run, the regular expression matches or the values are + equal.
notequalNot equal to. (i.e. request value != condition value). Note, this operator only work with + numeric rule types.
greaterGreater than. (i.e. request value > condition value). Note, this operator only work with + numeric + rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only work with numeric + rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator + only + work with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only + work with numeric rule types.
+ +

Examples:

+ +

+    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+
+    <condition type="user-in-role" operator="notequal">bigboss</condition>
+
+    <condition name="host" operator="notequal">www.example.com</condition>
+
+    <condition type="method" next="or">PROPFIND</condition>
+    <condition type="method">PUT</condition>
+
+ + +

<from> element

+ +

You must always have exactly one from for each rule or outbound-rule. Value can be a regular expression in the + Perl5 style. Note, from url's are relative to the context.

+ + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using case insentitive match. ie, "/WellingtoN" will match "/wellington". +
trueThis value will be matched using case sentitive match. ie, "/aAa" will NOT match "/aaa". +
+ +

Example:

+ +

+    <from>^/world/([a-z]+)$</from>
+
+ + +

<to> element

+ +

Value can be a regular replacement expression in the Perl5 style.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally + forwarded + to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as + UrlRewriteFilter. This is the same as doing: +
RequestDispatcher rq = request.getRequestDispatcher([to value]); +
rq.forward(request, response);
+
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. + This is the same a doing: +
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_PERMANENTLY is HTTP status code 301)
temporary-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
pre-include
post-include
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) + will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) + will NOT be called.
+ +

Note, "to" can be null ie, <to>null</to>, this will mean that the request will go no + further if the rule is matched (ie, this filter will not call chain.doFilter).

+ +

+    <to>/world.jsp?country=$1</to>
+
+ +

To elements can contain backreferences and variables.

+ + +

Backreferences

+ +

+    %N
+
+ +

Provides access to the grouped parts (parentheses) of the pattern from the last matched Condition + in the current rule. + N must be less than 10 and greater than 0 (i.e. %1, %2, %3 etc).

+ + +

Variables

+ +

+    %{VARIABLE-NAME}
+
+ +

Any valid condition type can be used as a variable name. ie, + '%{port}' will be translated to '80', + '%{year}' to '2005', + '%{cookie:myCookie}' would be translated to + 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

+ +

Valid types are condition types, see condition for a full description.

+ + +

<set> element

+ +

Allows you to set varous things if the rule is matched.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], + [value]) + (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], + [value]) + (note, name must be set).
response-headerThe same as response.setHeader([name], + [value]) + (note, name must be set).
cookie + Value can be in the format "[value][:domain[:lifetime[:path]]]". + This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain + field is the domain of the cookie, such as '.apache.org',the optional lifetime is the lifetime of the cookie + in seconds, and the optional path is the path of the cookie (note, name must be set). +
statusThe same as response.setStatus([value]) +
content-typeThe same as response.setContentType([value]) +
charsetThe same as response.setCharacterEncoding([value]) +
localeThe same as response.setLocale([value]) + + specify the Locale in the format + (valid + locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). +
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
+ +

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be + fetched in a servlet or + JSP using request.getAttribute("client").

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
+        <from>.*</from>
+        <set name="client">AvantGo</set>
+    </rule>
+    <rule>
+        <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
+        <from>.*</from>
+        <set name="client">Samsung SCH-6100</set>
+    </rule>
+
+ +

It is also possible to use regular replacement expressions as part of the + value similar to their usage in <to> elements:

+ +

+    <rule>
+        <from>/products/(.*)/(.*)/index.html</from>
+        <set name="urlrewrite.product.slug">$1</set>
+        <set name="urlrewrite.product.id">$2</set>
+        <to>/products?slug=$1&id=$2</to>
+    </rule>
+
+ + +

<run> element

+ +

Allows you to run a method on an object when a rule and it's conditions are matched.

+ + + + + + + + + + + + + + + + + + +
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default run)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) + e.g. run(HttpServletRequest request, HttpServletResponse response) +
Note, if init(ServletConfig) or destroy() is found they will be run at when + creating + or destroying an instance. +
neweachtime (optional, default false)If you want new instance of the class to be created before running each time set to true.
+ +

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, + HttpServletResponse) + will be invoked, the request will then be forwarded to /world-presentation.jsp.

+ +

+    <rule>
+        <from>^/world/[a-z]+/[a-z]+$</from>
+        <run class="com.blah.web.WorldServlet" method="doGet" />
+        <to>/world-presentation.jsp</to>
+    </rule>
+
+ +

Note, you can specify init-param's the same way you would for a servlet.

+ +

+    <run class="com.blah.web.MyServlet" method="doGet">
+        <init-param>
+            <param-name>someParamName</param-name>
+            <param-value>10</param-value>
+        </init-param>
+    </run>
+
+ +

If the method being called throws an Exception the original exception will be re-thrown as if it were the original + if it extends RuntimeException (eg, NullPointer), other exceptions are wrapped in a ServletException and thrown + so your container can handle them.

+ + +

<class-rule> element

+ +

Allows you to run a method every time a request come in for 100% dynamic rules. See the org.tuckey.web.filters.urlrewrite.sample package for an example.

+ + + + + + + + + + + + + + + + + + +
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default matches)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) + e.g. run(HttpServletRequest request, HttpServletResponse response) +
Note, if init(ServletConfig) or destroy() is found they will be run at when + creating or destroying an instance. +
last (optional, default trueIf false more rules will be processed following this rule even if it is matched (so that a better match may be found).
+ +

Example:

+ +

+    <class-rule class="com.blah.web.MyRuleClass" />
+
+ + + + +

Tips

+ +
    +
  • When you want to put an "&" in a rule you must enter it as the XML entity "&amp;"
  • +
  • For simplicity you might want to start all from's with a ^ and end them with a $. +
    In regular expressions ^ specifies the start of + the string and $ specifies the end. +
    ie, a request for /my/url/path will NOT match + <from>^/url/$</from> but it will match <from>/url/</from> +
    +
  • If using <outbound-rule> remember all urls in your code must be encoded e.g. + <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • +
  • Regular expressions are complex and a bit tricky at times, read + regular expression syntax for + Java. +
  • +
  • If you find regular expressions difficult use Wildcards.
  • +
  • "Context" is important. If you have an app with the context "/myapp" and you request the url + "/myapp/somefolder/somepage.jsp", the container tells UrlRewriteFilter that the url is "/somefolder/somepage.jsp". + This can be confusing, but basically your rules and conditions should not contain the context path + (it will be handled by the container).
  • +
+ + + + + + +

Wildcard Matching Engine

+ +

The wildcard matching engine can be used instead of regex. It is supported in conditions and rules + where match-type is set to wildcard (or default-match-type is set on the + urlrewrite element

+ +

e.g. /big/url/* will match /big/url/abc.html but will NOT + match /big/url/abc/dir/ or /big/url/abc/. + +

/big/url/** will match /big/url/abc.html, /big/url/abc/dir/ and + /big/url/abc/. + +

You can also use Regular expression style variable replacement, each match of a * will + be available for use in to and set elements using simple $1 + $2 variables.

+ +

e.g. /my/big/url/* will match /my/big/url/abc.html and $1 + will be set to abc.html.

+ +

Added in 3.0

+ + + + +

Ant Task

+ +

An Ant task has been written to allow validate the conf file and generation + of documentation. You can view a sample.

+ +

Paste the following into your build.xml file, then change the dest + and conf to point to the correct places. Note, the urlrewrite jar + file will need to be in your classpath.

+ +

+    <target name="urlrewrite-doc" depends="compile"
+        description="UrlRewriteFilter validation and documenting">
+
+    <taskdef
+        name="urlrewritedoc"
+        classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
+    <urlrewritedoc
+        conf="${build.home}/WEB-INF/urlrewrite.xml"
+        dest="urlrewrite-conf-overview.html" />
+    </target>
+
+ +
+ + + + + + diff --git a/src/doc/manual/3.0/introduction.html b/src/doc/manual/3.0/introduction.html index b921d773..1f5436e8 100644 --- a/src/doc/manual/3.0/introduction.html +++ b/src/doc/manual/3.0/introduction.html @@ -1,263 +1,263 @@ - - - - UrlRewriteFilter - Background - - - - - - - - - -
- - - -

Background

- - - -

A clean URL scheme is very important detail for any quality Web Application. UrlRewriteFilter provides a - toolkit to let you set URL patterns however you want.

- -

See Cool URIs don't change, by World Wide Web creator - Tim Berners-Lee, for excellent arguments on why URLs should be clean and usable.

- -

With the Apache webserver there is mod_rewrite for URL manipulation.

- -

In J2EE land the Servlet specification (by Sun) standardises the approach for dealing with Java web server -programming. We have come a long way from basic Servlets, JSP's, MVC frameworks etc but Java Web Application -Servers such as Tomcat are seldom used as front-line web servers, they almost always have Apache infront of them.

- -

If you want to use an app server as a front line web server UrlRewriteFilter will enable you to manage incoming -URL's in a much more flexible way than the app server usually lets you.

- -

You can find test cases in the source distribution. UrlRewriteFilter should work on any J2EE web application server - and has been spceifically tested using Cactus on the following web application - servers:

- - - -

The filter has been designed for maximum performance. Testing has indicated - that it should only slow down a request by 0.0005 of a second under normal circumstances - (depending on hardware and configuration etc.). Take a look at the source in the class - UrlRewriterTest.testLoadsOfRules() for more information.

- - - - -

License

- -

UrlRewriteFilter is distributed under the BSD License. For more information on see - opensource.org/licenses.

- -

If you want to purchase ad-hoc support, a support contract, custom development or a commercial license - please email sales@tuckey.co.nz.

- - - - - - -

Changelog

- -

3.0.4 Beta - Bug fix - cookie value not being set with variable replacement -
3.0.3 Beta - Bug fix - annotation processor rule sorting -
Bug Fix - evaluation boolean result was incorrect on failed condition instance matches -
3.0.2 Beta - Rule chaining bug fixes -
3.0.1 Beta -
Added "class-rule" element to enable 100% dynamic "Java Rules" -
Added experimental UrlrewriteTestCase to help with testing (see the source) -
Added experimental "catch" element to handle exceptions generated from "run"'s -
Added experimental annotation (@HttpUrl, @HttpParam) processor -
Bug fixes - -
3.0 Beta - Support for wildcard matching. -
Added "match-type" attribute to rule and outbound-rule. -
Added ability to specify charset decoding ("decodeusing" attribute to "urlrewrite" element) - -
Swapped "to" variable replacement and run processing, run processing now comes before "to" - variable replacement is done. dtd it has been swapped make sure you change the reference in your conf file. - Make sure element order is from, set, run, to. - -
Context addition to the url is now optional -
Query string matching on rule is now optional (defaults to false) -
before 3.0 you would specify -
<from>/blah.jsp?a=b</from> -
3.0 and up (unless use-query-string on urlrewrite element is set to true) -
<condition name="a">b</condition> -
<from>/blah.jsp</from> - -
2.6 - fixed bug with encode on to element defaulting to incorrect boolean (change to dtd) -
2.5.3 - cleaner exception handling when invoking "run" items, original exception thrown as if it were the - original if - it extends RuntimeException (eg, NullPointer), other exceptions wrapped in a ServletException and thrown -
2.5.2 - fixed bug with encodefirst attr not being set, - ability to specify wildcards on statusEnabledOnHosts, - added backreferences and variables for to element value, - logLevel init param can now include sysout:{level} ie, sysout:DEBUG for people who have trouble with context.log -
2.5.1 - bug fixes, Log initialisation and null auth type condition values -
2.5 - matcher changed to accept first match (not the whole string) please make sure you retest your rules - (ie, previously /res/js/l.js?aaa would not match /res/js/l.js, with this release it will), -
- support for logging to log4j or commons-logging (see filter params in manual), -
- fixed bug for when request.getCookies() returns null on some containers, -
- added encodefirst outbound-rule, outbound-rule now respects encode on "to". -
2.4 - removed all external library dependencies to make much more deploy friendly -
- no longer uses Jakarta ORO, this should't mean any change in regular expression handling but you should test - your - existing rules just in case. -
- fixed problem with rediredting to "null" this will now not proceed with the request if the rule is matched - (ie, chain.doFilter will not be called) -
- fixed problem with ant dependency on status page. -
2.3 (4/2005) - Added new outbound-rule for rewriting hyperlinks in JSP's, improved status page, added ability - to - run methods when a rule is matched -
2.0.1 (2/2005) - Fixed bug with rule processing when to element doesn't exist. -
2.0 (1/2005) - Minor bug fixes, last attribute on rule now defaults to false (thanks to Vineet Kumar for his - assistance). -
2.0-beta (12/2004) - Minor bug fixes, documentation improvements, ALL matches now done case insensitively by - default, case sensitivity can be set (see from and condition elements). -
2.0-alpha (11/2004) - First 2.0 release, added many new condition types, many new set types. -
1.2 (6/2004) - Added set element (ability to set random attributes on request, thanks for the idea - Russell), from now matches RELATIVE to context NOT root (if you - are - upgrading this may mean a change for you). -
1.1 (4/2004) - Ability to disable rules, Refactored to enable rewriter to be embedded, - changed logging to enable log level to be set, added name and note elements to rule for documentation, - ability to disable status page, ability to change status prefix, javadoc style ant task for an HTML - configuration report. -
1.0 (3/2004) - General tidy up of logging, tidy up of all code, dist now includes manual, log4j and junit - removed - from bin release. -
0.9 (2/2004) - Fixed conf loading problem in Resin, resolved concurrency issue with Perl5Compiler and - Perl5Matcher - (thanks Scott Askew!) -
0.8 (2/2004) - Removed dependency on "Commons Lang", Changed DTD path (bug fix), added ability to put time - fields in - "condition" element, added ability to put "operators" in the "condition" element, fixed multiple rules issue (bug - fix) -
0.7 (11/2003) - Improved test cases, documentation -
0.6 (8/2003) - Improved error handling, status page and condition matching -
0.5 (6/2003) - Improved configuration error handling -

- - -
- - - - - - + + + + UrlRewriteFilter - Background + + + + + + + + + +
+ + + +

Background

+ + + +

A clean URL scheme is very important detail for any quality Web Application. UrlRewriteFilter provides a + toolkit to let you set URL patterns however you want.

+ +

See Cool URIs don't change, by World Wide Web creator + Tim Berners-Lee, for excellent arguments on why URLs should be clean and usable.

+ +

With the Apache webserver there is mod_rewrite for URL manipulation.

+ +

In J2EE land the Servlet specification (by Sun) standardises the approach for dealing with Java web server +programming. We have come a long way from basic Servlets, JSP's, MVC frameworks etc but Java Web Application +Servers such as Tomcat are seldom used as front-line web servers, they almost always have Apache infront of them.

+ +

If you want to use an app server as a front line web server UrlRewriteFilter will enable you to manage incoming +URL's in a much more flexible way than the app server usually lets you.

+ +

You can find test cases in the source distribution. UrlRewriteFilter should work on any J2EE web application server + and has been spceifically tested using Cactus on the following web application + servers:

+ + + +

The filter has been designed for maximum performance. Testing has indicated + that it should only slow down a request by 0.0005 of a second under normal circumstances + (depending on hardware and configuration etc.). Take a look at the source in the class + UrlRewriterTest.testLoadsOfRules() for more information.

+ + + + +

License

+ +

UrlRewriteFilter is distributed under the BSD License. For more information on see + opensource.org/licenses.

+ +

If you want to purchase ad-hoc support, a support contract, custom development or a commercial license + please email sales@tuckey.co.nz.

+ + + + + + +

Changelog

+ +

3.0.4 Beta - Bug fix - cookie value not being set with variable replacement +
3.0.3 Beta - Bug fix - annotation processor rule sorting +
Bug Fix - evaluation boolean result was incorrect on failed condition instance matches +
3.0.2 Beta - Rule chaining bug fixes +
3.0.1 Beta +
Added "class-rule" element to enable 100% dynamic "Java Rules" +
Added experimental UrlrewriteTestCase to help with testing (see the source) +
Added experimental "catch" element to handle exceptions generated from "run"'s +
Added experimental annotation (@HttpUrl, @HttpParam) processor +
Bug fixes + +
3.0 Beta - Support for wildcard matching. +
Added "match-type" attribute to rule and outbound-rule. +
Added ability to specify charset decoding ("decodeusing" attribute to "urlrewrite" element) + +
Swapped "to" variable replacement and run processing, run processing now comes before "to" + variable replacement is done. dtd it has been swapped make sure you change the reference in your conf file. + Make sure element order is from, set, run, to. + +
Context addition to the url is now optional +
Query string matching on rule is now optional (defaults to false) +
before 3.0 you would specify +
<from>/blah.jsp?a=b</from> +
3.0 and up (unless use-query-string on urlrewrite element is set to true) +
<condition name="a">b</condition> +
<from>/blah.jsp</from> + +
2.6 - fixed bug with encode on to element defaulting to incorrect boolean (change to dtd) +
2.5.3 - cleaner exception handling when invoking "run" items, original exception thrown as if it were the + original if + it extends RuntimeException (eg, NullPointer), other exceptions wrapped in a ServletException and thrown +
2.5.2 - fixed bug with encodefirst attr not being set, + ability to specify wildcards on statusEnabledOnHosts, + added backreferences and variables for to element value, + logLevel init param can now include sysout:{level} ie, sysout:DEBUG for people who have trouble with context.log +
2.5.1 - bug fixes, Log initialisation and null auth type condition values +
2.5 - matcher changed to accept first match (not the whole string) please make sure you retest your rules + (ie, previously /res/js/l.js?aaa would not match /res/js/l.js, with this release it will), +
- support for logging to log4j or commons-logging (see filter params in manual), +
- fixed bug for when request.getCookies() returns null on some containers, +
- added encodefirst outbound-rule, outbound-rule now respects encode on "to". +
2.4 - removed all external library dependencies to make much more deploy friendly +
- no longer uses Jakarta ORO, this should't mean any change in regular expression handling but you should test + your + existing rules just in case. +
- fixed problem with rediredting to "null" this will now not proceed with the request if the rule is matched + (ie, chain.doFilter will not be called) +
- fixed problem with ant dependency on status page. +
2.3 (4/2005) - Added new outbound-rule for rewriting hyperlinks in JSP's, improved status page, added ability + to + run methods when a rule is matched +
2.0.1 (2/2005) - Fixed bug with rule processing when to element doesn't exist. +
2.0 (1/2005) - Minor bug fixes, last attribute on rule now defaults to false (thanks to Vineet Kumar for his + assistance). +
2.0-beta (12/2004) - Minor bug fixes, documentation improvements, ALL matches now done case insensitively by + default, case sensitivity can be set (see from and condition elements). +
2.0-alpha (11/2004) - First 2.0 release, added many new condition types, many new set types. +
1.2 (6/2004) - Added set element (ability to set random attributes on request, thanks for the idea + Russell), from now matches RELATIVE to context NOT root (if you + are + upgrading this may mean a change for you). +
1.1 (4/2004) - Ability to disable rules, Refactored to enable rewriter to be embedded, + changed logging to enable log level to be set, added name and note elements to rule for documentation, + ability to disable status page, ability to change status prefix, javadoc style ant task for an HTML + configuration report. +
1.0 (3/2004) - General tidy up of logging, tidy up of all code, dist now includes manual, log4j and junit + removed + from bin release. +
0.9 (2/2004) - Fixed conf loading problem in Resin, resolved concurrency issue with Perl5Compiler and + Perl5Matcher + (thanks Scott Askew!) +
0.8 (2/2004) - Removed dependency on "Commons Lang", Changed DTD path (bug fix), added ability to put time + fields in + "condition" element, added ability to put "operators" in the "condition" element, fixed multiple rules issue (bug + fix) +
0.7 (11/2003) - Improved test cases, documentation +
0.6 (8/2003) - Improved error handling, status page and condition matching +
0.5 (6/2003) - Improved configuration error handling +

+ + +
+ + + + + + diff --git a/src/doc/manual/3.1/annotation.html b/src/doc/manual/3.1/annotation.html index 3f38335b..ac04ee44 100644 --- a/src/doc/manual/3.1/annotation.html +++ b/src/doc/manual/3.1/annotation.html @@ -1,153 +1,153 @@ - - - - UrlRewriteFilter - Annotation - - - - - - - - - -
- - - -

URL Matching Annotations

- - - -

Support for annotations has been added as part of version 3 development. You must be using JDK 1.5 for this to work.

- -

The intention of annotations in UrlRewriteFilter is purely for conf file generation. The is NO runtime - dependency on the annotations.

- -

Annotations

- -

@HttpUrl

- -

Set the method up to be used when the url is Matched, matched groups are assigned to method paramters (if any).

- -

-    @HttpUrl("^/do-something/([0-9]+)$")
-    public void doSomething(Long id)
-    
- -

When a request for /do-something/1234, doSomething is called with id set to 1234.

- -

@HttpParam

- -

Sets the parameter from request.getParameter (handles type conversion as necessary)

- -

-    void doSomething(@HttpParam String name, @HttpParam long id, @HttpParam("uid") Long userId)
-    
- -

The above example will: -
name = request.getParameter("name"); -
id = convertTolongDefault0(request.getParameter("id")); -
userId = convertToLongDefaultNull(request.getParameter("uid")); -
An exception will never be thown during type conversion -

- - - - -

Conf Generation

- -

Add a post-compile step to your ant build script (requires ant 1.7+). - note, the annotation jar is included in the src version of UrlRewriteFilter.

- -

-    <target name="compile-urlrewrite-conf">
-       <path id="annotation-classpath">
-           <fileset file="lib/urlrewrite-annotation-3.1.0.jar"/>
-           <fileset file="lib/servlet-api.jar"/>
-       </path>
-       <mkdir dir="build/WEB-INF/"/>
-       <apt compile="false" factory="org.tuckey.web.filters.urlrewrite.annotation.HttpUrlAPTFactory"
-            srcdir="src/annotation/test/" classpathref="annotation-classpath">
-           <option name="saveRulesTo" value="build/WEB-INF/urlrewrite-generated.xml"/>
-       </apt>
-    </target>
-    
- -

This will generate to the file specified. Any errors will be output to stdout using the standard APT method. - Read the generated conf file and check it for errors.

- - -

Include the compiled conf file in your normal conf.

- -

-    <?xml version="1.0" encoding="utf-8"?>
-    <!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
-            "http://www.tuckey.org/res/dtds/urlrewrite3.0.dtd"
-    [
-        <!ENTITY included SYSTEM "urlrewrite-generated.xml">
-    ]>
-    <urlrewrite>
-
-        <!--
-            other rules...
-        -->
-
-        &included;
-
-
-    </urlrewrite>
-
- - -

Check your /rewrite-status for errors if things start going strange.

- -
- - - - - - + + + + UrlRewriteFilter - Annotation + + + + + + + + + +
+ + + +

URL Matching Annotations

+ + + +

Support for annotations has been added as part of version 3 development. You must be using JDK 1.5 for this to work.

+ +

The intention of annotations in UrlRewriteFilter is purely for conf file generation. The is NO runtime + dependency on the annotations.

+ +

Annotations

+ +

@HttpUrl

+ +

Set the method up to be used when the url is Matched, matched groups are assigned to method paramters (if any).

+ +

+    @HttpUrl("^/do-something/([0-9]+)$")
+    public void doSomething(Long id)
+    
+ +

When a request for /do-something/1234, doSomething is called with id set to 1234.

+ +

@HttpParam

+ +

Sets the parameter from request.getParameter (handles type conversion as necessary)

+ +

+    void doSomething(@HttpParam String name, @HttpParam long id, @HttpParam("uid") Long userId)
+    
+ +

The above example will: +
name = request.getParameter("name"); +
id = convertTolongDefault0(request.getParameter("id")); +
userId = convertToLongDefaultNull(request.getParameter("uid")); +
An exception will never be thown during type conversion +

+ + + + +

Conf Generation

+ +

Add a post-compile step to your ant build script (requires ant 1.7+). + note, the annotation jar is included in the src version of UrlRewriteFilter.

+ +

+    <target name="compile-urlrewrite-conf">
+       <path id="annotation-classpath">
+           <fileset file="lib/urlrewrite-annotation-3.1.0.jar"/>
+           <fileset file="lib/servlet-api.jar"/>
+       </path>
+       <mkdir dir="build/WEB-INF/"/>
+       <apt compile="false" factory="org.tuckey.web.filters.urlrewrite.annotation.HttpUrlAPTFactory"
+            srcdir="src/annotation/test/" classpathref="annotation-classpath">
+           <option name="saveRulesTo" value="build/WEB-INF/urlrewrite-generated.xml"/>
+       </apt>
+    </target>
+    
+ +

This will generate to the file specified. Any errors will be output to stdout using the standard APT method. + Read the generated conf file and check it for errors.

+ + +

Include the compiled conf file in your normal conf.

+ +

+    <?xml version="1.0" encoding="utf-8"?>
+    <!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.0//EN"
+            "http://www.tuckey.org/res/dtds/urlrewrite3.0.dtd"
+    [
+        <!ENTITY included SYSTEM "urlrewrite-generated.xml">
+    ]>
+    <urlrewrite>
+
+        <!--
+            other rules...
+        -->
+
+        &included;
+
+
+    </urlrewrite>
+
+ + +

Check your /rewrite-status for errors if things start going strange.

+ +
+ + + + + + diff --git a/src/doc/manual/3.1/doc.css b/src/doc/manual/3.1/doc.css index 28b31294..e66217f2 100644 --- a/src/doc/manual/3.1/doc.css +++ b/src/doc/manual/3.1/doc.css @@ -1,137 +1,137 @@ -body { - background: #c0c0c0; - font: 13px arial, helvetica, sans-serif; -} - -h1 { - color: #000000; - font-size: 2.5em; - padding: 0px 0px 0px 5px; - margin: 0px; - font-family: georgia, times, serif; -} - -#masthead { - font-family: georgia, times, serif; - font-size: 3.5em; - background-color: #efefef; - -moz-border-radius-topright: 20px; - margin-top: 5px; - padding: 5px; - padding-left: 15px; - width: 650px; -} - -#masthead a { - text-decoration: none; - color: black; -} -#masthead img { - vertical-align: 15%; -} - -h2 { - font-family: georgia, times, serif; - border-bottom: 1px solid #808080; - padding: 5px; -} - -h3 { - font-family: georgia, times, serif; - border-bottom: 1px solid #c0c0c0; - margin-top: 2em; - padding: 0.25em 0.25em 0em 0.5em; -} - -p { - padding: 0.25em 0.25em 0em 1.0em; -} - -code, pre { - font-family: 'Courier New', courier, monospace; - font-size: 11px; -} - -pre { - background: #eeeeff; - margin: 0.5em 3em 0.1em 3em; - padding: 0.25em 0.5em 0.5em 0.5em; -} - -table { - border: 1px solid #c0c0c0; - margin-left: 2em; - border-collapse: collapse; - border-spacing: 0; -} - -th, td { - border: 1px solid #eeeeee; - vertical-align: top; - padding: 3px; -} - -th { - background: #eeeeee; -} - -hr { - border: 0px; - background-color: #c0c0c0; -} - -.err { - color: #ff0000; -} - -#menu { - float:left; - width:160px; - background: #efefef; - Zmargin-top: 2px; - padding-bottom: 10px; - padding-left: 10px; - -moz-border-radius-bottomleft: 20px; -} - -#menu ul { - list-style-type: none; - margin-left: .5em; - padding-left: .5em; - margin-top: 7px; -} -#menu li { - margin-bottom: 7px; -} - -#main { - background: white; - border-left: 1px solid #c0c0c0; - border-top: 1px solid #c0c0c0; - border-right: 1px solid #808080; - border-bottom: 1px solid #808080; - margin-left: 170px; - padding: 15px; - -moz-border-radius-bottomleft: 20px; - min-height: 400px; -} - -#footer { - margin-top: 40px; - text-align: center; - font-size: small; - color: black; - text-transform: lowercase; -} - -#footer a { - text-decoration: none; -} - -.outdated { - border: 2px solid red; - background: #eeeeee; - padding: 5px; - font-weight: bold; -} - +body { + background: #c0c0c0; + font: 13px arial, helvetica, sans-serif; +} + +h1 { + color: #000000; + font-size: 2.5em; + padding: 0px 0px 0px 5px; + margin: 0px; + font-family: georgia, times, serif; +} + +#masthead { + font-family: georgia, times, serif; + font-size: 3.5em; + background-color: #efefef; + -moz-border-radius-topright: 20px; + margin-top: 5px; + padding: 5px; + padding-left: 15px; + width: 650px; +} + +#masthead a { + text-decoration: none; + color: black; +} +#masthead img { + vertical-align: 15%; +} + +h2 { + font-family: georgia, times, serif; + border-bottom: 1px solid #808080; + padding: 5px; +} + +h3 { + font-family: georgia, times, serif; + border-bottom: 1px solid #c0c0c0; + margin-top: 2em; + padding: 0.25em 0.25em 0em 0.5em; +} + +p { + padding: 0.25em 0.25em 0em 1.0em; +} + +code, pre { + font-family: 'Courier New', courier, monospace; + font-size: 11px; +} + +pre { + background: #eeeeff; + margin: 0.5em 3em 0.1em 3em; + padding: 0.25em 0.5em 0.5em 0.5em; +} + +table { + border: 1px solid #c0c0c0; + margin-left: 2em; + border-collapse: collapse; + border-spacing: 0; +} + +th, td { + border: 1px solid #eeeeee; + vertical-align: top; + padding: 3px; +} + +th { + background: #eeeeee; +} + +hr { + border: 0px; + background-color: #c0c0c0; +} + +.err { + color: #ff0000; +} + +#menu { + float:left; + width:160px; + background: #efefef; + Zmargin-top: 2px; + padding-bottom: 10px; + padding-left: 10px; + -moz-border-radius-bottomleft: 20px; +} + +#menu ul { + list-style-type: none; + margin-left: .5em; + padding-left: .5em; + margin-top: 7px; +} +#menu li { + margin-bottom: 7px; +} + +#main { + background: white; + border-left: 1px solid #c0c0c0; + border-top: 1px solid #c0c0c0; + border-right: 1px solid #808080; + border-bottom: 1px solid #808080; + margin-left: 170px; + padding: 15px; + -moz-border-radius-bottomleft: 20px; + min-height: 400px; +} + +#footer { + margin-top: 40px; + text-align: center; + font-size: small; + color: black; + text-transform: lowercase; +} + +#footer a { + text-decoration: none; +} + +.outdated { + border: 2px solid red; + background: #eeeeee; + padding: 5px; + font-weight: bold; +} + diff --git a/src/doc/manual/3.1/guide.html b/src/doc/manual/3.1/guide.html index ce2a809d..717da752 100644 --- a/src/doc/manual/3.1/guide.html +++ b/src/doc/manual/3.1/guide.html @@ -1,750 +1,750 @@ - - - - UrlRewriteFilter - Examples - - - - - - - - - -
- - - -

Examples

- -

Redirect one url

- -

-    <rule>
-        <from>^/some/old/page\.html$</from>
-        <to type="redirect">/very/new/page.html</to>
-    </rule>
-
- -

-    <rule match-type="wildcard">
-        <from>/some/old/page.html</from>
-        <to type="redirect">/very/new/page.html</to>
-    </rule>
-
- -

Redirect docs in a directory to another using wildcard engine.

- -

-    <urlrewrite default-match-type="wildcard">
-
-    <rule>
-        <from>/some/old/*.doc</from>
-        <to type="redirect">/very/new/$1.doc</to>
-    </rule>
-
-    </urlrewrite>
-
- -

Tiny/Freindly url

- -

-    <rule>
-        <from>^/zebra$</from>
-        <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
-    </rule>
-
- -

Default page as another (requests to / will be redirected)

- -

-    <rule>
-        <from>^/$</from>
-        <to type="redirect">/opencms/opencms/index.html</to>
-    </rule>
-
- -

Perform security checks in a centralised place

- -

-    <rule>
-        <condition type="user-in-role" operator="notequal">admin</condition>
-        <condition type="user-in-role" operator="notequal">bigboss</condition>
-        <from>^/admin/(.*)$</from>
-        <to>/go-away-please.html</to>
-    </rule>
-
- - -

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah - will be redirected to http://www.example.com/blah

- -

-    <rule>
-        <name>Domain Name Check</name>
-        <condition name="host" operator="notequal">www.example.com</condition>
-        <from>(.*)</from>
-        <to type="redirect">http://www.example.com/context$1</to>
-    </rule>
-
- - -

Disable access to a directory.

- -

-    <rule>
-        <name>Disable Directory</name>
-        <from>^/notliveyet/.*$</from>
-        <set type="status">403</set>
-        <to>null</to>
-    </rule>
-
- -

Redirect a directory (for moved content)

- -

-    <rule>
-        <from>^/some/olddir/(.*)$</from>
-        <to type="redirect">/very/newdir/$1</to>
-    </rule>
-
- -

Clean a URL

- -

-    <rule>
-        <from>^/products/([0-9]+)$</from>
-        <to>/products/index.jsp?product_id=$1</to>
-    </rule>
-
- -

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 - without the user noticing.

- -

-    <rule>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- -

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork -

- -

Browser detection

- -

-    <rule>
-        <condition name="user-agent">Mozilla/[1-4]</condition>
-        <from>^/some/page\.html$</from>
-        <to>/some/page-for-old-browsers.html</to>
-    </rule>
-
- -

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html - only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, - Mozilla/3 or Mozilla/4.

- - -

Security. Preclude certain types of method from you web application.

- -

-    <rule>
-        <condition type="method" next="or">PROPFIND</condition>
-        <condition type="method">PUT</condition>
-        <from>.*</from>
-        <to type="redirect">/bad-method.html</to>
-    </rule>
-
- - -

Sunday Specials

- -

-    <rule>
-        <condition type="dayofweek">1</condition>
-        <from>^/products/$</from>
-        <to>/products/sunday-specials.html</to>
-    </rule>
-
- - -

Set the "Cache-Control" HTTP response header for all requests

- -

-    <rule>
-        <from>.*</from>
-        <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
-    </rule>
-
- -

Forward a request to a servlet

- -

-    <rule>
-        <from>^/products/purchase$</from>
-        <to>/servlets/ProductsServlet</to>
-        <set name="action">purchase</set>
-    </rule>
-
- -

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and - inside - the servlet request.getAttribute("action") will return purchase.

- -

Set an "Expires" HTTP header 6 hours into the future for js, css and gif files

- -

-    <rule>
-        <from>^.*\.(js|css|gif)$</from>
-        <set type="expires">6 hours</set>
-    </rule>
-
- -

Hide jsessionid for requests from googlebot.

- -

-  <outbound-rule>
-       <name>Strip URL Session ID's</name>
-       <note>
-           Strip ;jsession=XXX from urls passed through
-response.encodeURL().
-           The characters ? and # are the only things we can use to
-find out where the jsessionid ends.
-           The expression in 'from' below contains three capture
-groups, the last two being optional.
-               1, everything before ;jesessionid
-               2, everything after ;jesessionid=XXX starting with a ?
-(to get the query string) up to #
-               3, everything ;jesessionid=XXX and optionally ?XXX
-starting with a # (to get the target)
-           eg,
-           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
-           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
-           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
-index.jsp#dfds
-           from u.jsp;jsessionid=wert.hg - u.jsp
-           from /;jsessionid=tyu - /
-       </note>
-       <condition name="user-agent">googlebot</condition>
-       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
-       <to>$1$2$3</to>
-   </outbound-rule<
-
- - - -

Method Invocation

- -

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have - any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

- -

Invoke a servlet directly

- -

-    <rule>
-    <from>^/products/purchase$</from>
-    <run class="com.blah.web.MyServlet" method="doGet" />
-    </rule>
-
- -

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is - matched on a request. (remeber this method needs to be public!)

- -

Use it to delagate cleanly to your methods

- -

-    <rule>
-        <from>^/pref-editor/addresses$</from>
-        <run class="com.blah.web.PrefsServlet" method="runAddresses" />
-    </rule>
-    <rule>
-        <from>^/pref-editor/phone-nums$</from>
-        <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
-    </rule>
-
- -

Browser based delagation to your methods

- -

-    <rule>
-        <condition name="user-agent">Mozilla/[1-4]</condition>
-        <from>^/content/.*$</from>
-        <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
-    </rule>
-    <rule>
-        <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-        <from>^/content/.*$</from>
-        <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
-        <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
-    </rule>
-
- -

When the method specified in the "run" is invoked it has full control over the request and response as if it were a - servlet.

- - - - - - - -

URL Abstraction

- -

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

- -

-    <rule>
-        <from>^/tidy/page$</from>
-        <to>/old/url/scheme/page.jsp</to>
-    </rule>
-    <outbound-rule>
-        <from>^/old/url/scheme/page.jsp$</from>
-        <to>/tidy/page</to>
-    </outbound-rule>
-
- -

Any incoming requests for /tidy/page will be transparently forwarded to - /old/url/scheme/page.jsp.

- -

If you use JSTL your JSP page would have something like:

-
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
- -

This will be rewritten upon output to:

-
<a href="/tidy/page">some link</a>
- -

Or if you use standard JSP:

-
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
- -

Will generate output like:

-
<a href="/tidy/page">some link</a>
- - - - -

mod_rewrite vs urlrewrite filter

- - -

Examples of mod_rewrite style conf vs urlrewrite filter conf are below, there are all examples copied directly from - Apache 2.0's official rewrite guide.

- -

-
-<rule>
-    <name>Canonical URLs</name>
-    <note>
-        On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
-        should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
-        of which URL the user supplied with the request he should finally see the canonical one only.
-
-        We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
-        and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
-        fix a missing trailing slash for /u/user.
-
-        RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
-        RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
-    </note>
-    <from>^/~([^/]+)/?(.*)</from>
-    <to type="redirect">/u/$1/$2</to>
-</rule>
-<rule>
-    <from>^/([uge])/([^/]+)$</from>
-    <to type="redirect">/$1/$2/</to>
-</rule>
-
-
-<rule>
-    <name>Canonical Hostnames</name>
-    <note>
-        The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
-        may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
-        example.com, you might use a variant of the following recipe.
-
-        RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
-        RewriteCond %{HTTP_HOST} !^$
-        RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
-    </note>
-    <condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
-    <condition name="host" operator="notequal">^$</condition>
-    <from>^/(.*)</from>
-    <to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
-</rule>
-
-
-<rule>
-    <name>Moved DocumentRoot</name>
-    <note>
-        Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
-        really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
-        Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
-        because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
-        stuff inside this data pool work for subsequent requests.
-
-        We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
-        Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
-        matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
-        With mod_rewrite it is really trivial:
-
-        RewriteRule ^/$ /e/www/ [R]
-    </note>
-    <from>^/$</from>
-    <to type="redirect">/e/www/</to>
-</rule>
-
-
-<rule>
-    <name>Trailing Slash Problem</name>
-    <note>
-        Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
-        If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
-        the server searches for a file named foo. And because this file is a directory it complains. Actually it
-        tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
-        instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
-
-        The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
-        correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
-        we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
-        images are included into this page with relative URLs, because the browser would request an in-lined object.
-        For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
-        external redirect!
-    </note>
-    <from>^/~quux/foo$</from>
-    <to type="redirect">/~quux/foo/</to>
-</rule>
-
-
-<rule>
-    <name>Move Homedirs to Different Webserver</name>
-    <note>
-        Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
-        homedirs on a webserver to another webserver. They usually need such things when establishing a newer
-        webserver which will replace the old one over time.
-
-        The solution is trivial with mod_rewrite (and urlrewrite filter). On the old webserver we just redirect all
-        /~user/anypath URLs to http://newserver/~user/anypath.
-
-        RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
-    </note>
-    <from>^/~(.+)</from>
-    <to type="redirect" last="true">http://newserver/~$1</to>
-</rule>
-
-
-<rule>
-    <name>Structured Homedirs</name>
-    <note>
-        Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
-        subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
-        /home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
-
-        We use the following ruleset to expand the tilde URLs into exactly the above layout.
-
-        RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
-    </note>
-    <from>^/~(([a-z])[a-z0-9]+)(.*)</from>
-    <to>/home/$2/$1/.www$3</to>
-</rule>
-
-
-<rule>
-    <name>Redirect Homedirs For Foreigners</name>
-    <note>
-        We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
-        stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
-
-        Just a rewrite condition:
-
-        RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
-        RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
-    </note>
-    <condition name="host">!^.+\.ourdomain\.com$</condition>
-    <from>^(/~.+)</from>
-    <to type="redirect" last="true">http://www.somewhere.com/$1</to>
-</rule>
-
-
-<rule>
-    <name>Time-Dependent Rewriting</name>
-    <note>
-        When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
-        instance redirects to specialized pages. How can it be done via mod_rewrite?
-
-        There are a lot of types in conjunction with operators we can do time-dependent redirects:
-
-        RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
-        RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
-        RewriteRule ^foo\.html$ foo.day.html
-        RewriteRule ^foo\.html$ foo.night.html
-    </note>
-    <condition type="hourofday" operator="greater">7</condition>
-    <condition type="hourofday" operator="less">19</condition>
-    <from>^foo\.html$</from>
-    <to>foo.day.html</to>
-</rule>
-<rule>
-    <from>^foo\.html$</from>
-    <to>foo.night.html</to>
-</rule>
-
-
-<rule>
-    <name></name>
-    <note>
-        Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
-        backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
-        renamed.
-
-        We rewrite the old URL to the new one internally via the following rule:
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ bar.html
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to>/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-    <name>From Old to New (extern)</name>
-    <note>
-        Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
-        for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
-        i.e. their browsers Location field should change, too.
-
-        We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ bar.html [R]
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to type="redirect">/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-    <name>Browser Dependent Content</name>
-    <note>
-        At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
-        content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
-        the Lynx browsers and a average feature version for all others.
-
-        We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
-        have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
-        "User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
-        stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
-        browsers receive page foo.32.html. This is done by the following ruleset:
-
-        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
-        RewriteRule ^foo\.html$ foo.NS.html [L]
-
-        RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
-        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
-        RewriteRule ^foo\.html$ foo.20.html [L]
-
-        RewriteRule ^foo\.html$ foo.32.html [L]
-    </note>
-    <condition name="user-agent">^Mozilla/3.*</condition>
-    <from>^foo\.html$</from>
-    <to last="true">foo.NS.html</to>
-</rule>
-<rule>
-    <condition name="user-agent" next="or">^Lynx/.*</condition>
-    <condition name="user-agent">^Mozilla/[12].*</condition>
-    <from>^foo\.html$</from>
-    <to last="true">foo.20.html</to>
-</rule>
-<rule>
-    <from>^foo\.html$</from>
-    <to last="true">foo.32.html</to>
-</rule>
-
-
-<rule>
-    <name>From Static to Dynamic</name>
-    <note>
-        How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
-        notice by the browser/user.
-
-        We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
-        a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to>/~quux/foo.jsp</to>
-</rule>
-
-<rule>
-    <name>Blocking of Robots</name>
-    <note>
-        How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
-        containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
-
-        We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
-        indexed area where the robot traversal would create big server load). We have to make sure that we forbid
-        access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
-        This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
-        information.
-
-        RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
-        RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
-        RewriteRule ^/~quux/foo/arc/.+ - [F]
-    </note>
-    <condition name="user-agent">^NameOfBadRobot.*</condition>
-    <condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
-    <from>^/~quux/foo/arc/.+</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-
-<rule>
-    <name>Blocked Inline-Images</name>
-    <note>
-        Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
-        nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
-        it adds useless traffic to our server.
-
-        While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
-        sends a HTTP Referer header.
-
-        RewriteCond %{HTTP_REFERER} !^$
-        RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
-        RewriteRule .*\.gif$ - [F]
-    </note>
-    <condition name="referer" operator="notequal">^$</condition>
-    <condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
-    <from>.*\.gif$</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-<rule>
-    <name>Blocked Inline-Images example 2</name>
-    <note>
-        RewriteCond %{HTTP_REFERER} !^$
-        RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
-        RewriteRule ^inlined-in-foo\.gif$ - [F]
-    </note>
-    <condition name="referer" operator="notequal">^$</condition>
-    <condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
-    <from>^inlined-in-foo\.gif$</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-
- - - -
- - - - - - + + + + UrlRewriteFilter - Examples + + + + + + + + + +
+ + + +

Examples

+ +

Redirect one url

+ +

+    <rule>
+        <from>^/some/old/page\.html$</from>
+        <to type="redirect">/very/new/page.html</to>
+    </rule>
+
+ +

+    <rule match-type="wildcard">
+        <from>/some/old/page.html</from>
+        <to type="redirect">/very/new/page.html</to>
+    </rule>
+
+ +

Redirect docs in a directory to another using wildcard engine.

+ +

+    <urlrewrite default-match-type="wildcard">
+
+    <rule>
+        <from>/some/old/*.doc</from>
+        <to type="redirect">/very/new/$1.doc</to>
+    </rule>
+
+    </urlrewrite>
+
+ +

Tiny/Freindly url

+ +

+    <rule>
+        <from>^/zebra$</from>
+        <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
+    </rule>
+
+ +

Default page as another (requests to / will be redirected)

+ +

+    <rule>
+        <from>^/$</from>
+        <to type="redirect">/opencms/opencms/index.html</to>
+    </rule>
+
+ +

Perform security checks in a centralised place

+ +

+    <rule>
+        <condition type="user-in-role" operator="notequal">admin</condition>
+        <condition type="user-in-role" operator="notequal">bigboss</condition>
+        <from>^/admin/(.*)$</from>
+        <to>/go-away-please.html</to>
+    </rule>
+
+ + +

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah + will be redirected to http://www.example.com/blah

+ +

+    <rule>
+        <name>Domain Name Check</name>
+        <condition name="host" operator="notequal">www.example.com</condition>
+        <from>(.*)</from>
+        <to type="redirect">http://www.example.com/context$1</to>
+    </rule>
+
+ + +

Disable access to a directory.

+ +

+    <rule>
+        <name>Disable Directory</name>
+        <from>^/notliveyet/.*$</from>
+        <set type="status">403</set>
+        <to>null</to>
+    </rule>
+
+ +

Redirect a directory (for moved content)

+ +

+    <rule>
+        <from>^/some/olddir/(.*)$</from>
+        <to type="redirect">/very/newdir/$1</to>
+    </rule>
+
+ +

Clean a URL

+ +

+    <rule>
+        <from>^/products/([0-9]+)$</from>
+        <to>/products/index.jsp?product_id=$1</to>
+    </rule>
+
+ +

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 + without the user noticing.

+ +

+    <rule>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ +

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork +

+ +

Browser detection

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/[1-4]</condition>
+        <from>^/some/page\.html$</from>
+        <to>/some/page-for-old-browsers.html</to>
+    </rule>
+
+ +

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html + only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, + Mozilla/3 or Mozilla/4.

+ + +

Security. Preclude certain types of method from you web application.

+ +

+    <rule>
+        <condition type="method" next="or">PROPFIND</condition>
+        <condition type="method">PUT</condition>
+        <from>.*</from>
+        <to type="redirect">/bad-method.html</to>
+    </rule>
+
+ + +

Sunday Specials

+ +

+    <rule>
+        <condition type="dayofweek">1</condition>
+        <from>^/products/$</from>
+        <to>/products/sunday-specials.html</to>
+    </rule>
+
+ + +

Set the "Cache-Control" HTTP response header for all requests

+ +

+    <rule>
+        <from>.*</from>
+        <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
+    </rule>
+
+ +

Forward a request to a servlet

+ +

+    <rule>
+        <from>^/products/purchase$</from>
+        <to>/servlets/ProductsServlet</to>
+        <set name="action">purchase</set>
+    </rule>
+
+ +

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and + inside + the servlet request.getAttribute("action") will return purchase.

+ +

Set an "Expires" HTTP header 6 hours into the future for js, css and gif files

+ +

+    <rule>
+        <from>^.*\.(js|css|gif)$</from>
+        <set type="expires">6 hours</set>
+    </rule>
+
+ +

Hide jsessionid for requests from googlebot.

+ +

+  <outbound-rule>
+       <name>Strip URL Session ID's</name>
+       <note>
+           Strip ;jsession=XXX from urls passed through
+response.encodeURL().
+           The characters ? and # are the only things we can use to
+find out where the jsessionid ends.
+           The expression in 'from' below contains three capture
+groups, the last two being optional.
+               1, everything before ;jesessionid
+               2, everything after ;jesessionid=XXX starting with a ?
+(to get the query string) up to #
+               3, everything ;jesessionid=XXX and optionally ?XXX
+starting with a # (to get the target)
+           eg,
+           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
+           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
+           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
+index.jsp#dfds
+           from u.jsp;jsessionid=wert.hg - u.jsp
+           from /;jsessionid=tyu - /
+       </note>
+       <condition name="user-agent">googlebot</condition>
+       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
+       <to>$1$2$3</to>
+   </outbound-rule<
+
+ + + +

Method Invocation

+ +

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have + any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

+ +

Invoke a servlet directly

+ +

+    <rule>
+    <from>^/products/purchase$</from>
+    <run class="com.blah.web.MyServlet" method="doGet" />
+    </rule>
+
+ +

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is + matched on a request. (remeber this method needs to be public!)

+ +

Use it to delagate cleanly to your methods

+ +

+    <rule>
+        <from>^/pref-editor/addresses$</from>
+        <run class="com.blah.web.PrefsServlet" method="runAddresses" />
+    </rule>
+    <rule>
+        <from>^/pref-editor/phone-nums$</from>
+        <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
+    </rule>
+
+ +

Browser based delagation to your methods

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/[1-4]</condition>
+        <from>^/content/.*$</from>
+        <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
+    </rule>
+    <rule>
+        <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+        <from>^/content/.*$</from>
+        <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
+        <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
+    </rule>
+
+ +

When the method specified in the "run" is invoked it has full control over the request and response as if it were a + servlet.

+ + + + + + + +

URL Abstraction

+ +

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

+ +

+    <rule>
+        <from>^/tidy/page$</from>
+        <to>/old/url/scheme/page.jsp</to>
+    </rule>
+    <outbound-rule>
+        <from>^/old/url/scheme/page.jsp$</from>
+        <to>/tidy/page</to>
+    </outbound-rule>
+
+ +

Any incoming requests for /tidy/page will be transparently forwarded to + /old/url/scheme/page.jsp.

+ +

If you use JSTL your JSP page would have something like:

+
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
+ +

This will be rewritten upon output to:

+
<a href="/tidy/page">some link</a>
+ +

Or if you use standard JSP:

+
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
+ +

Will generate output like:

+
<a href="/tidy/page">some link</a>
+ + + + +

mod_rewrite vs urlrewrite filter

+ + +

Examples of mod_rewrite style conf vs urlrewrite filter conf are below, there are all examples copied directly from + Apache 2.0's official rewrite guide.

+ +

+
+<rule>
+    <name>Canonical URLs</name>
+    <note>
+        On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
+        should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
+        of which URL the user supplied with the request he should finally see the canonical one only.
+
+        We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
+        and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
+        fix a missing trailing slash for /u/user.
+
+        RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
+        RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
+    </note>
+    <from>^/~([^/]+)/?(.*)</from>
+    <to type="redirect">/u/$1/$2</to>
+</rule>
+<rule>
+    <from>^/([uge])/([^/]+)$</from>
+    <to type="redirect">/$1/$2/</to>
+</rule>
+
+
+<rule>
+    <name>Canonical Hostnames</name>
+    <note>
+        The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
+        may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
+        example.com, you might use a variant of the following recipe.
+
+        RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
+        RewriteCond %{HTTP_HOST} !^$
+        RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
+    </note>
+    <condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
+    <condition name="host" operator="notequal">^$</condition>
+    <from>^/(.*)</from>
+    <to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
+</rule>
+
+
+<rule>
+    <name>Moved DocumentRoot</name>
+    <note>
+        Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
+        really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
+        Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
+        because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
+        stuff inside this data pool work for subsequent requests.
+
+        We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
+        Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
+        matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
+        With mod_rewrite it is really trivial:
+
+        RewriteRule ^/$ /e/www/ [R]
+    </note>
+    <from>^/$</from>
+    <to type="redirect">/e/www/</to>
+</rule>
+
+
+<rule>
+    <name>Trailing Slash Problem</name>
+    <note>
+        Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
+        If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
+        the server searches for a file named foo. And because this file is a directory it complains. Actually it
+        tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
+        instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
+
+        The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
+        correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
+        we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
+        images are included into this page with relative URLs, because the browser would request an in-lined object.
+        For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
+        external redirect!
+    </note>
+    <from>^/~quux/foo$</from>
+    <to type="redirect">/~quux/foo/</to>
+</rule>
+
+
+<rule>
+    <name>Move Homedirs to Different Webserver</name>
+    <note>
+        Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
+        homedirs on a webserver to another webserver. They usually need such things when establishing a newer
+        webserver which will replace the old one over time.
+
+        The solution is trivial with mod_rewrite (and urlrewrite filter). On the old webserver we just redirect all
+        /~user/anypath URLs to http://newserver/~user/anypath.
+
+        RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
+    </note>
+    <from>^/~(.+)</from>
+    <to type="redirect" last="true">http://newserver/~$1</to>
+</rule>
+
+
+<rule>
+    <name>Structured Homedirs</name>
+    <note>
+        Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
+        subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
+        /home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
+
+        We use the following ruleset to expand the tilde URLs into exactly the above layout.
+
+        RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
+    </note>
+    <from>^/~(([a-z])[a-z0-9]+)(.*)</from>
+    <to>/home/$2/$1/.www$3</to>
+</rule>
+
+
+<rule>
+    <name>Redirect Homedirs For Foreigners</name>
+    <note>
+        We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
+        stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
+
+        Just a rewrite condition:
+
+        RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
+        RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
+    </note>
+    <condition name="host">!^.+\.ourdomain\.com$</condition>
+    <from>^(/~.+)</from>
+    <to type="redirect" last="true">http://www.somewhere.com/$1</to>
+</rule>
+
+
+<rule>
+    <name>Time-Dependent Rewriting</name>
+    <note>
+        When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
+        instance redirects to specialized pages. How can it be done via mod_rewrite?
+
+        There are a lot of types in conjunction with operators we can do time-dependent redirects:
+
+        RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
+        RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
+        RewriteRule ^foo\.html$ foo.day.html
+        RewriteRule ^foo\.html$ foo.night.html
+    </note>
+    <condition type="hourofday" operator="greater">7</condition>
+    <condition type="hourofday" operator="less">19</condition>
+    <from>^foo\.html$</from>
+    <to>foo.day.html</to>
+</rule>
+<rule>
+    <from>^foo\.html$</from>
+    <to>foo.night.html</to>
+</rule>
+
+
+<rule>
+    <name></name>
+    <note>
+        Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
+        backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
+        renamed.
+
+        We rewrite the old URL to the new one internally via the following rule:
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ bar.html
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to>/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+    <name>From Old to New (extern)</name>
+    <note>
+        Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
+        for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
+        i.e. their browsers Location field should change, too.
+
+        We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ bar.html [R]
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to type="redirect">/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+    <name>Browser Dependent Content</name>
+    <note>
+        At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
+        content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
+        the Lynx browsers and a average feature version for all others.
+
+        We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
+        have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
+        "User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
+        stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
+        browsers receive page foo.32.html. This is done by the following ruleset:
+
+        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
+        RewriteRule ^foo\.html$ foo.NS.html [L]
+
+        RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
+        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
+        RewriteRule ^foo\.html$ foo.20.html [L]
+
+        RewriteRule ^foo\.html$ foo.32.html [L]
+    </note>
+    <condition name="user-agent">^Mozilla/3.*</condition>
+    <from>^foo\.html$</from>
+    <to last="true">foo.NS.html</to>
+</rule>
+<rule>
+    <condition name="user-agent" next="or">^Lynx/.*</condition>
+    <condition name="user-agent">^Mozilla/[12].*</condition>
+    <from>^foo\.html$</from>
+    <to last="true">foo.20.html</to>
+</rule>
+<rule>
+    <from>^foo\.html$</from>
+    <to last="true">foo.32.html</to>
+</rule>
+
+
+<rule>
+    <name>From Static to Dynamic</name>
+    <note>
+        How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
+        notice by the browser/user.
+
+        We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
+        a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to>/~quux/foo.jsp</to>
+</rule>
+
+<rule>
+    <name>Blocking of Robots</name>
+    <note>
+        How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
+        containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
+
+        We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
+        indexed area where the robot traversal would create big server load). We have to make sure that we forbid
+        access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
+        This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
+        information.
+
+        RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
+        RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
+        RewriteRule ^/~quux/foo/arc/.+ - [F]
+    </note>
+    <condition name="user-agent">^NameOfBadRobot.*</condition>
+    <condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
+    <from>^/~quux/foo/arc/.+</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+
+<rule>
+    <name>Blocked Inline-Images</name>
+    <note>
+        Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
+        nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
+        it adds useless traffic to our server.
+
+        While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
+        sends a HTTP Referer header.
+
+        RewriteCond %{HTTP_REFERER} !^$
+        RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
+        RewriteRule .*\.gif$ - [F]
+    </note>
+    <condition name="referer" operator="notequal">^$</condition>
+    <condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
+    <from>.*\.gif$</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+<rule>
+    <name>Blocked Inline-Images example 2</name>
+    <note>
+        RewriteCond %{HTTP_REFERER} !^$
+        RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
+        RewriteRule ^inlined-in-foo\.gif$ - [F]
+    </note>
+    <condition name="referer" operator="notequal">^$</condition>
+    <condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
+    <from>^inlined-in-foo\.gif$</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+
+ + + +
+ + + + + + diff --git a/src/doc/manual/3.1/index.html b/src/doc/manual/3.1/index.html index 91b6dd73..7a424f8f 100644 --- a/src/doc/manual/3.1/index.html +++ b/src/doc/manual/3.1/index.html @@ -1,1315 +1,1315 @@ - - - - UrlRewriteFilter - Manual - - - - - - - - - -
- - - -

Manual

- - -

Community support is available at UrlRewrite on StackOverflow.

- -

Read examples of usage and a - sample of the ant task report. - If you have feedback, or conf you want to share with the world email me. - If you have any suggestions/examples for this manual please post them to the - group.

- - - -

Install

- -
    -
  1. Download the zip (or tar.gz) and extract it into your - context's directory ie, so that urlrewrite.xml goes into the WEB-INF directory.
  2. -
  3. Add the following to your WEB-INF/web.xml (add it near the top above your - servlet mappings (if you have any)): (see filter - parameters for more options) -
    
    -    <filter>
    -       <filter-name>UrlRewriteFilter</filter-name>
    -       <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    -    </filter>
    -    <filter-mapping>
    -       <filter-name>UrlRewriteFilter</filter-name>
    -       <url-pattern>/*</url-pattern>
    -    </filter-mapping>
    -        
  4. -
  5. Add your own configuration to the WEB-INF/urlrewrite.xml that was created.
  6. -
  7. Restart the context.
  8. -
- -

You can visit http://127.0.0.1:8080/rewrite-status - (or whatever the address of your local webapp and context) - to see output (note: this page is only viewable from localhost).

- - - -

Filter Parameters

- -

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

- -

-    <filter>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-        <!-- set the amount of seconds the conf file will be checked for reload
-        can be a valid integer (0 denotes check every time,
-        -1 denotes no reload check, default -1) -->
-        <init-param>
-            <param-name>confReloadCheckInterval</param-name>
-            <param-value>60</param-value>
-        </init-param>
-
-        <!-- if you need to the conf file path can be changed
-        it is specified as a path relative to the root of your context
-        (default /WEB-INF/urlrewrite.xml) -->
-        <init-param>
-            <param-name>confPath</param-name>
-            <param-value>/WEB-INF/urlrewrite.xml</param-value>
-        </init-param>
-
-        <!-- sets up log level (will be logged to context log)
-        can be: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL, log4j, commons,
-        sysout:{level} (ie, sysout:DEBUG)
-        if you are having trouble using normal levels use sysout:DEBUG
-        (default WARN) -->
-        <init-param>
-            <param-name>logLevel</param-name>
-            <param-value>DEBUG</param-value>
-        </init-param>
-
-        <!-- you can change status path so that it does not
-        conflict with your installed apps (note, defaults
-        to /rewrite-status) note, must start with / -->
-        <init-param>
-            <param-name>statusPath</param-name>
-            <param-value>/status</param-value>
-        </init-param>
-
-        <!-- you can disable status page if desired
-        can be: true, false (default true) -->
-        <init-param>
-            <param-name>statusEnabled</param-name>
-            <param-value>true</param-value>
-        </init-param>
-
-        <!-- you may want to allow more hosts to look at the status page
-        statusEnabledOnHosts is a comma delimited list of hosts, * can
-        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
-        <init-param>
-            <param-name>statusEnabledOnHosts</param-name>
-            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
-        </init-param>
-
-        <!-- you may want to allow more hosts to look at the status page
-        statusEnabledOnHosts is a comma delimited list of hosts, * can
-        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
-        <init-param>
-            <param-name>statusEnabledOnHosts</param-name>
-            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
-        </init-param>
-
-        <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
-        is not specified confPath will be set to /WEB-INF/.htaccess) -->
-        <init-param>
-            <param-name>modRewriteConf</param-name>
-            <param-value>false</param-value>
-        </init-param>
-
-        <!-- load mod_rewrite style configuration from this parameter's value.
-                note, Setting this parameter will mean that all other conf parameters are ignored.
-            <init-param>
-                <param-name>modRewriteConfText</param-name>
-                <param-value>
-                    RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
-                    RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
-                </param-value>
-            </init-param>
-        -->
-
-    </filter>
-
-    <filter-mapping>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <url-pattern>/*</url-pattern>
-    </filter-mapping>
-
- -

Note, setting logLevel to log4j or commons will cause the built in loging to - call either log4j or - commons-logging as if they were the logging framework, - obviously you will need to have the jar for log4j or commons-logging in your classpath.

- - - - -

Configuration File WEB-INF/urlrewrite.xml

- -

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named - urlrewrite.xml. - It may be helpful to read the UrlRewriteFilter DTD - (Document Type Definition). Please also make sure you look at the examples. A simple - configuration file looks like:

- -

-    <?xml version="1.0" encoding="utf-8"?>
-
-    <!DOCTYPE urlrewrite
-        PUBLIC "-//tuckey.org//DTD UrlRewrite 3.1//EN"
-        "http://www.tuckey.org/res/dtds/urlrewrite3.1.dtd">
-
-    <urlrewrite>
-
-        <rule>
-           <from>^/some/olddir/(.*)$</from>
-           <to type="redirect">/very/newdir/$1</to>
-        </rule>
-
-        <rule match-type="wildcard">
-           <from>/blog/archive/**</from>
-           <to type="redirect">/roller/history/$1</to>
-        </rule>
-
-    </urlrewrite>
-
- - -

The urlrewrite.xml file must have a root element called "urlrewrite" and must contain - at least one "rule" element.

- -

A "rule" must contain a "from" and a "to", and can have zero or more "condition" elements and zero or more and/or - "set" elements.

- -

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then - the "from" will be applied to the request URL and the final URL generated by applying the - "to" to the "from" pattern. So long as the rule has matched then the "set" will be run.

- - - -

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

- -

-     Pattern.compile(<from> element);
-     pattern.matcher(request url);
-     matcher.replaceAll(<to> element);
-     if ( <condition> elements match && matcher.find() ) {
-         handle <set> elements (if any)
-         execute <run> elements (if any)
-         perform <to> element (if any)
-     }
- 
- - -

<urlrewrite> element

- -

The top level element.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
default-match-type
(optional)
regex (default)All rules and thier conditions will be processed using the Java Regular Expression engine (unless - match-type is specified on a rule).
wildcardAll rules and thier conditions will be processed using the Wildcard Expression - engine - (unless match-type is specified on a rule).
decode-using
(optional)
utf8 (default)When URL is decoded UTF-8 will be used.
nullDo not decode.
[encoding]Any string representing a supported character encoding eg, ISO-8859-1. - See Java Charset Object - for more info. -
use-query-string
(optional)
false (default)The query string will not be appended to the url that the "from" element matches against.
trueThe query string will be appended to the url that the "from" element matches against.
use-context
(optional)
false (default)The context path will not be added to the url that the "from" element matches against.
trueThe context path will be added to the url that the "from" element matches against.
- - -

<rule> element

- -

Zero or more. The basis of a rule.

- - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
match-type
(optional)
regex (default)This rule and it's conditions will be processed using the Java Regular Expression engine.
wildcardThis rule and it's conditions will be processed using the Wildcard Expression engine. -
- -

In the following example requests for /world/usa/nyc will be transparently forwarded to - /world.jsp

- -

-    <rule match-type="regex">
-       <from>^/world/([a-z]+)/([a-z]+)$</from>
-       <to>/world.jsp</to>
-    </rule>
-
- -

-    <rule match-type="wildcard">
-       <from>/world/*/*</from>
-       <to>/world.jsp</to>
-    </rule>
-
- - -

<outbound-rule> element

- -

Zero or more. This is very similar to a normal rule but it is used for rewriting urls that go through - response.encodeURL().

- - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
false (default)Run encodeURL() after running this outbound rule.
trueRun encodeURL() before running this outbound rule.
- -

May contain "run", "from", "to" and "set" element(s) also. Example:

- -

-    <outbound-rule>
-        <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
-        <to>/world/$1/$2</to>
-    </outbound-rule>
-
- -

Using the example above JSP's with the code -
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") - %>">nyc</a> -
will output -
<a href="/world/usa/nyc">nyc</a> -

- -

Or JSTL -
<a href="<c:url value="/world.jsp?country=${country}&amp;city=${city}" - />">nyc</a> -
will output -
<a href="/world/usa/nyc">nyc</a> -

- -

Note, If you are using JSTL (ie, <c:url) this will work also.

- -

<name> element

- -

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. - See ant task.

- -

-    <rule>
-        <name>World Rule</name>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- - -

<note> element

- -

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. - See ant task.

- -

-    <rule>
-        <name>World Rule</name>
-        <note>
-            Cleanly redirect world requests to JSP,
-            a country and city must be specified.
-            </note>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp</to>
-    </rule>
-
- - - -

<condition> element

- -

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run - (unless "next" is set to "or" obvoiusly).

- -

Value can be any Regular Expression.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD etc.
portThe port that the web application server is running on.
time - Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC otherwise known as unix - time). -
i.e. (new Date()).getTime() -
This can be used for making sure content goes live only at a time you set. -
year - Current year at the server. -
i.e. (Calendar.getInstance()).get(Calendar.YEAR) -
month - Month at the server. January is 0 -
i.e. (Calendar.getInstance()).get(Calendar.MONTH) -
dayofmonth - Day of the month at the server. March first is 1 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) -
dayofweek - Day of the week at the server. Saturday is 1, Sunday is 7 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) -
ampm - AM or PM time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) -
hourofday - The hour of the day (24 hour clock) at the server. 10pm is 22 -
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) -
minute - The minute field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) -
second - The second field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.SECOND) -
millisecond - The millisecond field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) -
attribute - Will check the value of a request attribute (don't confuse this with parameter!), name must be set when - using this type. -
i.e. request.getAttribute([name]) - -
auth-type - Will check the value of a request attribute (don't confuse this with parameter!) -
i.e. request.getAuthType() - -
character-encoding - The character encoding of the imcoming request. -
i.e. request.getCharacterEncoding() - -
content-length - The length of the imcoming request (can be useful if you want to deny large requests). -
i.e. request.getContentLength() - -
content-type - The type of the imcoming request. (this is probably not that useful) -
i.e. request.getContentType() - -
context-path - The context path of the imcoming request. -
i.e. request.getContextPath() - -
cookie - The value of a cookie, note, name must be specified to use this -
i.e. request.getCookies() - the find we the one with [name] specified and check the value. -
parameter - A tidier way of checking request parameters than looking for them in the query string. This will check for the - parameter in GET or POST, note, name must be specified. -
i.e. request.getParameter([name]) - -
path-info - i.e. request.getPathInfo() - -
path-translated - i.e. request.getPathTranslated() - -
protocolThe protocol used to make the request, e.g. HTTP/1.1 -
i.e. request.getProtocol() - -
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob -
i.e. request.getQueryString() - -
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 -
i.e. request.getRemoteAddr() - -
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, - this will only work if your app server is configured to lookup host names, most aren't). -
i.e. request.getRemoteHost() - -
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt -
i.e. request.getRemoteUser() - -
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 -
i.e. request.getRequestedSessionId() - -
request-uriReturns the part of this request's URL from the protocol name up to the query - string in the first line of the HTTP request -
i.e. request.getRequestURI() - -
request-urlReconstructs the URL the client used to make the request. The returned URL - contains a protocol, server name, port number, and server path, but it does not include query string parameters. -
i.e. request.getRequestURL() - -
session-attribute - (note, name must be set) -
i.e. session.getAttribute([name]) - -
session-isnew - Weather the session is new or not. -
i.e. session.isNew() - -
server-name - The host name of the server to which the request was sent (from the host header not the machine name). -
i.e. request.getServerName() - -
scheme - The scheme used for the request, e.g. http or https -
i.e. request.getScheme() - -
user-in-role - (Note, the value for this cannot be a regular expression) -
i.e. request.isUserInRole([value]) - -
name
(optional)
(can be anything)If type is header, this specifies the name of the HTTP header used to run the value - against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator to be used when the condition is run, the regular expression matches or the values are - equal.
notequalNot equal to. (i.e. request value != condition value). Note, this operator only work with - numeric rule types.
greaterGreater than. (i.e. request value > condition value). Note, this operator only work with - numeric - rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only work with numeric - rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator - only - work with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only - work with numeric rule types.
- -

Examples:

- -

-    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-
-    <condition type="user-in-role" operator="notequal">bigboss</condition>
-
-    <condition name="host" operator="notequal">www.example.com</condition>
-
-    <condition type="method" next="or">PROPFIND</condition>
-    <condition type="method">PUT</condition>
-
- - -

<from> element

- -

You must always have exactly one from for each rule or outbound-rule. Value can be a regular expression in the - Perl5 style. Note, from url's are relative to the context.

- - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using case insentitive match. ie, "/WellingtoN" will match "/wellington". -
trueThis value will be matched using case sentitive match. ie, "/aAa" will NOT match "/aaa". -
- -

Example:

- -

-    <from>^/world/([a-z]+)$</from>
-
- - -

<to> element

- -

Value can be a regular replacement expression in the Perl5 style.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally - forwarded - to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as - UrlRewriteFilter. This is the same as doing: -
RequestDispatcher rq = request.getRequestDispatcher([to value]); -
rq.forward(request, response);
-
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. - This is the same a doing: -
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_PERMANENTLY is HTTP status code 301)
temporary-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
pre-include
post-include
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) - will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) - will NOT be called.
- -

Note, "to" can be null ie, <to>null</to>, this will mean that the request will go no - further if the rule is matched (ie, this filter will not call chain.doFilter).

- -

-    <to>/world.jsp?country=$1</to>
-
- -

To elements can contain backreferences and variables.

- - -

Backreferences

- -

-    %N
-
- -

Provides access to the grouped parts (parentheses) of the pattern from the last matched Condition - in the current rule. - N must be less than 10 and greater than 0 (i.e. %1, %2, %3 etc).

- - -

Variables

- -

-    %{VARIABLE-NAME}
-
- -

Any valid condition type can be used as a variable name. ie, - '%{port}' will be translated to '80', - '%{year}' to '2005', - '%{cookie:myCookie}' would be translated to - 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

- -

Valid types are condition types, see condition for a full description.

- - -

Functions

- -

-    ${FUNCTION:PARAMS}
-
- -

Functions can be places in set and to elements.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nameexampleexample returns
replace${replace:my cat is a blue cat:cat:dog}my dog is a blue dog
replaceFirst${replace:my cat is a blue cat:cat:dog}my cat is a blue dog
escape${escape:a b c}a+b+c
unescape${unescape:a+b+c}a b c
lower${lower:Hello World}hello world
upper${upper:hello}HELLO
trim${trim: abc def }abc def
- - -

<set> element

- -

Allows you to set varous things if the rule is matched.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], - [value]) - (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], - [value]) - (note, name must be set).
response-headerThe same as response.setHeader([name], - [value]) - (note, name must be set).
cookie - Value can be in the format "[value][:domain[:lifetime[:path]]]". - This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain - field is the domain of the cookie, such as '.apache.org',the optional lifetime is the lifetime of the cookie - in seconds, and the optional path is the path of the cookie (note, name must be set). -
statusThe same as response.setStatus([value]) -
content-typeThe same as response.setContentType([value]) -
charsetThe same as response.setCharacterEncoding([value]) -
expiresWill set the Expires HTTP header by adding the time specified and current time - (this is mod_expires style). Syntax "{num type}*". - Units can be (singular or plural); - years, months, weeks, days, hours, minutes, seconds. -
eg, "1 day 2 seconds", "3 hours", "1 year 1 hour" -
localeThe same as response.setLocale([value]) - - specify the Locale in the format - (valid - locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). -
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
- -

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be - fetched in a servlet or - JSP using request.getAttribute("client").

- -

-    <rule>
-        <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
-        <from>.*</from>
-        <set name="client">AvantGo</set>
-    </rule>
-    <rule>
-        <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
-        <from>.*</from>
-        <set name="client">Samsung SCH-6100</set>
-    </rule>
-
- -

It is also possible to use regular replacement expressions as part of the - value similar to their usage in <to> elements:

- -

-    <rule>
-        <from>/products/(.*)/(.*)/index.html</from>
-        <set name="urlrewrite.product.slug">$1</set>
-        <set name="urlrewrite.product.id">$2</set>
-        <to>/products?slug=$1&id=$2</to>
-    </rule>
-
- -

<run> element

- -

Allows you to run a method on an object when a rule and it's conditions are matched.

- - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible valueExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional)run (default)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) - e.g. run(HttpServletRequest request, HttpServletResponse response) -
Note, if init(ServletConfig) or destroy() is found they will be run at when - creating - or destroying an instance. -
neweachtime (optional)false (default)One instance for each UrlRewriteFilter instance.
trueA new instance of the class will be created before running each time set to true.
- -

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, - HttpServletResponse) - will be invoked, the request will then be forwarded to /world-presentation.jsp.

- -

-    <rule>
-        <from>^/world/[a-z]+/[a-z]+$</from>
-        <run class="com.blah.web.WorldServlet" method="doGet" />
-        <to>/world-presentation.jsp</to>
-    </rule>
-
- -

Note, you can specify init-param's the same way you would for a servlet.

- -

-    <run class="com.blah.web.MyServlet" method="doGet">
-        <init-param>
-            <param-name>someParamName</param-name>
-            <param-value>10</param-value>
-        </init-param>
-    </run>
-
- -

If the method being called throws an Exception the original exception will be re-thrown as if it were the original - if it extends RuntimeException (eg, NullPointer), other exceptions are wrapped in a ServletException and thrown - so your container can handle them.

- - -

<class-rule> element

- -

Allows you to run a method every time a request come in for 100% dynamic rules. See the org.tuckey.web.filters.urlrewrite.sample package for an example.

- - - - - - - - - - - - - - - - - - -
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default matches)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) - e.g. run(HttpServletRequest request, HttpServletResponse response) -
Note, if init(ServletConfig) or destroy() is found they will be run at when - creating or destroying an instance. -
last (optional, default trueIf false more rules will be processed following this rule even if it is matched (so that a better match may be found).
- -

Example:

- -

-    <class-rule class="com.blah.web.MyRuleClass" />
-
- - - - -

Tips

- -
    -
  • When you want to put an "&" in a rule you must enter it as the XML entity "&amp;"
  • -
  • For simplicity you might want to start all from's with a ^ and end them with a $. -
    In regular expressions ^ specifies the start of - the string and $ specifies the end. -
    ie, a request for /my/url/path will NOT match - <from>^/url/$</from> but it will match <from>/url/</from> -
    -
  • If using <outbound-rule> remember all urls in your code must be encoded e.g. - <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • -
  • Regular expressions are complex and a bit tricky at times, read - regular expression syntax for - Java. -
  • -
  • If you find regular expressions difficult use Wildcards.
  • -
  • "Context" is important. If you have an app with the context "/myapp" and you request the url - "/myapp/somefolder/somepage.jsp", the container tells UrlRewriteFilter that the url is "/somefolder/somepage.jsp". - This can be confusing, but basically your rules and conditions should not contain the context path - (it will be handled by the container).
  • -
- - - - - - -

Wildcard Matching Engine

- -

The wildcard matching engine can be used instead of regex. It is supported in conditions and rules - where match-type is set to wildcard (or default-match-type is set on the - urlrewrite element

- -

e.g. /big/url/* will match /big/url/abc.html but will NOT - match /big/url/abc/dir/ or /big/url/abc/. - -

/big/url/** will match /big/url/abc.html, /big/url/abc/dir/ and - /big/url/abc/. - -

You can also use Regular expression style variable replacement, each match of a * will - be available for use in to and set elements using simple $1 - $2 variables.

- -

e.g. /my/big/url/* will match /my/big/url/abc.html and $1 - will be set to abc.html.

- -

Added in 3.0

- - - - -

Ant Task

- -

An Ant task has been written to allow validate the conf file and generation - of documentation. You can view a sample.

- -

Paste the following into your build.xml file, then change the dest - and conf to point to the correct places. Note, the urlrewrite jar - file will need to be in your classpath.

- -

-    <target name="urlrewrite-doc" depends="compile"
-        description="UrlRewriteFilter validation and documenting">
-
-    <taskdef
-        name="urlrewritedoc"
-        classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
-    <urlrewritedoc
-        conf="${build.home}/WEB-INF/urlrewrite.xml"
-        dest="urlrewrite-conf-overview.html" />
-    </target>
-
- - - - -

mod_rewrite Style Configuration

- -

Support for mod_rewrite is considered beta quality. Set modRewriteConf to true in filter parameters and -add a WEB-INF/.htaccess file with your mod_rewrite style configuration in it.

- -

Sample web.xml snippet (see also modRewriteConf and modRewriteConfText in Filter Parameters):

-

-    <filter>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-        <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
-        is not specified confPath will be set to /WEB-INF/.htaccess) -->
-        <init-param>
-            <param-name>modRewriteConf</param-name>
-            <param-value>true</param-value>
-        </init-param>
-
-    </filter>
-
-    <filter-mapping>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <url-pattern>/*</url-pattern>
-    </filter-mapping>
-
- -

Sample: WEB-INF/.htaccess

-

-     # redirect mozilla to another area
-     RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
-     RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
- 
- -

- - Documentation for the original mod_rewrite library - mostly applies, differences are documented below.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributeExplanation
RewriteLogLevelSpecified as int, trasnlated as: <= 1 - FATAL, 2 - ERROR, 3 - INFO, 4 - WARN, >= 5 DEBUG
RewriteLogSYSOUT, SYSERR, log4j, commons (if not set context logging will be used)
RewriteRuleCertain flags not supported: -
    -
  • chain flag [C] not supported
  • -
  • env flag [E] not supported
  • -
  • next flag [N] not supported
  • -
  • nosubreq flag [NS] not supported
  • -
  • Proxy flag [P] not supported
  • -
  • qsappend flag [QSA] not supported
  • -
  • Skip flag [S] not supported
  • -
-
RewriteBaseNot supported
RewriteLockNot supported
RewriteMapNot supported
RewriteOptionsNot supported
- - -
- - - - - - + + + + UrlRewriteFilter - Manual + + + + + + + + + +
+ + + +

Manual

+ + +

Community support is available at UrlRewrite on StackOverflow.

+ +

Read examples of usage and a + sample of the ant task report. + If you have feedback, or conf you want to share with the world email me. + If you have any suggestions/examples for this manual please post them to the + group.

+ + + +

Install

+ +
    +
  1. Download the zip (or tar.gz) and extract it into your + context's directory ie, so that urlrewrite.xml goes into the WEB-INF directory.
  2. +
  3. Add the following to your WEB-INF/web.xml (add it near the top above your + servlet mappings (if you have any)): (see filter + parameters for more options) +
    
    +    <filter>
    +       <filter-name>UrlRewriteFilter</filter-name>
    +       <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    +    </filter>
    +    <filter-mapping>
    +       <filter-name>UrlRewriteFilter</filter-name>
    +       <url-pattern>/*</url-pattern>
    +    </filter-mapping>
    +        
  4. +
  5. Add your own configuration to the WEB-INF/urlrewrite.xml that was created.
  6. +
  7. Restart the context.
  8. +
+ +

You can visit http://127.0.0.1:8080/rewrite-status + (or whatever the address of your local webapp and context) + to see output (note: this page is only viewable from localhost).

+ + + +

Filter Parameters

+ +

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

+ +

+    <filter>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+        <!-- set the amount of seconds the conf file will be checked for reload
+        can be a valid integer (0 denotes check every time,
+        -1 denotes no reload check, default -1) -->
+        <init-param>
+            <param-name>confReloadCheckInterval</param-name>
+            <param-value>60</param-value>
+        </init-param>
+
+        <!-- if you need to the conf file path can be changed
+        it is specified as a path relative to the root of your context
+        (default /WEB-INF/urlrewrite.xml) -->
+        <init-param>
+            <param-name>confPath</param-name>
+            <param-value>/WEB-INF/urlrewrite.xml</param-value>
+        </init-param>
+
+        <!-- sets up log level (will be logged to context log)
+        can be: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL, log4j, commons,
+        sysout:{level} (ie, sysout:DEBUG)
+        if you are having trouble using normal levels use sysout:DEBUG
+        (default WARN) -->
+        <init-param>
+            <param-name>logLevel</param-name>
+            <param-value>DEBUG</param-value>
+        </init-param>
+
+        <!-- you can change status path so that it does not
+        conflict with your installed apps (note, defaults
+        to /rewrite-status) note, must start with / -->
+        <init-param>
+            <param-name>statusPath</param-name>
+            <param-value>/status</param-value>
+        </init-param>
+
+        <!-- you can disable status page if desired
+        can be: true, false (default true) -->
+        <init-param>
+            <param-name>statusEnabled</param-name>
+            <param-value>true</param-value>
+        </init-param>
+
+        <!-- you may want to allow more hosts to look at the status page
+        statusEnabledOnHosts is a comma delimited list of hosts, * can
+        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
+        <init-param>
+            <param-name>statusEnabledOnHosts</param-name>
+            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
+        </init-param>
+
+        <!-- you may want to allow more hosts to look at the status page
+        statusEnabledOnHosts is a comma delimited list of hosts, * can
+        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
+        <init-param>
+            <param-name>statusEnabledOnHosts</param-name>
+            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
+        </init-param>
+
+        <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
+        is not specified confPath will be set to /WEB-INF/.htaccess) -->
+        <init-param>
+            <param-name>modRewriteConf</param-name>
+            <param-value>false</param-value>
+        </init-param>
+
+        <!-- load mod_rewrite style configuration from this parameter's value.
+                note, Setting this parameter will mean that all other conf parameters are ignored.
+            <init-param>
+                <param-name>modRewriteConfText</param-name>
+                <param-value>
+                    RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
+                    RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
+                </param-value>
+            </init-param>
+        -->
+
+    </filter>
+
+    <filter-mapping>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+ +

Note, setting logLevel to log4j or commons will cause the built in loging to + call either log4j or + commons-logging as if they were the logging framework, + obviously you will need to have the jar for log4j or commons-logging in your classpath.

+ + + + +

Configuration File WEB-INF/urlrewrite.xml

+ +

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named + urlrewrite.xml. + It may be helpful to read the UrlRewriteFilter DTD + (Document Type Definition). Please also make sure you look at the examples. A simple + configuration file looks like:

+ +

+    <?xml version="1.0" encoding="utf-8"?>
+
+    <!DOCTYPE urlrewrite
+        PUBLIC "-//tuckey.org//DTD UrlRewrite 3.1//EN"
+        "http://www.tuckey.org/res/dtds/urlrewrite3.1.dtd">
+
+    <urlrewrite>
+
+        <rule>
+           <from>^/some/olddir/(.*)$</from>
+           <to type="redirect">/very/newdir/$1</to>
+        </rule>
+
+        <rule match-type="wildcard">
+           <from>/blog/archive/**</from>
+           <to type="redirect">/roller/history/$1</to>
+        </rule>
+
+    </urlrewrite>
+
+ + +

The urlrewrite.xml file must have a root element called "urlrewrite" and must contain + at least one "rule" element.

+ +

A "rule" must contain a "from" and a "to", and can have zero or more "condition" elements and zero or more and/or + "set" elements.

+ +

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then + the "from" will be applied to the request URL and the final URL generated by applying the + "to" to the "from" pattern. So long as the rule has matched then the "set" will be run.

+ + + +

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

+ +

+     Pattern.compile(<from> element);
+     pattern.matcher(request url);
+     matcher.replaceAll(<to> element);
+     if ( <condition> elements match && matcher.find() ) {
+         handle <set> elements (if any)
+         execute <run> elements (if any)
+         perform <to> element (if any)
+     }
+ 
+ + +

<urlrewrite> element

+ +

The top level element.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
default-match-type
(optional)
regex (default)All rules and thier conditions will be processed using the Java Regular Expression engine (unless + match-type is specified on a rule).
wildcardAll rules and thier conditions will be processed using the Wildcard Expression + engine + (unless match-type is specified on a rule).
decode-using
(optional)
utf8 (default)When URL is decoded UTF-8 will be used.
nullDo not decode.
[encoding]Any string representing a supported character encoding eg, ISO-8859-1. + See Java Charset Object + for more info. +
use-query-string
(optional)
false (default)The query string will not be appended to the url that the "from" element matches against.
trueThe query string will be appended to the url that the "from" element matches against.
use-context
(optional)
false (default)The context path will not be added to the url that the "from" element matches against.
trueThe context path will be added to the url that the "from" element matches against.
+ + +

<rule> element

+ +

Zero or more. The basis of a rule.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
match-type
(optional)
regex (default)This rule and it's conditions will be processed using the Java Regular Expression engine.
wildcardThis rule and it's conditions will be processed using the Wildcard Expression engine. +
+ +

In the following example requests for /world/usa/nyc will be transparently forwarded to + /world.jsp

+ +

+    <rule match-type="regex">
+       <from>^/world/([a-z]+)/([a-z]+)$</from>
+       <to>/world.jsp</to>
+    </rule>
+
+ +

+    <rule match-type="wildcard">
+       <from>/world/*/*</from>
+       <to>/world.jsp</to>
+    </rule>
+
+ + +

<outbound-rule> element

+ +

Zero or more. This is very similar to a normal rule but it is used for rewriting urls that go through + response.encodeURL().

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
false (default)Run encodeURL() after running this outbound rule.
trueRun encodeURL() before running this outbound rule.
+ +

May contain "run", "from", "to" and "set" element(s) also. Example:

+ +

+    <outbound-rule>
+        <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
+        <to>/world/$1/$2</to>
+    </outbound-rule>
+
+ +

Using the example above JSP's with the code +
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") + %>">nyc</a> +
will output +
<a href="/world/usa/nyc">nyc</a> +

+ +

Or JSTL +
<a href="<c:url value="/world.jsp?country=${country}&amp;city=${city}" + />">nyc</a> +
will output +
<a href="/world/usa/nyc">nyc</a> +

+ +

Note, If you are using JSTL (ie, <c:url) this will work also.

+ +

<name> element

+ +

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +

+    <rule>
+        <name>World Rule</name>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ + +

<note> element

+ +

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +

+    <rule>
+        <name>World Rule</name>
+        <note>
+            Cleanly redirect world requests to JSP,
+            a country and city must be specified.
+            </note>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp</to>
+    </rule>
+
+ + + +

<condition> element

+ +

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run + (unless "next" is set to "or" obvoiusly).

+ +

Value can be any Regular Expression.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD etc.
portThe port that the web application server is running on.
time + Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC otherwise known as unix + time). +
i.e. (new Date()).getTime() +
This can be used for making sure content goes live only at a time you set. +
year + Current year at the server. +
i.e. (Calendar.getInstance()).get(Calendar.YEAR) +
month + Month at the server. January is 0 +
i.e. (Calendar.getInstance()).get(Calendar.MONTH) +
dayofmonth + Day of the month at the server. March first is 1 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) +
dayofweek + Day of the week at the server. Saturday is 1, Sunday is 7 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) +
ampm + AM or PM time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) +
hourofday + The hour of the day (24 hour clock) at the server. 10pm is 22 +
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) +
minute + The minute field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) +
second + The second field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.SECOND) +
millisecond + The millisecond field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) +
attribute + Will check the value of a request attribute (don't confuse this with parameter!), name must be set when + using this type. +
i.e. request.getAttribute([name]) + +
auth-type + Will check the value of a request attribute (don't confuse this with parameter!) +
i.e. request.getAuthType() + +
character-encoding + The character encoding of the imcoming request. +
i.e. request.getCharacterEncoding() + +
content-length + The length of the imcoming request (can be useful if you want to deny large requests). +
i.e. request.getContentLength() + +
content-type + The type of the imcoming request. (this is probably not that useful) +
i.e. request.getContentType() + +
context-path + The context path of the imcoming request. +
i.e. request.getContextPath() + +
cookie + The value of a cookie, note, name must be specified to use this +
i.e. request.getCookies() + the find we the one with [name] specified and check the value. +
parameter + A tidier way of checking request parameters than looking for them in the query string. This will check for the + parameter in GET or POST, note, name must be specified. +
i.e. request.getParameter([name]) + +
path-info + i.e. request.getPathInfo() + +
path-translated + i.e. request.getPathTranslated() + +
protocolThe protocol used to make the request, e.g. HTTP/1.1 +
i.e. request.getProtocol() + +
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob +
i.e. request.getQueryString() + +
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 +
i.e. request.getRemoteAddr() + +
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, + this will only work if your app server is configured to lookup host names, most aren't). +
i.e. request.getRemoteHost() + +
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt +
i.e. request.getRemoteUser() + +
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 +
i.e. request.getRequestedSessionId() + +
request-uriReturns the part of this request's URL from the protocol name up to the query + string in the first line of the HTTP request +
i.e. request.getRequestURI() + +
request-urlReconstructs the URL the client used to make the request. The returned URL + contains a protocol, server name, port number, and server path, but it does not include query string parameters. +
i.e. request.getRequestURL() + +
session-attribute + (note, name must be set) +
i.e. session.getAttribute([name]) + +
session-isnew + Weather the session is new or not. +
i.e. session.isNew() + +
server-name + The host name of the server to which the request was sent (from the host header not the machine name). +
i.e. request.getServerName() + +
scheme + The scheme used for the request, e.g. http or https +
i.e. request.getScheme() + +
user-in-role + (Note, the value for this cannot be a regular expression) +
i.e. request.isUserInRole([value]) + +
name
(optional)
(can be anything)If type is header, this specifies the name of the HTTP header used to run the value + against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator to be used when the condition is run, the regular expression matches or the values are + equal.
notequalNot equal to. (i.e. request value != condition value). Note, this operator only work with + numeric rule types.
greaterGreater than. (i.e. request value > condition value). Note, this operator only work with + numeric + rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only work with numeric + rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator + only + work with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only + work with numeric rule types.
+ +

Examples:

+ +

+    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+
+    <condition type="user-in-role" operator="notequal">bigboss</condition>
+
+    <condition name="host" operator="notequal">www.example.com</condition>
+
+    <condition type="method" next="or">PROPFIND</condition>
+    <condition type="method">PUT</condition>
+
+ + +

<from> element

+ +

You must always have exactly one from for each rule or outbound-rule. Value can be a regular expression in the + Perl5 style. Note, from url's are relative to the context.

+ + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using case insentitive match. ie, "/WellingtoN" will match "/wellington". +
trueThis value will be matched using case sentitive match. ie, "/aAa" will NOT match "/aaa". +
+ +

Example:

+ +

+    <from>^/world/([a-z]+)$</from>
+
+ + +

<to> element

+ +

Value can be a regular replacement expression in the Perl5 style.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally + forwarded + to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as + UrlRewriteFilter. This is the same as doing: +
RequestDispatcher rq = request.getRequestDispatcher([to value]); +
rq.forward(request, response);
+
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. + This is the same a doing: +
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_PERMANENTLY is HTTP status code 301)
temporary-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
pre-include
post-include
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) + will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) + will NOT be called.
+ +

Note, "to" can be null ie, <to>null</to>, this will mean that the request will go no + further if the rule is matched (ie, this filter will not call chain.doFilter).

+ +

+    <to>/world.jsp?country=$1</to>
+
+ +

To elements can contain backreferences and variables.

+ + +

Backreferences

+ +

+    %N
+
+ +

Provides access to the grouped parts (parentheses) of the pattern from the last matched Condition + in the current rule. + N must be less than 10 and greater than 0 (i.e. %1, %2, %3 etc).

+ + +

Variables

+ +

+    %{VARIABLE-NAME}
+
+ +

Any valid condition type can be used as a variable name. ie, + '%{port}' will be translated to '80', + '%{year}' to '2005', + '%{cookie:myCookie}' would be translated to + 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

+ +

Valid types are condition types, see condition for a full description.

+ + +

Functions

+ +

+    ${FUNCTION:PARAMS}
+
+ +

Functions can be places in set and to elements.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
nameexampleexample returns
replace${replace:my cat is a blue cat:cat:dog}my dog is a blue dog
replaceFirst${replace:my cat is a blue cat:cat:dog}my cat is a blue dog
escape${escape:a b c}a+b+c
unescape${unescape:a+b+c}a b c
lower${lower:Hello World}hello world
upper${upper:hello}HELLO
trim${trim: abc def }abc def
+ + +

<set> element

+ +

Allows you to set varous things if the rule is matched.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], + [value]) + (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], + [value]) + (note, name must be set).
response-headerThe same as response.setHeader([name], + [value]) + (note, name must be set).
cookie + Value can be in the format "[value][:domain[:lifetime[:path]]]". + This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain + field is the domain of the cookie, such as '.apache.org',the optional lifetime is the lifetime of the cookie + in seconds, and the optional path is the path of the cookie (note, name must be set). +
statusThe same as response.setStatus([value]) +
content-typeThe same as response.setContentType([value]) +
charsetThe same as response.setCharacterEncoding([value]) +
expiresWill set the Expires HTTP header by adding the time specified and current time + (this is mod_expires style). Syntax "{num type}*". + Units can be (singular or plural); + years, months, weeks, days, hours, minutes, seconds. +
eg, "1 day 2 seconds", "3 hours", "1 year 1 hour" +
localeThe same as response.setLocale([value]) + + specify the Locale in the format + (valid + locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). +
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
+ +

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be + fetched in a servlet or + JSP using request.getAttribute("client").

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
+        <from>.*</from>
+        <set name="client">AvantGo</set>
+    </rule>
+    <rule>
+        <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
+        <from>.*</from>
+        <set name="client">Samsung SCH-6100</set>
+    </rule>
+
+ +

It is also possible to use regular replacement expressions as part of the + value similar to their usage in <to> elements:

+ +

+    <rule>
+        <from>/products/(.*)/(.*)/index.html</from>
+        <set name="urlrewrite.product.slug">$1</set>
+        <set name="urlrewrite.product.id">$2</set>
+        <to>/products?slug=$1&id=$2</to>
+    </rule>
+
+ +

<run> element

+ +

Allows you to run a method on an object when a rule and it's conditions are matched.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible valueExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional)run (default)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) + e.g. run(HttpServletRequest request, HttpServletResponse response) +
Note, if init(ServletConfig) or destroy() is found they will be run at when + creating + or destroying an instance. +
neweachtime (optional)false (default)One instance for each UrlRewriteFilter instance.
trueA new instance of the class will be created before running each time set to true.
+ +

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, + HttpServletResponse) + will be invoked, the request will then be forwarded to /world-presentation.jsp.

+ +

+    <rule>
+        <from>^/world/[a-z]+/[a-z]+$</from>
+        <run class="com.blah.web.WorldServlet" method="doGet" />
+        <to>/world-presentation.jsp</to>
+    </rule>
+
+ +

Note, you can specify init-param's the same way you would for a servlet.

+ +

+    <run class="com.blah.web.MyServlet" method="doGet">
+        <init-param>
+            <param-name>someParamName</param-name>
+            <param-value>10</param-value>
+        </init-param>
+    </run>
+
+ +

If the method being called throws an Exception the original exception will be re-thrown as if it were the original + if it extends RuntimeException (eg, NullPointer), other exceptions are wrapped in a ServletException and thrown + so your container can handle them.

+ + +

<class-rule> element

+ +

Allows you to run a method every time a request come in for 100% dynamic rules. See the org.tuckey.web.filters.urlrewrite.sample package for an example.

+ + + + + + + + + + + + + + + + + + +
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default matches)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) + e.g. run(HttpServletRequest request, HttpServletResponse response) +
Note, if init(ServletConfig) or destroy() is found they will be run at when + creating or destroying an instance. +
last (optional, default trueIf false more rules will be processed following this rule even if it is matched (so that a better match may be found).
+ +

Example:

+ +

+    <class-rule class="com.blah.web.MyRuleClass" />
+
+ + + + +

Tips

+ +
    +
  • When you want to put an "&" in a rule you must enter it as the XML entity "&amp;"
  • +
  • For simplicity you might want to start all from's with a ^ and end them with a $. +
    In regular expressions ^ specifies the start of + the string and $ specifies the end. +
    ie, a request for /my/url/path will NOT match + <from>^/url/$</from> but it will match <from>/url/</from> +
    +
  • If using <outbound-rule> remember all urls in your code must be encoded e.g. + <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • +
  • Regular expressions are complex and a bit tricky at times, read + regular expression syntax for + Java. +
  • +
  • If you find regular expressions difficult use Wildcards.
  • +
  • "Context" is important. If you have an app with the context "/myapp" and you request the url + "/myapp/somefolder/somepage.jsp", the container tells UrlRewriteFilter that the url is "/somefolder/somepage.jsp". + This can be confusing, but basically your rules and conditions should not contain the context path + (it will be handled by the container).
  • +
+ + + + + + +

Wildcard Matching Engine

+ +

The wildcard matching engine can be used instead of regex. It is supported in conditions and rules + where match-type is set to wildcard (or default-match-type is set on the + urlrewrite element

+ +

e.g. /big/url/* will match /big/url/abc.html but will NOT + match /big/url/abc/dir/ or /big/url/abc/. + +

/big/url/** will match /big/url/abc.html, /big/url/abc/dir/ and + /big/url/abc/. + +

You can also use Regular expression style variable replacement, each match of a * will + be available for use in to and set elements using simple $1 + $2 variables.

+ +

e.g. /my/big/url/* will match /my/big/url/abc.html and $1 + will be set to abc.html.

+ +

Added in 3.0

+ + + + +

Ant Task

+ +

An Ant task has been written to allow validate the conf file and generation + of documentation. You can view a sample.

+ +

Paste the following into your build.xml file, then change the dest + and conf to point to the correct places. Note, the urlrewrite jar + file will need to be in your classpath.

+ +

+    <target name="urlrewrite-doc" depends="compile"
+        description="UrlRewriteFilter validation and documenting">
+
+    <taskdef
+        name="urlrewritedoc"
+        classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
+    <urlrewritedoc
+        conf="${build.home}/WEB-INF/urlrewrite.xml"
+        dest="urlrewrite-conf-overview.html" />
+    </target>
+
+ + + + +

mod_rewrite Style Configuration

+ +

Support for mod_rewrite is considered beta quality. Set modRewriteConf to true in filter parameters and +add a WEB-INF/.htaccess file with your mod_rewrite style configuration in it.

+ +

Sample web.xml snippet (see also modRewriteConf and modRewriteConfText in Filter Parameters):

+

+    <filter>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+        <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
+        is not specified confPath will be set to /WEB-INF/.htaccess) -->
+        <init-param>
+            <param-name>modRewriteConf</param-name>
+            <param-value>true</param-value>
+        </init-param>
+
+    </filter>
+
+    <filter-mapping>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+    </filter-mapping>
+
+ +

Sample: WEB-INF/.htaccess

+

+     # redirect mozilla to another area
+     RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
+     RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
+ 
+ +

+ + Documentation for the original mod_rewrite library + mostly applies, differences are documented below.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeExplanation
RewriteLogLevelSpecified as int, trasnlated as: <= 1 - FATAL, 2 - ERROR, 3 - INFO, 4 - WARN, >= 5 DEBUG
RewriteLogSYSOUT, SYSERR, log4j, commons (if not set context logging will be used)
RewriteRuleCertain flags not supported: +
    +
  • chain flag [C] not supported
  • +
  • env flag [E] not supported
  • +
  • next flag [N] not supported
  • +
  • nosubreq flag [NS] not supported
  • +
  • Proxy flag [P] not supported
  • +
  • qsappend flag [QSA] not supported
  • +
  • Skip flag [S] not supported
  • +
+
RewriteBaseNot supported
RewriteLockNot supported
RewriteMapNot supported
RewriteOptionsNot supported
+ + +
+ + + + + + diff --git a/src/doc/manual/3.1/introduction.html b/src/doc/manual/3.1/introduction.html index 23404c72..2b1e7fa1 100644 --- a/src/doc/manual/3.1/introduction.html +++ b/src/doc/manual/3.1/introduction.html @@ -1,275 +1,275 @@ - - - - UrlRewriteFilter - Background - - - - - - - - - -
- - - -

Background

- - - -

A clean URL scheme is very important detail for any quality Web Application. UrlRewriteFilter provides a - toolkit to let you set URL patterns however you want.

- -

See Cool URIs don't change, by World Wide Web creator - Tim Berners-Lee, for excellent arguments on why URLs should be clean and usable.

- -

With the Apache webserver there is mod_rewrite for URL manipulation.

- -

In J2EE land the Servlet specification (by Sun) standardises the approach for dealing with Java web server -programming. We have come a long way from basic Servlets, JSP's, MVC frameworks etc but Java Web Application -Servers such as Tomcat are seldom used as front-line web servers, they almost always have Apache infront of them.

- -

If you want to use an app server as a front line web server UrlRewriteFilter will enable you to manage incoming -URL's in a much more flexible way than the app server usually lets you.

- -

You can find test cases in the source distribution. UrlRewriteFilter should work on any J2EE web application server - and has been spceifically tested using Cactus on the following web application - servers:

- - - -

The filter has been designed for maximum performance. Testing has indicated - that it should only slow down a request by 0.0005 of a second under normal circumstances - (depending on hardware and configuration etc.). Take a look at the source in the class - UrlRewriterTest.testLoadsOfRules() for more information.

- - - - -

License

- -

UrlRewriteFilter is distributed under the BSD License. For more information on see - opensource.org/licenses.

- -

If you want to purchase ad-hoc support, a support contract, custom development or a commercial license - please email sales@tuckey.co.nz.

- - - - - - -

Changelog

- -
    -
  • Version 3.1 -
      -
    • Rules are now allowed to have only condition and set elements
    • -
    • Basic functions in "set", and "to" elements eg, ${trim:%1}
    • -
    • Experimental mod_rewrite style configuration
    • -
    • Bug fix: xml entites containing jndi protocol now correctly loaded
    • -
    -
  • -
- -

- 3.0.4 Beta - Bug fix - cookie value not being set with variable replacement -
3.0.3 Beta - Bug fix - annotation processor rule sorting -
Bug Fix - evaluation boolean result was incorrect on failed condition instance matches -
3.0.2 Beta - Rule chaining bug fixes -
3.0.1 Beta -
Added "class-rule" element to enable 100% dynamic "Java Rules" -
Added experimental UrlrewriteTestCase to help with testing (see the source) -
Added experimental "catch" element to handle exceptions generated from "run"'s -
Added experimental annotation (@HttpUrl, @HttpParam) processor -
Bug fixes - -
3.0 Beta - Support for wildcard matching. -
Added "match-type" attribute to rule and outbound-rule. -
Added ability to specify charset decoding ("decodeusing" attribute to "urlrewrite" element) - -
Swapped "to" variable replacement and run processing, run processing now comes before "to" - variable replacement is done. dtd it has been swapped make sure you change the reference in your conf file. - Make sure element order is from, set, run, to. - -
Context addition to the url is now optional -
Query string matching on rule is now optional (defaults to false) -
before 3.0 you would specify -
<from>/blah.jsp?a=b</from> -
3.0 and up (unless use-query-string on urlrewrite element is set to true) -
<condition name="a">b</condition> -
<from>/blah.jsp</from> - -
2.6 - fixed bug with encode on to element defaulting to incorrect boolean (change to dtd) -
2.5.3 - cleaner exception handling when invoking "run" items, original exception thrown as if it were the - original if - it extends RuntimeException (eg, NullPointer), other exceptions wrapped in a ServletException and thrown -
2.5.2 - fixed bug with encodefirst attr not being set, - ability to specify wildcards on statusEnabledOnHosts, - added backreferences and variables for to element value, - logLevel init param can now include sysout:{level} ie, sysout:DEBUG for people who have trouble with context.log -
2.5.1 - bug fixes, Log initialisation and null auth type condition values -
2.5 - matcher changed to accept first match (not the whole string) please make sure you retest your rules - (ie, previously /res/js/l.js?aaa would not match /res/js/l.js, with this release it will), -
- support for logging to log4j or commons-logging (see filter params in manual), -
- fixed bug for when request.getCookies() returns null on some containers, -
- added encodefirst outbound-rule, outbound-rule now respects encode on "to". -
2.4 - removed all external library dependencies to make much more deploy friendly -
- no longer uses Jakarta ORO, this should't mean any change in regular expression handling but you should test - your - existing rules just in case. -
- fixed problem with rediredting to "null" this will now not proceed with the request if the rule is matched - (ie, chain.doFilter will not be called) -
- fixed problem with ant dependency on status page. -
2.3 (4/2005) - Added new outbound-rule for rewriting hyperlinks in JSP's, improved status page, added ability - to - run methods when a rule is matched -
2.0.1 (2/2005) - Fixed bug with rule processing when to element doesn't exist. -
2.0 (1/2005) - Minor bug fixes, last attribute on rule now defaults to false (thanks to Vineet Kumar for his - assistance). -
2.0-beta (12/2004) - Minor bug fixes, documentation improvements, ALL matches now done case insensitively by - default, case sensitivity can be set (see from and condition elements). -
2.0-alpha (11/2004) - First 2.0 release, added many new condition types, many new set types. -
1.2 (6/2004) - Added set element (ability to set random attributes on request, thanks for the idea - Russell), from now matches RELATIVE to context NOT root (if you - are - upgrading this may mean a change for you). -
1.1 (4/2004) - Ability to disable rules, Refactored to enable rewriter to be embedded, - changed logging to enable log level to be set, added name and note elements to rule for documentation, - ability to disable status page, ability to change status prefix, javadoc style ant task for an HTML - configuration report. -
1.0 (3/2004) - General tidy up of logging, tidy up of all code, dist now includes manual, log4j and junit - removed - from bin release. -
0.9 (2/2004) - Fixed conf loading problem in Resin, resolved concurrency issue with Perl5Compiler and - Perl5Matcher - (thanks Scott Askew!) -
0.8 (2/2004) - Removed dependency on "Commons Lang", Changed DTD path (bug fix), added ability to put time - fields in - "condition" element, added ability to put "operators" in the "condition" element, fixed multiple rules issue (bug - fix) -
0.7 (11/2003) - Improved test cases, documentation -
0.6 (8/2003) - Improved error handling, status page and condition matching -
0.5 (6/2003) - Improved configuration error handling -

- - -
- - - - - - + + + + UrlRewriteFilter - Background + + + + + + + + + +
+ + + +

Background

+ + + +

A clean URL scheme is very important detail for any quality Web Application. UrlRewriteFilter provides a + toolkit to let you set URL patterns however you want.

+ +

See Cool URIs don't change, by World Wide Web creator + Tim Berners-Lee, for excellent arguments on why URLs should be clean and usable.

+ +

With the Apache webserver there is mod_rewrite for URL manipulation.

+ +

In J2EE land the Servlet specification (by Sun) standardises the approach for dealing with Java web server +programming. We have come a long way from basic Servlets, JSP's, MVC frameworks etc but Java Web Application +Servers such as Tomcat are seldom used as front-line web servers, they almost always have Apache infront of them.

+ +

If you want to use an app server as a front line web server UrlRewriteFilter will enable you to manage incoming +URL's in a much more flexible way than the app server usually lets you.

+ +

You can find test cases in the source distribution. UrlRewriteFilter should work on any J2EE web application server + and has been spceifically tested using Cactus on the following web application + servers:

+ + + +

The filter has been designed for maximum performance. Testing has indicated + that it should only slow down a request by 0.0005 of a second under normal circumstances + (depending on hardware and configuration etc.). Take a look at the source in the class + UrlRewriterTest.testLoadsOfRules() for more information.

+ + + + +

License

+ +

UrlRewriteFilter is distributed under the BSD License. For more information on see + opensource.org/licenses.

+ +

If you want to purchase ad-hoc support, a support contract, custom development or a commercial license + please email sales@tuckey.co.nz.

+ + + + + + +

Changelog

+ +
    +
  • Version 3.1 +
      +
    • Rules are now allowed to have only condition and set elements
    • +
    • Basic functions in "set", and "to" elements eg, ${trim:%1}
    • +
    • Experimental mod_rewrite style configuration
    • +
    • Bug fix: xml entites containing jndi protocol now correctly loaded
    • +
    +
  • +
+ +

+ 3.0.4 Beta - Bug fix - cookie value not being set with variable replacement +
3.0.3 Beta - Bug fix - annotation processor rule sorting +
Bug Fix - evaluation boolean result was incorrect on failed condition instance matches +
3.0.2 Beta - Rule chaining bug fixes +
3.0.1 Beta +
Added "class-rule" element to enable 100% dynamic "Java Rules" +
Added experimental UrlrewriteTestCase to help with testing (see the source) +
Added experimental "catch" element to handle exceptions generated from "run"'s +
Added experimental annotation (@HttpUrl, @HttpParam) processor +
Bug fixes + +
3.0 Beta - Support for wildcard matching. +
Added "match-type" attribute to rule and outbound-rule. +
Added ability to specify charset decoding ("decodeusing" attribute to "urlrewrite" element) + +
Swapped "to" variable replacement and run processing, run processing now comes before "to" + variable replacement is done. dtd it has been swapped make sure you change the reference in your conf file. + Make sure element order is from, set, run, to. + +
Context addition to the url is now optional +
Query string matching on rule is now optional (defaults to false) +
before 3.0 you would specify +
<from>/blah.jsp?a=b</from> +
3.0 and up (unless use-query-string on urlrewrite element is set to true) +
<condition name="a">b</condition> +
<from>/blah.jsp</from> + +
2.6 - fixed bug with encode on to element defaulting to incorrect boolean (change to dtd) +
2.5.3 - cleaner exception handling when invoking "run" items, original exception thrown as if it were the + original if + it extends RuntimeException (eg, NullPointer), other exceptions wrapped in a ServletException and thrown +
2.5.2 - fixed bug with encodefirst attr not being set, + ability to specify wildcards on statusEnabledOnHosts, + added backreferences and variables for to element value, + logLevel init param can now include sysout:{level} ie, sysout:DEBUG for people who have trouble with context.log +
2.5.1 - bug fixes, Log initialisation and null auth type condition values +
2.5 - matcher changed to accept first match (not the whole string) please make sure you retest your rules + (ie, previously /res/js/l.js?aaa would not match /res/js/l.js, with this release it will), +
- support for logging to log4j or commons-logging (see filter params in manual), +
- fixed bug for when request.getCookies() returns null on some containers, +
- added encodefirst outbound-rule, outbound-rule now respects encode on "to". +
2.4 - removed all external library dependencies to make much more deploy friendly +
- no longer uses Jakarta ORO, this should't mean any change in regular expression handling but you should test + your + existing rules just in case. +
- fixed problem with rediredting to "null" this will now not proceed with the request if the rule is matched + (ie, chain.doFilter will not be called) +
- fixed problem with ant dependency on status page. +
2.3 (4/2005) - Added new outbound-rule for rewriting hyperlinks in JSP's, improved status page, added ability + to + run methods when a rule is matched +
2.0.1 (2/2005) - Fixed bug with rule processing when to element doesn't exist. +
2.0 (1/2005) - Minor bug fixes, last attribute on rule now defaults to false (thanks to Vineet Kumar for his + assistance). +
2.0-beta (12/2004) - Minor bug fixes, documentation improvements, ALL matches now done case insensitively by + default, case sensitivity can be set (see from and condition elements). +
2.0-alpha (11/2004) - First 2.0 release, added many new condition types, many new set types. +
1.2 (6/2004) - Added set element (ability to set random attributes on request, thanks for the idea + Russell), from now matches RELATIVE to context NOT root (if you + are + upgrading this may mean a change for you). +
1.1 (4/2004) - Ability to disable rules, Refactored to enable rewriter to be embedded, + changed logging to enable log level to be set, added name and note elements to rule for documentation, + ability to disable status page, ability to change status prefix, javadoc style ant task for an HTML + configuration report. +
1.0 (3/2004) - General tidy up of logging, tidy up of all code, dist now includes manual, log4j and junit + removed + from bin release. +
0.9 (2/2004) - Fixed conf loading problem in Resin, resolved concurrency issue with Perl5Compiler and + Perl5Matcher + (thanks Scott Askew!) +
0.8 (2/2004) - Removed dependency on "Commons Lang", Changed DTD path (bug fix), added ability to put time + fields in + "condition" element, added ability to put "operators" in the "condition" element, fixed multiple rules issue (bug + fix) +
0.7 (11/2003) - Improved test cases, documentation +
0.6 (8/2003) - Improved error handling, status page and condition matching +
0.5 (6/2003) - Improved configuration error handling +

+ + +
+ + + + + + diff --git a/src/doc/manual/3.2/annotation.html b/src/doc/manual/3.2/annotation.html index 83591a83..50bd1a59 100644 --- a/src/doc/manual/3.2/annotation.html +++ b/src/doc/manual/3.2/annotation.html @@ -1,163 +1,163 @@ - - - - UrlRewriteFilter - Annotation - - - - - - - - - -
- - - -

URL Matching Annotations

- - - -

Support for annotations has been added as part of version 3 development. You must be using JDK 1.6 for this to work.

- -

The intention of annotations in UrlRewriteFilter is purely for conf file generation. The is NO runtime - dependency on the annotations.

- -

Annotations

- -

@HttpUrl

- -

Set the method up to be used when the url is Matched, matched groups are assigned to method paramters (if any).

- -

-    @HttpUrl("^/do-something/([0-9]+)$")
-    public void doSomething(Long id)
-    
- -

When a request for /do-something/1234, doSomething is called with id set to 1234.

- -

@HttpParam

- -

Sets the parameter from request.getParameter (handles type conversion as necessary)

- -

-    void doSomething(@HttpParam String name, @HttpParam long id, @HttpParam("uid") Long userId)
-    
- -

The above example will: -
name = request.getParameter("name"); -
id = convertTolongDefault0(request.getParameter("id")); -
userId = convertToLongDefaultNull(request.getParameter("uid")); -
An exception will never be thown during type conversion -

- - - - -

Conf Generation

- -

With Java 1.6 the javac tool handles annotation processing. So this means all you need to do is have a - "urlrewriteDest" option specified and have urlrewritefilter jar in your classpath. Example of compilerarg - elements that would be used with javac ant task:

- -

-<compilerarg line="-AurlrewriteDest=build/WEB-INF/urlrewrite-generated.xml"/>
-<!-- optional arguments
-<compilerarg value="-AurlrewriteShowPositions=true"/>
-<compilerarg value="-AurlrewriteDebug=true"/>
--->
-
- -

An example compile ant task with urlrewrite option might look like:

- -

-<target name="compile-urlrewrite-conf">
-   <javac srcdir="src/" destdir="build/WEB-INF/classes">
-        <classpath refid="compile.classpath"/>
-        <classpath path="lib/urlrewrite-3.2.0.jar"/>
-        <compilerarg line="-AurlrewriteDest=build/WEB-INF/urlrewrite-generated.xml"/>
-   </javac>
-   <!-- check file generated ok (if not you may be using the wrong jdk version)-->
-   <available property="urlrewrite.generated" file="build/WEB-INF/urlrewrite-generated.xml"/>
-   <fail unless="urlrewrite.generated" />
-</target>
-
- -

This will generate to the file specified. Any errors will be output to stdout using the standard APT method. - Read the generated conf file and check it for errors.

- - -

Include the compiled conf file in your normal conf.

- -

-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
-        "http://www.tuckey.org/res/dtds/urlrewrite3.2.dtd"
-[
-    <!ENTITY included SYSTEM "urlrewrite-generated.xml">
-]>
-<urlrewrite>
-
-    <!--
-        other rules...
-    -->
-
-    &included;
-
-
-</urlrewrite>
-
- - -

Check your /rewrite-status for errors if things start going strange.

- -
- - - - - - + + + + UrlRewriteFilter - Annotation + + + + + + + + + +
+ + + +

URL Matching Annotations

+ + + +

Support for annotations has been added as part of version 3 development. You must be using JDK 1.6 for this to work.

+ +

The intention of annotations in UrlRewriteFilter is purely for conf file generation. The is NO runtime + dependency on the annotations.

+ +

Annotations

+ +

@HttpUrl

+ +

Set the method up to be used when the url is Matched, matched groups are assigned to method paramters (if any).

+ +

+    @HttpUrl("^/do-something/([0-9]+)$")
+    public void doSomething(Long id)
+    
+ +

When a request for /do-something/1234, doSomething is called with id set to 1234.

+ +

@HttpParam

+ +

Sets the parameter from request.getParameter (handles type conversion as necessary)

+ +

+    void doSomething(@HttpParam String name, @HttpParam long id, @HttpParam("uid") Long userId)
+    
+ +

The above example will: +
name = request.getParameter("name"); +
id = convertTolongDefault0(request.getParameter("id")); +
userId = convertToLongDefaultNull(request.getParameter("uid")); +
An exception will never be thown during type conversion +

+ + + + +

Conf Generation

+ +

With Java 1.6 the javac tool handles annotation processing. So this means all you need to do is have a + "urlrewriteDest" option specified and have urlrewritefilter jar in your classpath. Example of compilerarg + elements that would be used with javac ant task:

+ +

+<compilerarg line="-AurlrewriteDest=build/WEB-INF/urlrewrite-generated.xml"/>
+<!-- optional arguments
+<compilerarg value="-AurlrewriteShowPositions=true"/>
+<compilerarg value="-AurlrewriteDebug=true"/>
+-->
+
+ +

An example compile ant task with urlrewrite option might look like:

+ +

+<target name="compile-urlrewrite-conf">
+   <javac srcdir="src/" destdir="build/WEB-INF/classes">
+        <classpath refid="compile.classpath"/>
+        <classpath path="lib/urlrewrite-3.2.0.jar"/>
+        <compilerarg line="-AurlrewriteDest=build/WEB-INF/urlrewrite-generated.xml"/>
+   </javac>
+   <!-- check file generated ok (if not you may be using the wrong jdk version)-->
+   <available property="urlrewrite.generated" file="build/WEB-INF/urlrewrite-generated.xml"/>
+   <fail unless="urlrewrite.generated" />
+</target>
+
+ +

This will generate to the file specified. Any errors will be output to stdout using the standard APT method. + Read the generated conf file and check it for errors.

+ + +

Include the compiled conf file in your normal conf.

+ +

+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
+        "http://www.tuckey.org/res/dtds/urlrewrite3.2.dtd"
+[
+    <!ENTITY included SYSTEM "urlrewrite-generated.xml">
+]>
+<urlrewrite>
+
+    <!--
+        other rules...
+    -->
+
+    &included;
+
+
+</urlrewrite>
+
+ + +

Check your /rewrite-status for errors if things start going strange.

+ +
+ + + + + + diff --git a/src/doc/manual/3.2/doc.css b/src/doc/manual/3.2/doc.css index f8c90dca..27e8aa39 100644 --- a/src/doc/manual/3.2/doc.css +++ b/src/doc/manual/3.2/doc.css @@ -1,139 +1,139 @@ -body { - background: #c0c0c0; - font: 13px arial, helvetica, sans-serif; -} - -#logo { - vertical-align: middle; -} - -h1 { - color: #000000; - font-size: 2.5em; - padding: 0px 0px 0px 5px; - margin: 0px; - font-family: georgia, times, serif; -} - -#masthead { - font-family: georgia, times, serif; - font-size: 3.5em; - background-color: #efefef; - -moz-border-radius-topright: 20px; - margin-top: 5px; - padding: 5px; - padding-left: 15px; - width: 650px; -} - -#masthead a { - text-decoration: none; - color: black; -} - - -h2 { - font-family: georgia, times, serif; - border-bottom: 1px solid #808080; - padding: 5px; -} - -h3 { - font-family: georgia, times, serif; - border-bottom: 1px solid #c0c0c0; - margin-top: 2em; - padding: 0.25em 0.25em 0em 0.5em; -} - -p { - padding: 0.25em 0.25em 0em 1.0em; -} - -code, pre { - font-family: 'Courier New', courier, monospace; - font-size: 11px; -} - -pre { - background: #eeeeff; - margin: 0.5em 3em 0.1em 3em; - padding: 0.25em 0.5em 0.5em 0.5em; -} - -table { - border: 1px solid #c0c0c0; - margin-left: 2em; - border-collapse: collapse; - border-spacing: 0; -} - -th, td { - border: 1px solid #eeeeee; - vertical-align: top; - padding: 3px; -} - -th { - background: #eeeeee; -} - -hr { - border: 0px; - background-color: #c0c0c0; -} - -.err { - color: #ff0000; -} - -#menu { - float:left; - width:160px; - background: #efefef; - Zmargin-top: 2px; - padding-bottom: 10px; - padding-left: 10px; - -moz-border-radius-bottomleft: 20px; -} - -#menu ul { - list-style-type: none; - margin-left: .5em; - padding-left: .5em; - margin-top: 7px; -} -#menu li { - margin-bottom: 7px; -} - -#main { - background: white; - border-left: 1px solid #c0c0c0; - border-top: 1px solid #c0c0c0; - border-right: 1px solid #808080; - border-bottom: 1px solid #808080; - margin-left: 170px; - padding: 15px; - -moz-border-radius-bottomleft: 20px; - min-height: 400px; -} - -#footer { - margin-top: 40px; - text-align: center; - font-size: small; - color: black; - text-transform: lowercase; -} - -#footer a { - text-decoration: none; -} - -.outdated { - border: 2px solid red; - background: #eeeeee; - padding: 5px; - font-weight: bold; -} - +body { + background: #c0c0c0; + font: 13px arial, helvetica, sans-serif; +} + +#logo { + vertical-align: middle; +} + +h1 { + color: #000000; + font-size: 2.5em; + padding: 0px 0px 0px 5px; + margin: 0px; + font-family: georgia, times, serif; +} + +#masthead { + font-family: georgia, times, serif; + font-size: 3.5em; + background-color: #efefef; + -moz-border-radius-topright: 20px; + margin-top: 5px; + padding: 5px; + padding-left: 15px; + width: 650px; +} + +#masthead a { + text-decoration: none; + color: black; +} + + +h2 { + font-family: georgia, times, serif; + border-bottom: 1px solid #808080; + padding: 5px; +} + +h3 { + font-family: georgia, times, serif; + border-bottom: 1px solid #c0c0c0; + margin-top: 2em; + padding: 0.25em 0.25em 0em 0.5em; +} + +p { + padding: 0.25em 0.25em 0em 1.0em; +} + +code, pre { + font-family: 'Courier New', courier, monospace; + font-size: 11px; +} + +pre { + background: #eeeeff; + margin: 0.5em 3em 0.1em 3em; + padding: 0.25em 0.5em 0.5em 0.5em; +} + +table { + border: 1px solid #c0c0c0; + margin-left: 2em; + border-collapse: collapse; + border-spacing: 0; +} + +th, td { + border: 1px solid #eeeeee; + vertical-align: top; + padding: 3px; +} + +th { + background: #eeeeee; +} + +hr { + border: 0px; + background-color: #c0c0c0; +} + +.err { + color: #ff0000; +} + +#menu { + float:left; + width:160px; + background: #efefef; + Zmargin-top: 2px; + padding-bottom: 10px; + padding-left: 10px; + -moz-border-radius-bottomleft: 20px; +} + +#menu ul { + list-style-type: none; + margin-left: .5em; + padding-left: .5em; + margin-top: 7px; +} +#menu li { + margin-bottom: 7px; +} + +#main { + background: white; + border-left: 1px solid #c0c0c0; + border-top: 1px solid #c0c0c0; + border-right: 1px solid #808080; + border-bottom: 1px solid #808080; + margin-left: 170px; + padding: 15px; + -moz-border-radius-bottomleft: 20px; + min-height: 400px; +} + +#footer { + margin-top: 40px; + text-align: center; + font-size: small; + color: black; + text-transform: lowercase; +} + +#footer a { + text-decoration: none; +} + +.outdated { + border: 2px solid red; + background: #eeeeee; + padding: 5px; + font-weight: bold; +} + diff --git a/src/doc/manual/3.2/guide.html b/src/doc/manual/3.2/guide.html index 6754b707..673fa644 100644 --- a/src/doc/manual/3.2/guide.html +++ b/src/doc/manual/3.2/guide.html @@ -1,781 +1,781 @@ - - - - UrlRewriteFilter - Examples - - - - - - - - - -
- - - -

Examples

- -

Redirect one url

- -

-    <rule>
-        <from>^/some/old/page\.html$</from>
-        <to type="redirect">/very/new/page.html</to>
-    </rule>
-
- -

-    <rule match-type="wildcard">
-        <from>/some/old/page.html</from>
-        <to type="redirect">/very/new/page.html</to>
-    </rule>
-
- -

Redirect docs in a directory to another using wildcard engine.

- -

-    <urlrewrite default-match-type="wildcard">
-
-    <rule>
-        <from>/some/old/*.doc</from>
-        <to type="redirect">/very/new/$1.doc</to>
-    </rule>
-
-    </urlrewrite>
-
- -

Tiny/Freindly url

- -

-    <rule>
-        <from>^/zebra$</from>
-        <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
-    </rule>
-
- -

Default page as another (requests to / will be redirected)

- -

-    <rule>
-        <from>^/$</from>
-        <to type="redirect">/opencms/opencms/index.html</to>
-    </rule>
-
- -

Perform security checks in a centralised place

- -

-    <rule>
-        <condition type="user-in-role" operator="notequal">admin</condition>
-        <condition type="user-in-role" operator="notequal">bigboss</condition>
-        <from>^/admin/(.*)$</from>
-        <to>/go-away-please.html</to>
-    </rule>
-
- - -

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah - will be redirected to http://www.example.com/blah

- -

-    <rule>
-        <name>Domain Name Check</name>
-        <condition name="host" operator="notequal">www.example.com</condition>
-        <from>^(.*)$</from>
-        <to type="redirect">http://www.example.com/context$1</to>
-    </rule>
-
- - -

Disable access to a directory.

- -

-    <rule>
-        <name>Disable Directory</name>
-        <from>^/notliveyet/.*$</from>
-        <set type="status">403</set>
-        <to>null</to>
-    </rule>
-
- -

Redirect a directory (for moved content)

- -

-    <rule>
-        <from>^/some/olddir/(.*)$</from>
-        <to type="redirect">/very/newdir/$1</to>
-    </rule>
-
- -

Clean a URL

- -

-    <rule>
-        <from>^/products/([0-9]+)$</from>
-        <to>/products/index.jsp?product_id=$1</to>
-    </rule>
-
- -

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 - without the user noticing.

- -

-    <rule>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- -

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork -

- -

Browser detection

- -

-    <rule>
-        <condition name="user-agent">Mozilla/[1-4]</condition>
-        <from>^/some/page\.html$</from>
-        <to>/some/page-for-old-browsers.html</to>
-    </rule>
-
- -

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html - only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, - Mozilla/3 or Mozilla/4.

- - -

Security. Preclude certain types of method from you web application.

- -

-    <rule>
-        <condition type="method" next="or">PROPFIND</condition>
-        <condition type="method">PUT</condition>
-        <from>.*</from>
-        <to type="redirect">/bad-method.html</to>
-    </rule>
-
- - -

Sunday Specials

- -

-    <rule>
-        <condition type="dayofweek">1</condition>
-        <from>^/products/$</from>
-        <to>/products/sunday-specials.html</to>
-    </rule>
-
- - -

Set the "Cache-Control" HTTP response header for all requests

- -

-    <rule>
-        <from>.*</from>
-        <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
-    </rule>
-
- -

Forward a request to a servlet

- -

-    <rule>
-        <from>^/products/purchase$</from>
-        <to>/servlets/ProductsServlet</to>
-        <set name="action">purchase</set>
-    </rule>
-
- -

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and - inside - the servlet request.getAttribute("action") will return purchase.

- -

Set an "Expires" HTTP header 6 hours into the future for js, css and gif files

- -

-    <rule>
-        <from>^.*\.(js|css|gif)$</from>
-        <set type="expires">6 hours</set>
-    </rule>
-
- -

Hide jsessionid for requests from googlebot.

- -

-  <outbound-rule>
-       <name>Strip URL Session ID's</name>
-       <note>
-           Strip ;jsession=XXX from urls passed through
-response.encodeURL().
-           The characters ? and # are the only things we can use to
-find out where the jsessionid ends.
-           The expression in 'from' below contains three capture
-groups, the last two being optional.
-               1, everything before ;jesessionid
-               2, everything after ;jesessionid=XXX starting with a ?
-(to get the query string) up to #
-               3, everything ;jesessionid=XXX and optionally ?XXX
-starting with a # (to get the target)
-           eg,
-           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
-           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
-           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
-index.jsp#dfds
-           from u.jsp;jsessionid=wert.hg - u.jsp
-           from /;jsessionid=tyu - /
-       </note>
-       <condition name="user-agent">googlebot</condition>
-       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
-       <to>$1$2$3</to>
-   </outbound-rule>
-
- -

Permanently redirect incoming URLs containing jsessionid.

- -

-  <rule>
-       <name>Strip URL Session ID's</name>
-       <note>
-           Strip ;jsession=XXX from urls passed through
-response.encodeURL().
-           The characters ? and # are the only things we can use to
-find out where the jsessionid ends.
-           The expression in 'from' below contains three capture
-groups, the last two being optional.
-               1, everything before ;jesessionid
-               2, everything after ;jesessionid=XXX starting with a ?
-(to get the query string) up to #
-               3, everything ;jesessionid=XXX and optionally ?XXX
-starting with a # (to get the target)
-           eg,
-           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
-           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
-           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
-index.jsp#dfds
-           from u.jsp;jsessionid=wert.hg - u.jsp
-           from /;jsessionid=tyu - /
-       </note>
-       <condition type="requested-session-id-from-url" operator="equal">true</condition>
-       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
-       <to type="permanent-redirect">$1$2$3</to>
-   </rule>
-
- - - -

Method Invocation

- -

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have - any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

- -

Invoke a servlet directly

- -

-    <rule>
-    <from>^/products/purchase$</from>
-    <run class="com.blah.web.MyServlet" method="doGet" />
-    </rule>
-
- -

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is - matched on a request. (remeber this method needs to be public!)

- -

Use it to delagate cleanly to your methods

- -

-    <rule>
-        <from>^/pref-editor/addresses$</from>
-        <run class="com.blah.web.PrefsServlet" method="runAddresses" />
-    </rule>
-    <rule>
-        <from>^/pref-editor/phone-nums$</from>
-        <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
-    </rule>
-
- -

Browser based delagation to your methods

- -

-    <rule>
-        <condition name="user-agent">Mozilla/[1-4]</condition>
-        <from>^/content/.*$</from>
-        <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
-    </rule>
-    <rule>
-        <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-        <from>^/content/.*$</from>
-        <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
-        <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
-    </rule>
-
- -

When the method specified in the "run" is invoked it has full control over the request and response as if it were a - servlet.

- - - - - - - -

URL Abstraction

- -

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

- -

-    <rule>
-        <from>^/tidy/page$</from>
-        <to>/old/url/scheme/page.jsp</to>
-    </rule>
-    <outbound-rule>
-        <from>^/old/url/scheme/page.jsp$</from>
-        <to>/tidy/page</to>
-    </outbound-rule>
-
- -

Any incoming requests for /tidy/page will be transparently forwarded to - /old/url/scheme/page.jsp.

- -

If you use JSTL your JSP page would have something like:

-
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
- -

This will be rewritten upon output to:

-
<a href="/tidy/page">some link</a>
- -

Or if you use standard JSP:

-
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
- -

Will generate output like:

-
<a href="/tidy/page">some link</a>
- - - - -

mod_rewrite vs urlrewrite filter

- - -

Examples of mod_rewrite style conf vs urlrewrite filter conf are below, there are all examples copied directly from - Apache 2.0's official rewrite guide.

- -

-
-<rule>
-    <name>Canonical URLs</name>
-    <note>
-        On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
-        should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
-        of which URL the user supplied with the request he should finally see the canonical one only.
-
-        We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
-        and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
-        fix a missing trailing slash for /u/user.
-
-        RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
-        RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
-    </note>
-    <from>^/~([^/]+)/?(.*)</from>
-    <to type="redirect">/u/$1/$2</to>
-</rule>
-<rule>
-    <from>^/([uge])/([^/]+)$</from>
-    <to type="redirect">/$1/$2/</to>
-</rule>
-
-
-<rule>
-    <name>Canonical Hostnames</name>
-    <note>
-        The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
-        may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
-        example.com, you might use a variant of the following recipe.
-
-        RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
-        RewriteCond %{HTTP_HOST} !^$
-        RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
-    </note>
-    <condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
-    <condition name="host" operator="notequal">^$</condition>
-    <from>^/(.*)</from>
-    <to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
-</rule>
-
-
-<rule>
-    <name>Moved DocumentRoot</name>
-    <note>
-        Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
-        really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
-        Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
-        because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
-        stuff inside this data pool work for subsequent requests.
-
-        We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
-        Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
-        matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
-        With mod_rewrite it is really trivial:
-
-        RewriteRule ^/$ /e/www/ [R]
-    </note>
-    <from>^/$</from>
-    <to type="redirect">/e/www/</to>
-</rule>
-
-
-<rule>
-    <name>Trailing Slash Problem</name>
-    <note>
-        Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
-        If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
-        the server searches for a file named foo. And because this file is a directory it complains. Actually it
-        tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
-        instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
-
-        The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
-        correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
-        we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
-        images are included into this page with relative URLs, because the browser would request an in-lined object.
-        For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
-        external redirect!
-    </note>
-    <from>^/~quux/foo$</from>
-    <to type="redirect">/~quux/foo/</to>
-</rule>
-
-
-<rule>
-    <name>Move Homedirs to Different Webserver</name>
-    <note>
-        Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
-        homedirs on a webserver to another webserver. They usually need such things when establishing a newer
-        webserver which will replace the old one over time.
-
-        The solution is trivial with mod_rewrite (and urlrewrite filter). On the old webserver we just redirect all
-        /~user/anypath URLs to http://newserver/~user/anypath.
-
-        RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
-    </note>
-    <from>^/~(.+)</from>
-    <to type="redirect" last="true">http://newserver/~$1</to>
-</rule>
-
-
-<rule>
-    <name>Structured Homedirs</name>
-    <note>
-        Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
-        subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
-        /home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
-
-        We use the following ruleset to expand the tilde URLs into exactly the above layout.
-
-        RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
-    </note>
-    <from>^/~(([a-z])[a-z0-9]+)(.*)</from>
-    <to>/home/$2/$1/.www$3</to>
-</rule>
-
-
-<rule>
-    <name>Redirect Homedirs For Foreigners</name>
-    <note>
-        We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
-        stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
-
-        Just a rewrite condition:
-
-        RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
-        RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
-    </note>
-    <condition name="host">!^.+\.ourdomain\.com$</condition>
-    <from>^(/~.+)</from>
-    <to type="redirect" last="true">http://www.somewhere.com/$1</to>
-</rule>
-
-
-<rule>
-    <name>Time-Dependent Rewriting</name>
-    <note>
-        When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
-        instance redirects to specialized pages. How can it be done via mod_rewrite?
-
-        There are a lot of types in conjunction with operators we can do time-dependent redirects:
-
-        RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
-        RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
-        RewriteRule ^foo\.html$ foo.day.html
-        RewriteRule ^foo\.html$ foo.night.html
-    </note>
-    <condition type="hourofday" operator="greater">7</condition>
-    <condition type="hourofday" operator="less">19</condition>
-    <from>^foo\.html$</from>
-    <to>foo.day.html</to>
-</rule>
-<rule>
-    <from>^foo\.html$</from>
-    <to>foo.night.html</to>
-</rule>
-
-
-<rule>
-    <name></name>
-    <note>
-        Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
-        backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
-        renamed.
-
-        We rewrite the old URL to the new one internally via the following rule:
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ bar.html
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to>/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-    <name>From Old to New (extern)</name>
-    <note>
-        Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
-        for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
-        i.e. their browsers Location field should change, too.
-
-        We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ bar.html [R]
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to type="redirect">/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-    <name>Browser Dependent Content</name>
-    <note>
-        At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
-        content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
-        the Lynx browsers and a average feature version for all others.
-
-        We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
-        have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
-        "User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
-        stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
-        browsers receive page foo.32.html. This is done by the following ruleset:
-
-        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
-        RewriteRule ^foo\.html$ foo.NS.html [L]
-
-        RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
-        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
-        RewriteRule ^foo\.html$ foo.20.html [L]
-
-        RewriteRule ^foo\.html$ foo.32.html [L]
-    </note>
-    <condition name="user-agent">^Mozilla/3.*</condition>
-    <from>^foo\.html$</from>
-    <to last="true">foo.NS.html</to>
-</rule>
-<rule>
-    <condition name="user-agent" next="or">^Lynx/.*</condition>
-    <condition name="user-agent">^Mozilla/[12].*</condition>
-    <from>^foo\.html$</from>
-    <to last="true">foo.20.html</to>
-</rule>
-<rule>
-    <from>^foo\.html$</from>
-    <to last="true">foo.32.html</to>
-</rule>
-
-
-<rule>
-    <name>From Static to Dynamic</name>
-    <note>
-        How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
-        notice by the browser/user.
-
-        We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
-        a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to>/~quux/foo.jsp</to>
-</rule>
-
-<rule>
-    <name>Blocking of Robots</name>
-    <note>
-        How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
-        containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
-
-        We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
-        indexed area where the robot traversal would create big server load). We have to make sure that we forbid
-        access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
-        This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
-        information.
-
-        RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
-        RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
-        RewriteRule ^/~quux/foo/arc/.+ - [F]
-    </note>
-    <condition name="user-agent">^NameOfBadRobot.*</condition>
-    <condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
-    <from>^/~quux/foo/arc/.+</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-
-<rule>
-    <name>Blocked Inline-Images</name>
-    <note>
-        Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
-        nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
-        it adds useless traffic to our server.
-
-        While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
-        sends a HTTP Referer header.
-
-        RewriteCond %{HTTP_REFERER} !^$
-        RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
-        RewriteRule .*\.gif$ - [F]
-    </note>
-    <condition name="referer" operator="notequal">^$</condition>
-    <condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
-    <from>.*\.gif$</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-<rule>
-    <name>Blocked Inline-Images example 2</name>
-    <note>
-        RewriteCond %{HTTP_REFERER} !^$
-        RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
-        RewriteRule ^inlined-in-foo\.gif$ - [F]
-    </note>
-    <condition name="referer" operator="notequal">^$</condition>
-    <condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
-    <from>^inlined-in-foo\.gif$</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-
- - - -
- - - - - - + + + + UrlRewriteFilter - Examples + + + + + + + + + +
+ + + +

Examples

+ +

Redirect one url

+ +

+    <rule>
+        <from>^/some/old/page\.html$</from>
+        <to type="redirect">/very/new/page.html</to>
+    </rule>
+
+ +

+    <rule match-type="wildcard">
+        <from>/some/old/page.html</from>
+        <to type="redirect">/very/new/page.html</to>
+    </rule>
+
+ +

Redirect docs in a directory to another using wildcard engine.

+ +

+    <urlrewrite default-match-type="wildcard">
+
+    <rule>
+        <from>/some/old/*.doc</from>
+        <to type="redirect">/very/new/$1.doc</to>
+    </rule>
+
+    </urlrewrite>
+
+ +

Tiny/Freindly url

+ +

+    <rule>
+        <from>^/zebra$</from>
+        <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
+    </rule>
+
+ +

Default page as another (requests to / will be redirected)

+ +

+    <rule>
+        <from>^/$</from>
+        <to type="redirect">/opencms/opencms/index.html</to>
+    </rule>
+
+ +

Perform security checks in a centralised place

+ +

+    <rule>
+        <condition type="user-in-role" operator="notequal">admin</condition>
+        <condition type="user-in-role" operator="notequal">bigboss</condition>
+        <from>^/admin/(.*)$</from>
+        <to>/go-away-please.html</to>
+    </rule>
+
+ + +

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah + will be redirected to http://www.example.com/blah

+ +

+    <rule>
+        <name>Domain Name Check</name>
+        <condition name="host" operator="notequal">www.example.com</condition>
+        <from>^(.*)$</from>
+        <to type="redirect">http://www.example.com/context$1</to>
+    </rule>
+
+ + +

Disable access to a directory.

+ +

+    <rule>
+        <name>Disable Directory</name>
+        <from>^/notliveyet/.*$</from>
+        <set type="status">403</set>
+        <to>null</to>
+    </rule>
+
+ +

Redirect a directory (for moved content)

+ +

+    <rule>
+        <from>^/some/olddir/(.*)$</from>
+        <to type="redirect">/very/newdir/$1</to>
+    </rule>
+
+ +

Clean a URL

+ +

+    <rule>
+        <from>^/products/([0-9]+)$</from>
+        <to>/products/index.jsp?product_id=$1</to>
+    </rule>
+
+ +

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 + without the user noticing.

+ +

+    <rule>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ +

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork +

+ +

Browser detection

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/[1-4]</condition>
+        <from>^/some/page\.html$</from>
+        <to>/some/page-for-old-browsers.html</to>
+    </rule>
+
+ +

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html + only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, + Mozilla/3 or Mozilla/4.

+ + +

Security. Preclude certain types of method from you web application.

+ +

+    <rule>
+        <condition type="method" next="or">PROPFIND</condition>
+        <condition type="method">PUT</condition>
+        <from>.*</from>
+        <to type="redirect">/bad-method.html</to>
+    </rule>
+
+ + +

Sunday Specials

+ +

+    <rule>
+        <condition type="dayofweek">1</condition>
+        <from>^/products/$</from>
+        <to>/products/sunday-specials.html</to>
+    </rule>
+
+ + +

Set the "Cache-Control" HTTP response header for all requests

+ +

+    <rule>
+        <from>.*</from>
+        <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
+    </rule>
+
+ +

Forward a request to a servlet

+ +

+    <rule>
+        <from>^/products/purchase$</from>
+        <to>/servlets/ProductsServlet</to>
+        <set name="action">purchase</set>
+    </rule>
+
+ +

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and + inside + the servlet request.getAttribute("action") will return purchase.

+ +

Set an "Expires" HTTP header 6 hours into the future for js, css and gif files

+ +

+    <rule>
+        <from>^.*\.(js|css|gif)$</from>
+        <set type="expires">6 hours</set>
+    </rule>
+
+ +

Hide jsessionid for requests from googlebot.

+ +

+  <outbound-rule>
+       <name>Strip URL Session ID's</name>
+       <note>
+           Strip ;jsession=XXX from urls passed through
+response.encodeURL().
+           The characters ? and # are the only things we can use to
+find out where the jsessionid ends.
+           The expression in 'from' below contains three capture
+groups, the last two being optional.
+               1, everything before ;jesessionid
+               2, everything after ;jesessionid=XXX starting with a ?
+(to get the query string) up to #
+               3, everything ;jesessionid=XXX and optionally ?XXX
+starting with a # (to get the target)
+           eg,
+           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
+           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
+           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
+index.jsp#dfds
+           from u.jsp;jsessionid=wert.hg - u.jsp
+           from /;jsessionid=tyu - /
+       </note>
+       <condition name="user-agent">googlebot</condition>
+       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
+       <to>$1$2$3</to>
+   </outbound-rule>
+
+ +

Permanently redirect incoming URLs containing jsessionid.

+ +

+  <rule>
+       <name>Strip URL Session ID's</name>
+       <note>
+           Strip ;jsession=XXX from urls passed through
+response.encodeURL().
+           The characters ? and # are the only things we can use to
+find out where the jsessionid ends.
+           The expression in 'from' below contains three capture
+groups, the last two being optional.
+               1, everything before ;jesessionid
+               2, everything after ;jesessionid=XXX starting with a ?
+(to get the query string) up to #
+               3, everything ;jesessionid=XXX and optionally ?XXX
+starting with a # (to get the target)
+           eg,
+           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
+           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
+           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
+index.jsp#dfds
+           from u.jsp;jsessionid=wert.hg - u.jsp
+           from /;jsessionid=tyu - /
+       </note>
+       <condition type="requested-session-id-from-url" operator="equal">true</condition>
+       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
+       <to type="permanent-redirect">$1$2$3</to>
+   </rule>
+
+ + + +

Method Invocation

+ +

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have + any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

+ +

Invoke a servlet directly

+ +

+    <rule>
+    <from>^/products/purchase$</from>
+    <run class="com.blah.web.MyServlet" method="doGet" />
+    </rule>
+
+ +

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is + matched on a request. (remeber this method needs to be public!)

+ +

Use it to delagate cleanly to your methods

+ +

+    <rule>
+        <from>^/pref-editor/addresses$</from>
+        <run class="com.blah.web.PrefsServlet" method="runAddresses" />
+    </rule>
+    <rule>
+        <from>^/pref-editor/phone-nums$</from>
+        <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
+    </rule>
+
+ +

Browser based delagation to your methods

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/[1-4]</condition>
+        <from>^/content/.*$</from>
+        <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
+    </rule>
+    <rule>
+        <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+        <from>^/content/.*$</from>
+        <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
+        <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
+    </rule>
+
+ +

When the method specified in the "run" is invoked it has full control over the request and response as if it were a + servlet.

+ + + + + + + +

URL Abstraction

+ +

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

+ +

+    <rule>
+        <from>^/tidy/page$</from>
+        <to>/old/url/scheme/page.jsp</to>
+    </rule>
+    <outbound-rule>
+        <from>^/old/url/scheme/page.jsp$</from>
+        <to>/tidy/page</to>
+    </outbound-rule>
+
+ +

Any incoming requests for /tidy/page will be transparently forwarded to + /old/url/scheme/page.jsp.

+ +

If you use JSTL your JSP page would have something like:

+
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
+ +

This will be rewritten upon output to:

+
<a href="/tidy/page">some link</a>
+ +

Or if you use standard JSP:

+
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
+ +

Will generate output like:

+
<a href="/tidy/page">some link</a>
+ + + + +

mod_rewrite vs urlrewrite filter

+ + +

Examples of mod_rewrite style conf vs urlrewrite filter conf are below, there are all examples copied directly from + Apache 2.0's official rewrite guide.

+ +

+
+<rule>
+    <name>Canonical URLs</name>
+    <note>
+        On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
+        should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
+        of which URL the user supplied with the request he should finally see the canonical one only.
+
+        We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
+        and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
+        fix a missing trailing slash for /u/user.
+
+        RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
+        RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
+    </note>
+    <from>^/~([^/]+)/?(.*)</from>
+    <to type="redirect">/u/$1/$2</to>
+</rule>
+<rule>
+    <from>^/([uge])/([^/]+)$</from>
+    <to type="redirect">/$1/$2/</to>
+</rule>
+
+
+<rule>
+    <name>Canonical Hostnames</name>
+    <note>
+        The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
+        may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
+        example.com, you might use a variant of the following recipe.
+
+        RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
+        RewriteCond %{HTTP_HOST} !^$
+        RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
+    </note>
+    <condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
+    <condition name="host" operator="notequal">^$</condition>
+    <from>^/(.*)</from>
+    <to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
+</rule>
+
+
+<rule>
+    <name>Moved DocumentRoot</name>
+    <note>
+        Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
+        really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
+        Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
+        because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
+        stuff inside this data pool work for subsequent requests.
+
+        We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
+        Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
+        matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
+        With mod_rewrite it is really trivial:
+
+        RewriteRule ^/$ /e/www/ [R]
+    </note>
+    <from>^/$</from>
+    <to type="redirect">/e/www/</to>
+</rule>
+
+
+<rule>
+    <name>Trailing Slash Problem</name>
+    <note>
+        Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
+        If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
+        the server searches for a file named foo. And because this file is a directory it complains. Actually it
+        tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
+        instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
+
+        The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
+        correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
+        we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
+        images are included into this page with relative URLs, because the browser would request an in-lined object.
+        For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
+        external redirect!
+    </note>
+    <from>^/~quux/foo$</from>
+    <to type="redirect">/~quux/foo/</to>
+</rule>
+
+
+<rule>
+    <name>Move Homedirs to Different Webserver</name>
+    <note>
+        Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
+        homedirs on a webserver to another webserver. They usually need such things when establishing a newer
+        webserver which will replace the old one over time.
+
+        The solution is trivial with mod_rewrite (and urlrewrite filter). On the old webserver we just redirect all
+        /~user/anypath URLs to http://newserver/~user/anypath.
+
+        RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
+    </note>
+    <from>^/~(.+)</from>
+    <to type="redirect" last="true">http://newserver/~$1</to>
+</rule>
+
+
+<rule>
+    <name>Structured Homedirs</name>
+    <note>
+        Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
+        subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
+        /home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
+
+        We use the following ruleset to expand the tilde URLs into exactly the above layout.
+
+        RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
+    </note>
+    <from>^/~(([a-z])[a-z0-9]+)(.*)</from>
+    <to>/home/$2/$1/.www$3</to>
+</rule>
+
+
+<rule>
+    <name>Redirect Homedirs For Foreigners</name>
+    <note>
+        We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
+        stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
+
+        Just a rewrite condition:
+
+        RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
+        RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
+    </note>
+    <condition name="host">!^.+\.ourdomain\.com$</condition>
+    <from>^(/~.+)</from>
+    <to type="redirect" last="true">http://www.somewhere.com/$1</to>
+</rule>
+
+
+<rule>
+    <name>Time-Dependent Rewriting</name>
+    <note>
+        When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
+        instance redirects to specialized pages. How can it be done via mod_rewrite?
+
+        There are a lot of types in conjunction with operators we can do time-dependent redirects:
+
+        RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
+        RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
+        RewriteRule ^foo\.html$ foo.day.html
+        RewriteRule ^foo\.html$ foo.night.html
+    </note>
+    <condition type="hourofday" operator="greater">7</condition>
+    <condition type="hourofday" operator="less">19</condition>
+    <from>^foo\.html$</from>
+    <to>foo.day.html</to>
+</rule>
+<rule>
+    <from>^foo\.html$</from>
+    <to>foo.night.html</to>
+</rule>
+
+
+<rule>
+    <name></name>
+    <note>
+        Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
+        backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
+        renamed.
+
+        We rewrite the old URL to the new one internally via the following rule:
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ bar.html
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to>/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+    <name>From Old to New (extern)</name>
+    <note>
+        Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
+        for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
+        i.e. their browsers Location field should change, too.
+
+        We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ bar.html [R]
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to type="redirect">/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+    <name>Browser Dependent Content</name>
+    <note>
+        At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
+        content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
+        the Lynx browsers and a average feature version for all others.
+
+        We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
+        have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
+        "User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
+        stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
+        browsers receive page foo.32.html. This is done by the following ruleset:
+
+        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
+        RewriteRule ^foo\.html$ foo.NS.html [L]
+
+        RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
+        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
+        RewriteRule ^foo\.html$ foo.20.html [L]
+
+        RewriteRule ^foo\.html$ foo.32.html [L]
+    </note>
+    <condition name="user-agent">^Mozilla/3.*</condition>
+    <from>^foo\.html$</from>
+    <to last="true">foo.NS.html</to>
+</rule>
+<rule>
+    <condition name="user-agent" next="or">^Lynx/.*</condition>
+    <condition name="user-agent">^Mozilla/[12].*</condition>
+    <from>^foo\.html$</from>
+    <to last="true">foo.20.html</to>
+</rule>
+<rule>
+    <from>^foo\.html$</from>
+    <to last="true">foo.32.html</to>
+</rule>
+
+
+<rule>
+    <name>From Static to Dynamic</name>
+    <note>
+        How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
+        notice by the browser/user.
+
+        We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
+        a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to>/~quux/foo.jsp</to>
+</rule>
+
+<rule>
+    <name>Blocking of Robots</name>
+    <note>
+        How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
+        containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
+
+        We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
+        indexed area where the robot traversal would create big server load). We have to make sure that we forbid
+        access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
+        This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
+        information.
+
+        RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
+        RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
+        RewriteRule ^/~quux/foo/arc/.+ - [F]
+    </note>
+    <condition name="user-agent">^NameOfBadRobot.*</condition>
+    <condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
+    <from>^/~quux/foo/arc/.+</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+
+<rule>
+    <name>Blocked Inline-Images</name>
+    <note>
+        Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
+        nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
+        it adds useless traffic to our server.
+
+        While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
+        sends a HTTP Referer header.
+
+        RewriteCond %{HTTP_REFERER} !^$
+        RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
+        RewriteRule .*\.gif$ - [F]
+    </note>
+    <condition name="referer" operator="notequal">^$</condition>
+    <condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
+    <from>.*\.gif$</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+<rule>
+    <name>Blocked Inline-Images example 2</name>
+    <note>
+        RewriteCond %{HTTP_REFERER} !^$
+        RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
+        RewriteRule ^inlined-in-foo\.gif$ - [F]
+    </note>
+    <condition name="referer" operator="notequal">^$</condition>
+    <condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
+    <from>^inlined-in-foo\.gif$</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+
+ + + +
+ + + + + + diff --git a/src/doc/manual/3.2/index.html b/src/doc/manual/3.2/index.html index 58da745a..d7552c3c 100644 --- a/src/doc/manual/3.2/index.html +++ b/src/doc/manual/3.2/index.html @@ -1,1458 +1,1458 @@ - - - - UrlRewriteFilter - Manual - - - - - - - - - -
- - - -

Manual

- - -

Community support is available at UrlRewrite on StackOverflow.

- -

Read examples of usage and a - sample of the ant task report. - If you have feedback, or conf you want to share with the world email me. - If you have any suggestions/examples for this manual please post them to the - group.

- - - -

Install

- -
    -
  1. Download the zip (or tar.gz) and extract it into your - context's directory ie, so that urlrewrite.xml goes into the WEB-INF directory.
  2. -
  3. Add the following to your WEB-INF/web.xml (add it near the top above your - servlet mappings (if you have any)): (see filter - parameters for more options) -
    
    -    <filter>
    -        <filter-name>UrlRewriteFilter</filter-name>
    -        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    -    </filter>
    -    <filter-mapping>
    -        <filter-name>UrlRewriteFilter</filter-name>
    -        <url-pattern>/*</url-pattern>
    -        <dispatcher>REQUEST</dispatcher>
    -        <dispatcher>FORWARD</dispatcher>
    -    </filter-mapping>
    -        
  4. -
  5. Add your own configuration to the WEB-INF/urlrewrite.xml that was created.
  6. -
  7. Restart the context.
  8. -
- -

You can visit http://127.0.0.1:8080/rewrite-status - (or whatever the address of your local webapp and context) - to see output (note: this page is only viewable from localhost).

- - - -

Filter Parameters

- -

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

- -

-    <filter>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-        <!-- set the amount of seconds the conf file will be checked for reload
-        can be a valid integer (0 denotes check every time,
-        -1 denotes no reload check, default -1) -->
-        <init-param>
-            <param-name>confReloadCheckInterval</param-name>
-            <param-value>60</param-value>
-        </init-param>
-
-        <!-- if you need to the conf file path can be changed
-        it is specified as a path relative to the root of your context
-        (default /WEB-INF/urlrewrite.xml) -->
-        <init-param>
-            <param-name>confPath</param-name>
-            <param-value>/WEB-INF/urlrewrite.xml</param-value>
-        </init-param>
-
-        <!-- sets up log level (will be logged to context log)
-        can be: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL, log4j, commons, slf4j,
-        sysout:{level} (ie, sysout:DEBUG)
-        if you are having trouble using normal levels use sysout:DEBUG
-        (default WARN) -->
-        <init-param>
-            <param-name>logLevel</param-name>
-            <param-value>DEBUG</param-value>
-        </init-param>
-
-        <!-- you can change status path so that it does not
-        conflict with your installed apps (note, defaults
-        to /rewrite-status) note, must start with / -->
-        <init-param>
-            <param-name>statusPath</param-name>
-            <param-value>/status</param-value>
-        </init-param>
-
-        <!-- you can disable status page if desired
-        can be: true, false (default true) -->
-        <init-param>
-            <param-name>statusEnabled</param-name>
-            <param-value>true</param-value>
-        </init-param>
-
-        <!-- you may want to allow more hosts to look at the status page
-        statusEnabledOnHosts is a comma delimited list of hosts, * can
-        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
-        <init-param>
-            <param-name>statusEnabledOnHosts</param-name>
-            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
-        </init-param>
-
-        <!-- you may want to allow more hosts to look at the status page
-        statusEnabledOnHosts is a comma delimited list of hosts, * can
-        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
-        <init-param>
-            <param-name>statusEnabledOnHosts</param-name>
-            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
-        </init-param>
-
-        <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
-        is not specified confPath will be set to /WEB-INF/.htaccess) -->
-        <init-param>
-            <param-name>modRewriteConf</param-name>
-            <param-value>false</param-value>
-        </init-param>
-
-        <!-- load mod_rewrite style configuration from this parameter's value.
-                note, Setting this parameter will mean that all other conf parameters are ignored.
-            <init-param>
-                <param-name>modRewriteConfText</param-name>
-                <param-value>
-                    RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
-                    RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
-                </param-value>
-            </init-param>
-        -->
-
-        <!-- defaults to false. allow conf file to be set by calling /rewrite-status/?conf=/WEB-INF/urlrewrite2.xml
-                designed to be used for testing only
-            <init-param>
-                <param-name>allowConfSwapViaHttp</param-name>
-                <param-value>false</param-value>
-            </init-param>
-        -->
-
-    </filter>
-
-    <filter-mapping>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <url-pattern>/*</url-pattern>
-        <dispatcher>REQUEST</dispatcher>
-        <dispatcher>FORWARD</dispatcher>
-    </filter-mapping>
-
- -

Note, setting logLevel to log4j or commons will cause the built in loging to - call either log4j or - commons-logging as if they were the logging framework, - obviously you will need to have the jar for log4j or commons-logging in your classpath.

- - - -

Configuration File WEB-INF/urlrewrite.xml

- - - - - -
- - <urlrewrite>   - <rule>   - <outbound-rule>   - <class-rule> -
- <name>   - <note>   - <condition>   - <from>   - <to>   - <set>   - <run>   -
- Back References   - Variables   - Functions   -
-
-
- -

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named - urlrewrite.xml. - It may be helpful to read the UrlRewriteFilter DTD - (Document Type Definition). Please also make sure you look at the examples. A simple - configuration file looks like:

- -

-    <?xml version="1.0" encoding="utf-8"?>
-
-    <!DOCTYPE urlrewrite
-        PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
-        "http://www.tuckey.org/res/dtds/urlrewrite3.2.dtd">
-
-    <urlrewrite>
-
-        <rule>
-           <from>^/some/olddir/(.*)$</from>
-           <to type="redirect">/very/newdir/$1</to>
-        </rule>
-
-        <rule match-type="wildcard">
-           <from>/blog/archive/**</from>
-           <to type="redirect">/roller/history/$1</to>
-        </rule>
-
-    </urlrewrite>
-
- - -

The urlrewrite.xml file must have a root element called "urlrewrite" and must contain - at least one "rule" element.

- -

A "rule" must contain a "from" and a "to", and can have zero or more "condition" elements and zero or more and/or - "set" elements.

- -

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then - the "from" will be applied to the request URL and the final URL generated by applying the - "to" to the "from" pattern. So long as the rule has matched then the "set" will be run.

- - - -

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

- -

-    Pattern.compile(<from> element);
-    pattern.matcher(request url);
-    matcher.replaceAll(<to> element);
-    if ( <condition> elements match && matcher.find() ) {
-        handle <set> elements (if any)
-        execute <run> elements (if any)
-        perform <to> element (if any)
-    }
-
- - - -

<urlrewrite> element

- -

The top level element.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
default-match-type
(optional)
regex (default)All rules and thier conditions will be processed using the Java Regular Expression engine (unless - match-type is specified on a rule).
wildcardAll rules and thier conditions will be processed using the Wildcard Expression - engine - (unless match-type is specified on a rule).
decode-using
(optional)
header,utf8 (default)When URL is decoded request.getCharacterEncoding() will be used, if that is empty UTF-8 will be used. -
nullDo not decode at all. (note, this means the literal string null e.g. decode-using="null")
headerOnly use request.getCharacterEncoding() to decode.
[encoding]Only use a specific character encoding eg, ISO-8859-1. - See Java Charset Object - for all character encodings. -
header,[encoding] - When URL is decoded request.getCharacterEncoding() will be used, if that is empty a specific character - encoding eg, ISO-8859-1. - See Java Charset Object - for all character encodings. -
use-query-string
(optional)
false (default)The query string will not be appended to the url that the "from" element matches against.
trueThe query string will be appended to the url that the "from" element matches against.
use-context
(optional)
false (default)The context path will not be added to the url that the "from" element matches against.
trueThe context path will be added to the url that the "from" element matches against.
- - - -

<rule> element

- -

Zero or more. The basis of a rule.

- - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
match-type
(optional)
regex (default)This rule and it's conditions will be processed using the Java Regular Expression engine.
wildcardThis rule and it's conditions will be processed using the Wildcard Expression engine. -
- -

In the following example requests for /world/usa/nyc will be transparently forwarded to - /world.jsp

- -

-    <rule match-type="regex">
-       <from>^/world/([a-z]+)/([a-z]+)$</from>
-       <to>/world.jsp</to>
-    </rule>
-
- -

-    <rule match-type="wildcard">
-       <from>/world/*/*</from>
-       <to>/world.jsp</to>
-    </rule>
-
- - - -

<outbound-rule> element

- -

Zero or more. This is very similar to a normal rule but it is used for rewriting urls that go through - response.encodeURL().

- - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
false (default)Run encodeURL() after running this outbound rule.
trueRun encodeURL() before running this outbound rule.
- -

May contain "run", "from", "to" and "set" element(s) also. Example:

- -

-    <outbound-rule>
-        <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
-        <to>/world/$1/$2</to>
-    </outbound-rule>
-
- -

Using the example above JSP's with the code -
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") - %>">nyc</a> -
will output -
<a href="/world/usa/nyc">nyc</a> -

- -

Or JSTL -
<a href="<c:url value="/world.jsp?country=${country}&amp;city=${city}" - />">nyc</a> -
will output -
<a href="/world/usa/nyc">nyc</a> -

- -

Note, If you are using JSTL (ie, <c:url) this will work also.

- - - -

<name> element

- -

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. - See ant task.

- -

-    <rule>
-        <name>World Rule</name>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- - - -

<note> element

- -

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. - See ant task.

- -

-    <rule>
-        <name>World Rule</name>
-        <note>
-            Cleanly redirect world requests to JSP,
-            a country and city must be specified.
-        </note>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp</to>
-    </rule>
-
- - - -

<condition> element

- -

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run - (unless "next" is set to "or" obvoiusly).

- -

Value can be any Regular Expression.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD etc.
portThe port that the web application server is running on.
time - Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC otherwise known as unix - time). -
i.e. (new Date()).getTime() -
This can be used for making sure content goes live only at a time you set. -
year - Current year at the server. -
i.e. (Calendar.getInstance()).get(Calendar.YEAR) -
month - Month at the server. January is 0 -
i.e. (Calendar.getInstance()).get(Calendar.MONTH) -
dayofmonth - Day of the month at the server. March first is 1 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) -
dayofweek - Day of the week at the server. Saturday is 1, Sunday is 7 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) -
ampm - AM or PM time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) -
hourofday - The hour of the day (24 hour clock) at the server. 10pm is 22 -
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) -
minute - The minute field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) -
second - The second field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.SECOND) -
millisecond - The millisecond field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) -
attribute - Will check the value of a request attribute (don't confuse this with parameter!), name must be set when - using this type. -
i.e. request.getAttribute([name]) - -
auth-type - Will check the value of a request attribute (don't confuse this with parameter!) -
i.e. request.getAuthType() - -
character-encoding - The character encoding of the imcoming request. -
i.e. request.getCharacterEncoding() - -
content-length - The length of the imcoming request (can be useful if you want to deny large requests). -
i.e. request.getContentLength() - -
content-type - The type of the imcoming request. (this is probably not that useful) -
i.e. request.getContentType() - -
context-path - The context path of the imcoming request. -
i.e. request.getContextPath() - -
cookie - The value of a cookie, note, name must be specified to use this -
i.e. request.getCookies() - the find we the one with [name] specified and check the value. -
parameter - A tidier way of checking request parameters than looking for them in the query string. This will check for the - parameter in GET or POST, note, name must be specified. -
i.e. request.getParameter([name]) - -
path-info - i.e. request.getPathInfo() - -
path-translated - i.e. request.getPathTranslated() - -
protocolThe protocol used to make the request, e.g. HTTP/1.1 -
i.e. request.getProtocol() - -
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob -
i.e. request.getQueryString() - -
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 -
i.e. request.getRemoteAddr() - -
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, - this will only work if your app server is configured to lookup host names, most aren't). -
i.e. request.getRemoteHost() - -
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt -
i.e. request.getRemoteUser() - -
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 -
i.e. request.getRequestedSessionId() - -
requested-session-id-from-cookieWhether the requested session ID is from a cookie or not -
i.e. request.isRequestedSessionIdFromCookie() - -
requested-session-id-from-urlWhether the requested session ID is from the URL or not -
i.e. request.isRequestedSessionIdFromURL() - -
requested-session-id-validWhether the requested session ID is valid or not -
i.e. request.isRequestedSessionIdValid() - -
request-uriReturns the part of this request's URL from the protocol name up to the query - string in the first line of the HTTP request -
i.e. request.getRequestURI() - -
request-urlReconstructs the URL the client used to make the request. The returned URL - contains a protocol, server name, port number, and server path, but it does not include query string parameters. -
i.e. request.getRequestURL() - -
session-attribute - (note, name must be set) -
i.e. session.getAttribute([name]) - -
session-isnew - Weather the session is new or not. -
i.e. session.isNew() - -
server-name - The host name of the server to which the request was sent (from the host header not the machine name). -
i.e. request.getServerName() - -
scheme - The scheme used for the request, e.g. http or https -
i.e. request.getScheme() - -
user-in-role - (Note, the value for this cannot be a regular expression) -
i.e. request.isUserInRole([value]) - -
name
(optional)
(can be anything)If type is header, this specifies the name of the HTTP header used to run the value - against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator to be used when the condition is run, the regular expression matches or the values are - equal.
notequalNot equal to. (i.e. request value != condition value). Note, this operator only work with - numeric rule types.
greaterGreater than. (i.e. request value > condition value). Note, this operator only work with - numeric - rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only work with numeric - rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator - only - work with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only - work with numeric rule types.
- -

Examples:

- -

-    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-
-    <condition type="user-in-role" operator="notequal">bigboss</condition>
-
-    <condition name="host" operator="notequal">www.example.com</condition>
-
-    <condition type="method" next="or">PROPFIND</condition>
-    <condition type="method">PUT</condition>
-
- - - -

<from> element

- -

You must always have exactly one from for each rule or outbound-rule. Value can be a regular expression in the - Perl5 style. Note, from url's are relative to the context.

- - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using case insentitive match. ie, "/WellingtoN" will match "/wellington". -
trueThis value will be matched using case sentitive match. ie, "/aAa" will NOT match "/aaa". -
- -

Example:

- -

-    <from>^/world/([a-z]+)$</from>
-
- - -

<to> element

- -

Value can be a regular replacement expression in the Perl5 style.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally - forwarded - to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as - UrlRewriteFilter. This is the same as doing: -
RequestDispatcher rq = request.getRequestDispatcher([to value]); -
rq.forward(request, response);
-
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. - This is the same a doing: -
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_PERMANENTLY is HTTP status code 301)
temporary-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
pre-include
post-include
proxyThe request will be proxied to the full url specified. commons-http and commons-codec must both be in the - classpath to use this feature. -
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) - will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) - will NOT be called.
context
(optional)
If your application server is configured to allow "cross context" communication then this attribute can be used - to forward (and only forward, not redirect or other "to" types) requests to a named servlet context. -
-
On Tomcat, for instance, the application contexts in the server configuration (server.xml or - context.xml) need the option crossContext="true". For instance, the two applications mentioned before - ("app" and "forum") have to be defined as: -
-
<Context docBase="app" path="/app" reloadable="true" crossContext="true"/> -
<Context docBase="forum" path="/forum" reloadable="true" crossContext="true"/> -
- -

Note, "to" can be null ie, <to>null</to>, this will mean that the request will go no - further if the rule is matched (ie, this filter will not call chain.doFilter).

- -

If "to" is set to -, no substitution will take place and the request will go on like nothing happened (ie, this filter will call chain.doFilter).

- -

-    <to>/world.jsp?country=$1</to>
-
- -

To elements can contain backreferences and variables.

- - -

Backreferences

- -

-    %N
-
- -

Provides access to the grouped parts (parentheses) of the pattern from the last matched Condition - in the current rule. - N must be less than 10 and greater than 0 (i.e. %1, %2, %3 etc).

- - -

Variables

- -

-    %{VARIABLE-NAME}
-
- -

Any valid condition type can be used as a variable name. ie, - '%{port}' will be translated to '80', - '%{year}' to '2005', - '%{cookie:myCookie}' would be translated to - 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

- -

Valid types are condition types, see condition for a full description.

- - -

Functions

- -

-    ${FUNCTION:PARAMS}
-
- -

Functions can be places in set and to elements.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
nameexampleexample returns
replace${replace:my cat is a blue cat:cat:dog}my dog is a blue dog
replaceFirst${replaceFirst:my cat is a blue cat:cat:dog}my cat is a blue dog
escape${escape:a b c}a+b+c
unescape${unescape:a+b+c}a b c
lower${lower:Hello World}hello world
upper${upper:hello}HELLO
trim${trim: abc def }abc def
- - - -

<set> element

- -

Allows you to set varous things if the rule is matched.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], - [value]) - (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], - [value]) - (note, name must be set).
response-headerThe same as response.setHeader([name], - [value]) - (note, name must be set).
cookie - Value can be in the format "[value][:domain[:lifetime[:path]]]". - This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain - field is the domain of the cookie, such as '.apache.org',the optional lifetime is the lifetime of the cookie - in seconds, and the optional path is the path of the cookie (note, name must be set). -
statusThe same as response.setStatus([value]) -
content-typeThe same as response.setContentType([value]) -
charsetThe same as response.setCharacterEncoding([value]) -
expiresWill set the Expires HTTP header by adding the time specified and current time - (this is mod_expires style). Syntax "{num type}*". - Units can be (singular or plural); - years, months, weeks, days, hours, minutes, seconds. -
eg, "1 day 2 seconds", "3 hours", "1 year 1 hour" -
localeThe same as response.setLocale([value]) - - specify the Locale in the format - (valid - locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). -
parameterEnables you to override a request.getParameter(String) with a custom value
methodEnables you to override request.getMethod() with a custom value
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
- -

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be - fetched in a servlet or - JSP using request.getAttribute("client").

- -

-    <rule>
-        <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
-        <from>.*</from>
-        <set name="client">AvantGo</set>
-    </rule>
-    <rule>
-        <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
-        <from>.*</from>
-        <set name="client">Samsung SCH-6100</set>
-    </rule>
-
- -

It is also possible to use regular replacement expressions as part of the - value similar to their usage in <to> elements:

- -

-    <rule>
-        <from>/products/(.*)/(.*)/index.html</from>
-        <set name="urlrewrite.product.slug">$1</set>
-        <set name="urlrewrite.product.id">$2</set>
-        <to>/products?slug=$1&id=$2</to>
-    </rule>
-
- - -

<run> element

- -

Allows you to run a method on an object when a rule and it's conditions are matched.

- - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible valueExplanation
class The class you want to run a method on. Must be a fully qualified name.
method (optional)run (default)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) - e.g. run(HttpServletRequest request, HttpServletResponse response) -
Note, if init(ServletConfig) or destroy() is found they will be run at when - creating - or destroying an instance. -
neweachtime (optional)false (default)One instance for each UrlRewriteFilter instance.
trueA new instance of the class will be created before running each time set to true.
- -

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, - HttpServletResponse) - will be invoked, the request will then be forwarded to /world-presentation.jsp.

- -

-    <rule>
-        <from>^/world/[a-z]+/[a-z]+$</from>
-        <run class="com.blah.web.WorldServlet" method="doGet" />
-        <to>/world-presentation.jsp</to>
-    </rule>
-
- -

Note, you can specify init-param's the same way you would for a servlet.

- -

-    <run class="com.blah.web.MyServlet" method="doGet">
-        <init-param>
-            <param-name>someParamName</param-name>
-            <param-value>10</param-value>
-        </init-param>
-    </run>
-
- -

If the method being called throws an Exception the original exception will be re-thrown as if it were the original - if it extends RuntimeException (eg, NullPointer), other exceptions are wrapped in a ServletException and thrown - so your container can handle them.

- - - -

<class-rule> element

- -

Allows you to run a method every time a request come in for 100% dynamic rules. See the org.tuckey.web.filters.urlrewrite.sample package for an example.

- - - - - - - - - - - - - - - - - - -
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default matches)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) - e.g. run(HttpServletRequest request, HttpServletResponse response) -
Note, if init(ServletConfig) or destroy() is found they will be run at when - creating or destroying an instance. -
last (optional, default trueIf false more rules will be processed following this rule even if it is matched (so that a better match may be found).
- -

Example:

- -

-    <class-rule class="com.blah.web.MyRuleClass" />
-
- - - -

Tips

- -
    -
  • When you want to put an "&" in a rule you must enter it as the XML entity "&amp;"
  • -
  • For simplicity you might want to start all from's with a ^ and end them with a $. -
    In regular expressions ^ specifies the start of - the string and $ specifies the end. -
    ie, a request for /my/url/path will NOT match - <from>^/url/$</from> but it will match <from>/url/</from> -
    -
  • If using <outbound-rule> remember all urls in your code must be encoded e.g. - <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • -
  • Regular expressions are complex and a bit tricky at times, read - regular expression syntax for - Java. -
  • -
  • If you find regular expressions difficult use Wildcards.
  • -
  • "Context" is important. If you have an app with the context "/myapp" and you request the url - "/myapp/somefolder/somepage.jsp", the container tells UrlRewriteFilter that the url is "/somefolder/somepage.jsp". - This can be confusing, but basically your rules and conditions should not contain the context path - (it will be handled by the container).
  • -
- - - - - -

Wildcard Matching Engine

- -

The wildcard matching engine can be used instead of regex. It is supported in conditions and rules - where match-type is set to wildcard (or default-match-type is set on the - urlrewrite element

- -

e.g. /big/url/* will match /big/url/abc.html but will NOT - match /big/url/abc/dir/ or /big/url/abc/. - -

/big/url/** will match /big/url/abc.html, /big/url/abc/dir/ and - /big/url/abc/. - -

You can also use Regular expression style variable replacement, each match of a * will - be available for use in to and set elements using simple $1 - $2 variables.

- -

e.g. /my/big/url/* will match /my/big/url/abc.html and $1 - will be set to abc.html.

- -

Added in 3.0

- - - -

Ant Task

- -

An Ant task has been written to allow validate the conf file and generation - of documentation. You can view a sample.

- -

Paste the following into your build.xml file, then change the dest - and conf to point to the correct places. Note, the urlrewrite jar - file will need to be in your classpath.

- -

-    <target name="urlrewrite-doc" depends="compile"
-        description="UrlRewriteFilter validation and documenting">
-
-    <taskdef name="urlrewritedoc" classpath="lib/urlrewrite-3.2.0.jar"
-        classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
-    <urlrewritedoc
-        conf="${build.home}/WEB-INF/urlrewrite.xml"
-        dest="urlrewrite-conf-overview.html" />
-    </target>
-
- - - -

mod_rewrite Style Configuration

- -

Sample web.xml snippet:

- -

-     <filter>
-         <filter-name>UrlRewriteFilter</filter-name>
-         <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-         <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
-         is not specified confPath will be set to /WEB-INF/.htaccess) -->
-         <init-param>
-             <param-name>modRewriteConfText</param-name>
-             <param-value><![CDATA[
-
-                 # redirect mozilla to another area
-                 RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
-                 RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
-
-             ]]></param-value>
-         </init-param>
-
-     </filter>
-
-     <filter-mapping>
-         <filter-name>UrlRewriteFilter</filter-name>
-         <url-pattern>/*</url-pattern>
-         <dispatcher>REQUEST</dispatcher>
-         <dispatcher>FORWARD</dispatcher>
-     </filter-mapping>
-
- - -

OR alternately set modRewriteConf to true in filter parameters and add a WEB-INF/.htaccess file with - your mod_rewrite style configuration in it.

- -

-    <filter>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-        <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
-        is not specified confPath will be set to /WEB-INF/.htaccess) -->
-        <init-param>
-            <param-name>modRewriteConf</param-name>
-            <param-value>true</param-value>
-        </init-param>
-
-    </filter>
-
-    <filter-mapping>
-        <filter-name>UrlRewriteFilter</filter-name>
-        <url-pattern>/*</url-pattern>
-        <dispatcher>REQUEST</dispatcher>
-        <dispatcher>FORWARD</dispatcher>
-    </filter-mapping>
-
- -

Sample: WEB-INF/.htaccess

- -

-     # redirect mozilla to another area
-     RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
-     RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
- 
- -

- - Documentation for the original mod_rewrite library - mostly applies, differences are documented below.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributeExplanation
RewriteLogLevelSpecified as int, trasnlated as: <= 1 - FATAL, 2 - ERROR, 3 - INFO, 4 - WARN, >= 5 DEBUG
RewriteLogSYSOUT, SYSERR, log4j, commons (if not set context logging will be used)
RewriteRule - Supported but note: - - - Certain flags not supported: -
    -
  • chain flag [C] not supported
  • -
  • env flag [E] not supported
  • -
  • next flag [N] not supported
  • -
  • nosubreq flag [NS] not supported
  • -
  • qsappend flag [QSA] not supported
  • -
  • Skip flag [S] not supported
  • -
-
RewriteBaseNot supported
RewriteLockNot supported
RewriteMapNot supported
RewriteOptionsNot supported
- - -
- - - - - - + + + + UrlRewriteFilter - Manual + + + + + + + + + +
+ + + +

Manual

+ + +

Community support is available at UrlRewrite on StackOverflow.

+ +

Read examples of usage and a + sample of the ant task report. + If you have feedback, or conf you want to share with the world email me. + If you have any suggestions/examples for this manual please post them to the + group.

+ + + +

Install

+ +
    +
  1. Download the zip (or tar.gz) and extract it into your + context's directory ie, so that urlrewrite.xml goes into the WEB-INF directory.
  2. +
  3. Add the following to your WEB-INF/web.xml (add it near the top above your + servlet mappings (if you have any)): (see filter + parameters for more options) +
    
    +    <filter>
    +        <filter-name>UrlRewriteFilter</filter-name>
    +        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    +    </filter>
    +    <filter-mapping>
    +        <filter-name>UrlRewriteFilter</filter-name>
    +        <url-pattern>/*</url-pattern>
    +        <dispatcher>REQUEST</dispatcher>
    +        <dispatcher>FORWARD</dispatcher>
    +    </filter-mapping>
    +        
  4. +
  5. Add your own configuration to the WEB-INF/urlrewrite.xml that was created.
  6. +
  7. Restart the context.
  8. +
+ +

You can visit http://127.0.0.1:8080/rewrite-status + (or whatever the address of your local webapp and context) + to see output (note: this page is only viewable from localhost).

+ + + +

Filter Parameters

+ +

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

+ +

+    <filter>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+        <!-- set the amount of seconds the conf file will be checked for reload
+        can be a valid integer (0 denotes check every time,
+        -1 denotes no reload check, default -1) -->
+        <init-param>
+            <param-name>confReloadCheckInterval</param-name>
+            <param-value>60</param-value>
+        </init-param>
+
+        <!-- if you need to the conf file path can be changed
+        it is specified as a path relative to the root of your context
+        (default /WEB-INF/urlrewrite.xml) -->
+        <init-param>
+            <param-name>confPath</param-name>
+            <param-value>/WEB-INF/urlrewrite.xml</param-value>
+        </init-param>
+
+        <!-- sets up log level (will be logged to context log)
+        can be: TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL, log4j, commons, slf4j,
+        sysout:{level} (ie, sysout:DEBUG)
+        if you are having trouble using normal levels use sysout:DEBUG
+        (default WARN) -->
+        <init-param>
+            <param-name>logLevel</param-name>
+            <param-value>DEBUG</param-value>
+        </init-param>
+
+        <!-- you can change status path so that it does not
+        conflict with your installed apps (note, defaults
+        to /rewrite-status) note, must start with / -->
+        <init-param>
+            <param-name>statusPath</param-name>
+            <param-value>/status</param-value>
+        </init-param>
+
+        <!-- you can disable status page if desired
+        can be: true, false (default true) -->
+        <init-param>
+            <param-name>statusEnabled</param-name>
+            <param-value>true</param-value>
+        </init-param>
+
+        <!-- you may want to allow more hosts to look at the status page
+        statusEnabledOnHosts is a comma delimited list of hosts, * can
+        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
+        <init-param>
+            <param-name>statusEnabledOnHosts</param-name>
+            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
+        </init-param>
+
+        <!-- you may want to allow more hosts to look at the status page
+        statusEnabledOnHosts is a comma delimited list of hosts, * can
+        be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
+        <init-param>
+            <param-name>statusEnabledOnHosts</param-name>
+            <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
+        </init-param>
+
+        <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
+        is not specified confPath will be set to /WEB-INF/.htaccess) -->
+        <init-param>
+            <param-name>modRewriteConf</param-name>
+            <param-value>false</param-value>
+        </init-param>
+
+        <!-- load mod_rewrite style configuration from this parameter's value.
+                note, Setting this parameter will mean that all other conf parameters are ignored.
+            <init-param>
+                <param-name>modRewriteConfText</param-name>
+                <param-value>
+                    RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
+                    RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
+                </param-value>
+            </init-param>
+        -->
+
+        <!-- defaults to false. allow conf file to be set by calling /rewrite-status/?conf=/WEB-INF/urlrewrite2.xml
+                designed to be used for testing only
+            <init-param>
+                <param-name>allowConfSwapViaHttp</param-name>
+                <param-value>false</param-value>
+            </init-param>
+        -->
+
+    </filter>
+
+    <filter-mapping>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+        <dispatcher>REQUEST</dispatcher>
+        <dispatcher>FORWARD</dispatcher>
+    </filter-mapping>
+
+ +

Note, setting logLevel to log4j or commons will cause the built in loging to + call either log4j or + commons-logging as if they were the logging framework, + obviously you will need to have the jar for log4j or commons-logging in your classpath.

+ + + +

Configuration File WEB-INF/urlrewrite.xml

+ + + + + +
+ + <urlrewrite>   + <rule>   + <outbound-rule>   + <class-rule> +
+ <name>   + <note>   + <condition>   + <from>   + <to>   + <set>   + <run>   +
+ Back References   + Variables   + Functions   +
+
+
+ +

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named + urlrewrite.xml. + It may be helpful to read the UrlRewriteFilter DTD + (Document Type Definition). Please also make sure you look at the examples. A simple + configuration file looks like:

+ +

+    <?xml version="1.0" encoding="utf-8"?>
+
+    <!DOCTYPE urlrewrite
+        PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
+        "http://www.tuckey.org/res/dtds/urlrewrite3.2.dtd">
+
+    <urlrewrite>
+
+        <rule>
+           <from>^/some/olddir/(.*)$</from>
+           <to type="redirect">/very/newdir/$1</to>
+        </rule>
+
+        <rule match-type="wildcard">
+           <from>/blog/archive/**</from>
+           <to type="redirect">/roller/history/$1</to>
+        </rule>
+
+    </urlrewrite>
+
+ + +

The urlrewrite.xml file must have a root element called "urlrewrite" and must contain + at least one "rule" element.

+ +

A "rule" must contain a "from" and a "to", and can have zero or more "condition" elements and zero or more and/or + "set" elements.

+ +

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then + the "from" will be applied to the request URL and the final URL generated by applying the + "to" to the "from" pattern. So long as the rule has matched then the "set" will be run.

+ + + +

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

+ +

+    Pattern.compile(<from> element);
+    pattern.matcher(request url);
+    matcher.replaceAll(<to> element);
+    if ( <condition> elements match && matcher.find() ) {
+        handle <set> elements (if any)
+        execute <run> elements (if any)
+        perform <to> element (if any)
+    }
+
+ + + +

<urlrewrite> element

+ +

The top level element.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
default-match-type
(optional)
regex (default)All rules and thier conditions will be processed using the Java Regular Expression engine (unless + match-type is specified on a rule).
wildcardAll rules and thier conditions will be processed using the Wildcard Expression + engine + (unless match-type is specified on a rule).
decode-using
(optional)
header,utf8 (default)When URL is decoded request.getCharacterEncoding() will be used, if that is empty UTF-8 will be used. +
nullDo not decode at all. (note, this means the literal string null e.g. decode-using="null")
headerOnly use request.getCharacterEncoding() to decode.
[encoding]Only use a specific character encoding eg, ISO-8859-1. + See Java Charset Object + for all character encodings. +
header,[encoding] + When URL is decoded request.getCharacterEncoding() will be used, if that is empty a specific character + encoding eg, ISO-8859-1. + See Java Charset Object + for all character encodings. +
use-query-string
(optional)
false (default)The query string will not be appended to the url that the "from" element matches against.
trueThe query string will be appended to the url that the "from" element matches against.
use-context
(optional)
false (default)The context path will not be added to the url that the "from" element matches against.
trueThe context path will be added to the url that the "from" element matches against.
+ + + +

<rule> element

+ +

Zero or more. The basis of a rule.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
match-type
(optional)
regex (default)This rule and it's conditions will be processed using the Java Regular Expression engine.
wildcardThis rule and it's conditions will be processed using the Wildcard Expression engine. +
+ +

In the following example requests for /world/usa/nyc will be transparently forwarded to + /world.jsp

+ +

+    <rule match-type="regex">
+       <from>^/world/([a-z]+)/([a-z]+)$</from>
+       <to>/world.jsp</to>
+    </rule>
+
+ +

+    <rule match-type="wildcard">
+       <from>/world/*/*</from>
+       <to>/world.jsp</to>
+    </rule>
+
+ + + +

<outbound-rule> element

+ +

Zero or more. This is very similar to a normal rule but it is used for rewriting urls that go through + response.encodeURL().

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
false (default)Run encodeURL() after running this outbound rule.
trueRun encodeURL() before running this outbound rule.
+ +

May contain "run", "from", "to" and "set" element(s) also. Example:

+ +

+    <outbound-rule>
+        <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
+        <to>/world/$1/$2</to>
+    </outbound-rule>
+
+ +

Using the example above JSP's with the code +
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") + %>">nyc</a> +
will output +
<a href="/world/usa/nyc">nyc</a> +

+ +

Or JSTL +
<a href="<c:url value="/world.jsp?country=${country}&amp;city=${city}" + />">nyc</a> +
will output +
<a href="/world/usa/nyc">nyc</a> +

+ +

Note, If you are using JSTL (ie, <c:url) this will work also.

+ + + +

<name> element

+ +

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +

+    <rule>
+        <name>World Rule</name>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ + + +

<note> element

+ +

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +

+    <rule>
+        <name>World Rule</name>
+        <note>
+            Cleanly redirect world requests to JSP,
+            a country and city must be specified.
+        </note>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp</to>
+    </rule>
+
+ + + +

<condition> element

+ +

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run + (unless "next" is set to "or" obvoiusly).

+ +

Value can be any Regular Expression.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD etc.
portThe port that the web application server is running on.
time + Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC otherwise known as unix + time). +
i.e. (new Date()).getTime() +
This can be used for making sure content goes live only at a time you set. +
year + Current year at the server. +
i.e. (Calendar.getInstance()).get(Calendar.YEAR) +
month + Month at the server. January is 0 +
i.e. (Calendar.getInstance()).get(Calendar.MONTH) +
dayofmonth + Day of the month at the server. March first is 1 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) +
dayofweek + Day of the week at the server. Saturday is 1, Sunday is 7 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) +
ampm + AM or PM time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) +
hourofday + The hour of the day (24 hour clock) at the server. 10pm is 22 +
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) +
minute + The minute field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) +
second + The second field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.SECOND) +
millisecond + The millisecond field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) +
attribute + Will check the value of a request attribute (don't confuse this with parameter!), name must be set when + using this type. +
i.e. request.getAttribute([name]) + +
auth-type + Will check the value of a request attribute (don't confuse this with parameter!) +
i.e. request.getAuthType() + +
character-encoding + The character encoding of the imcoming request. +
i.e. request.getCharacterEncoding() + +
content-length + The length of the imcoming request (can be useful if you want to deny large requests). +
i.e. request.getContentLength() + +
content-type + The type of the imcoming request. (this is probably not that useful) +
i.e. request.getContentType() + +
context-path + The context path of the imcoming request. +
i.e. request.getContextPath() + +
cookie + The value of a cookie, note, name must be specified to use this +
i.e. request.getCookies() + the find we the one with [name] specified and check the value. +
parameter + A tidier way of checking request parameters than looking for them in the query string. This will check for the + parameter in GET or POST, note, name must be specified. +
i.e. request.getParameter([name]) + +
path-info + i.e. request.getPathInfo() + +
path-translated + i.e. request.getPathTranslated() + +
protocolThe protocol used to make the request, e.g. HTTP/1.1 +
i.e. request.getProtocol() + +
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob +
i.e. request.getQueryString() + +
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 +
i.e. request.getRemoteAddr() + +
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, + this will only work if your app server is configured to lookup host names, most aren't). +
i.e. request.getRemoteHost() + +
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt +
i.e. request.getRemoteUser() + +
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 +
i.e. request.getRequestedSessionId() + +
requested-session-id-from-cookieWhether the requested session ID is from a cookie or not +
i.e. request.isRequestedSessionIdFromCookie() + +
requested-session-id-from-urlWhether the requested session ID is from the URL or not +
i.e. request.isRequestedSessionIdFromURL() + +
requested-session-id-validWhether the requested session ID is valid or not +
i.e. request.isRequestedSessionIdValid() + +
request-uriReturns the part of this request's URL from the protocol name up to the query + string in the first line of the HTTP request +
i.e. request.getRequestURI() + +
request-urlReconstructs the URL the client used to make the request. The returned URL + contains a protocol, server name, port number, and server path, but it does not include query string parameters. +
i.e. request.getRequestURL() + +
session-attribute + (note, name must be set) +
i.e. session.getAttribute([name]) + +
session-isnew + Weather the session is new or not. +
i.e. session.isNew() + +
server-name + The host name of the server to which the request was sent (from the host header not the machine name). +
i.e. request.getServerName() + +
scheme + The scheme used for the request, e.g. http or https +
i.e. request.getScheme() + +
user-in-role + (Note, the value for this cannot be a regular expression) +
i.e. request.isUserInRole([value]) + +
name
(optional)
(can be anything)If type is header, this specifies the name of the HTTP header used to run the value + against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator to be used when the condition is run, the regular expression matches or the values are + equal.
notequalNot equal to. (i.e. request value != condition value). Note, this operator only work with + numeric rule types.
greaterGreater than. (i.e. request value > condition value). Note, this operator only work with + numeric + rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only work with numeric + rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator + only + work with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only + work with numeric rule types.
+ +

Examples:

+ +

+    <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+
+    <condition type="user-in-role" operator="notequal">bigboss</condition>
+
+    <condition name="host" operator="notequal">www.example.com</condition>
+
+    <condition type="method" next="or">PROPFIND</condition>
+    <condition type="method">PUT</condition>
+
+ + + +

<from> element

+ +

You must always have exactly one from for each rule or outbound-rule. Value can be a regular expression in the + Perl5 style. Note, from url's are relative to the context.

+ + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using case insentitive match. ie, "/WellingtoN" will match "/wellington". +
trueThis value will be matched using case sentitive match. ie, "/aAa" will NOT match "/aaa". +
+ +

Example:

+ +

+    <from>^/world/([a-z]+)$</from>
+
+ + +

<to> element

+ +

Value can be a regular replacement expression in the Perl5 style.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally + forwarded + to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as + UrlRewriteFilter. This is the same as doing: +
RequestDispatcher rq = request.getRequestDispatcher([to value]); +
rq.forward(request, response);
+
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. + This is the same a doing: +
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_PERMANENTLY is HTTP status code 301)
temporary-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
pre-include
post-include
proxyThe request will be proxied to the full url specified. commons-http and commons-codec must both be in the + classpath to use this feature. +
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) + will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) + will NOT be called.
context
(optional)
If your application server is configured to allow "cross context" communication then this attribute can be used + to forward (and only forward, not redirect or other "to" types) requests to a named servlet context. +
+
On Tomcat, for instance, the application contexts in the server configuration (server.xml or + context.xml) need the option crossContext="true". For instance, the two applications mentioned before + ("app" and "forum") have to be defined as: +
+
<Context docBase="app" path="/app" reloadable="true" crossContext="true"/> +
<Context docBase="forum" path="/forum" reloadable="true" crossContext="true"/> +
+ +

Note, "to" can be null ie, <to>null</to>, this will mean that the request will go no + further if the rule is matched (ie, this filter will not call chain.doFilter).

+ +

If "to" is set to -, no substitution will take place and the request will go on like nothing happened (ie, this filter will call chain.doFilter).

+ +

+    <to>/world.jsp?country=$1</to>
+
+ +

To elements can contain backreferences and variables.

+ + +

Backreferences

+ +

+    %N
+
+ +

Provides access to the grouped parts (parentheses) of the pattern from the last matched Condition + in the current rule. + N must be less than 10 and greater than 0 (i.e. %1, %2, %3 etc).

+ + +

Variables

+ +

+    %{VARIABLE-NAME}
+
+ +

Any valid condition type can be used as a variable name. ie, + '%{port}' will be translated to '80', + '%{year}' to '2005', + '%{cookie:myCookie}' would be translated to + 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

+ +

Valid types are condition types, see condition for a full description.

+ + +

Functions

+ +

+    ${FUNCTION:PARAMS}
+
+ +

Functions can be places in set and to elements.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
nameexampleexample returns
replace${replace:my cat is a blue cat:cat:dog}my dog is a blue dog
replaceFirst${replaceFirst:my cat is a blue cat:cat:dog}my cat is a blue dog
escape${escape:a b c}a+b+c
unescape${unescape:a+b+c}a b c
lower${lower:Hello World}hello world
upper${upper:hello}HELLO
trim${trim: abc def }abc def
+ + + +

<set> element

+ +

Allows you to set varous things if the rule is matched.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], + [value]) + (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], + [value]) + (note, name must be set).
response-headerThe same as response.setHeader([name], + [value]) + (note, name must be set).
cookie + Value can be in the format "[value][:domain[:lifetime[:path]]]". + This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain + field is the domain of the cookie, such as '.apache.org',the optional lifetime is the lifetime of the cookie + in seconds, and the optional path is the path of the cookie (note, name must be set). +
statusThe same as response.setStatus([value]) +
content-typeThe same as response.setContentType([value]) +
charsetThe same as response.setCharacterEncoding([value]) +
expiresWill set the Expires HTTP header by adding the time specified and current time + (this is mod_expires style). Syntax "{num type}*". + Units can be (singular or plural); + years, months, weeks, days, hours, minutes, seconds. +
eg, "1 day 2 seconds", "3 hours", "1 year 1 hour" +
localeThe same as response.setLocale([value]) + + specify the Locale in the format + (valid + locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). +
parameterEnables you to override a request.getParameter(String) with a custom value
methodEnables you to override request.getMethod() with a custom value
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
+ +

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be + fetched in a servlet or + JSP using request.getAttribute("client").

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
+        <from>.*</from>
+        <set name="client">AvantGo</set>
+    </rule>
+    <rule>
+        <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
+        <from>.*</from>
+        <set name="client">Samsung SCH-6100</set>
+    </rule>
+
+ +

It is also possible to use regular replacement expressions as part of the + value similar to their usage in <to> elements:

+ +

+    <rule>
+        <from>/products/(.*)/(.*)/index.html</from>
+        <set name="urlrewrite.product.slug">$1</set>
+        <set name="urlrewrite.product.id">$2</set>
+        <to>/products?slug=$1&id=$2</to>
+    </rule>
+
+ + +

<run> element

+ +

Allows you to run a method on an object when a rule and it's conditions are matched.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible valueExplanation
class The class you want to run a method on. Must be a fully qualified name.
method (optional)run (default)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) + e.g. run(HttpServletRequest request, HttpServletResponse response) +
Note, if init(ServletConfig) or destroy() is found they will be run at when + creating + or destroying an instance. +
neweachtime (optional)false (default)One instance for each UrlRewriteFilter instance.
trueA new instance of the class will be created before running each time set to true.
+ +

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, + HttpServletResponse) + will be invoked, the request will then be forwarded to /world-presentation.jsp.

+ +

+    <rule>
+        <from>^/world/[a-z]+/[a-z]+$</from>
+        <run class="com.blah.web.WorldServlet" method="doGet" />
+        <to>/world-presentation.jsp</to>
+    </rule>
+
+ +

Note, you can specify init-param's the same way you would for a servlet.

+ +

+    <run class="com.blah.web.MyServlet" method="doGet">
+        <init-param>
+            <param-name>someParamName</param-name>
+            <param-value>10</param-value>
+        </init-param>
+    </run>
+
+ +

If the method being called throws an Exception the original exception will be re-thrown as if it were the original + if it extends RuntimeException (eg, NullPointer), other exceptions are wrapped in a ServletException and thrown + so your container can handle them.

+ + + +

<class-rule> element

+ +

Allows you to run a method every time a request come in for 100% dynamic rules. See the org.tuckey.web.filters.urlrewrite.sample package for an example.

+ + + + + + + + + + + + + + + + + + +
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default matches)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) + e.g. run(HttpServletRequest request, HttpServletResponse response) +
Note, if init(ServletConfig) or destroy() is found they will be run at when + creating or destroying an instance. +
last (optional, default trueIf false more rules will be processed following this rule even if it is matched (so that a better match may be found).
+ +

Example:

+ +

+    <class-rule class="com.blah.web.MyRuleClass" />
+
+ + + +

Tips

+ +
    +
  • When you want to put an "&" in a rule you must enter it as the XML entity "&amp;"
  • +
  • For simplicity you might want to start all from's with a ^ and end them with a $. +
    In regular expressions ^ specifies the start of + the string and $ specifies the end. +
    ie, a request for /my/url/path will NOT match + <from>^/url/$</from> but it will match <from>/url/</from> +
    +
  • If using <outbound-rule> remember all urls in your code must be encoded e.g. + <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • +
  • Regular expressions are complex and a bit tricky at times, read + regular expression syntax for + Java. +
  • +
  • If you find regular expressions difficult use Wildcards.
  • +
  • "Context" is important. If you have an app with the context "/myapp" and you request the url + "/myapp/somefolder/somepage.jsp", the container tells UrlRewriteFilter that the url is "/somefolder/somepage.jsp". + This can be confusing, but basically your rules and conditions should not contain the context path + (it will be handled by the container).
  • +
+ + + + + +

Wildcard Matching Engine

+ +

The wildcard matching engine can be used instead of regex. It is supported in conditions and rules + where match-type is set to wildcard (or default-match-type is set on the + urlrewrite element

+ +

e.g. /big/url/* will match /big/url/abc.html but will NOT + match /big/url/abc/dir/ or /big/url/abc/. + +

/big/url/** will match /big/url/abc.html, /big/url/abc/dir/ and + /big/url/abc/. + +

You can also use Regular expression style variable replacement, each match of a * will + be available for use in to and set elements using simple $1 + $2 variables.

+ +

e.g. /my/big/url/* will match /my/big/url/abc.html and $1 + will be set to abc.html.

+ +

Added in 3.0

+ + + +

Ant Task

+ +

An Ant task has been written to allow validate the conf file and generation + of documentation. You can view a sample.

+ +

Paste the following into your build.xml file, then change the dest + and conf to point to the correct places. Note, the urlrewrite jar + file will need to be in your classpath.

+ +

+    <target name="urlrewrite-doc" depends="compile"
+        description="UrlRewriteFilter validation and documenting">
+
+    <taskdef name="urlrewritedoc" classpath="lib/urlrewrite-3.2.0.jar"
+        classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
+    <urlrewritedoc
+        conf="${build.home}/WEB-INF/urlrewrite.xml"
+        dest="urlrewrite-conf-overview.html" />
+    </target>
+
+ + + +

mod_rewrite Style Configuration

+ +

Sample web.xml snippet:

+ +

+     <filter>
+         <filter-name>UrlRewriteFilter</filter-name>
+         <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+         <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
+         is not specified confPath will be set to /WEB-INF/.htaccess) -->
+         <init-param>
+             <param-name>modRewriteConfText</param-name>
+             <param-value><![CDATA[
+
+                 # redirect mozilla to another area
+                 RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
+                 RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
+
+             ]]></param-value>
+         </init-param>
+
+     </filter>
+
+     <filter-mapping>
+         <filter-name>UrlRewriteFilter</filter-name>
+         <url-pattern>/*</url-pattern>
+         <dispatcher>REQUEST</dispatcher>
+         <dispatcher>FORWARD</dispatcher>
+     </filter-mapping>
+
+ + +

OR alternately set modRewriteConf to true in filter parameters and add a WEB-INF/.htaccess file with + your mod_rewrite style configuration in it.

+ +

+    <filter>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+        <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
+        is not specified confPath will be set to /WEB-INF/.htaccess) -->
+        <init-param>
+            <param-name>modRewriteConf</param-name>
+            <param-value>true</param-value>
+        </init-param>
+
+    </filter>
+
+    <filter-mapping>
+        <filter-name>UrlRewriteFilter</filter-name>
+        <url-pattern>/*</url-pattern>
+        <dispatcher>REQUEST</dispatcher>
+        <dispatcher>FORWARD</dispatcher>
+    </filter-mapping>
+
+ +

Sample: WEB-INF/.htaccess

+ +

+     # redirect mozilla to another area
+     RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
+     RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
+ 
+ +

+ + Documentation for the original mod_rewrite library + mostly applies, differences are documented below.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeExplanation
RewriteLogLevelSpecified as int, trasnlated as: <= 1 - FATAL, 2 - ERROR, 3 - INFO, 4 - WARN, >= 5 DEBUG
RewriteLogSYSOUT, SYSERR, log4j, commons (if not set context logging will be used)
RewriteRule + Supported but note: + + + Certain flags not supported: +
    +
  • chain flag [C] not supported
  • +
  • env flag [E] not supported
  • +
  • next flag [N] not supported
  • +
  • nosubreq flag [NS] not supported
  • +
  • qsappend flag [QSA] not supported
  • +
  • Skip flag [S] not supported
  • +
+
RewriteBaseNot supported
RewriteLockNot supported
RewriteMapNot supported
RewriteOptionsNot supported
+ + +
+ + + + + + diff --git a/src/doc/manual/3.2/introduction.html b/src/doc/manual/3.2/introduction.html index 0782ee29..c149b6c1 100644 --- a/src/doc/manual/3.2/introduction.html +++ b/src/doc/manual/3.2/introduction.html @@ -1,373 +1,373 @@ - - - - UrlRewriteFilter - Background - - - - - - - - - -
- - - -

Background

- - - -

A clean URL scheme is very important detail for any quality Web Application. UrlRewriteFilter provides a - toolkit to let you set URL patterns however you want.

- -

See Cool URIs don't change, by World Wide Web creator - Tim Berners-Lee, for excellent arguments on why URLs should be clean and usable.

- -

With the Apache webserver there is mod_rewrite for URL manipulation.

- -

In J2EE land the Servlet specification (by Sun) standardises the approach for dealing with Java web server -programming. We have come a long way from basic Servlets, JSP's, MVC frameworks etc but Java Web Application -Servers such as Tomcat are seldom used as front-line web servers, they almost always have Apache infront of them.

- -

If you want to use an app server as a front line web server UrlRewriteFilter will enable you to manage incoming -URL's in a much more flexible way than the app server usually lets you.

- -

You can find test cases in the source distribution. UrlRewriteFilter should work on any J2EE web application server - and has been tested using Cargo on the following web application - servers:

- - - -

The filter has been designed for maximum performance. Testing has indicated - that it should only slow down a request by 0.0005 of a second under normal circumstances - (depending on hardware and configuration etc.). Take a look at the source in the class - UrlRewriterTest.testLoadsOfRules() for more information.

- - - - -

License

- -

UrlRewriteFilter is distributed under the BSD License. For more information on see - opensource.org/licenses.

- -

If you want to purchase ad-hoc support, a support contract or custom development - please email sales@tuckey.co.nz.

- - - - - - -

Changelog

- -
    -
  • 3.2.0 -
      -
    • Added "no substitution" ability with to element eg, <to>-</to>
    • -
    • In urlrewrite.xml allow rule, class-rule and outbound-rule elements in any order
    • -
    • Fixed bug with handling of references in functions (ie, to allow this: ${replace:$1:-:+} )
    • -
    • Added slf4j logging support for logLevel (filter parameter)
    • -
    • Added function for calculating string length (eg, ${length:asdf} would return 4)
    • -
    • Added "proxy" to type, to enable requests to be proxied to another server
    • -
    • Added "context" attribute to <to> type, to enable requests to sent to other contexts (assuming app server configured to do this)
    • -
    • JDK 6+ Annotation processor
    • -
    • JDK 5 & 6+ Annotation processors included in main jar file
    • -
    • Fixed bug with decoding urls and added ability to specify 'header' type decoding
    • -
    • Added allowConfSwapViaHttp filter parameter to allow configuration swap out at runtime.
    • -
    -
  • -
  • 3.1.0 -
      -
    • Rules are now allowed to have only condition and set elements
    • -
    • Basic functions in "set", and "to" elements eg, ${trim:%1}
    • -
    • Experimental mod_rewrite style configuration
    • -
    • Bug fix: xml entites containing jndi protocol now correctly loaded
    • -
    -
  • -
  • 3.0.4 Beta -
      -
    • Bug fix - cookie value not being set with variable replacement
    • -
    -
  • -
  • 3.0.3 Beta -
      -
    • Bug fix - annotation processor rule sorting
    • -
    • Bug Fix - evaluation boolean result was incorrect on failed condition instance matches
    • -
    -
  • -
  • 3.0.2 Beta -
      -
    • Rule chaining bug fixes
    • -
    -
  • -
  • 3.0.1 Beta -
      -
    • Added "class-rule" element to enable 100% dynamic "Java Rules"
    • -
    • Added experimental UrlrewriteTestCase to help with testing (see the source)
    • -
    • Added experimental "catch" element to handle exceptions generated from "run"'s
    • -
    • Added experimental annotation (@HttpUrl, @HttpParam) processor
    • -
    • Minor Bug fixes
    • -
    -
  • -
  • 3.0 Beta -
      -
    • Support for wildcard matching.
    • -
    • Added "match-type" attribute to rule and outbound-rule.
    • -
    • Added ability to specify charset decoding ("decodeusing" attribute to "urlrewrite" element)
    • -
    • Swapped "to" variable replacement and run processing, run processing now comes before "to" - variable replacement is done. dtd it has been swapped make sure you change the reference in your conf file. - Make sure element order is from, set, run, to.
    • -
    • Context addition to the url is now optional
    • -
    • Query string matching on rule is now optional (defaults to false) -
      before 3.0 you would specify -
      <from>/blah.jsp?a=b</from> -
      3.0 and up (unless use-query-string on urlrewrite element is set to true) -
      <condition name="a">b</condition> -
      <from>/blah.jsp</from>
    • -
    -
  • -
  • 2.6 -
      -
    • fixed bug with encode on to element defaulting to incorrect boolean (change to dtd)
    • -
    -
  • -
  • 2.5.3 -
      -
    • cleaner exception handling when invoking "run" items, original exception thrown as if it were the - original if it extends RuntimeException (eg, NullPointer), other exceptions wrapped in a ServletException and thrown
    • -
    -
  • -
  • 2.5.2 -
      -
    • fixed bug with encodefirst attr not being set
    • -
    • ability to specify wildcards on statusEnabledOnHosts
    • -
    • added backreferences and variables for to element value
    • -
    • logLevel init param can now include sysout:{level} ie, sysout:DEBUG for people who have trouble with context.log
    • -
    -
  • -
  • 2.5.1 -
      -
    • bug fixes, Log initialisation and null auth type condition values
    • -
    -
  • -
  • 2.5 -
      -
    • matcher changed to accept first match (not the whole string) please make sure you retest your rules - (ie, previously /res/js/l.js?aaa would not match /res/js/l.js, with this release it will)
    • -
    • support for logging to log4j or commons-logging (see filter params in manual)
    • -
    • fixed bug for when request.getCookies() returns null on some containers
    • -
    • added encodefirst outbound-rule, outbound-rule now respects encode on "to".
    • -
    - -
  • -
  • 2.4 -
      -
    • removed all external library dependencies to make much more deploy friendly
    • -
    • no longer uses Jakarta ORO, this should't mean any change in regular expression handling but you should test - your existing rules just in case.
    • -
    • fixed problem with rediredting to "null" this will now not proceed with the request if the rule is matched - (ie, chain.doFilter will not be called)
    • -
    • fixed problem with ant dependency on status page
    • -
    -
  • -
  • 2.3 (4/2005) -
      -
    • Added new outbound-rule for rewriting hyperlinks in JSP's, improved status page, added ability - to run methods when a rule is matched
    • -
    -
  • -
  • 2.0.1 (2/2005) -
      -
    • Fixed bug with rule processing when to element doesn't exist.
    • -
    -
  • -
  • 2.0 (1/2005) -
      -
    • Minor bug fixes, last attribute on rule now defaults to false (thanks to Vineet Kumar for his - assistance).
    • -
    -
  • -
  • 2.0-beta (12/2004) -
      -
    • Minor bug fixes, documentation improvements, ALL matches now done case insensitively by - default, case sensitivity can be set (see from and condition elements).
    • -
    -
  • -
  • 2.0-alpha (11/2004) -
      -
    • First 2.0 release, added many new condition types, many new set types.
    • -
    -
  • -
  • 1.2 (6/2004) -
      -
    • Added set element (ability to set random attributes on request, thanks for the idea - Russell), from now matches RELATIVE to context NOT root (if you - are upgrading this may mean a change for you).
    • -
    -
  • -
  • 1.1 (4/2004) -
      -
    • Ability to disable rules, Refactored to enable rewriter to be embedded, - changed logging to enable log level to be set, added name and note elements to rule for documentation, - ability to disable status page, ability to change status prefix, javadoc style ant task for an HTML - configuration report.
    • -
    -
  • -
  • 1.0 (3/2004) -
      -
    • General tidy up of logging, tidy up of all code, dist now includes manual, log4j and junit - removed from bin release.
    • -
    -
  • -
  • 0.9 (2/2004) -
      -
    • Fixed conf loading problem in Resin, resolved concurrency issue with Perl5Compiler and - Perl5Matcher (thanks Scott Askew!)
    • -
    -
  • -
  • 0.8 (2/2004) -
      -
    • Removed dependency on "Commons Lang", Changed DTD path (bug fix), added ability to put time - fields in "condition" element, added ability to put "operators" in the "condition" element, fixed multiple rules issue (bug fix)
    • -
    -
  • -
  • 0.7 (11/2003) -
      -
    • Improved test cases, documentation
    • -
    -
  • -
  • 0.6 (8/2003) -
      -
    • Improved error handling, status page and condition matching
    • -
    -
  • -
  • 0.5 (6/2003) -
      -
    • Improved configuration error handling
    • -
    -
  • -
- - - -
- - - - - - + + + + UrlRewriteFilter - Background + + + + + + + + + +
+ + + +

Background

+ + + +

A clean URL scheme is very important detail for any quality Web Application. UrlRewriteFilter provides a + toolkit to let you set URL patterns however you want.

+ +

See Cool URIs don't change, by World Wide Web creator + Tim Berners-Lee, for excellent arguments on why URLs should be clean and usable.

+ +

With the Apache webserver there is mod_rewrite for URL manipulation.

+ +

In J2EE land the Servlet specification (by Sun) standardises the approach for dealing with Java web server +programming. We have come a long way from basic Servlets, JSP's, MVC frameworks etc but Java Web Application +Servers such as Tomcat are seldom used as front-line web servers, they almost always have Apache infront of them.

+ +

If you want to use an app server as a front line web server UrlRewriteFilter will enable you to manage incoming +URL's in a much more flexible way than the app server usually lets you.

+ +

You can find test cases in the source distribution. UrlRewriteFilter should work on any J2EE web application server + and has been tested using Cargo on the following web application + servers:

+ + + +

The filter has been designed for maximum performance. Testing has indicated + that it should only slow down a request by 0.0005 of a second under normal circumstances + (depending on hardware and configuration etc.). Take a look at the source in the class + UrlRewriterTest.testLoadsOfRules() for more information.

+ + + + +

License

+ +

UrlRewriteFilter is distributed under the BSD License. For more information on see + opensource.org/licenses.

+ +

If you want to purchase ad-hoc support, a support contract or custom development + please email sales@tuckey.co.nz.

+ + + + + + +

Changelog

+ +
    +
  • 3.2.0 +
      +
    • Added "no substitution" ability with to element eg, <to>-</to>
    • +
    • In urlrewrite.xml allow rule, class-rule and outbound-rule elements in any order
    • +
    • Fixed bug with handling of references in functions (ie, to allow this: ${replace:$1:-:+} )
    • +
    • Added slf4j logging support for logLevel (filter parameter)
    • +
    • Added function for calculating string length (eg, ${length:asdf} would return 4)
    • +
    • Added "proxy" to type, to enable requests to be proxied to another server
    • +
    • Added "context" attribute to <to> type, to enable requests to sent to other contexts (assuming app server configured to do this)
    • +
    • JDK 6+ Annotation processor
    • +
    • JDK 5 & 6+ Annotation processors included in main jar file
    • +
    • Fixed bug with decoding urls and added ability to specify 'header' type decoding
    • +
    • Added allowConfSwapViaHttp filter parameter to allow configuration swap out at runtime.
    • +
    +
  • +
  • 3.1.0 +
      +
    • Rules are now allowed to have only condition and set elements
    • +
    • Basic functions in "set", and "to" elements eg, ${trim:%1}
    • +
    • Experimental mod_rewrite style configuration
    • +
    • Bug fix: xml entites containing jndi protocol now correctly loaded
    • +
    +
  • +
  • 3.0.4 Beta +
      +
    • Bug fix - cookie value not being set with variable replacement
    • +
    +
  • +
  • 3.0.3 Beta +
      +
    • Bug fix - annotation processor rule sorting
    • +
    • Bug Fix - evaluation boolean result was incorrect on failed condition instance matches
    • +
    +
  • +
  • 3.0.2 Beta +
      +
    • Rule chaining bug fixes
    • +
    +
  • +
  • 3.0.1 Beta +
      +
    • Added "class-rule" element to enable 100% dynamic "Java Rules"
    • +
    • Added experimental UrlrewriteTestCase to help with testing (see the source)
    • +
    • Added experimental "catch" element to handle exceptions generated from "run"'s
    • +
    • Added experimental annotation (@HttpUrl, @HttpParam) processor
    • +
    • Minor Bug fixes
    • +
    +
  • +
  • 3.0 Beta +
      +
    • Support for wildcard matching.
    • +
    • Added "match-type" attribute to rule and outbound-rule.
    • +
    • Added ability to specify charset decoding ("decodeusing" attribute to "urlrewrite" element)
    • +
    • Swapped "to" variable replacement and run processing, run processing now comes before "to" + variable replacement is done. dtd it has been swapped make sure you change the reference in your conf file. + Make sure element order is from, set, run, to.
    • +
    • Context addition to the url is now optional
    • +
    • Query string matching on rule is now optional (defaults to false) +
      before 3.0 you would specify +
      <from>/blah.jsp?a=b</from> +
      3.0 and up (unless use-query-string on urlrewrite element is set to true) +
      <condition name="a">b</condition> +
      <from>/blah.jsp</from>
    • +
    +
  • +
  • 2.6 +
      +
    • fixed bug with encode on to element defaulting to incorrect boolean (change to dtd)
    • +
    +
  • +
  • 2.5.3 +
      +
    • cleaner exception handling when invoking "run" items, original exception thrown as if it were the + original if it extends RuntimeException (eg, NullPointer), other exceptions wrapped in a ServletException and thrown
    • +
    +
  • +
  • 2.5.2 +
      +
    • fixed bug with encodefirst attr not being set
    • +
    • ability to specify wildcards on statusEnabledOnHosts
    • +
    • added backreferences and variables for to element value
    • +
    • logLevel init param can now include sysout:{level} ie, sysout:DEBUG for people who have trouble with context.log
    • +
    +
  • +
  • 2.5.1 +
      +
    • bug fixes, Log initialisation and null auth type condition values
    • +
    +
  • +
  • 2.5 +
      +
    • matcher changed to accept first match (not the whole string) please make sure you retest your rules + (ie, previously /res/js/l.js?aaa would not match /res/js/l.js, with this release it will)
    • +
    • support for logging to log4j or commons-logging (see filter params in manual)
    • +
    • fixed bug for when request.getCookies() returns null on some containers
    • +
    • added encodefirst outbound-rule, outbound-rule now respects encode on "to".
    • +
    + +
  • +
  • 2.4 +
      +
    • removed all external library dependencies to make much more deploy friendly
    • +
    • no longer uses Jakarta ORO, this should't mean any change in regular expression handling but you should test + your existing rules just in case.
    • +
    • fixed problem with rediredting to "null" this will now not proceed with the request if the rule is matched + (ie, chain.doFilter will not be called)
    • +
    • fixed problem with ant dependency on status page
    • +
    +
  • +
  • 2.3 (4/2005) +
      +
    • Added new outbound-rule for rewriting hyperlinks in JSP's, improved status page, added ability + to run methods when a rule is matched
    • +
    +
  • +
  • 2.0.1 (2/2005) +
      +
    • Fixed bug with rule processing when to element doesn't exist.
    • +
    +
  • +
  • 2.0 (1/2005) +
      +
    • Minor bug fixes, last attribute on rule now defaults to false (thanks to Vineet Kumar for his + assistance).
    • +
    +
  • +
  • 2.0-beta (12/2004) +
      +
    • Minor bug fixes, documentation improvements, ALL matches now done case insensitively by + default, case sensitivity can be set (see from and condition elements).
    • +
    +
  • +
  • 2.0-alpha (11/2004) +
      +
    • First 2.0 release, added many new condition types, many new set types.
    • +
    +
  • +
  • 1.2 (6/2004) +
      +
    • Added set element (ability to set random attributes on request, thanks for the idea + Russell), from now matches RELATIVE to context NOT root (if you + are upgrading this may mean a change for you).
    • +
    +
  • +
  • 1.1 (4/2004) +
      +
    • Ability to disable rules, Refactored to enable rewriter to be embedded, + changed logging to enable log level to be set, added name and note elements to rule for documentation, + ability to disable status page, ability to change status prefix, javadoc style ant task for an HTML + configuration report.
    • +
    +
  • +
  • 1.0 (3/2004) +
      +
    • General tidy up of logging, tidy up of all code, dist now includes manual, log4j and junit + removed from bin release.
    • +
    +
  • +
  • 0.9 (2/2004) +
      +
    • Fixed conf loading problem in Resin, resolved concurrency issue with Perl5Compiler and + Perl5Matcher (thanks Scott Askew!)
    • +
    +
  • +
  • 0.8 (2/2004) +
      +
    • Removed dependency on "Commons Lang", Changed DTD path (bug fix), added ability to put time + fields in "condition" element, added ability to put "operators" in the "condition" element, fixed multiple rules issue (bug fix)
    • +
    +
  • +
  • 0.7 (11/2003) +
      +
    • Improved test cases, documentation
    • +
    +
  • +
  • 0.6 (8/2003) +
      +
    • Improved error handling, status page and condition matching
    • +
    +
  • +
  • 0.5 (6/2003) +
      +
    • Improved configuration error handling
    • +
    +
  • +
+ + + +
+ + + + + + diff --git a/src/doc/manual/4.0/annotation.html b/src/doc/manual/4.0/annotation.html index 0c50c376..54b6bf49 100644 --- a/src/doc/manual/4.0/annotation.html +++ b/src/doc/manual/4.0/annotation.html @@ -1,182 +1,182 @@ - - - - UrlRewriteFilter - Annotation - - - - - - -
-
-

- - UrlRewriteFilter 4.0.3

-
- -
- - -
- -

URL Matching Annotations

- - - -

Support for annotations has been added as part of version 3 development. You must be using JDK 1.6 for this to work.

- -

The intention of annotations in UrlRewriteFilter is purely for conf file generation. The is NO runtime - dependency on the annotations.

- -

Annotations

- -

@HttpUrl

- -

Set the method up to be used when the url is Matched, matched groups are assigned to method paramters (if any).

- -

-    @HttpUrl("^/do-something/([0-9]+)$")
-    public void doSomething(Long id)
-    
- -

When a request for /do-something/1234, doSomething is called with id set to 1234.

- -

@HttpParam

- -

Sets the parameter from request.getParameter (handles type conversion as necessary)

- -

-    void doSomething(@HttpParam String name, @HttpParam long id, @HttpParam("uid") Long userId)
-    
- -

The above example will: -
name = request.getParameter("name"); -
id = convertTolongDefault0(request.getParameter("id")); -
userId = convertToLongDefaultNull(request.getParameter("uid")); -
An exception will never be thown during type conversion -

- - - - -

Conf Generation

- -

With Java 1.6 the javac tool handles annotation processing. So this means all you need to do is have a - "urlrewriteDest" option specified and have urlrewritefilter annotations jar in your classpath. Example of compilerarg - elements that would be used with javac ant task:

- -

-<compilerarg line="-AurlrewriteDest=build/WEB-INF/urlrewrite-generated.xml"/>
-<!-- optional arguments
-<compilerarg value="-AurlrewriteShowPositions=true"/>
-<compilerarg value="-AurlrewriteDebug=true"/>
--->
-
- -

An example compile ant task with urlrewrite option might look like:

- -

-<target name="compile-urlrewrite-conf">
-   <javac srcdir="src/" destdir="build/WEB-INF/classes">
-        <classpath refid="compile.classpath"/>
-        <classpath path="lib/urlrewritefilter-annotation-4.0.3.jar"/>
-        <compilerarg line="-AurlrewriteDest=build/WEB-INF/urlrewrite-generated.xml"/>
-   </javac>
-   <!-- check file generated ok (if not you may be using the wrong jdk version)-->
-   <available property="urlrewrite.generated" file="build/WEB-INF/urlrewrite-generated.xml"/>
-   <fail unless="urlrewrite.generated" />
-</target>
-
- -

This will generate to the file specified. Any errors will be output to stdout using the standard APT method. - Read the generated conf file and check it for errors.

- - -

Include the compiled conf file in your normal conf.

- -

-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
-        "http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd"
-[
-    <!ENTITY included SYSTEM "urlrewrite-generated.xml">
-]>
-<urlrewrite>
-
-    <!--
-        other rules...
-    -->
-
-    &included;
-
-
-</urlrewrite>
-
- - -

Check your /rewrite-status for errors if things start going strange.

- -
-
- - - - - - + + + + UrlRewriteFilter - Annotation + + + + + + +
+
+

+ + UrlRewriteFilter 4.0.3

+
+ +
+ + +
+ +

URL Matching Annotations

+ + + +

Support for annotations has been added as part of version 3 development. You must be using JDK 1.6 for this to work.

+ +

The intention of annotations in UrlRewriteFilter is purely for conf file generation. The is NO runtime + dependency on the annotations.

+ +

Annotations

+ +

@HttpUrl

+ +

Set the method up to be used when the url is Matched, matched groups are assigned to method paramters (if any).

+ +

+    @HttpUrl("^/do-something/([0-9]+)$")
+    public void doSomething(Long id)
+    
+ +

When a request for /do-something/1234, doSomething is called with id set to 1234.

+ +

@HttpParam

+ +

Sets the parameter from request.getParameter (handles type conversion as necessary)

+ +

+    void doSomething(@HttpParam String name, @HttpParam long id, @HttpParam("uid") Long userId)
+    
+ +

The above example will: +
name = request.getParameter("name"); +
id = convertTolongDefault0(request.getParameter("id")); +
userId = convertToLongDefaultNull(request.getParameter("uid")); +
An exception will never be thown during type conversion +

+ + + + +

Conf Generation

+ +

With Java 1.6 the javac tool handles annotation processing. So this means all you need to do is have a + "urlrewriteDest" option specified and have urlrewritefilter annotations jar in your classpath. Example of compilerarg + elements that would be used with javac ant task:

+ +

+<compilerarg line="-AurlrewriteDest=build/WEB-INF/urlrewrite-generated.xml"/>
+<!-- optional arguments
+<compilerarg value="-AurlrewriteShowPositions=true"/>
+<compilerarg value="-AurlrewriteDebug=true"/>
+-->
+
+ +

An example compile ant task with urlrewrite option might look like:

+ +

+<target name="compile-urlrewrite-conf">
+   <javac srcdir="src/" destdir="build/WEB-INF/classes">
+        <classpath refid="compile.classpath"/>
+        <classpath path="lib/urlrewritefilter-annotation-4.0.3.jar"/>
+        <compilerarg line="-AurlrewriteDest=build/WEB-INF/urlrewrite-generated.xml"/>
+   </javac>
+   <!-- check file generated ok (if not you may be using the wrong jdk version)-->
+   <available property="urlrewrite.generated" file="build/WEB-INF/urlrewrite-generated.xml"/>
+   <fail unless="urlrewrite.generated" />
+</target>
+
+ +

This will generate to the file specified. Any errors will be output to stdout using the standard APT method. + Read the generated conf file and check it for errors.

+ + +

Include the compiled conf file in your normal conf.

+ +

+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
+        "http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd"
+[
+    <!ENTITY included SYSTEM "urlrewrite-generated.xml">
+]>
+<urlrewrite>
+
+    <!--
+        other rules...
+    -->
+
+    &included;
+
+
+</urlrewrite>
+
+ + +

Check your /rewrite-status for errors if things start going strange.

+ +
+
+ + + + + + diff --git a/src/doc/manual/4.0/doc.css b/src/doc/manual/4.0/doc.css index f73faf47..6cf3363f 100644 --- a/src/doc/manual/4.0/doc.css +++ b/src/doc/manual/4.0/doc.css @@ -1,103 +1,103 @@ - - -@import url("http://www.tuckey.org/res/bootstrap/css/bootstrap.css"); -@import url("http://fonts.googleapis.com/css?family=Open+Sans:400,700italic"); - -body { - font-family: 'open sans', Sans-Serif; -} -.top { - margin-top: 20px; - border-top: 4px solid black; -} -.footer, #footer { - margin-top: 50px; - padding-top: 10px; - border-top: 4px solid black; - margin-bottom: 100px; -} -a { - color: #4979c0; -} - -#main h1 { - border-bottom: none; - font-size: 24px; - margin-top: 0; -} -h1, h2 { - text-align: center; - font-weight: 700; - font-style: italic; -} -h1 { - margin-top: 15px; - margin-bottom: 30px; - font-size: 50px; - line-height: 60px; -} -h2 { - border-bottom: none; - margin-top: 40px; - margin-bottom: 20px; -} -h3 { - border-bottom: none; - margin-top: 20px; - margin-bottom: 10px; -} -big { - font-size: 20px; - line-height: 25px; -} - - -#logo { - vertical-align: middle; -} - -#masthead { - -moz-border-radius-topright: 20px; -} - -#masthead a { - text-decoration: none; - color: black; -} - -hr { - border: 0px; - background-color: #c0c0c0; -} - -pre { - margin-top: 5px; - margin-bottom: 5px; -} - -.err { - color: #ff0000; -} - -#menu ul { - list-style-type: none; - margin-left: .5em; - padding-left: .5em; - margin-top: 7px; -} -#menu li { - margin-bottom: 7px; -} - -#main { - min-height: 400px; -} - -#footer { - text-align: center; - font-size: small; -} - -#footer a { - text-decoration: none; -} + + +@import url("http://www.tuckey.org/res/bootstrap/css/bootstrap.css"); +@import url("http://fonts.googleapis.com/css?family=Open+Sans:400,700italic"); + +body { + font-family: 'open sans', Sans-Serif; +} +.top { + margin-top: 20px; + border-top: 4px solid black; +} +.footer, #footer { + margin-top: 50px; + padding-top: 10px; + border-top: 4px solid black; + margin-bottom: 100px; +} +a { + color: #4979c0; +} + +#main h1 { + border-bottom: none; + font-size: 24px; + margin-top: 0; +} +h1, h2 { + text-align: center; + font-weight: 700; + font-style: italic; +} +h1 { + margin-top: 15px; + margin-bottom: 30px; + font-size: 50px; + line-height: 60px; +} +h2 { + border-bottom: none; + margin-top: 40px; + margin-bottom: 20px; +} +h3 { + border-bottom: none; + margin-top: 20px; + margin-bottom: 10px; +} +big { + font-size: 20px; + line-height: 25px; +} + + +#logo { + vertical-align: middle; +} + +#masthead { + -moz-border-radius-topright: 20px; +} + +#masthead a { + text-decoration: none; + color: black; +} + +hr { + border: 0px; + background-color: #c0c0c0; +} + +pre { + margin-top: 5px; + margin-bottom: 5px; +} + +.err { + color: #ff0000; +} + +#menu ul { + list-style-type: none; + margin-left: .5em; + padding-left: .5em; + margin-top: 7px; +} +#menu li { + margin-bottom: 7px; +} + +#main { + min-height: 400px; +} + +#footer { + text-align: center; + font-size: small; +} + +#footer a { + text-decoration: none; +} diff --git a/src/doc/manual/4.0/guide.html b/src/doc/manual/4.0/guide.html index f39fd9ec..46dd8bf1 100644 --- a/src/doc/manual/4.0/guide.html +++ b/src/doc/manual/4.0/guide.html @@ -1,820 +1,820 @@ - - - - UrlRewriteFilter - Examples - - - - - - -
-
-

- - UrlRewriteFilter 4.0.3

-
- -
- - -
- - -

Examples

- -

Redirect one url

- -

-    <rule>
-        <from>^/some/old/page\.html$</from>
-        <to type="redirect">/very/new/page.html</to>
-    </rule>
-
- -

-    <rule match-type="wildcard">
-        <from>/some/old/page.html</from>
-        <to type="redirect">/very/new/page.html</to>
-    </rule>
-
- -

Redirect docs in a directory to another using wildcard engine.

- -

-    <urlrewrite default-match-type="wildcard">
-
-    <rule>
-        <from>/some/old/*.doc</from>
-        <to type="redirect">/very/new/$1.doc</to>
-    </rule>
-
-    </urlrewrite>
-
- -

Tiny/Freindly url

- -

-    <rule>
-        <from>^/zebra$</from>
-        <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
-    </rule>
-
- -

Default page as another (requests to / will be redirected)

- -

-    <rule>
-        <from>^/$</from>
-        <to type="redirect">/opencms/opencms/index.html</to>
-    </rule>
-
- -

Perform security checks in a centralised place

- -

-    <rule>
-        <condition type="user-in-role" operator="notequal">admin</condition>
-        <condition type="user-in-role" operator="notequal">bigboss</condition>
-        <from>^/admin/(.*)$</from>
-        <to>/go-away-please.html</to>
-    </rule>
-
- - -

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah - will be redirected to http://www.example.com/blah

- -

-    <rule>
-        <name>Domain Name Check</name>
-        <condition name="host" operator="notequal">www.example.com</condition>
-        <from>^(.*)$</from>
-        <to type="redirect">http://www.example.com/context$1</to>
-    </rule>
-
- - -

Disable access to a directory.

- -

-    <rule>
-        <name>Disable Directory</name>
-        <from>^/notliveyet/.*$</from>
-        <set type="status">403</set>
-        <to>null</to>
-    </rule>
-
- -

Redirect a directory (for moved content)

- -

-    <rule>
-        <from>^/some/olddir/(.*)$</from>
-        <to type="redirect">/very/newdir/$1</to>
-    </rule>
-
- -

Clean a URL

- -

-    <rule>
-        <from>^/products/([0-9]+)$</from>
-        <to>/products/index.jsp?product_id=$1</to>
-    </rule>
-
- -

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 - without the user noticing.

- -

-    <rule>
-        <from>^/world/([a-z]+)/([a-z]+)$</from>
-        <to>/world.jsp?country=$1&amp;city=$2</to>
-    </rule>
-
- -

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork -

- -

Browser detection

- -

-    <rule>
-        <condition name="user-agent">Mozilla/[1-4]</condition>
-        <from>^/some/page\.html$</from>
-        <to>/some/page-for-old-browsers.html</to>
-    </rule>
-
- -

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html - only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, - Mozilla/3 or Mozilla/4.

- - -

Security. Preclude certain types of method from you web application.

- -

-    <rule>
-        <condition type="method" next="or">PROPFIND</condition>
-        <condition type="method">PUT</condition>
-        <from>.*</from>
-        <to type="redirect">/bad-method.html</to>
-    </rule>
-
- - -

Sunday Specials

- -

-    <rule>
-        <condition type="dayofweek">1</condition>
-        <from>^/products/$</from>
-        <to>/products/sunday-specials.html</to>
-    </rule>
-
- - -

Set the "Cache-Control" HTTP response header for all requests

- -

-    <rule>
-        <from>.*</from>
-        <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
-    </rule>
-
- -

Forward a request to a servlet

- -

-    <rule>
-        <from>^/products/purchase$</from>
-        <set name="action">purchase</set>
-        <to>/servlets/ProductsServlet</to>
-    </rule>
-
- -

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and - inside - the servlet request.getAttribute("action") will return purchase.

- -

Set an "Expires" HTTP header 6 hours into the future for js, css and gif files

- -

-    <rule>
-        <from>^.*\.(js|css|gif)$</from>
-        <set type="expires">6 hours</set>
-    </rule>
-
- -

Hide jsessionid for requests from googlebot.

- -

-  <outbound-rule>
-       <name>Strip URL Session ID's</name>
-       <note>
-           Strip ;jsession=XXX from urls passed through
-response.encodeURL().
-           The characters ? and # are the only things we can use to
-find out where the jsessionid ends.
-           The expression in 'from' below contains three capture
-groups, the last two being optional.
-               1, everything before ;jesessionid
-               2, everything after ;jesessionid=XXX starting with a ?
-(to get the query string) up to #
-               3, everything ;jesessionid=XXX and optionally ?XXX
-starting with a # (to get the target)
-           eg,
-           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
-           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
-           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
-index.jsp#dfds
-           from u.jsp;jsessionid=wert.hg - u.jsp
-           from /;jsessionid=tyu - /
-       </note>
-       <condition name="user-agent">googlebot</condition>
-       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
-       <to>$1$2$3</to>
-   </outbound-rule>
-
- -

Permanently redirect incoming URLs containing jsessionid.

- -

-  <rule>
-       <name>Strip URL Session ID's</name>
-       <note>
-           Strip ;jsession=XXX from urls passed through
-response.encodeURL().
-           The characters ? and # are the only things we can use to
-find out where the jsessionid ends.
-           The expression in 'from' below contains three capture
-groups, the last two being optional.
-               1, everything before ;jesessionid
-               2, everything after ;jesessionid=XXX starting with a ?
-(to get the query string) up to #
-               3, everything ;jesessionid=XXX and optionally ?XXX
-starting with a # (to get the target)
-           eg,
-           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
-           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
-           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
-index.jsp#dfds
-           from u.jsp;jsessionid=wert.hg - u.jsp
-           from /;jsessionid=tyu - /
-       </note>
-       <condition type="requested-session-id-from-url" operator="equal">true</condition>
-       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
-       <to type="permanent-redirect">$1$2$3</to>
-   </rule>
-
- - - -

Method Invocation

- -

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have - any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

- -

Invoke a servlet directly

- -

-    <rule>
-    <from>^/products/purchase$</from>
-    <run class="com.blah.web.MyServlet" method="doGet" />
-    </rule>
-
- -

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is - matched on a request. (remeber this method needs to be public!)

- -

Use it to delagate cleanly to your methods

- -

-    <rule>
-        <from>^/pref-editor/addresses$</from>
-        <run class="com.blah.web.PrefsServlet" method="runAddresses" />
-    </rule>
-    <rule>
-        <from>^/pref-editor/phone-nums$</from>
-        <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
-    </rule>
-
- -

Browser based delagation to your methods

- -

-    <rule>
-        <condition name="user-agent">Mozilla/[1-4]</condition>
-        <from>^/content/.*$</from>
-        <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
-    </rule>
-    <rule>
-        <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-        <from>^/content/.*$</from>
-        <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
-        <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
-    </rule>
-
- -

When the method specified in the "run" is invoked it has full control over the request and response as if it were a - servlet.

- - - - - - - -

URL Abstraction

- -

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

- -

-    <rule>
-        <from>^/tidy/page$</from>
-        <to>/old/url/scheme/page.jsp</to>
-    </rule>
-    <outbound-rule>
-        <from>^/old/url/scheme/page.jsp$</from>
-        <to>/tidy/page</to>
-    </outbound-rule>
-
- -

Any incoming requests for /tidy/page will be transparently forwarded to - /old/url/scheme/page.jsp.

- -

If you use JSTL your JSP page would have something like:

-
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
- -

This will be rewritten upon output to:

-
<a href="/tidy/page">some link</a>
- -

Or if you use standard JSP:

-
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
- -

Will generate output like:

-
<a href="/tidy/page">some link</a>
- - - - -

mod_rewrite vs UrlRewriteFilter

- - -

Examples of mod_rewrite style conf vs UrlRewriteFilter conf are below, there are all examples copied directly from - Apache 2.0's official rewrite guide.

- -

-
-<rule>
-    <name>Canonical URLs</name>
-    <note>
-        On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
-        should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
-        of which URL the user supplied with the request he should finally see the canonical one only.
-
-        We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
-        and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
-        fix a missing trailing slash for /u/user.
-
-        RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
-        RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
-    </note>
-    <from>^/~([^/]+)/?(.*)</from>
-    <to type="redirect">/u/$1/$2</to>
-</rule>
-<rule>
-    <from>^/([uge])/([^/]+)$</from>
-    <to type="redirect">/$1/$2/</to>
-</rule>
-
-
-<rule>
-    <name>Canonical Hostnames</name>
-    <note>
-        The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
-        may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
-        example.com, you might use a variant of the following recipe.
-
-        RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
-        RewriteCond %{HTTP_HOST} !^$
-        RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
-    </note>
-    <condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
-    <condition name="host" operator="notequal">^$</condition>
-    <from>^/(.*)</from>
-    <to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
-</rule>
-
-
-<rule>
-    <name>Moved DocumentRoot</name>
-    <note>
-        Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
-        really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
-        Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
-        because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
-        stuff inside this data pool work for subsequent requests.
-
-        We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
-        Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
-        matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
-        With mod_rewrite it is really trivial:
-
-        RewriteRule ^/$ /e/www/ [R]
-    </note>
-    <from>^/$</from>
-    <to type="redirect">/e/www/</to>
-</rule>
-
-
-<rule>
-    <name>Trailing Slash Problem</name>
-    <note>
-        Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
-        If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
-        the server searches for a file named foo. And because this file is a directory it complains. Actually it
-        tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
-        instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
-
-        The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
-        correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
-        we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
-        images are included into this page with relative URLs, because the browser would request an in-lined object.
-        For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
-        external redirect!
-    </note>
-    <from>^/~quux/foo$</from>
-    <to type="redirect">/~quux/foo/</to>
-</rule>
-
-
-<rule>
-    <name>Move Homedirs to Different Webserver</name>
-    <note>
-        Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
-        homedirs on a webserver to another webserver. They usually need such things when establishing a newer
-        webserver which will replace the old one over time.
-
-        The solution is trivial with mod_rewrite (and UrlRewriteFilter). On the old webserver we just redirect all
-        /~user/anypath URLs to http://newserver/~user/anypath.
-
-        RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
-    </note>
-    <from>^/~(.+)</from>
-    <to type="redirect" last="true">http://newserver/~$1</to>
-</rule>
-
-
-<rule>
-    <name>Structured Homedirs</name>
-    <note>
-        Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
-        subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
-        /home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
-
-        We use the following ruleset to expand the tilde URLs into exactly the above layout.
-
-        RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
-    </note>
-    <from>^/~(([a-z])[a-z0-9]+)(.*)</from>
-    <to>/home/$2/$1/.www$3</to>
-</rule>
-
-
-<rule>
-    <name>Redirect Homedirs For Foreigners</name>
-    <note>
-        We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
-        stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
-
-        Just a rewrite condition:
-
-        RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
-        RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
-    </note>
-    <condition name="host">!^.+\.ourdomain\.com$</condition>
-    <from>^(/~.+)</from>
-    <to type="redirect" last="true">http://www.somewhere.com/$1</to>
-</rule>
-
-
-<rule>
-    <name>Time-Dependent Rewriting</name>
-    <note>
-        When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
-        instance redirects to specialized pages. How can it be done via mod_rewrite?
-
-        There are a lot of types in conjunction with operators we can do time-dependent redirects:
-
-        RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
-        RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
-        RewriteRule ^foo\.html$ foo.day.html
-        RewriteRule ^foo\.html$ foo.night.html
-    </note>
-    <condition type="hourofday" operator="greater">7</condition>
-    <condition type="hourofday" operator="less">19</condition>
-    <from>^foo\.html$</from>
-    <to>foo.day.html</to>
-</rule>
-<rule>
-    <from>^foo\.html$</from>
-    <to>foo.night.html</to>
-</rule>
-
-
-<rule>
-    <name></name>
-    <note>
-        Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
-        backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
-        renamed.
-
-        We rewrite the old URL to the new one internally via the following rule:
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ bar.html
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to>/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-    <name>From Old to New (extern)</name>
-    <note>
-        Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
-        for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
-        i.e. their browsers Location field should change, too.
-
-        We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ bar.html [R]
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to type="redirect">/~quux/bar.html</to>
-</rule>
-
-
-<rule>
-    <name>Browser Dependent Content</name>
-    <note>
-        At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
-        content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
-        the Lynx browsers and a average feature version for all others.
-
-        We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
-        have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
-        "User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
-        stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
-        browsers receive page foo.32.html. This is done by the following ruleset:
-
-        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
-        RewriteRule ^foo\.html$ foo.NS.html [L]
-
-        RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
-        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
-        RewriteRule ^foo\.html$ foo.20.html [L]
-
-        RewriteRule ^foo\.html$ foo.32.html [L]
-    </note>
-    <condition name="user-agent">^Mozilla/3.*</condition>
-    <from>^foo\.html$</from>
-    <to last="true">foo.NS.html</to>
-</rule>
-<rule>
-    <condition name="user-agent" next="or">^Lynx/.*</condition>
-    <condition name="user-agent">^Mozilla/[12].*</condition>
-    <from>^foo\.html$</from>
-    <to last="true">foo.20.html</to>
-</rule>
-<rule>
-    <from>^foo\.html$</from>
-    <to last="true">foo.32.html</to>
-</rule>
-
-
-<rule>
-    <name>From Static to Dynamic</name>
-    <note>
-        How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
-        notice by the browser/user.
-
-        We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
-        a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
-
-        RewriteBase /~quux/
-        RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
-    </note>
-    <from>^/~quux/foo\.html$</from>
-    <to>/~quux/foo.jsp</to>
-</rule>
-
-<rule>
-    <name>Blocking of Robots</name>
-    <note>
-        How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
-        containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
-
-        We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
-        indexed area where the robot traversal would create big server load). We have to make sure that we forbid
-        access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
-        This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
-        information.
-
-        RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
-        RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
-        RewriteRule ^/~quux/foo/arc/.+ - [F]
-    </note>
-    <condition name="user-agent">^NameOfBadRobot.*</condition>
-    <condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
-    <from>^/~quux/foo/arc/.+</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-
-<rule>
-    <name>Blocked Inline-Images</name>
-    <note>
-        Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
-        nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
-        it adds useless traffic to our server.
-
-        While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
-        sends a HTTP Referer header.
-
-        RewriteCond %{HTTP_REFERER} !^$
-        RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
-        RewriteRule .*\.gif$ - [F]
-    </note>
-    <condition name="referer" operator="notequal">^$</condition>
-    <condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
-    <from>.*\.gif$</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-<rule>
-    <name>Blocked Inline-Images example 2</name>
-    <note>
-        RewriteCond %{HTTP_REFERER} !^$
-        RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
-        RewriteRule ^inlined-in-foo\.gif$ - [F]
-    </note>
-    <condition name="referer" operator="notequal">^$</condition>
-    <condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
-    <from>^inlined-in-foo\.gif$</from>
-    <set type="status">403</set>
-    <to>null</to>
-</rule>
-
-
- - - - - -

Extending UrlRewriteFilter

- - -

To extend the basic rule functionality make a subclass of org.tuckey.web.filters.urlrewrite.extend.RewriteRule

- -

For an example of an extended rule see: -
src/java/org/tuckey/web/filters/urlrewrite/sample/SampleRewriteRule.java -

- -

A "class-rule" is configured by adding it into urlrewrite.xml as follows:

- -
<class-rule class="org.tuckey.web.filters.urlrewrite.TestRuleObj"/>
- -

Or for a method with a name other than "matches":

-
<class-rule class="org.tuckey.web.filters.urlrewrite.TestRuleObj" method="trial"/>
- - - -
-
- - - - - - + + + + UrlRewriteFilter - Examples + + + + + + +
+
+

+ + UrlRewriteFilter 4.0.3

+
+ +
+ + +
+ + +

Examples

+ +

Redirect one url

+ +

+    <rule>
+        <from>^/some/old/page\.html$</from>
+        <to type="redirect">/very/new/page.html</to>
+    </rule>
+
+ +

+    <rule match-type="wildcard">
+        <from>/some/old/page.html</from>
+        <to type="redirect">/very/new/page.html</to>
+    </rule>
+
+ +

Redirect docs in a directory to another using wildcard engine.

+ +

+    <urlrewrite default-match-type="wildcard">
+
+    <rule>
+        <from>/some/old/*.doc</from>
+        <to type="redirect">/very/new/$1.doc</to>
+    </rule>
+
+    </urlrewrite>
+
+ +

Tiny/Freindly url

+ +

+    <rule>
+        <from>^/zebra$</from>
+        <to type="redirect">/big/ugly/url/1,23,56,23132.html</to>
+    </rule>
+
+ +

Default page as another (requests to / will be redirected)

+ +

+    <rule>
+        <from>^/$</from>
+        <to type="redirect">/opencms/opencms/index.html</to>
+    </rule>
+
+ +

Perform security checks in a centralised place

+ +

+    <rule>
+        <condition type="user-in-role" operator="notequal">admin</condition>
+        <condition type="user-in-role" operator="notequal">bigboss</condition>
+        <from>^/admin/(.*)$</from>
+        <to>/go-away-please.html</to>
+    </rule>
+
+ + +

Check that users are using the correct domain name to get to your site. ie, users gong to http://example.com/blah + will be redirected to http://www.example.com/blah

+ +

+    <rule>
+        <name>Domain Name Check</name>
+        <condition name="host" operator="notequal">www.example.com</condition>
+        <from>^(.*)$</from>
+        <to type="redirect">http://www.example.com/context$1</to>
+    </rule>
+
+ + +

Disable access to a directory.

+ +

+    <rule>
+        <name>Disable Directory</name>
+        <from>^/notliveyet/.*$</from>
+        <set type="status">403</set>
+        <to>null</to>
+    </rule>
+
+ +

Redirect a directory (for moved content)

+ +

+    <rule>
+        <from>^/some/olddir/(.*)$</from>
+        <to type="redirect">/very/newdir/$1</to>
+    </rule>
+
+ +

Clean a URL

+ +

+    <rule>
+        <from>^/products/([0-9]+)$</from>
+        <to>/products/index.jsp?product_id=$1</to>
+    </rule>
+
+ +

e.g. /products/1234 will be passed on to /products/index.jsp?product_id=1234 + without the user noticing.

+ +

+    <rule>
+        <from>^/world/([a-z]+)/([a-z]+)$</from>
+        <to>/world.jsp?country=$1&amp;city=$2</to>
+    </rule>
+
+ +

e.g. /world/unitedstates/newyork will be passed on to /world.jsp?country=unitedstates&city=newyork +

+ +

Browser detection

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/[1-4]</condition>
+        <from>^/some/page\.html$</from>
+        <to>/some/page-for-old-browsers.html</to>
+    </rule>
+
+ +

e.g. will pass the request for /some/page.html on to /some/page-for-old-browsers.html + only for older browsers whose user agent strings match Mozilla/1, Mozilla/2, + Mozilla/3 or Mozilla/4.

+ + +

Security. Preclude certain types of method from you web application.

+ +

+    <rule>
+        <condition type="method" next="or">PROPFIND</condition>
+        <condition type="method">PUT</condition>
+        <from>.*</from>
+        <to type="redirect">/bad-method.html</to>
+    </rule>
+
+ + +

Sunday Specials

+ +

+    <rule>
+        <condition type="dayofweek">1</condition>
+        <from>^/products/$</from>
+        <to>/products/sunday-specials.html</to>
+    </rule>
+
+ + +

Set the "Cache-Control" HTTP response header for all requests

+ +

+    <rule>
+        <from>.*</from>
+        <set type="response-header" name="Cache-Control">max-age=3600, must-revalidate</set>
+    </rule>
+
+ +

Forward a request to a servlet

+ +

+    <rule>
+        <from>^/products/purchase$</from>
+        <set name="action">purchase</set>
+        <to>/servlets/ProductsServlet</to>
+    </rule>
+
+ +

e.g. the request /products/purchase will be forwarded to /servlets/ProductsServlet and + inside + the servlet request.getAttribute("action") will return purchase.

+ +

Set an "Expires" HTTP header 6 hours into the future for js, css and gif files

+ +

+    <rule>
+        <from>^.*\.(js|css|gif)$</from>
+        <set type="expires">6 hours</set>
+    </rule>
+
+ +

Hide jsessionid for requests from googlebot.

+ +

+  <outbound-rule>
+       <name>Strip URL Session ID's</name>
+       <note>
+           Strip ;jsession=XXX from urls passed through
+response.encodeURL().
+           The characters ? and # are the only things we can use to
+find out where the jsessionid ends.
+           The expression in 'from' below contains three capture
+groups, the last two being optional.
+               1, everything before ;jesessionid
+               2, everything after ;jesessionid=XXX starting with a ?
+(to get the query string) up to #
+               3, everything ;jesessionid=XXX and optionally ?XXX
+starting with a # (to get the target)
+           eg,
+           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
+           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
+           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
+index.jsp#dfds
+           from u.jsp;jsessionid=wert.hg - u.jsp
+           from /;jsessionid=tyu - /
+       </note>
+       <condition name="user-agent">googlebot</condition>
+       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
+       <to>$1$2$3</to>
+   </outbound-rule>
+
+ +

Permanently redirect incoming URLs containing jsessionid.

+ +

+  <rule>
+       <name>Strip URL Session ID's</name>
+       <note>
+           Strip ;jsession=XXX from urls passed through
+response.encodeURL().
+           The characters ? and # are the only things we can use to
+find out where the jsessionid ends.
+           The expression in 'from' below contains three capture
+groups, the last two being optional.
+               1, everything before ;jesessionid
+               2, everything after ;jesessionid=XXX starting with a ?
+(to get the query string) up to #
+               3, everything ;jesessionid=XXX and optionally ?XXX
+starting with a # (to get the target)
+           eg,
+           from index.jsp;jsessionid=sss?qqq to index.jsp?qqq
+           from index.jsp;jsessionid=sss?qqq#ttt to index.jsp?qqq#ttt
+           from index.jsp;jsessionid=asdasdasdsadsadasd#dfds -
+index.jsp#dfds
+           from u.jsp;jsessionid=wert.hg - u.jsp
+           from /;jsessionid=tyu - /
+       </note>
+       <condition type="requested-session-id-from-url" operator="equal">true</condition>
+       <from>^(.*?)(?:\;jsessionid=[^\?#]*)?(\?[^#]*)?(#.*)?$</from>
+       <to type="permanent-redirect">$1$2$3</to>
+   </rule>
+
+ + + +

Method Invocation

+ +

The standard servlet mapping that is done via web.xml is rather limiting. Only *.xxx or /xxxx/*, no abilty to have + any sort of smart matching. Using UrlRewriteFilter any rule when matched can be set to run method(s) on a class.

+ +

Invoke a servlet directly

+ +

+    <rule>
+    <from>^/products/purchase$</from>
+    <run class="com.blah.web.MyServlet" method="doGet" />
+    </rule>
+
+ +

This will invoke doGet(HttpServletRequest request, HttpServletResponse response) when the "from" is + matched on a request. (remeber this method needs to be public!)

+ +

Use it to delagate cleanly to your methods

+ +

+    <rule>
+        <from>^/pref-editor/addresses$</from>
+        <run class="com.blah.web.PrefsServlet" method="runAddresses" />
+    </rule>
+    <rule>
+        <from>^/pref-editor/phone-nums$</from>
+        <run class="com.blah.web.PrefsServlet" method="runPhoneNums" />
+    </rule>
+
+ +

Browser based delagation to your methods

+ +

+    <rule>
+        <condition name="user-agent">Mozilla/[1-4]</condition>
+        <from>^/content/.*$</from>
+        <run class="com.blah.web.ContentServlet" method="runForOldBrowsers" />
+    </rule>
+    <rule>
+        <condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+        <from>^/content/.*$</from>
+        <run class="com.blah.web.GeneralServlet" method="runRobotMonitor" />
+        <run class="com.blah.web.ContentServlet" method="runForNewBrowsers" />
+    </rule>
+
+ +

When the method specified in the "run" is invoked it has full control over the request and response as if it were a + servlet.

+ + + + + + + +

URL Abstraction

+ +

Both incoming request and embedded links in JSP's can be rewritten allowing full URL abstraction.

+ +

+    <rule>
+        <from>^/tidy/page$</from>
+        <to>/old/url/scheme/page.jsp</to>
+    </rule>
+    <outbound-rule>
+        <from>^/old/url/scheme/page.jsp$</from>
+        <to>/tidy/page</to>
+    </outbound-rule>
+
+ +

Any incoming requests for /tidy/page will be transparently forwarded to + /old/url/scheme/page.jsp.

+ +

If you use JSTL your JSP page would have something like:

+
<a href="<c:url value="/old/url/scheme/page.jsp"/>">some link</a>
+ +

This will be rewritten upon output to:

+
<a href="/tidy/page">some link</a>
+ +

Or if you use standard JSP:

+
<a href="<%= response.encodeURL("/old/url/scheme/page.jsp") %>">some link</a>
+ +

Will generate output like:

+
<a href="/tidy/page">some link</a>
+ + + + +

mod_rewrite vs UrlRewriteFilter

+ + +

Examples of mod_rewrite style conf vs UrlRewriteFilter conf are below, there are all examples copied directly from + Apache 2.0's official rewrite guide.

+ +

+
+<rule>
+    <name>Canonical URLs</name>
+    <note>
+        On some webservers there are more than one URL for a resource. Usually there are canonical URLs (which
+        should be actually used and distributed) and those which are just shortcuts, internal ones, etc. Independent
+        of which URL the user supplied with the request he should finally see the canonical one only.
+
+        We do an external HTTP redirect for all non-canonical URLs to fix them in the location view of the Browser
+        and for all subsequent requests. In the example ruleset below we replace /~user by the canonical /u/user and
+        fix a missing trailing slash for /u/user.
+
+        RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
+        RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
+    </note>
+    <from>^/~([^/]+)/?(.*)</from>
+    <to type="redirect">/u/$1/$2</to>
+</rule>
+<rule>
+    <from>^/([uge])/([^/]+)$</from>
+    <to type="redirect">/$1/$2/</to>
+</rule>
+
+
+<rule>
+    <name>Canonical Hostnames</name>
+    <note>
+        The goal of this rule is to force the use of a particular hostname, in preference to other hostnames which
+        may be used to reach the same site. For example, if you wish to force the use of www.example.com instead of
+        example.com, you might use a variant of the following recipe.
+
+        RewriteCond %{HTTP_HOST} !^fully\.qualified\.domain\.name [NC]
+        RewriteCond %{HTTP_HOST} !^$
+        RewriteRule ^/(.*) http://fully.qualified.domain.name/$1 [L,R]
+    </note>
+    <condition name="host" operator="notequal">^fully\.qualified\.domain\.name</condition>
+    <condition name="host" operator="notequal">^$</condition>
+    <from>^/(.*)</from>
+    <to type="redirect" last="true">http://fully.qualified.domain.name/$1</to>
+</rule>
+
+
+<rule>
+    <name>Moved DocumentRoot</name>
+    <note>
+        Usually the DocumentRoot of the webserver directly relates to the URL "/". But often this data is not
+        really of top-level priority, it is perhaps just one entity of a lot of data pools. For instance at our
+        Intranet sites there are /e/www/ (the homepage for WWW), /e/sww/ (the homepage for the Intranet) etc. Now
+        because the data of the DocumentRoot stays at /e/www/ we had to make sure that all inlined images and other
+        stuff inside this data pool work for subsequent requests.
+
+        We just redirect the URL / to /e/www/. While is seems trivial it is actually trivial with mod_rewrite, only.
+        Because the typical old mechanisms of URL Aliases (as provides by mod_alias and friends) only used prefix
+        matching. With this you cannot do such a redirection because the DocumentRoot is a prefix of all URLs.
+        With mod_rewrite it is really trivial:
+
+        RewriteRule ^/$ /e/www/ [R]
+    </note>
+    <from>^/$</from>
+    <to type="redirect">/e/www/</to>
+</rule>
+
+
+<rule>
+    <name>Trailing Slash Problem</name>
+    <note>
+        Every webmaster can sing a song about the problem of the trailing slash on URLs referencing directories.
+        If they are missing, the server dumps an error, because if you say /~quux/foo instead of /~quux/foo/ then
+        the server searches for a file named foo. And because this file is a directory it complains. Actually it
+        tries to fix it itself in most of the cases, but sometimes this mechanism need to be emulated by you. For
+        instance after you have done a lot of complicated URL rewritings to CGI scripts etc.
+
+        The solution to this subtle problem is to let the server add the trailing slash automatically. To do this
+        correctly we have to use an external redirect, so the browser correctly requests subsequent images etc. If
+        we only did a internal rewrite, this would only work for the directory page, but would go wrong when any
+        images are included into this page with relative URLs, because the browser would request an in-lined object.
+        For instance, a request for image.gif in /~quux/foo/index.html would become /~quux/image.gif without the
+        external redirect!
+    </note>
+    <from>^/~quux/foo$</from>
+    <to type="redirect">/~quux/foo/</to>
+</rule>
+
+
+<rule>
+    <name>Move Homedirs to Different Webserver</name>
+    <note>
+        Many webmasters have asked for a solution to the following situation: They wanted to redirect just all
+        homedirs on a webserver to another webserver. They usually need such things when establishing a newer
+        webserver which will replace the old one over time.
+
+        The solution is trivial with mod_rewrite (and UrlRewriteFilter). On the old webserver we just redirect all
+        /~user/anypath URLs to http://newserver/~user/anypath.
+
+        RewriteRule ^/~(.+) http://newserver/~$1 [R,L]
+    </note>
+    <from>^/~(.+)</from>
+    <to type="redirect" last="true">http://newserver/~$1</to>
+</rule>
+
+
+<rule>
+    <name>Structured Homedirs</name>
+    <note>
+        Some sites with thousands of users usually use a structured homedir layout, i.e. each homedir is in a
+        subdirectory which begins for instance with the first character of the username. So, /~foo/anypath is
+        /home/f/foo/.www/anypath while /~bar/anypath is /home/b/bar/.www/anypath.
+
+        We use the following ruleset to expand the tilde URLs into exactly the above layout.
+
+        RewriteRule ^/~(([a-z])[a-z0-9]+)(.*) /home/$2/$1/.www$3
+    </note>
+    <from>^/~(([a-z])[a-z0-9]+)(.*)</from>
+    <to>/home/$2/$1/.www$3</to>
+</rule>
+
+
+<rule>
+    <name>Redirect Homedirs For Foreigners</name>
+    <note>
+        We want to redirect homedir URLs to another webserver www.somewhere.com when the requesting user does not
+        stay in the local domain ourdomain.com. This is sometimes used in virtual host contexts.
+
+        Just a rewrite condition:
+
+        RewriteCond %{REMOTE_HOST} !^.+\.ourdomain\.com$
+        RewriteRule ^(/~.+) http://www.somewhere.com/$1 [R,L]
+    </note>
+    <condition name="host">!^.+\.ourdomain\.com$</condition>
+    <from>^(/~.+)</from>
+    <to type="redirect" last="true">http://www.somewhere.com/$1</to>
+</rule>
+
+
+<rule>
+    <name>Time-Dependent Rewriting</name>
+    <note>
+        When tricks like time-dependent content should happen a lot of webmasters still use CGI scripts which do for
+        instance redirects to specialized pages. How can it be done via mod_rewrite?
+
+        There are a lot of types in conjunction with operators we can do time-dependent redirects:
+
+        RewriteCond %{TIME_HOUR}%{TIME_MIN} >0700
+        RewriteCond %{TIME_HOUR}%{TIME_MIN} <1900
+        RewriteRule ^foo\.html$ foo.day.html
+        RewriteRule ^foo\.html$ foo.night.html
+    </note>
+    <condition type="hourofday" operator="greater">7</condition>
+    <condition type="hourofday" operator="less">19</condition>
+    <from>^foo\.html$</from>
+    <to>foo.day.html</to>
+</rule>
+<rule>
+    <from>^foo\.html$</from>
+    <to>foo.night.html</to>
+</rule>
+
+
+<rule>
+    <name></name>
+    <note>
+        Assume we have recently renamed the page foo.html to bar.html and now want to provide the old URL for
+        backward compatibility. Actually we want that users of the old URL even not recognize that the pages was
+        renamed.
+
+        We rewrite the old URL to the new one internally via the following rule:
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ bar.html
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to>/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+    <name>From Old to New (extern)</name>
+    <note>
+        Assume again that we have recently renamed the page foo.html to bar.html and now want to provide the old URL
+        for backward compatibility. But this time we want that the users of the old URL get hinted to the new one,
+        i.e. their browsers Location field should change, too.
+
+        We force a HTTP redirect to the new URL which leads to a change of the browsers and thus the users view:
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ bar.html [R]
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to type="redirect">/~quux/bar.html</to>
+</rule>
+
+
+<rule>
+    <name>Browser Dependent Content</name>
+    <note>
+        At least for important top-level pages it is sometimes necessary to provide the optimum of browser dependent
+        content, i.e. one has to provide a maximum version for the latest Netscape variants, a minimum version for
+        the Lynx browsers and a average feature version for all others.
+
+        We cannot use content negotiation because the browsers do not provide their type in that form. Instead we
+        have to act on the HTTP header "User-Agent". The following condig does the following: If the HTTP header
+        "User-Agent" begins with "Mozilla/3", the page foo.html is rewritten to foo.NS.html and and the rewriting
+        stops. If the browser is "Lynx" or "Mozilla" of version 1 or 2 the URL becomes foo.20.html. All other
+        browsers receive page foo.32.html. This is done by the following ruleset:
+
+        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/3.*
+        RewriteRule ^foo\.html$ foo.NS.html [L]
+
+        RewriteCond %{HTTP_USER_AGENT} ^Lynx/.* [OR]
+        RewriteCond %{HTTP_USER_AGENT} ^Mozilla/[12].*
+        RewriteRule ^foo\.html$ foo.20.html [L]
+
+        RewriteRule ^foo\.html$ foo.32.html [L]
+    </note>
+    <condition name="user-agent">^Mozilla/3.*</condition>
+    <from>^foo\.html$</from>
+    <to last="true">foo.NS.html</to>
+</rule>
+<rule>
+    <condition name="user-agent" next="or">^Lynx/.*</condition>
+    <condition name="user-agent">^Mozilla/[12].*</condition>
+    <from>^foo\.html$</from>
+    <to last="true">foo.20.html</to>
+</rule>
+<rule>
+    <from>^foo\.html$</from>
+    <to last="true">foo.32.html</to>
+</rule>
+
+
+<rule>
+    <name>From Static to Dynamic</name>
+    <note>
+        How can we transform a static page foo.html into a dynamic variant foo.cgi in a seamless way, i.e. without
+        notice by the browser/user.
+
+        We just rewrite the URL to the jsp/servlet and force the correct MIME-type so it gets really run as
+        a CGI-script. This way a request to /~quux/foo.html internally leads to the invocation of /~quux/foo.jsp.
+
+        RewriteBase /~quux/
+        RewriteRule ^foo\.html$ foo.cgi [T=application/x-httpd-cgi]
+    </note>
+    <from>^/~quux/foo\.html$</from>
+    <to>/~quux/foo.jsp</to>
+</rule>
+
+<rule>
+    <name>Blocking of Robots</name>
+    <note>
+        How can we block a really annoying robot from retrieving pages of a specific webarea? A /robots.txt file
+        containing entries of the "Robot Exclusion Protocol" is typically not enough to get rid of such a robot.
+
+        We use a ruleset which forbids the URLs of the webarea /~quux/foo/arc/ (perhaps a very deep directory
+        indexed area where the robot traversal would create big server load). We have to make sure that we forbid
+        access only to the particular robot, i.e. just forbidding the host where the robot runs is not enough.
+        This would block users from this host, too. We accomplish this by also matching the User-Agent HTTP header
+        information.
+
+        RewriteCond %{HTTP_USER_AGENT} ^NameOfBadRobot.*
+        RewriteCond %{REMOTE_ADDR} ^123\.45\.67\.[8-9]$
+        RewriteRule ^/~quux/foo/arc/.+ - [F]
+    </note>
+    <condition name="user-agent">^NameOfBadRobot.*</condition>
+    <condition type="remote-addr">^123\.45\.67\.[8-9]$</condition>
+    <from>^/~quux/foo/arc/.+</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+
+<rule>
+    <name>Blocked Inline-Images</name>
+    <note>
+        Assume we have under http://www.quux-corp.de/~quux/ some pages with inlined GIF graphics. These graphics are
+        nice, so others directly incorporate them via hyperlinks to their pages. We don't like this practice because
+        it adds useless traffic to our server.
+
+        While we cannot 100% protect the images from inclusion, we can at least restrict the cases where the browser
+        sends a HTTP Referer header.
+
+        RewriteCond %{HTTP_REFERER} !^$
+        RewriteCond %{HTTP_REFERER} !^http://www.quux-corp.de/~quux/.*$ [NC]
+        RewriteRule .*\.gif$ - [F]
+    </note>
+    <condition name="referer" operator="notequal">^$</condition>
+    <condition name="referer" operator="notequal">^http://www.quux-corp.de/~quux/.*$</condition>
+    <from>.*\.gif$</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+<rule>
+    <name>Blocked Inline-Images example 2</name>
+    <note>
+        RewriteCond %{HTTP_REFERER} !^$
+        RewriteCond %{HTTP_REFERER} !.*/foo-with-gif\.html$
+        RewriteRule ^inlined-in-foo\.gif$ - [F]
+    </note>
+    <condition name="referer" operator="notequal">^$</condition>
+    <condition name="referer" operator="notequal">.*/foo-with-gif\.html$</condition>
+    <from>^inlined-in-foo\.gif$</from>
+    <set type="status">403</set>
+    <to>null</to>
+</rule>
+
+
+ + + + + +

Extending UrlRewriteFilter

+ + +

To extend the basic rule functionality make a subclass of org.tuckey.web.filters.urlrewrite.extend.RewriteRule

+ +

For an example of an extended rule see: +
src/java/org/tuckey/web/filters/urlrewrite/sample/SampleRewriteRule.java +

+ +

A "class-rule" is configured by adding it into urlrewrite.xml as follows:

+ +
<class-rule class="org.tuckey.web.filters.urlrewrite.TestRuleObj"/>
+ +

Or for a method with a name other than "matches":

+
<class-rule class="org.tuckey.web.filters.urlrewrite.TestRuleObj" method="trial"/>
+ + + +
+
+ + + + + + diff --git a/src/doc/manual/4.0/index.html b/src/doc/manual/4.0/index.html index 6c2efab6..e1c9360c 100644 --- a/src/doc/manual/4.0/index.html +++ b/src/doc/manual/4.0/index.html @@ -1,1493 +1,1493 @@ - - - - UrlRewriteFilter - Manual - - - - - - -
-
-

- - UrlRewriteFilter 4.0.3

-
- -
- - -
- -

Manual

- - -

Community support is available at UrlRewrite on StackOverflow.

- -

Read examples of usage and a - sample of the ant task report. - If you have any suggestions/examples for this manual, please post them to the - group.

- - - -

Install

- -
    -
  1. Add Maven dependency below or add - urlrewritefilter-4.0.3.jar - directly into your WEB-INF/lib directory. -
    <dependency>
    -    <groupId>org.tuckey</groupId>
    -    <artifactId>urlrewritefilter</artifactId>
    -    <version>4.0.3</version>
    -</dependency>
  2. -
  3. Add the following to your WEB-INF/web.xml (add it near the top above your - servlet mappings (if you have any)): (see filter - parameters for more options) -
    <filter>
    -    <filter-name>UrlRewriteFilter</filter-name>
    -    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    -</filter>
    -<filter-mapping>
    -    <filter-name>UrlRewriteFilter</filter-name>
    -    <url-pattern>/*</url-pattern>
    -    <dispatcher>REQUEST</dispatcher>
    -    <dispatcher>FORWARD</dispatcher>
    -</filter-mapping>
  4. -
  5. Add urlrewrite.xml - into your WEB-INF directory. (src/main/webapp/WEB-INF/ for Maven users)
  6. -
  7. Restart the context.
  8. -
- -

You can visit http://127.0.0.1:8080/rewrite-status - (or whatever the address of your local webapp and context) - to see the output (note: this page is only viewable from localhost).

- - - -

Filter Parameters

- -

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

- -
-<filter>
-    <filter-name>UrlRewriteFilter</filter-name>
-    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-    <!-- set the amount of seconds the conf file will be checked for reload
-    can be a valid integer (0 denotes check every time,
-    -1 denotes no reload check, default -1) -->
-    <init-param>
-        <param-name>confReloadCheckInterval</param-name>
-        <param-value>60</param-value>
-    </init-param>
-
-    <!-- if you need to the conf file path can be changed
-    it is specified as a path relative to the root of your context
-    (default /WEB-INF/urlrewrite.xml) -->
-    <init-param>
-        <param-name>confPath</param-name>
-        <param-value>/WEB-INF/urlrewrite.xml</param-value>
-    </init-param>
-
-    <!-- sets up log level (will be logged to context log)
-    can be: slf4j, TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL,
-    sysout:{level} (ie, sysout:DEBUG)
-    if you are having trouble using normal levels use sysout:DEBUG
-    (default WARN) -->
-    <init-param>
-        <param-name>logLevel</param-name>
-        <param-value>DEBUG</param-value>
-    </init-param>
-
-    <!-- you can change status path so that it does not
-    conflict with your installed apps (note, defaults
-    to /rewrite-status) note, must start with / -->
-    <init-param>
-        <param-name>statusPath</param-name>
-        <param-value>/status</param-value>
-    </init-param>
-
-    <!-- you can disable status page if desired
-    can be: true, false (default true) -->
-    <init-param>
-        <param-name>statusEnabled</param-name>
-        <param-value>true</param-value>
-    </init-param>
-
-    <!-- you may want to allow more hosts to look at the status page
-    statusEnabledOnHosts is a comma delimited list of hosts, * can
-    be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
-    <init-param>
-        <param-name>statusEnabledOnHosts</param-name>
-        <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
-    </init-param>
-
-    <!-- you may want to allow more hosts to look at the status page
-    statusEnabledOnHosts is a comma delimited list of hosts, * can
-    be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
-    <init-param>
-        <param-name>statusEnabledOnHosts</param-name>
-        <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
-    </init-param>
-
-    <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
-    is not specified confPath will be set to /WEB-INF/.htaccess) -->
-    <init-param>
-        <param-name>modRewriteConf</param-name>
-        <param-value>false</param-value>
-    </init-param>
-
-    <!-- load mod_rewrite style configuration from this parameter's value.
-            note, Setting this parameter will mean that all other conf parameters are ignored.
-        <init-param>
-            <param-name>modRewriteConfText</param-name>
-            <param-value>
-                RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
-                RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
-            </param-value>
-        </init-param>
-    -->
-
-    <!-- defaults to false. allow conf file to be set by calling /rewrite-status/?conf=/WEB-INF/urlrewrite2.xml
-            designed to be used for testing only
-        <init-param>
-            <param-name>allowConfSwapViaHttp</param-name>
-            <param-value>false</param-value>
-        </init-param>
-    -->
-
-</filter>
-
-<filter-mapping>
-    <filter-name>UrlRewriteFilter</filter-name>
-    <url-pattern>/*</url-pattern>
-    <dispatcher>REQUEST</dispatcher>
-    <dispatcher>FORWARD</dispatcher>
-</filter-mapping>
-
- -

Note, setting logLevel to slf4j will cause the built-in logging to - call slf4j as if it was the logging framework; - obviously, you will need to have the jar for slf4j in your classpath.

- - - -

Configuration File WEB-INF/urlrewrite.xml

- - - - - -
- - <urlrewrite>   - <rule>   - <outbound-rule>   - <class-rule> -
- <name>   - <note>   - <condition>   - <from>   - <to>   - <set>   - <run>   -
- Back References   - Variables   - Functions   -
-
-
- -

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named - urlrewrite.xml. - It may be helpful to read the UrlRewriteFilter DTD - (Document Type Definition). Please also make sure you look at the examples. A simple - configuration file looks like this:

- -
-<?xml version="1.0" encoding="utf-8"?>
-
-<!DOCTYPE urlrewrite
-    PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
-    "http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
-
-<urlrewrite>
-
-    <rule>
-       <from>^/some/olddir/(.*)$</from>
-       <to type="redirect">/very/newdir/$1</to>
-    </rule>
-
-    <rule match-type="wildcard">
-       <from>/blog/archive/**</from>
-       <to type="redirect">/roller/history/$1</to>
-    </rule>
-
-</urlrewrite>
-
- - -

The urlrewrite.xml file must have a root element called "urlrewrite" and contain - at least one "rule" element.

- -

A "rule" must contain a "from" and a "to" and can have zero or more "condition" elements and zero or more and/or - "set" elements.

- -

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then - the "from" will be applied to the request URL and the final URL generated by applying the - "to" to the "from" pattern. So long as a rule has matched, then the "set" will be run.

- - - -

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

- -
-Pattern.compile(<from> element);
-pattern.matcher(request url);
-matcher.replaceAll(<to> element);
-if ( <condition> elements match && matcher.find() ) {
-    handle <set> elements (if any)
-    execute <run> elements (if any)
-    perform <to> element (if any)
-}
-
- - - -

<urlrewrite> element

- -

The top-level element.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
default-match-type
(optional)
regex (default)All rules and conditions will be processed using the Java Regular Expression engine (unless - match-type is specified on a rule).
wildcardAll rules and conditions will be processed using the Wildcard Expression - engine - (unless match-type is specified on a rule).
decode-using
(optional)
header,utf8 (default)When URL is decoded request.getCharacterEncoding() will be used, if that is empty UTF-8 will be used. -
nullDo not decode at all. (note, this means the literal string null e.g. decode-using="null")
headerOnly use request.getCharacterEncoding() to decode.
[encoding]Only use a specific character encoding, e.g., ISO-8859-1. - See Java Charset Object - for all character encodings. -
header,[encoding] - When URL is decoded request.getCharacterEncoding() will be used, if that is empty a specific character - encoding, e.g., ISO-8859-1. - See Java Charset Object - for all character encodings. -
use-query-string
(optional)
false (default)The query string will not be appended to the URL that the "from" element matches against.
trueThe query string will be appended to the URL that the "from" element matches against.
use-context
(optional)
false (default)The context path will not be added to the URL that the "from" element matches against.
trueThe context path will be added to the URL that the "from" element matches against.
- - - -

<rule> element

- -

Zero or more. The basis of a rule.

- - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
match-type
(optional)
regex (default)This rule and its conditions will be processed using the Java Regular Expression engine.
wildcardThis rule and its conditions will be processed using the Wildcard Expression engine. -
- -

In the following example requests for /world/usa/nyc will be transparently forwarded to - /world.jsp

- -
-<rule match-type="regex">
-   <from>^/world/([a-z]+)/([a-z]+)$</from>
-   <to>/world.jsp</to>
-</rule>
-
- -
-<rule match-type="wildcard">
-   <from>/world/*/*</from>
-   <to>/world.jsp</to>
-</rule>
-
- - - -

<outbound-rule> element

- -

Zero or more. This is very similar to a standard rule, but it is used for rewriting URLs that go through - response.encodeURL().

- - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
false (default)Run encodeURL() after running this outbound-rule.
trueRun encodeURL() before running this outbound-rule.
- -

May contain "run", "from", "to" and "set" element(s) also. Example:

- -
-<outbound-rule>
-    <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
-    <to>/world/$1/$2</to>
-</outbound-rule>
-
- -

Using the example above JSP's with the code -
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") - %>">nyc</a> -
will output -
<a href="/world/usa/nyc">nyc</a> -

- -

Or JSTL -
<a href="<c:url value="/world.jsp?country=${country}&amp;city=${city}" - />">nyc</a> -
will output -
<a href="/world/usa/nyc">nyc</a> -

- -

Note, If you are using JSTL (ie, <c:url), this will work also.

- - - -

<name> element

- -

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. - See ant task.

- -
-<rule>
-    <name>World Rule</name>
-    <from>^/world/([a-z]+)/([a-z]+)$</from>
-    <to>/world.jsp?country=$1&amp;city=$2</to>
-</rule>
-
- - - -

<note> element

- -

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. - See ant task.

- -
-<rule>
-    <name>World Rule</name>
-    <note>
-        Cleanly redirect world requests to JSP,
-        a country and city must be specified.
-    </note>
-    <from>^/world/([a-z]+)/([a-z]+)$</from>
-    <to>/world.jsp</to>
-</rule>
-
- - - -

<condition> element

- -

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run - (unless "next" is set to "or" obviously).

- -

Value can be any Regular Expression.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD, etc.
portThe port that the web application server is running on.
time - Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC, otherwise known as Unix - time). -
i.e. (new Date()).getTime() -
This can be used for making sure content goes live only at a time you set. -
year - Current year at the server. -
i.e. (Calendar.getInstance()).get(Calendar.YEAR) -
month - Month at the server. January is 0 -
i.e. (Calendar.getInstance()).get(Calendar.MONTH) -
dayofmonth - Day of the month at the server. March first is 1 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) -
dayofweek - Day of the week at the server. Saturday is 1, Sunday is 7 -
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) -
ampm - AM or PM time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) -
hourofday - The hour of the day (24 hour clock) at the server. 10pm is 22 -
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) -
minute - The minute field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) -
second - The second field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.SECOND) -
millisecond - The millisecond field of the current time at the server. -
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) -
attribute - Will check the value of a request attribute (don't confuse this with parameter!), name must be set when - using this type. -
i.e. request.getAttribute([name]) - -
auth-type - Will check the value of a request attribute (don't confuse this with parameter!) -
i.e. request.getAuthType() - -
character-encoding - The character encoding of the imcoming request. -
i.e. request.getCharacterEncoding() - -
content-length - The length of the imcoming request (can be useful if you want to deny large requests). -
i.e. request.getContentLength() - -
content-type - The type of the imcoming request. (this is probably not that useful) -
i.e. request.getContentType() - -
context-path - The context path of the imcoming request. -
i.e. request.getContextPath() - -
cookie - The value of a cookie, note, name must be specified to use this -
i.e. request.getCookies() - the find we the one with [name] specified and check the value. -
parameter - A tidier way of checking request parameters than looking for them in the query string. This will check for the - parameter in GET or POST, note, name must be specified. -
i.e. request.getParameter([name]) - -
path-info - i.e. request.getPathInfo() - -
path-translated - i.e. request.getPathTranslated() - -
protocolThe protocol used to make the request, e.g. HTTP/1.1 -
i.e. request.getProtocol() - -
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob -
i.e. request.getQueryString() - -
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 -
i.e. request.getRemoteAddr() - -
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, - this will only work if your app server is configured to lookup host names, most aren't). -
i.e. request.getRemoteHost() - -
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt -
i.e. request.getRemoteUser() - -
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 -
i.e. request.getRequestedSessionId() - -
requested-session-id-from-cookieWhether the requested session ID is from a cookie or not -
i.e. request.isRequestedSessionIdFromCookie() - -
requested-session-id-from-urlWhether the requested session ID is from the URL or not -
i.e. request.isRequestedSessionIdFromURL() - -
requested-session-id-validWhether the requested session ID is valid or not -
i.e. request.isRequestedSessionIdValid() - -
request-uriReturns the part of this request's URL from the protocol name up to the query - string in the first line of the HTTP request -
i.e. request.getRequestURI() - -
request-urlReconstructs the URL the client used to make the request. The returned URL - contains a protocol, server name, port number, and server path, but it does not include query string parameters. -
i.e. request.getRequestURL() - -
session-attribute - (note, name must be set) -
i.e. session.getAttribute([name]) - -
session-isnew - Weather the session is new or not. -
i.e. session.isNew() - -
server-name - The host name of the server to which the request was sent (from the host header not the machine name). -
i.e. request.getServerName() - -
scheme - The scheme used for the request, e.g. http or https -
i.e. request.getScheme() - -
user-in-role - (Note, the value for this cannot be a regular expression) -
i.e. request.isUserInRole([value]) - -
name
(optional)
(can be anything)If the type is a header, this specifies the name of the HTTP header used to run the value - against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator is to be used when the condition is run, the regular expression matches, or the values are - equal.
notequalNot equal to. (i.e. request value != condition value).
greaterGreater than. (i.e. request value > condition value). Note, this operator only works with - numeric - rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only works with numeric - rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator - only - works with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only - works with numeric rule types.
- -

Examples:

- -
-<condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
-
-<condition type="user-in-role" operator="notequal">bigboss</condition>
-
-<condition name="host" operator="notequal">www.example.com</condition>
-
-<condition type="method" next="or">PROPFIND</condition>
-<condition type="method">PUT</condition>
-
- - - -

<from> element

- -

You must always have exactly one for each rule or outbound-rule. Value can be a regular expression in the - Perl5 style. Note, "from" URLs are relative to the context.

- - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using a case insentitive match. Ie, "/WellingtoN" will match "/wellington". -
trueThis value will be matched using a case sensitive match. ie, "/aAa" will NOT match "/aaa". -
- -

Example:

- -
-<from>^/world/([a-z]+)$</from>
-
- - -

<to> element

- -

Value can be a regular replacement expression in the Perl5 style.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally - forwarded - to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as - UrlRewriteFilter. This is the same as doing: -
RequestDispatcher rq = request.getRequestDispatcher([to value]); -
rq.forward(request, response);
-
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. - This is the same a doing: -
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_PERMANENTLY is the HTTP status code 301)
temporary-redirectThe same as doing: -
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); -
response.setHeader("Location", [to value]);
-
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
pre-include
post-include
proxyThe request will be proxied to the full URL specified. commons-http and commons-codec must both be in the - classpath to use this feature. -
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) - will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) - will NOT be called.
context
(optional)
If your application server is configured to allow "cross-context" communication, then this attribute can be used - to forward (and only forward, not redirect or other "to" types) requests to a named servlet context. -
-
On Tomcat, for instance, the application contexts in the server configuration (server.xml or - context.xml) need the option crossContext="true". For instance, the two applications mentioned before - ("app" and "forum") have to be defined as: -
-
<Context docBase="app" path="/app" reloadable="true" crossContext="true"/> -
<Context docBase="forum" path="/forum" reloadable="true" crossContext="true"/> -
qsappend
(optional)
false (default)
trueAppend the query string to the to url when redirecting or forwarding.
- -

Note, "to" can be null, i.e., <to>null</to>; this will mean that the request will go no - further if the rule is matched (i.e., this filter will not call chain.doFilter).

- -

If "to" is set to -, no substitution will take place, and the request will go on like nothing happened (i.e., this filter will call chain.doFilter).

- -
-<to>/world.jsp?country=$1</to>
-
- -

To elements can contain backreferences and variables.

- - -

Backreferences

- -
-%N
-
- -

Provides access to the grouped parts (parentheses) of the pattern from the last matched Condition - in the current rule. - N must be less than 10 and greater than 0 (i.e. %1, %2, %3 etc).

- - -

Variables

- -
-%{VARIABLE-NAME}
-
- -

Any valid condition type can be used as a variable name. ie, - '%{port}' will be translated to '80', - '%{year}' to '2005', - '%{cookie:myCookie}' would be translated to - 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

- -

Valid types are condition types; see condition for a full description.

- - -

Functions

- -
-${FUNCTION:PARAMS}
-
- -

Functions can be places in set and to elements.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NameExampleExample ReturnsExplanation
replace${replace:my cat is a blue cat:cat:dog}my dog is a blue dog
replaceFirst${replaceFirst:my cat is a blue cat:cat:dog}my cat is a blue dog
escape${escape:utf8:a b c}a+b+cEscapes/Encodes string using URLEncoder.encode using the specified encoding.
unescape${unescape:utf8:a+b+c}a b cUnescapes/Unencodes string using URLEncoder.decode using the specified encoding.
lower${lower:Hello World}hello world
upper${upper:hello}HELLO
trim${trim: abc def }abc def
- - - -

<set> element

- -

Allows you to set various things if the rule is matched.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], - [value]) - (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], - [value]) - (note, name must be set).
response-headerThe same as response.setHeader([name], - [value]) - (note, name must be set).
cookie - Value can be in the format "[value][:domain[:lifetime[:path]]]". - This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain - field is the domain of the cookie, such as '.apache.org', the optional lifetime is the lifetime of the cookie - in seconds, and the optional path is the path of the cookie (note, a name must be set). -
statusThe same as response.setStatus([value]) -
content-typeThe same as response.setContentType([value]) -
charsetThe same as response.setCharacterEncoding([value]) -
expiresWill set the Expires HTTP header by adding the time specified and current time - (this is mod_expires style). Syntax "{num type}*". - Units can be (singular or plural); - years, months, weeks, days, hours, minutes, seconds. -
eg, "1 day 2 seconds", "3 hours", "1 year 1 hour" -
localeThe same as response.setLocale([value]) - - specify the Locale in the format - (valid - locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). -
parameterEnables you to override a request.getParameter(String) with a custom value
methodEnables you to override request.getMethod() with a custom value
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
- -

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be - fetched in a servlet or - JSP using request.getAttribute("client").

- -
-<rule>
-    <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
-    <from>.*</from>
-    <set name="client">AvantGo</set>
-</rule>
-<rule>
-    <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
-    <from>.*</from>
-    <set name="client">Samsung SCH-6100</set>
-</rule>
-
- -

It is also possible to use regular replacement expressions as part of the - value similar to their usage in <to> elements:

- -
-<rule>
-    <from>/products/(.*)/(.*)/index.html</from>
-    <set name="urlrewrite.product.slug">$1</set>
-    <set name="urlrewrite.product.id">$2</set>
-    <to>/products?slug=$1&id=$2</to>
-</rule>
-
- - -

<run> element

- -

Allows you to run a method on an object when a rule and its conditions are matched.

- - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributePossible valueExplanation
class The class you want to run a method on. Must be a fully qualified name.
method (optional)run (default)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) - e.g. run(HttpServletRequest request, HttpServletResponse response) -
Note, if init(ServletConfig) or destroy() is found, they will be run at when - creating - or destroying an instance. -
neweachtime (optional)false (default)One instance for each UrlRewriteFilter instance.
trueA new instance of the class will be created before running each time set to true.
- -

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, - HttpServletResponse) - will be invoked, the request will then be forwarded to /world-presentation.jsp.

- -
-<rule>
-    <from>^/world/[a-z]+/[a-z]+$</from>
-    <run class="com.blah.web.WorldServlet" method="doGet" />
-    <to>/world-presentation.jsp</to>
-</rule>
-
- -

Note, you can specify init-param's the same way you would for a servlet.

- -
-<run class="com.blah.web.MyServlet" method="doGet">
-    <init-param>
-        <param-name>someParamName</param-name>
-        <param-value>10</param-value>
-    </init-param>
-</run>
-
- -

If the method being called throws an Exception, the original exception will be re-thrown as if it were the original - if it extends RuntimeException (e.g., NullPointer). Other exceptions are wrapped in a ServletException and thrown - so your container can handle them.

- - - -

<class-rule> element

- -

Allows you to run a method every time a request comes in for 100% dynamic rules. See the org.tuckey.web.filters.urlrewrite.sample package for an example.

- - - - - - - - - - - - - - - - - - -
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default matches)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) - e.g. run(HttpServletRequest request, HttpServletResponse response) -
Note, if init(ServletConfig) or destroy() is found, they will be run when - creating or destroying an instance. -
last (optional, default trueIf false more rules will be processed following this rule even if it is matched (so that a better match may be found).
- -

Example:

- -
-<class-rule class="com.blah.web.MyRuleClass" />
-
- - - -

Tips

- -
    -
  • When you want to put an "&" in a rule, you must enter it as the XML entity "&amp;"
  • -
  • For simplicity, you might want to start all from's with a ^ and end them with a $. -
    In regular expressions, ^ specifies the start of - the string, and $ defines the end. -
    ie, a request for /my/url/path will NOT match - <from>^/url/$</from> but it will match <from>/url/</from> -
    -
  • If using <outbound-rule> remember all URLs in your code must be encoded e.g. - <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • -
  • Regular expressions are complex and a bit tricky at times; read - regular expression syntax for - Java. -
  • -
  • If you find regular expressions difficult, use Wildcards.
  • -
  • "Context" is important. If you have an app with the context "/myapp" and you request the URL - "/myapp/somefolder/somepage.jsp", the container tells UrlRewriteFilter that the URL is "/somefolder/somepage.jsp". - This can be confusing, but basically, your rules and conditions should not contain the context path - (it will be handled by the container).
  • -
- - - - -

Wildcard Matching Engine

- -

The wildcard matching engine can be used instead of regex. It is supported in conditions and rules - where match-type is set to wildcard (or default-match-type is set on the - urlrewrite element

- -

e.g. /big/url/* will match /big/url/abc.html but will NOT - match /big/url/abc/dir/ or /big/url/abc/. - -

/big/url/** will match /big/url/abc.html, /big/url/abc/dir/ and - /big/url/abc/. - -

You can also use Regular expression style variable replacement; each match of a * will - be available for use in to and set elements using simple $1 - $2 variables.

- -

e.g. /my/big/url/* will match /my/big/url/abc.html and $1 - will be set to abc.html.

- -

Added in 3.0

- - - -

Ant Task

- -

An Ant task has been written to allow validate the conf file and generation - of documentation. You can view a sample.

- -

Paste the following into your build.xml file, then change the dest - and conf to point to the correct places. Note, the urlrewrite jar - file will need to be in your classpath.

- -
-<target name="urlrewrite-doc" depends="compile"
-    description="UrlRewriteFilter validation and documenting">
-
-<taskdef name="urlrewritedoc" classpath="lib/urlrewritefilter-4.0.3.jar"
-    classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
-<urlrewritedoc
-    conf="${build.home}/WEB-INF/urlrewrite.xml"
-    dest="urlrewrite-conf-overview.html" />
-</target>
-
- - - -

mod_rewrite Style Configuration

- -

Sample web.xml snippet:

- -
- <filter>
-     <filter-name>UrlRewriteFilter</filter-name>
-     <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-     <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
-     is not specified confPath will be set to /WEB-INF/.htaccess) -->
-     <init-param>
-         <param-name>modRewriteConfText</param-name>
-         <param-value><![CDATA[
-
-             # redirect mozilla to another area
-             RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
-             RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
-
-         ]]></param-value>
-     </init-param>
-
- </filter>
-
- <filter-mapping>
-     <filter-name>UrlRewriteFilter</filter-name>
-     <url-pattern>/*</url-pattern>
-     <dispatcher>REQUEST</dispatcher>
-     <dispatcher>FORWARD</dispatcher>
- </filter-mapping>
-
- - -

OR alternately set modRewriteConf to true in filter parameters and add a WEB-INF/.htaccess file with - your mod_rewrite style configuration in it.

- -
-<filter>
-    <filter-name>UrlRewriteFilter</filter-name>
-    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
-
-    <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
-    is not specified confPath will be set to /WEB-INF/.htaccess) -->
-    <init-param>
-        <param-name>modRewriteConf</param-name>
-        <param-value>true</param-value>
-    </init-param>
-
-</filter>
-
-<filter-mapping>
-    <filter-name>UrlRewriteFilter</filter-name>
-    <url-pattern>/*</url-pattern>
-    <dispatcher>REQUEST</dispatcher>
-    <dispatcher>FORWARD</dispatcher>
-</filter-mapping>
-
- -

Sample: WEB-INF/.htaccess

- -
-# redirect mozilla to another area
-RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
-RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
- 
- -

- - Documentation for the original mod_rewrite library - mainly applies; differences are documented below.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AttributeExplanation
RewriteLogLevelSpecified as int, trasnlated as: <= 1 - FATAL, 2 - ERROR, 3 - INFO, 4 - WARN, >= 5 DEBUG
RewriteLogSYSOUT, SYSERR, slf4j (if not set, servlet context logging will be used)
RewriteRule - Supported but note: - - - Certain flags not supported: -
    -
  • chain flag [C] not supported
  • -
  • env flag [E] not supported
  • -
  • next flag [N] not supported
  • -
  • nosubreq flag [NS] not supported
  • -
  • Skip flag [S] not supported
  • -
-
RewriteBaseNot supported
RewriteLockNot supported
RewriteMapNot supported
RewriteOptionsNot supported
- - -
-
- - - - - - + + + + UrlRewriteFilter - Manual + + + + + + +
+
+

+ + UrlRewriteFilter 4.0.3

+
+ +
+ + +
+ +

Manual

+ + +

Community support is available at UrlRewrite on StackOverflow.

+ +

Read examples of usage and a + sample of the ant task report. + If you have any suggestions/examples for this manual, please post them to the + group.

+ + + +

Install

+ +
    +
  1. Add Maven dependency below or add + urlrewritefilter-4.0.3.jar + directly into your WEB-INF/lib directory. +
    <dependency>
    +    <groupId>org.tuckey</groupId>
    +    <artifactId>urlrewritefilter</artifactId>
    +    <version>4.0.3</version>
    +</dependency>
  2. +
  3. Add the following to your WEB-INF/web.xml (add it near the top above your + servlet mappings (if you have any)): (see filter + parameters for more options) +
    <filter>
    +    <filter-name>UrlRewriteFilter</filter-name>
    +    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
    +</filter>
    +<filter-mapping>
    +    <filter-name>UrlRewriteFilter</filter-name>
    +    <url-pattern>/*</url-pattern>
    +    <dispatcher>REQUEST</dispatcher>
    +    <dispatcher>FORWARD</dispatcher>
    +</filter-mapping>
  4. +
  5. Add urlrewrite.xml + into your WEB-INF directory. (src/main/webapp/WEB-INF/ for Maven users)
  6. +
  7. Restart the context.
  8. +
+ +

You can visit http://127.0.0.1:8080/rewrite-status + (or whatever the address of your local webapp and context) + to see the output (note: this page is only viewable from localhost).

+ + + +

Filter Parameters

+ +

There are a few advanced filter parameters for enabling conf file reloading etc. There are self-explanatory.

+ +
+<filter>
+    <filter-name>UrlRewriteFilter</filter-name>
+    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+    <!-- set the amount of seconds the conf file will be checked for reload
+    can be a valid integer (0 denotes check every time,
+    -1 denotes no reload check, default -1) -->
+    <init-param>
+        <param-name>confReloadCheckInterval</param-name>
+        <param-value>60</param-value>
+    </init-param>
+
+    <!-- if you need to the conf file path can be changed
+    it is specified as a path relative to the root of your context
+    (default /WEB-INF/urlrewrite.xml) -->
+    <init-param>
+        <param-name>confPath</param-name>
+        <param-value>/WEB-INF/urlrewrite.xml</param-value>
+    </init-param>
+
+    <!-- sets up log level (will be logged to context log)
+    can be: slf4j, TRACE, DEBUG, INFO (default), WARN, ERROR, FATAL,
+    sysout:{level} (ie, sysout:DEBUG)
+    if you are having trouble using normal levels use sysout:DEBUG
+    (default WARN) -->
+    <init-param>
+        <param-name>logLevel</param-name>
+        <param-value>DEBUG</param-value>
+    </init-param>
+
+    <!-- you can change status path so that it does not
+    conflict with your installed apps (note, defaults
+    to /rewrite-status) note, must start with / -->
+    <init-param>
+        <param-name>statusPath</param-name>
+        <param-value>/status</param-value>
+    </init-param>
+
+    <!-- you can disable status page if desired
+    can be: true, false (default true) -->
+    <init-param>
+        <param-name>statusEnabled</param-name>
+        <param-value>true</param-value>
+    </init-param>
+
+    <!-- you may want to allow more hosts to look at the status page
+    statusEnabledOnHosts is a comma delimited list of hosts, * can
+    be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
+    <init-param>
+        <param-name>statusEnabledOnHosts</param-name>
+        <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
+    </init-param>
+
+    <!-- you may want to allow more hosts to look at the status page
+    statusEnabledOnHosts is a comma delimited list of hosts, * can
+    be used as a wildcard (defaults to "localhost, local, 127.0.0.1") -->
+    <init-param>
+        <param-name>statusEnabledOnHosts</param-name>
+        <param-value>localhost, dev.*.myco.com, *.uat.mycom.com</param-value>
+    </init-param>
+
+    <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
+    is not specified confPath will be set to /WEB-INF/.htaccess) -->
+    <init-param>
+        <param-name>modRewriteConf</param-name>
+        <param-value>false</param-value>
+    </init-param>
+
+    <!-- load mod_rewrite style configuration from this parameter's value.
+            note, Setting this parameter will mean that all other conf parameters are ignored.
+        <init-param>
+            <param-name>modRewriteConfText</param-name>
+            <param-value>
+                RewriteRule ^/~([^/]+)/?(.*) /u/$1/$2 [R]
+                RewriteRule ^/([uge])/([^/]+)$ /$1/$2/ [R]
+            </param-value>
+        </init-param>
+    -->
+
+    <!-- defaults to false. allow conf file to be set by calling /rewrite-status/?conf=/WEB-INF/urlrewrite2.xml
+            designed to be used for testing only
+        <init-param>
+            <param-name>allowConfSwapViaHttp</param-name>
+            <param-value>false</param-value>
+        </init-param>
+    -->
+
+</filter>
+
+<filter-mapping>
+    <filter-name>UrlRewriteFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+    <dispatcher>REQUEST</dispatcher>
+    <dispatcher>FORWARD</dispatcher>
+</filter-mapping>
+
+ +

Note, setting logLevel to slf4j will cause the built-in logging to + call slf4j as if it was the logging framework; + obviously, you will need to have the jar for slf4j in your classpath.

+ + + +

Configuration File WEB-INF/urlrewrite.xml

+ + + + + +
+ + <urlrewrite>   + <rule>   + <outbound-rule>   + <class-rule> +
+ <name>   + <note>   + <condition>   + <from>   + <to>   + <set>   + <run>   +
+ Back References   + Variables   + Functions   +
+
+
+ +

Configuration is done via a simple XML file that lives in your WEB-INF folder. It should be named + urlrewrite.xml. + It may be helpful to read the UrlRewriteFilter DTD + (Document Type Definition). Please also make sure you look at the examples. A simple + configuration file looks like this:

+ +
+<?xml version="1.0" encoding="utf-8"?>
+
+<!DOCTYPE urlrewrite
+    PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
+    "http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
+
+<urlrewrite>
+
+    <rule>
+       <from>^/some/olddir/(.*)$</from>
+       <to type="redirect">/very/newdir/$1</to>
+    </rule>
+
+    <rule match-type="wildcard">
+       <from>/blog/archive/**</from>
+       <to type="redirect">/roller/history/$1</to>
+    </rule>
+
+</urlrewrite>
+
+ + +

The urlrewrite.xml file must have a root element called "urlrewrite" and contain + at least one "rule" element.

+ +

A "rule" must contain a "from" and a "to" and can have zero or more "condition" elements and zero or more and/or + "set" elements.

+ +

When a "rule" is processed against an incoming request, all the "condition" elements must be met, then + the "from" will be applied to the request URL and the final URL generated by applying the + "to" to the "from" pattern. So long as a rule has matched, then the "set" will be run.

+ + + +

When executing a rule the filter will (very simplified) loop over all rules and for each do something like this psuedo code:

+ +
+Pattern.compile(<from> element);
+pattern.matcher(request url);
+matcher.replaceAll(<to> element);
+if ( <condition> elements match && matcher.find() ) {
+    handle <set> elements (if any)
+    execute <run> elements (if any)
+    perform <to> element (if any)
+}
+
+ + + +

<urlrewrite> element

+ +

The top-level element.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
default-match-type
(optional)
regex (default)All rules and conditions will be processed using the Java Regular Expression engine (unless + match-type is specified on a rule).
wildcardAll rules and conditions will be processed using the Wildcard Expression + engine + (unless match-type is specified on a rule).
decode-using
(optional)
header,utf8 (default)When URL is decoded request.getCharacterEncoding() will be used, if that is empty UTF-8 will be used. +
nullDo not decode at all. (note, this means the literal string null e.g. decode-using="null")
headerOnly use request.getCharacterEncoding() to decode.
[encoding]Only use a specific character encoding, e.g., ISO-8859-1. + See Java Charset Object + for all character encodings. +
header,[encoding] + When URL is decoded request.getCharacterEncoding() will be used, if that is empty a specific character + encoding, e.g., ISO-8859-1. + See Java Charset Object + for all character encodings. +
use-query-string
(optional)
false (default)The query string will not be appended to the URL that the "from" element matches against.
trueThe query string will be appended to the URL that the "from" element matches against.
use-context
(optional)
false (default)The context path will not be added to the URL that the "from" element matches against.
trueThe context path will be added to the URL that the "from" element matches against.
+ + + +

<rule> element

+ +

Zero or more. The basis of a rule.

+ + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
match-type
(optional)
regex (default)This rule and its conditions will be processed using the Java Regular Expression engine.
wildcardThis rule and its conditions will be processed using the Wildcard Expression engine. +
+ +

In the following example requests for /world/usa/nyc will be transparently forwarded to + /world.jsp

+ +
+<rule match-type="regex">
+   <from>^/world/([a-z]+)/([a-z]+)$</from>
+   <to>/world.jsp</to>
+</rule>
+
+ +
+<rule match-type="wildcard">
+   <from>/world/*/*</from>
+   <to>/world.jsp</to>
+</rule>
+
+ + + +

<outbound-rule> element

+ +

Zero or more. This is very similar to a standard rule, but it is used for rewriting URLs that go through + response.encodeURL().

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
enabled
(optional)
true (default)Enable this rule.
falseDisable this rule.
encodefirst
(optional)
false (default)Run encodeURL() after running this outbound-rule.
trueRun encodeURL() before running this outbound-rule.
+ +

May contain "run", "from", "to" and "set" element(s) also. Example:

+ +
+<outbound-rule>
+    <from>^/world.jsp?country=([a-z]+)&amp;city=([a-z]+)$</from>
+    <to>/world/$1/$2</to>
+</outbound-rule>
+
+ +

Using the example above JSP's with the code +
<a href="<%= response.encodeURL("/world.jsp?country=usa&amp;city=nyc") + %>">nyc</a> +
will output +
<a href="/world/usa/nyc">nyc</a> +

+ +

Or JSTL +
<a href="<c:url value="/world.jsp?country=${country}&amp;city=${city}" + />">nyc</a> +
will output +
<a href="/world/usa/nyc">nyc</a> +

+ +

Note, If you are using JSTL (ie, <c:url), this will work also.

+ + + +

<name> element

+ +

An optional element used for documenting the name of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +
+<rule>
+    <name>World Rule</name>
+    <from>^/world/([a-z]+)/([a-z]+)$</from>
+    <to>/world.jsp?country=$1&amp;city=$2</to>
+</rule>
+
+ + + +

<note> element

+ +

A simple optional element used for documentation of the rule. This can be used with rule and outbound-rule. + See ant task.

+ +
+<rule>
+    <name>World Rule</name>
+    <note>
+        Cleanly redirect world requests to JSP,
+        a country and city must be specified.
+    </note>
+    <from>^/world/([a-z]+)/([a-z]+)$</from>
+    <to>/world.jsp</to>
+</rule>
+
+ + + +

<condition> element

+ +

An element that lets you choose conditions for the rule. Note, all conditions must be met for the rule to be run + (unless "next" is set to "or" obviously).

+ +

Value can be any Regular Expression.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
header (default)If used, the header name must be specified in the "name" attribute.
methodThe method of the request. GET, POST, HEAD, etc.
portThe port that the web application server is running on.
time + Current time at the server (this will be the number of seconds since 00:00:00 1970-01-01 UTC, otherwise known as Unix + time). +
i.e. (new Date()).getTime() +
This can be used for making sure content goes live only at a time you set. +
year + Current year at the server. +
i.e. (Calendar.getInstance()).get(Calendar.YEAR) +
month + Month at the server. January is 0 +
i.e. (Calendar.getInstance()).get(Calendar.MONTH) +
dayofmonth + Day of the month at the server. March first is 1 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_MONTH) +
dayofweek + Day of the week at the server. Saturday is 1, Sunday is 7 +
i.e. (Calendar.getInstance()).get(Calendar.DAY_OF_WEEK) +
ampm + AM or PM time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.AM_PM) +
hourofday + The hour of the day (24 hour clock) at the server. 10pm is 22 +
i.e. (Calendar.getInstance()).get(Calendar.HOUR_OF_DAY) +
minute + The minute field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MINUTE) +
second + The second field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.SECOND) +
millisecond + The millisecond field of the current time at the server. +
i.e. (Calendar.getInstance()).get(Calendar.MILLISECOND) +
attribute + Will check the value of a request attribute (don't confuse this with parameter!), name must be set when + using this type. +
i.e. request.getAttribute([name]) + +
auth-type + Will check the value of a request attribute (don't confuse this with parameter!) +
i.e. request.getAuthType() + +
character-encoding + The character encoding of the imcoming request. +
i.e. request.getCharacterEncoding() + +
content-length + The length of the imcoming request (can be useful if you want to deny large requests). +
i.e. request.getContentLength() + +
content-type + The type of the imcoming request. (this is probably not that useful) +
i.e. request.getContentType() + +
context-path + The context path of the imcoming request. +
i.e. request.getContextPath() + +
cookie + The value of a cookie, note, name must be specified to use this +
i.e. request.getCookies() + the find we the one with [name] specified and check the value. +
parameter + A tidier way of checking request parameters than looking for them in the query string. This will check for the + parameter in GET or POST, note, name must be specified. +
i.e. request.getParameter([name]) + +
path-info + i.e. request.getPathInfo() + +
path-translated + i.e. request.getPathTranslated() + +
protocolThe protocol used to make the request, e.g. HTTP/1.1 +
i.e. request.getProtocol() + +
query-stringThe query string used to make the request (if any), e.g. id=2345&name=bob +
i.e. request.getQueryString() + +
remote-addrThe IP address of the host making the request, e.g. 123.123.123.12 +
i.e. request.getRemoteAddr() + +
remote-hostThe host name of the host making the request, e.g. 123qw-dsl.att.com (note, + this will only work if your app server is configured to lookup host names, most aren't). +
i.e. request.getRemoteHost() + +
remote-userThe login of the user making this request, if the user has been authenticated, e.g. bobt +
i.e. request.getRemoteUser() + +
requested-session-idReturns the session ID specified by the client, e.g. 2344asd234sada4 +
i.e. request.getRequestedSessionId() + +
requested-session-id-from-cookieWhether the requested session ID is from a cookie or not +
i.e. request.isRequestedSessionIdFromCookie() + +
requested-session-id-from-urlWhether the requested session ID is from the URL or not +
i.e. request.isRequestedSessionIdFromURL() + +
requested-session-id-validWhether the requested session ID is valid or not +
i.e. request.isRequestedSessionIdValid() + +
request-uriReturns the part of this request's URL from the protocol name up to the query + string in the first line of the HTTP request +
i.e. request.getRequestURI() + +
request-urlReconstructs the URL the client used to make the request. The returned URL + contains a protocol, server name, port number, and server path, but it does not include query string parameters. +
i.e. request.getRequestURL() + +
session-attribute + (note, name must be set) +
i.e. session.getAttribute([name]) + +
session-isnew + Weather the session is new or not. +
i.e. session.isNew() + +
server-name + The host name of the server to which the request was sent (from the host header not the machine name). +
i.e. request.getServerName() + +
scheme + The scheme used for the request, e.g. http or https +
i.e. request.getScheme() + +
user-in-role + (Note, the value for this cannot be a regular expression) +
i.e. request.isUserInRole([value]) + +
name
(optional)
(can be anything)If the type is a header, this specifies the name of the HTTP header used to run the value + against.
next
(optional)
and (default)The next "rule" and this "rule" must match.
orThe next "rule" or this "condition" may match.
operator
(optional)
equal (default)Equals. The operator is to be used when the condition is run, the regular expression matches, or the values are + equal.
notequalNot equal to. (i.e. request value != condition value).
greaterGreater than. (i.e. request value > condition value). Note, this operator only works with + numeric + rule types.
lessLess than. (i.e. request value < condition value). Note, this operator only works with numeric + rule types.
greaterorequalGreater to or equal to. (i.e. request value >= condition value). Note, this operator + only + works with numeric rule types.
lessorequalLess than or equal to. (i.e. request value <= condition value). Note, this operator only + works with numeric rule types.
+ +

Examples:

+ +
+<condition name="user-agent" operator="notequal">Mozilla/[1-4]</condition>
+
+<condition type="user-in-role" operator="notequal">bigboss</condition>
+
+<condition name="host" operator="notequal">www.example.com</condition>
+
+<condition type="method" next="or">PROPFIND</condition>
+<condition type="method">PUT</condition>
+
+ + + +

<from> element

+ +

You must always have exactly one for each rule or outbound-rule. Value can be a regular expression in the + Perl5 style. Note, "from" URLs are relative to the context.

+ + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
casesensitive
(optional)
false (default)This value will be matched using a case insentitive match. Ie, "/WellingtoN" will match "/wellington". +
trueThis value will be matched using a case sensitive match. ie, "/aAa" will NOT match "/aaa". +
+ +

Example:

+ +
+<from>^/world/([a-z]+)$</from>
+
+ + +

<to> element

+ +

Value can be a regular replacement expression in the Perl5 style.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
forward (default)Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally + forwarded + to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as + UrlRewriteFilter. This is the same as doing: +
RequestDispatcher rq = request.getRequestDispatcher([to value]); +
rq.forward(request, response);
+
passthroughIdentical to "forward".
redirectRequests matching the "conditions" and the "from" for this rule will be HTTP redirected. + This is the same a doing: +
HttpServletResponse.sendRedirect([to value]))
permanent-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_PERMANENTLY is the HTTP status code 301)
temporary-redirectThe same as doing: +
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); +
response.setHeader("Location", [to value]);
+
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
pre-include
post-include
proxyThe request will be proxied to the full URL specified. commons-http and commons-codec must both be in the + classpath to use this feature. +
last
(optional)
false (default)The rest of the "rules" will be processed if this one succeeds.
trueNo more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule)response.encodeURL([to]) + will be run on the to url before performing the rewrite.
true (default if under outbound-rule)response.encodeURL([to]) + will NOT be called.
context
(optional)
If your application server is configured to allow "cross-context" communication, then this attribute can be used + to forward (and only forward, not redirect or other "to" types) requests to a named servlet context. +
+
On Tomcat, for instance, the application contexts in the server configuration (server.xml or + context.xml) need the option crossContext="true". For instance, the two applications mentioned before + ("app" and "forum") have to be defined as: +
+
<Context docBase="app" path="/app" reloadable="true" crossContext="true"/> +
<Context docBase="forum" path="/forum" reloadable="true" crossContext="true"/> +
qsappend
(optional)
false (default)
trueAppend the query string to the to url when redirecting or forwarding.
+ +

Note, "to" can be null, i.e., <to>null</to>; this will mean that the request will go no + further if the rule is matched (i.e., this filter will not call chain.doFilter).

+ +

If "to" is set to -, no substitution will take place, and the request will go on like nothing happened (i.e., this filter will call chain.doFilter).

+ +
+<to>/world.jsp?country=$1</to>
+
+ +

To elements can contain backreferences and variables.

+ + +

Backreferences

+ +
+%N
+
+ +

Provides access to the grouped parts (parentheses) of the pattern from the last matched Condition + in the current rule. + N must be less than 10 and greater than 0 (i.e. %1, %2, %3 etc).

+ + +

Variables

+ +
+%{VARIABLE-NAME}
+
+ +

Any valid condition type can be used as a variable name. ie, + '%{port}' will be translated to '80', + '%{year}' to '2005', + '%{cookie:myCookie}' would be translated to + 'myCookieValue' (assuming the user had a cookie named myCookie with the value myCookieValue).

+ +

Valid types are condition types; see condition for a full description.

+ + +

Functions

+ +
+${FUNCTION:PARAMS}
+
+ +

Functions can be places in set and to elements.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameExampleExample ReturnsExplanation
replace${replace:my cat is a blue cat:cat:dog}my dog is a blue dog
replaceFirst${replaceFirst:my cat is a blue cat:cat:dog}my cat is a blue dog
escape${escape:utf8:a b c}a+b+cEscapes/Encodes string using URLEncoder.encode using the specified encoding.
unescape${unescape:utf8:a+b+c}a b cUnescapes/Unencodes string using URLEncoder.decode using the specified encoding.
lower${lower:Hello World}hello world
upper${upper:hello}HELLO
trim${trim: abc def }abc def
+ + + +

<set> element

+ +

Allows you to set various things if the rule is matched.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible ValueExplanation
type
(optional)
request (default)The same as request.setAttribute([name], + [value]) + (note, name must be set).
sessionThe same as request.getSesison(true).setAttribute([name], + [value]) + (note, name must be set).
response-headerThe same as response.setHeader([name], + [value]) + (note, name must be set).
cookie + Value can be in the format "[value][:domain[:lifetime[:path]]]". + This sets a cookie on the client's browser. The cookie's name is specified by the name attribute. The domain + field is the domain of the cookie, such as '.apache.org', the optional lifetime is the lifetime of the cookie + in seconds, and the optional path is the path of the cookie (note, a name must be set). +
statusThe same as response.setStatus([value]) +
content-typeThe same as response.setContentType([value]) +
charsetThe same as response.setCharacterEncoding([value]) +
expiresWill set the Expires HTTP header by adding the time specified and current time + (this is mod_expires style). Syntax "{num type}*". + Units can be (singular or plural); + years, months, weeks, days, hours, minutes, seconds. +
eg, "1 day 2 seconds", "3 hours", "1 year 1 hour" +
localeThe same as response.setLocale([value]) + + specify the Locale in the format + (valid + locales are, zh, zh-CN, zh-CN-southern i.e. "-" separating the language, country and variant (if any)). +
parameterEnables you to override a request.getParameter(String) with a custom value
methodEnables you to override request.getMethod() with a custom value
name
(optional)
(can be anything)If type is request, session, response-header, cookie this specifies the name item.
+ +

In the following example a request attribute "client" will be set to "AvantGo" or "Samsung SCH-6100", this can be + fetched in a servlet or + JSP using request.getAttribute("client").

+ +
+<rule>
+    <condition name="user-agent">Mozilla/3\.0 (compatible; AvantGo .*)</from>
+    <from>.*</from>
+    <set name="client">AvantGo</set>
+</rule>
+<rule>
+    <condition name="user-agent">UP\.Browser/3.*SC03 .* </from>
+    <from>.*</from>
+    <set name="client">Samsung SCH-6100</set>
+</rule>
+
+ +

It is also possible to use regular replacement expressions as part of the + value similar to their usage in <to> elements:

+ +
+<rule>
+    <from>/products/(.*)/(.*)/index.html</from>
+    <set name="urlrewrite.product.slug">$1</set>
+    <set name="urlrewrite.product.id">$2</set>
+    <to>/products?slug=$1&id=$2</to>
+</rule>
+
+ + +

<run> element

+ +

Allows you to run a method on an object when a rule and its conditions are matched.

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributePossible valueExplanation
class The class you want to run a method on. Must be a fully qualified name.
method (optional)run (default)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) + e.g. run(HttpServletRequest request, HttpServletResponse response) +
Note, if init(ServletConfig) or destroy() is found, they will be run at when + creating + or destroying an instance. +
neweachtime (optional)false (default)One instance for each UrlRewriteFilter instance.
trueA new instance of the class will be created before running each time set to true.
+ +

When the rule in the following example is matched, WorldServlet.goGet(HttpServletRequest, + HttpServletResponse) + will be invoked, the request will then be forwarded to /world-presentation.jsp.

+ +
+<rule>
+    <from>^/world/[a-z]+/[a-z]+$</from>
+    <run class="com.blah.web.WorldServlet" method="doGet" />
+    <to>/world-presentation.jsp</to>
+</rule>
+
+ +

Note, you can specify init-param's the same way you would for a servlet.

+ +
+<run class="com.blah.web.MyServlet" method="doGet">
+    <init-param>
+        <param-name>someParamName</param-name>
+        <param-value>10</param-value>
+    </init-param>
+</run>
+
+ +

If the method being called throws an Exception, the original exception will be re-thrown as if it were the original + if it extends RuntimeException (e.g., NullPointer). Other exceptions are wrapped in a ServletException and thrown + so your container can handle them.

+ + + +

<class-rule> element

+ +

Allows you to run a method every time a request comes in for 100% dynamic rules. See the org.tuckey.web.filters.urlrewrite.sample package for an example.

+ + + + + + + + + + + + + + + + + + +
AttributeExplanation
classThe class you want to run a method on. Must be a fully qualified name.
method (optional, default matches)The method you want to run, the method must have the parameters (HttpServletRequest, HttpServletResponse) + e.g. run(HttpServletRequest request, HttpServletResponse response) +
Note, if init(ServletConfig) or destroy() is found, they will be run when + creating or destroying an instance. +
last (optional, default trueIf false more rules will be processed following this rule even if it is matched (so that a better match may be found).
+ +

Example:

+ +
+<class-rule class="com.blah.web.MyRuleClass" />
+
+ + + +

Tips

+ +
    +
  • When you want to put an "&" in a rule, you must enter it as the XML entity "&amp;"
  • +
  • For simplicity, you might want to start all from's with a ^ and end them with a $. +
    In regular expressions, ^ specifies the start of + the string, and $ defines the end. +
    ie, a request for /my/url/path will NOT match + <from>^/url/$</from> but it will match <from>/url/</from> +
    +
  • If using <outbound-rule> remember all URLs in your code must be encoded e.g. + <a href="<%= response.encodeURL("/some/olddir/b.jsp") %>">my link</a>
  • +
  • Regular expressions are complex and a bit tricky at times; read + regular expression syntax for + Java. +
  • +
  • If you find regular expressions difficult, use Wildcards.
  • +
  • "Context" is important. If you have an app with the context "/myapp" and you request the URL + "/myapp/somefolder/somepage.jsp", the container tells UrlRewriteFilter that the URL is "/somefolder/somepage.jsp". + This can be confusing, but basically, your rules and conditions should not contain the context path + (it will be handled by the container).
  • +
+ + + + +

Wildcard Matching Engine

+ +

The wildcard matching engine can be used instead of regex. It is supported in conditions and rules + where match-type is set to wildcard (or default-match-type is set on the + urlrewrite element

+ +

e.g. /big/url/* will match /big/url/abc.html but will NOT + match /big/url/abc/dir/ or /big/url/abc/. + +

/big/url/** will match /big/url/abc.html, /big/url/abc/dir/ and + /big/url/abc/. + +

You can also use Regular expression style variable replacement; each match of a * will + be available for use in to and set elements using simple $1 + $2 variables.

+ +

e.g. /my/big/url/* will match /my/big/url/abc.html and $1 + will be set to abc.html.

+ +

Added in 3.0

+ + + +

Ant Task

+ +

An Ant task has been written to allow validate the conf file and generation + of documentation. You can view a sample.

+ +

Paste the following into your build.xml file, then change the dest + and conf to point to the correct places. Note, the urlrewrite jar + file will need to be in your classpath.

+ +
+<target name="urlrewrite-doc" depends="compile"
+    description="UrlRewriteFilter validation and documenting">
+
+<taskdef name="urlrewritedoc" classpath="lib/urlrewritefilter-4.0.3.jar"
+    classname="org.tuckey.web.filters.urlrewrite.UrlRewriteDocTask" />
+<urlrewritedoc
+    conf="${build.home}/WEB-INF/urlrewrite.xml"
+    dest="urlrewrite-conf-overview.html" />
+</target>
+
+ + + +

mod_rewrite Style Configuration

+ +

Sample web.xml snippet:

+ +
+ <filter>
+     <filter-name>UrlRewriteFilter</filter-name>
+     <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+     <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
+     is not specified confPath will be set to /WEB-INF/.htaccess) -->
+     <init-param>
+         <param-name>modRewriteConfText</param-name>
+         <param-value><![CDATA[
+
+             # redirect mozilla to another area
+             RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
+             RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
+
+         ]]></param-value>
+     </init-param>
+
+ </filter>
+
+ <filter-mapping>
+     <filter-name>UrlRewriteFilter</filter-name>
+     <url-pattern>/*</url-pattern>
+     <dispatcher>REQUEST</dispatcher>
+     <dispatcher>FORWARD</dispatcher>
+ </filter-mapping>
+
+ + +

OR alternately set modRewriteConf to true in filter parameters and add a WEB-INF/.htaccess file with + your mod_rewrite style configuration in it.

+ +
+<filter>
+    <filter-name>UrlRewriteFilter</filter-name>
+    <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
+
+    <!-- defaults to false. use mod_rewrite style configuration file (if this is true and confPath
+    is not specified confPath will be set to /WEB-INF/.htaccess) -->
+    <init-param>
+        <param-name>modRewriteConf</param-name>
+        <param-value>true</param-value>
+    </init-param>
+
+</filter>
+
+<filter-mapping>
+    <filter-name>UrlRewriteFilter</filter-name>
+    <url-pattern>/*</url-pattern>
+    <dispatcher>REQUEST</dispatcher>
+    <dispatcher>FORWARD</dispatcher>
+</filter-mapping>
+
+ +

Sample: WEB-INF/.htaccess

+ +
+# redirect mozilla to another area
+RewriteCond  %{HTTP_USER_AGENT}  ^Mozilla.*
+RewriteRule  ^/no-moz-here$                 /homepage.max.html  [L]
+ 
+ +

+ + Documentation for the original mod_rewrite library + mainly applies; differences are documented below.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeExplanation
RewriteLogLevelSpecified as int, trasnlated as: <= 1 - FATAL, 2 - ERROR, 3 - INFO, 4 - WARN, >= 5 DEBUG
RewriteLogSYSOUT, SYSERR, slf4j (if not set, servlet context logging will be used)
RewriteRule + Supported but note: + + + Certain flags not supported: +
    +
  • chain flag [C] not supported
  • +
  • env flag [E] not supported
  • +
  • next flag [N] not supported
  • +
  • nosubreq flag [NS] not supported
  • +
  • Skip flag [S] not supported
  • +
+
RewriteBaseNot supported
RewriteLockNot supported
RewriteMapNot supported
RewriteOptionsNot supported
+ + +
+
+ + + + + + diff --git a/src/doc/manual/4.0/introduction.html b/src/doc/manual/4.0/introduction.html index 7c39ab73..9fff0bb1 100644 --- a/src/doc/manual/4.0/introduction.html +++ b/src/doc/manual/4.0/introduction.html @@ -1,435 +1,435 @@ - - - - UrlRewriteFilter - Background - - - - - - -
-
-

- - UrlRewriteFilter 4.0.3

-
- -
- - -
- -

Background

- - - -

A clean URL scheme is very important detail for any quality Web Application. UrlRewriteFilter provides a - toolkit to let you set URL patterns however you want.

- -

See Cool URIs don't change, by World Wide Web creator - Tim Berners-Lee, for excellent arguments on why URLs should be clean and usable.

- -

With the Apache webserver there is mod_rewrite for URL manipulation.

- -

In J2EE land the Servlet specification (by Sun) standardises the approach for dealing with Java web server -programming. We have come a long way from basic Servlets, JSP's, MVC frameworks etc but Java Web Application -Servers such as Tomcat are seldom used as front-line web servers, they almost always have Apache infront of them.

- -

If you want to use an app server as a front line web server UrlRewriteFilter will enable you to manage incoming -URL's in a much more flexible way than the app server usually lets you.

- -

You can find test cases in the source distribution. UrlRewriteFilter should work on any J2EE web application server - and has been tested using Cargo on the following web application - servers:

- - - -

The filter has been designed for maximum performance. Testing has indicated - that it should only slow down a request by 0.0005 of a second under normal circumstances - (depending on hardware and configuration etc.). Take a look at the source in the class - org.tuckey.web.filters.urlrewrite.PerformanceTest.testLoadsOfRules() for more information.

- - - - -

License

- -

UrlRewriteFilter is distributed under the BSD License. For more information on see - opensource.org/licenses.

- -

If you want to purchase ad-hoc support, a support contract or custom development - please email sales@tuckey.co.nz.

- - - - - - -

Changelog

- -
    -
  • 4.0.5 -
      -
    • Bug fix for appending query strings breaking URL - (issue 116)
    • -
    -
  • - -
  • 4.0.4 -
      -
    • Changes to build process (not formally released)
    • -
    -
  • - -
  • 4.0.3 -
      -
    • Minor fix for identifying versions
    • -
    -
  • - -
  • 4.0.2 -
      -
    • Bug Fix for gzip filtering
    • -
    -
  • - -
  • 4.0.1 Beta -
      -
    • Rewrite of the way Encoding/Decoding is handled - (issue 27)
    • -
    • Support for file existence tests via new condition type request-filename and operators isdir, isfile, isfilewithsize, notdir, notfile, notfilewithsize - (issue 49)
    • -
    • Support for qsappend - (issue 31)
    • -
    • New condition types requested-session-id-from-cookie, requested-session-id-from-url, requested-session-id-valid
    • -
    • Ability to conditionally GZip responses using the gzip conf element
    • -
    • Fixed bug: ":" char in url results in java.io.UnsupportedEncodingException - (issue 30)
    • -
    • Fixed bug: Wildcard matcher and $ in URL causes exception - (issue 71)
    • -
    • Dropped support for log4j and commons-logging. Just use slf4j instead. This removes 2 x dependencies.
    • -
    - -
  • - -
  • 3.2.0 -
      -
    • Added "no substitution" ability with to element eg, <to>-</to>
    • -
    • In urlrewrite.xml allow rule, class-rule and outbound-rule elements in any order
    • -
    • Fixed bug with handling of references in functions (ie, to allow this: ${replace:$1:-:+} )
    • -
    • Added slf4j logging support for logLevel (filter parameter)
    • -
    • Added function for calculating string length (eg, ${length:asdf} would return 4)
    • -
    • Added "proxy" to type, to enable requests to be proxied to another server
    • -
    • Added "context" attribute to <to> type, to enable requests to sent to other contexts (assuming app server configured to do this)
    • -
    • JDK 6+ Annotation processor
    • -
    • JDK 5 & 6+ Annotation processors included in main jar file
    • -
    • Fixed bug with decoding urls and added ability to specify 'header' type decoding
    • -
    • Added allowConfSwapViaHttp filter parameter to allow configuration swap out at runtime.
    • -
    -
  • -
  • 3.1.0 -
      -
    • Rules are now allowed to have only condition and set elements
    • -
    • Basic functions in "set", and "to" elements eg, ${trim:%1}
    • -
    • Experimental mod_rewrite style configuration
    • -
    • Bug fix: xml entites containing jndi protocol now correctly loaded
    • -
    -
  • -
  • 3.0.4 Beta -
      -
    • Bug fix - cookie value not being set with variable replacement
    • -
    -
  • -
  • 3.0.3 Beta -
      -
    • Bug fix - annotation processor rule sorting
    • -
    • Bug Fix - evaluation boolean result was incorrect on failed condition instance matches
    • -
    -
  • -
  • 3.0.2 Beta -
      -
    • Rule chaining bug fixes
    • -
    -
  • -
  • 3.0.1 Beta -
      -
    • Added "class-rule" element to enable 100% dynamic "Java Rules"
    • -
    • Added experimental UrlrewriteTestCase to help with testing (see the source)
    • -
    • Added experimental "catch" element to handle exceptions generated from "run"'s
    • -
    • Added experimental annotation (@HttpUrl, @HttpParam) processor
    • -
    • Minor Bug fixes
    • -
    -
  • -
  • 3.0 Beta -
      -
    • Support for wildcard matching.
    • -
    • Added "match-type" attribute to rule and outbound-rule.
    • -
    • Added ability to specify charset decoding ("decodeusing" attribute to "urlrewrite" element)
    • -
    • Swapped "to" variable replacement and run processing, run processing now comes before "to" - variable replacement is done. dtd it has been swapped make sure you change the reference in your conf file. - Make sure element order is from, set, run, to.
    • -
    • Context addition to the url is now optional
    • -
    • Query string matching on rule is now optional (defaults to false) -
      before 3.0 you would specify -
      <from>/blah.jsp?a=b</from> -
      3.0 and up (unless use-query-string on urlrewrite element is set to true) -
      <condition name="a">b</condition> -
      <from>/blah.jsp</from>
    • -
    -
  • -
  • 2.6 -
      -
    • fixed bug with encode on to element defaulting to incorrect boolean (change to dtd)
    • -
    -
  • -
  • 2.5.3 -
      -
    • cleaner exception handling when invoking "run" items, original exception thrown as if it were the - original if it extends RuntimeException (eg, NullPointer), other exceptions wrapped in a ServletException and thrown
    • -
    -
  • -
  • 2.5.2 -
      -
    • fixed bug with encodefirst attr not being set
    • -
    • ability to specify wildcards on statusEnabledOnHosts
    • -
    • added backreferences and variables for to element value
    • -
    • logLevel init param can now include sysout:{level} ie, sysout:DEBUG for people who have trouble with context.log
    • -
    -
  • -
  • 2.5.1 -
      -
    • bug fixes, Log initialisation and null auth type condition values
    • -
    -
  • -
  • 2.5 -
      -
    • matcher changed to accept first match (not the whole string) please make sure you retest your rules - (ie, previously /res/js/l.js?aaa would not match /res/js/l.js, with this release it will)
    • -
    • support for logging to log4j or commons-logging (see filter params in manual)
    • -
    • fixed bug for when request.getCookies() returns null on some containers
    • -
    • added encodefirst outbound-rule, outbound-rule now respects encode on "to".
    • -
    - -
  • -
  • 2.4 -
      -
    • removed all external library dependencies to make much more deploy friendly
    • -
    • no longer uses Jakarta ORO, this should't mean any change in regular expression handling but you should test - your existing rules just in case.
    • -
    • fixed problem with rediredting to "null" this will now not proceed with the request if the rule is matched - (ie, chain.doFilter will not be called)
    • -
    • fixed problem with ant dependency on status page
    • -
    -
  • -
  • 2.3 (4/2005) -
      -
    • Added new outbound-rule for rewriting hyperlinks in JSP's, improved status page, added ability - to run methods when a rule is matched
    • -
    -
  • -
  • 2.0.1 (2/2005) -
      -
    • Fixed bug with rule processing when to element doesn't exist.
    • -
    -
  • -
  • 2.0 (1/2005) -
      -
    • Minor bug fixes, last attribute on rule now defaults to false (thanks to Vineet Kumar for his - assistance).
    • -
    -
  • -
  • 2.0-beta (12/2004) -
      -
    • Minor bug fixes, documentation improvements, ALL matches now done case insensitively by - default, case sensitivity can be set (see from and condition elements).
    • -
    -
  • -
  • 2.0-alpha (11/2004) -
      -
    • First 2.0 release, added many new condition types, many new set types.
    • -
    -
  • -
  • 1.2 (6/2004) -
      -
    • Added set element (ability to set random attributes on request, thanks for the idea - Russell), from now matches RELATIVE to context NOT root (if you - are upgrading this may mean a change for you).
    • -
    -
  • -
  • 1.1 (4/2004) -
      -
    • Ability to disable rules, Refactored to enable rewriter to be embedded, - changed logging to enable log level to be set, added name and note elements to rule for documentation, - ability to disable status page, ability to change status prefix, javadoc style ant task for an HTML - configuration report.
    • -
    -
  • -
  • 1.0 (3/2004) -
      -
    • General tidy up of logging, tidy up of all code, dist now includes manual, log4j and junit - removed from bin release.
    • -
    -
  • -
  • 0.9 (2/2004) -
      -
    • Fixed conf loading problem in Resin, resolved concurrency issue with Perl5Compiler and - Perl5Matcher (thanks Scott Askew!)
    • -
    -
  • -
  • 0.8 (2/2004) -
      -
    • Removed dependency on "Commons Lang", Changed DTD path (bug fix), added ability to put time - fields in "condition" element, added ability to put "operators" in the "condition" element, fixed multiple rules issue (bug fix)
    • -
    -
  • -
  • 0.7 (11/2003) -
      -
    • Improved test cases, documentation
    • -
    -
  • -
  • 0.6 (8/2003) -
      -
    • Improved error handling, status page and condition matching
    • -
    -
  • -
  • 0.5 (6/2003) -
      -
    • Improved configuration error handling
    • -
    -
  • -
- - - -
-
- - - - - - + + + + UrlRewriteFilter - Background + + + + + + +
+
+

+ + UrlRewriteFilter 4.0.3

+
+ +
+ + +
+ +

Background

+ + + +

A clean URL scheme is very important detail for any quality Web Application. UrlRewriteFilter provides a + toolkit to let you set URL patterns however you want.

+ +

See Cool URIs don't change, by World Wide Web creator + Tim Berners-Lee, for excellent arguments on why URLs should be clean and usable.

+ +

With the Apache webserver there is mod_rewrite for URL manipulation.

+ +

In J2EE land the Servlet specification (by Sun) standardises the approach for dealing with Java web server +programming. We have come a long way from basic Servlets, JSP's, MVC frameworks etc but Java Web Application +Servers such as Tomcat are seldom used as front-line web servers, they almost always have Apache infront of them.

+ +

If you want to use an app server as a front line web server UrlRewriteFilter will enable you to manage incoming +URL's in a much more flexible way than the app server usually lets you.

+ +

You can find test cases in the source distribution. UrlRewriteFilter should work on any J2EE web application server + and has been tested using Cargo on the following web application + servers:

+ + + +

The filter has been designed for maximum performance. Testing has indicated + that it should only slow down a request by 0.0005 of a second under normal circumstances + (depending on hardware and configuration etc.). Take a look at the source in the class + org.tuckey.web.filters.urlrewrite.PerformanceTest.testLoadsOfRules() for more information.

+ + + + +

License

+ +

UrlRewriteFilter is distributed under the BSD License. For more information on see + opensource.org/licenses.

+ +

If you want to purchase ad-hoc support, a support contract or custom development + please email sales@tuckey.co.nz.

+ + + + + + +

Changelog

+ +
    +
  • 4.0.5 +
      +
    • Bug fix for appending query strings breaking URL + (issue 116)
    • +
    +
  • + +
  • 4.0.4 +
      +
    • Changes to build process (not formally released)
    • +
    +
  • + +
  • 4.0.3 +
      +
    • Minor fix for identifying versions
    • +
    +
  • + +
  • 4.0.2 +
      +
    • Bug Fix for gzip filtering
    • +
    +
  • + +
  • 4.0.1 Beta +
      +
    • Rewrite of the way Encoding/Decoding is handled + (issue 27)
    • +
    • Support for file existence tests via new condition type request-filename and operators isdir, isfile, isfilewithsize, notdir, notfile, notfilewithsize + (issue 49)
    • +
    • Support for qsappend + (issue 31)
    • +
    • New condition types requested-session-id-from-cookie, requested-session-id-from-url, requested-session-id-valid
    • +
    • Ability to conditionally GZip responses using the gzip conf element
    • +
    • Fixed bug: ":" char in url results in java.io.UnsupportedEncodingException + (issue 30)
    • +
    • Fixed bug: Wildcard matcher and $ in URL causes exception + (issue 71)
    • +
    • Dropped support for log4j and commons-logging. Just use slf4j instead. This removes 2 x dependencies.
    • +
    + +
  • + +
  • 3.2.0 +
      +
    • Added "no substitution" ability with to element eg, <to>-</to>
    • +
    • In urlrewrite.xml allow rule, class-rule and outbound-rule elements in any order
    • +
    • Fixed bug with handling of references in functions (ie, to allow this: ${replace:$1:-:+} )
    • +
    • Added slf4j logging support for logLevel (filter parameter)
    • +
    • Added function for calculating string length (eg, ${length:asdf} would return 4)
    • +
    • Added "proxy" to type, to enable requests to be proxied to another server
    • +
    • Added "context" attribute to <to> type, to enable requests to sent to other contexts (assuming app server configured to do this)
    • +
    • JDK 6+ Annotation processor
    • +
    • JDK 5 & 6+ Annotation processors included in main jar file
    • +
    • Fixed bug with decoding urls and added ability to specify 'header' type decoding
    • +
    • Added allowConfSwapViaHttp filter parameter to allow configuration swap out at runtime.
    • +
    +
  • +
  • 3.1.0 +
      +
    • Rules are now allowed to have only condition and set elements
    • +
    • Basic functions in "set", and "to" elements eg, ${trim:%1}
    • +
    • Experimental mod_rewrite style configuration
    • +
    • Bug fix: xml entites containing jndi protocol now correctly loaded
    • +
    +
  • +
  • 3.0.4 Beta +
      +
    • Bug fix - cookie value not being set with variable replacement
    • +
    +
  • +
  • 3.0.3 Beta +
      +
    • Bug fix - annotation processor rule sorting
    • +
    • Bug Fix - evaluation boolean result was incorrect on failed condition instance matches
    • +
    +
  • +
  • 3.0.2 Beta +
      +
    • Rule chaining bug fixes
    • +
    +
  • +
  • 3.0.1 Beta +
      +
    • Added "class-rule" element to enable 100% dynamic "Java Rules"
    • +
    • Added experimental UrlrewriteTestCase to help with testing (see the source)
    • +
    • Added experimental "catch" element to handle exceptions generated from "run"'s
    • +
    • Added experimental annotation (@HttpUrl, @HttpParam) processor
    • +
    • Minor Bug fixes
    • +
    +
  • +
  • 3.0 Beta +
      +
    • Support for wildcard matching.
    • +
    • Added "match-type" attribute to rule and outbound-rule.
    • +
    • Added ability to specify charset decoding ("decodeusing" attribute to "urlrewrite" element)
    • +
    • Swapped "to" variable replacement and run processing, run processing now comes before "to" + variable replacement is done. dtd it has been swapped make sure you change the reference in your conf file. + Make sure element order is from, set, run, to.
    • +
    • Context addition to the url is now optional
    • +
    • Query string matching on rule is now optional (defaults to false) +
      before 3.0 you would specify +
      <from>/blah.jsp?a=b</from> +
      3.0 and up (unless use-query-string on urlrewrite element is set to true) +
      <condition name="a">b</condition> +
      <from>/blah.jsp</from>
    • +
    +
  • +
  • 2.6 +
      +
    • fixed bug with encode on to element defaulting to incorrect boolean (change to dtd)
    • +
    +
  • +
  • 2.5.3 +
      +
    • cleaner exception handling when invoking "run" items, original exception thrown as if it were the + original if it extends RuntimeException (eg, NullPointer), other exceptions wrapped in a ServletException and thrown
    • +
    +
  • +
  • 2.5.2 +
      +
    • fixed bug with encodefirst attr not being set
    • +
    • ability to specify wildcards on statusEnabledOnHosts
    • +
    • added backreferences and variables for to element value
    • +
    • logLevel init param can now include sysout:{level} ie, sysout:DEBUG for people who have trouble with context.log
    • +
    +
  • +
  • 2.5.1 +
      +
    • bug fixes, Log initialisation and null auth type condition values
    • +
    +
  • +
  • 2.5 +
      +
    • matcher changed to accept first match (not the whole string) please make sure you retest your rules + (ie, previously /res/js/l.js?aaa would not match /res/js/l.js, with this release it will)
    • +
    • support for logging to log4j or commons-logging (see filter params in manual)
    • +
    • fixed bug for when request.getCookies() returns null on some containers
    • +
    • added encodefirst outbound-rule, outbound-rule now respects encode on "to".
    • +
    + +
  • +
  • 2.4 +
      +
    • removed all external library dependencies to make much more deploy friendly
    • +
    • no longer uses Jakarta ORO, this should't mean any change in regular expression handling but you should test + your existing rules just in case.
    • +
    • fixed problem with rediredting to "null" this will now not proceed with the request if the rule is matched + (ie, chain.doFilter will not be called)
    • +
    • fixed problem with ant dependency on status page
    • +
    +
  • +
  • 2.3 (4/2005) +
      +
    • Added new outbound-rule for rewriting hyperlinks in JSP's, improved status page, added ability + to run methods when a rule is matched
    • +
    +
  • +
  • 2.0.1 (2/2005) +
      +
    • Fixed bug with rule processing when to element doesn't exist.
    • +
    +
  • +
  • 2.0 (1/2005) +
      +
    • Minor bug fixes, last attribute on rule now defaults to false (thanks to Vineet Kumar for his + assistance).
    • +
    +
  • +
  • 2.0-beta (12/2004) +
      +
    • Minor bug fixes, documentation improvements, ALL matches now done case insensitively by + default, case sensitivity can be set (see from and condition elements).
    • +
    +
  • +
  • 2.0-alpha (11/2004) +
      +
    • First 2.0 release, added many new condition types, many new set types.
    • +
    +
  • +
  • 1.2 (6/2004) +
      +
    • Added set element (ability to set random attributes on request, thanks for the idea + Russell), from now matches RELATIVE to context NOT root (if you + are upgrading this may mean a change for you).
    • +
    +
  • +
  • 1.1 (4/2004) +
      +
    • Ability to disable rules, Refactored to enable rewriter to be embedded, + changed logging to enable log level to be set, added name and note elements to rule for documentation, + ability to disable status page, ability to change status prefix, javadoc style ant task for an HTML + configuration report.
    • +
    +
  • +
  • 1.0 (3/2004) +
      +
    • General tidy up of logging, tidy up of all code, dist now includes manual, log4j and junit + removed from bin release.
    • +
    +
  • +
  • 0.9 (2/2004) +
      +
    • Fixed conf loading problem in Resin, resolved concurrency issue with Perl5Compiler and + Perl5Matcher (thanks Scott Askew!)
    • +
    +
  • +
  • 0.8 (2/2004) +
      +
    • Removed dependency on "Commons Lang", Changed DTD path (bug fix), added ability to put time + fields in "condition" element, added ability to put "operators" in the "condition" element, fixed multiple rules issue (bug fix)
    • +
    +
  • +
  • 0.7 (11/2003) +
      +
    • Improved test cases, documentation
    • +
    +
  • +
  • 0.6 (8/2003) +
      +
    • Improved error handling, status page and condition matching
    • +
    +
  • +
  • 0.5 (6/2003) +
      +
    • Improved configuration error handling
    • +
    +
  • +
+ + + +
+
+ + + + + + diff --git a/src/doc/manual/4.0/urlrewrite.xml b/src/doc/manual/4.0/urlrewrite.xml index 70d30b17..a5f596c4 100644 --- a/src/doc/manual/4.0/urlrewrite.xml +++ b/src/doc/manual/4.0/urlrewrite.xml @@ -1,97 +1,97 @@ - - - - - - - - - The rule means that requests to /test/status/ will be redirected to /rewrite-status - the url will be rewritten. - - /test/status/ - %{context-path}/rewrite-status - - - - - - The outbound-rule specifies that when response.encodeURL is called (if you are using JSTL c:url) - the url /rewrite-status will be rewritten to /test/status/. - - The above rule and this outbound-rule means that end users should never see the - url /rewrite-status only /test/status/ both in thier location bar and in hyperlinks - in your pages. - - /rewrite-status - /test/status/ - - - - - - - + + + + + + + + + The rule means that requests to /test/status/ will be redirected to /rewrite-status + the url will be rewritten. + + /test/status/ + %{context-path}/rewrite-status + + + + + + The outbound-rule specifies that when response.encodeURL is called (if you are using JSTL c:url) + the url /rewrite-status will be rewritten to /test/status/. + + The above rule and this outbound-rule means that end users should never see the + url /rewrite-status only /test/status/ both in thier location bar and in hyperlinks + in your pages. + + /rewrite-status + /test/status/ + + + + + + + diff --git a/src/doc/manual/guide.html b/src/doc/manual/guide.html index 5ed552dc..8815796f 100644 --- a/src/doc/manual/guide.html +++ b/src/doc/manual/guide.html @@ -1,14 +1,14 @@ - - - - UrlRewriteFilter - Guide - - - - -

Latest Guide

-

Version 4.0 Guide

- - + + + + UrlRewriteFilter - Guide + + + + +

Latest Guide

+

Version 4.0 Guide

+ + \ No newline at end of file diff --git a/src/doc/manual/index.html b/src/doc/manual/index.html index e7318471..78304b97 100644 --- a/src/doc/manual/index.html +++ b/src/doc/manual/index.html @@ -1,14 +1,14 @@ - - - - UrlRewriteFilter - Manual - - - - -

Latest Documentation

-

Version 4.0 Documentation

- - + + + + UrlRewriteFilter - Manual + + + + +

Latest Documentation

+

Version 4.0 Documentation

+ + \ No newline at end of file diff --git a/src/doc/maven-request.txt b/src/doc/maven-request.txt index 227f3c30..723d3d25 100644 --- a/src/doc/maven-request.txt +++ b/src/doc/maven-request.txt @@ -1,13 +1,13 @@ - - -Upload UrlRewriteFilter @version@ - -# TODO FULL URL HERE # urlrewritefilter-@version@-maven-bundle.jar - -http://www.tuckey.org/urlrewrite/ - -UrlRewriteFilter - -Based on the popular and very useful mod_rewrite for apache, UrlRewriteFilter is a Java Web Filter for any J2EE -compliant web application server (such as Resin, Orion or Tomcat), which allows you to rewrite URLs before they get to -your code. It is a very powerful tool just like Apache's mod_rewrite. + + +Upload UrlRewriteFilter @version@ + +# TODO FULL URL HERE # urlrewritefilter-@version@-maven-bundle.jar + +http://www.tuckey.org/urlrewrite/ + +UrlRewriteFilter + +Based on the popular and very useful mod_rewrite for apache, UrlRewriteFilter is a Java Web Filter for any J2EE +compliant web application server (such as Resin, Orion or Tomcat), which allows you to rewrite URLs before they get to +your code. It is a very powerful tool just like Apache's mod_rewrite. diff --git a/src/main/java/org/tuckey/web/filters/urlrewrite/doc/doc.css b/src/main/java/org/tuckey/web/filters/urlrewrite/doc/doc.css index 1a1c8647..fe1a09f7 100644 --- a/src/main/java/org/tuckey/web/filters/urlrewrite/doc/doc.css +++ b/src/main/java/org/tuckey/web/filters/urlrewrite/doc/doc.css @@ -1,139 +1,139 @@ -body { - background: #c0c0c0; - font: 13px arial, helvetica, sans-serif; -} - -#logo { - vertical-align: middle; -} - -h1 { - color: #000000; - font-size: 2.5em; - padding: 0px 0px 0px 5px; - margin: 0px; - font-family: georgia, times, serif; -} - -#masthead { - font-family: georgia, times, serif; - font-size: 3.5em; - background-color: #efefef; - -moz-border-radius-topright: 20px; - margin-top: 5px; - padding: 5px; - padding-left: 15px; - width: 650px; -} - -#masthead a { - text-decoration: none; - color: black; -} - - -h2 { - font-family: georgia, times, serif; - border-bottom: 1px solid #808080; - padding: 5px; -} - -h3 { - font-family: georgia, times, serif; - border-bottom: 1px solid #c0c0c0; - margin-top: 2em; - padding: 0.25em 0.25em 0em 0.5em; -} - -p { - padding: 0.25em 0.25em 0em 1.0em; -} - -code, pre { - font-family: 'Courier New', courier, monospace; - font-size: 11px; -} - -pre { - background: #eeeeff; - margin: 0.5em 3em 0.1em 3em; - padding: 0.25em 0.5em 0.5em 0.5em; -} - -table { - border: 1px solid #c0c0c0; - margin-left: 2em; - border-collapse: collapse; - border-spacing: 0; -} - -th, td { - border: 1px solid #eeeeee; - vertical-align: top; - padding: 3px; -} - -th { - background: #eeeeee; -} - -hr { - border: 0px; - background-color: #c0c0c0; -} - -.err { - color: #ff0000; -} - -#menu { - float:left; - width:160px; - background: #efefef; - Zmargin-top: 2px; - padding-bottom: 10px; - padding-left: 10px; - -moz-border-radius-bottomleft: 20px; -} - -#menu ul { - list-style-type: none; - margin-left: .5em; - padding-left: .5em; - margin-top: 7px; -} -#menu li { - margin-bottom: 7px; -} - -#main { - background: white; - border-left: 1px solid #c0c0c0; - border-top: 1px solid #c0c0c0; - border-right: 1px solid #808080; - border-bottom: 1px solid #808080; - margin-left: 170px; - padding: 15px; - -moz-border-radius-bottomleft: 20px; - min-height: 400px; -} - -#footer { - margin-top: 40px; - text-align: center; - font-size: small; - color: black; - text-transform: lowercase; -} - -#footer a { - text-decoration: none; -} - -.outdated { - border: 2px solid red; - background: #eeeeee; - padding: 5px; - font-weight: bold; -} - +body { + background: #c0c0c0; + font: 13px arial, helvetica, sans-serif; +} + +#logo { + vertical-align: middle; +} + +h1 { + color: #000000; + font-size: 2.5em; + padding: 0px 0px 0px 5px; + margin: 0px; + font-family: georgia, times, serif; +} + +#masthead { + font-family: georgia, times, serif; + font-size: 3.5em; + background-color: #efefef; + -moz-border-radius-topright: 20px; + margin-top: 5px; + padding: 5px; + padding-left: 15px; + width: 650px; +} + +#masthead a { + text-decoration: none; + color: black; +} + + +h2 { + font-family: georgia, times, serif; + border-bottom: 1px solid #808080; + padding: 5px; +} + +h3 { + font-family: georgia, times, serif; + border-bottom: 1px solid #c0c0c0; + margin-top: 2em; + padding: 0.25em 0.25em 0em 0.5em; +} + +p { + padding: 0.25em 0.25em 0em 1.0em; +} + +code, pre { + font-family: 'Courier New', courier, monospace; + font-size: 11px; +} + +pre { + background: #eeeeff; + margin: 0.5em 3em 0.1em 3em; + padding: 0.25em 0.5em 0.5em 0.5em; +} + +table { + border: 1px solid #c0c0c0; + margin-left: 2em; + border-collapse: collapse; + border-spacing: 0; +} + +th, td { + border: 1px solid #eeeeee; + vertical-align: top; + padding: 3px; +} + +th { + background: #eeeeee; +} + +hr { + border: 0px; + background-color: #c0c0c0; +} + +.err { + color: #ff0000; +} + +#menu { + float:left; + width:160px; + background: #efefef; + Zmargin-top: 2px; + padding-bottom: 10px; + padding-left: 10px; + -moz-border-radius-bottomleft: 20px; +} + +#menu ul { + list-style-type: none; + margin-left: .5em; + padding-left: .5em; + margin-top: 7px; +} +#menu li { + margin-bottom: 7px; +} + +#main { + background: white; + border-left: 1px solid #c0c0c0; + border-top: 1px solid #c0c0c0; + border-right: 1px solid #808080; + border-bottom: 1px solid #808080; + margin-left: 170px; + padding: 15px; + -moz-border-radius-bottomleft: 20px; + min-height: 400px; +} + +#footer { + margin-top: 40px; + text-align: center; + font-size: small; + color: black; + text-transform: lowercase; +} + +#footer a { + text-decoration: none; +} + +.outdated { + border: 2px solid red; + background: #eeeeee; + padding: 5px; + font-weight: bold; +} + diff --git a/src/main/java/org/tuckey/web/filters/urlrewrite/json/JsonWriter.java b/src/main/java/org/tuckey/web/filters/urlrewrite/json/JsonWriter.java index 695863a3..29994039 100644 --- a/src/main/java/org/tuckey/web/filters/urlrewrite/json/JsonWriter.java +++ b/src/main/java/org/tuckey/web/filters/urlrewrite/json/JsonWriter.java @@ -1,219 +1,219 @@ -package org.tuckey.web.filters.urlrewrite.json; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.text.CharacterIterator; -import java.text.StringCharacterIterator; -import java.util.Collection; -import java.util.Iterator; -import java.util.Map; -import java.util.Stack; - -/* - * Based on org.stringtree.json.JsonWriter, code under Apache Public - * License, LGPL or GPL. - */ -public class JsonWriter { - - private StringBuffer buf = new StringBuffer(); - private Stack calls = new Stack(); - boolean emitClassName = true; - - public JsonWriter(boolean emitClassName) { - this.emitClassName = emitClassName; - } - - public JsonWriter() { - this(true); - } - - public String write(Object object) { - buf.setLength(0); - value(object); - return buf.toString(); - } - - public String write(long n) { - return String.valueOf(n); - } - - public String write(double d) { - return String.valueOf(d); - } - - public String write(char c) { - return "\"" + c + "\""; - } - - public String write(boolean b) { - return String.valueOf(b); - } - - private void value(Object object) { - if (object == null || cyclic(object)) { - add("null"); - } else { - calls.push(object); - if (object instanceof Class) string(object); - else if (object instanceof Boolean) bool(((Boolean) object).booleanValue()); - else if (object instanceof Number) add(object); - else if (object instanceof String) string(object); - else if (object instanceof Character) string(object); - else if (object instanceof Map) map((Map) object); - else if (object.getClass().isArray()) array(object); - else if (object instanceof Iterator) array((Iterator) object); - else if (object instanceof Collection) array(((Collection) object).iterator()); - else bean(object); - calls.pop(); - } - } - - private boolean cyclic(Object object) { - Iterator it = calls.iterator(); - while (it.hasNext()) { - Object called = it.next(); - if (object == called) return true; - } - return false; - } - - private void bean(Object object) { - add("{"); - BeanInfo info; - boolean addedSomething = false; - try { - info = Introspector.getBeanInfo(object.getClass()); - PropertyDescriptor[] props = info.getPropertyDescriptors(); - for (int i = 0; i < props.length; ++i) { - PropertyDescriptor prop = props[i]; - String name = prop.getName(); - // ignore stacktraces - if ( object instanceof Throwable && "stackTrace".equals(name) ) continue; - // ignore class element of JSONRPCErrorBean - if ( object instanceof JsonRpcErrorBean && "class".equals(name) ) continue; - // for JSONRPCBean ignore result or error depending on weather error present - if ( object instanceof JsonRpcBean) { - if ("class".equals(name) ) continue; - JsonRpcBean rpcBean = (JsonRpcBean) object; - if (rpcBean.getError() == null && "error".equals(name) ) continue; - if (rpcBean.getError() != null && "result".equals(name) ) continue; - } - Method accessor = prop.getReadMethod(); - if ((emitClassName || !"class".equals(name)) && accessor != null) { - if (!accessor.isAccessible()) accessor.setAccessible(true); - Object value = accessor.invoke(object, (Object[]) null); - if (addedSomething) add(','); - add(name, value); - addedSomething = true; - } - } - Field[] ff = object.getClass().getFields(); - for (int i = 0; i < ff.length; ++i) { - Field field = ff[i]; - if (addedSomething) add(','); - add(field.getName(), field.get(object)); - addedSomething = true; - } - } catch (IllegalAccessException iae) { - iae.printStackTrace(); - } catch (InvocationTargetException ite) { - ite.getCause().printStackTrace(); - ite.printStackTrace(); - } catch (IntrospectionException ie) { - ie.printStackTrace(); - } - add("}"); - } - - private void add(String name, Object value) { - add('"'); - add(name); - add("\":"); - value(value); - } - - private void map(Map map) { - add("{"); - Iterator it = map.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry e = (Map.Entry) it.next(); - value(e.getKey()); - add(":"); - value(e.getValue()); - if (it.hasNext()) add(','); - } - add("}"); - } - - private void array(Iterator it) { - add("["); - while (it.hasNext()) { - value(it.next()); - if (it.hasNext()) add(","); - } - add("]"); - } - - private void array(Object object) { - add("["); - int length = Array.getLength(object); - for (int i = 0; i < length; ++i) { - value(Array.get(object, i)); - if (i < length - 1) add(','); - } - add("]"); - } - - private void bool(boolean b) { - add(b ? "true" : "false"); - } - - private void string(Object obj) { - add('"'); - CharacterIterator it = new StringCharacterIterator(obj.toString()); - for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { - if (c == '"') add("\\\""); - else if (c == '\\') add("\\\\"); - else if (c == '/') add("\\/"); - else if (c == '\b') add("\\b"); - else if (c == '\f') add("\\f"); - else if (c == '\n') add("\\n"); - else if (c == '\r') add("\\r"); - else if (c == '\t') add("\\t"); - else if (Character.isISOControl(c)) { - unicode(c); - } else { - add(c); - } - } - add('"'); - } - - private void add(Object obj) { - buf.append(obj); - } - - private void add(char c) { - buf.append(c); - } - - static char[] hex = "0123456789ABCDEF".toCharArray(); - - private void unicode(char c) { - add("\\u"); - int n = c; - for (int i = 0; i < 4; ++i) { - int digit = (n & 0xf000) >> 12; - add(hex[digit]); - n <<= 4; - } - } - - -} +package org.tuckey.web.filters.urlrewrite.json; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.Collection; +import java.util.Iterator; +import java.util.Map; +import java.util.Stack; + +/* + * Based on org.stringtree.json.JsonWriter, code under Apache Public + * License, LGPL or GPL. + */ +public class JsonWriter { + + private StringBuffer buf = new StringBuffer(); + private Stack calls = new Stack(); + boolean emitClassName = true; + + public JsonWriter(boolean emitClassName) { + this.emitClassName = emitClassName; + } + + public JsonWriter() { + this(true); + } + + public String write(Object object) { + buf.setLength(0); + value(object); + return buf.toString(); + } + + public String write(long n) { + return String.valueOf(n); + } + + public String write(double d) { + return String.valueOf(d); + } + + public String write(char c) { + return "\"" + c + "\""; + } + + public String write(boolean b) { + return String.valueOf(b); + } + + private void value(Object object) { + if (object == null || cyclic(object)) { + add("null"); + } else { + calls.push(object); + if (object instanceof Class) string(object); + else if (object instanceof Boolean) bool(((Boolean) object).booleanValue()); + else if (object instanceof Number) add(object); + else if (object instanceof String) string(object); + else if (object instanceof Character) string(object); + else if (object instanceof Map) map((Map) object); + else if (object.getClass().isArray()) array(object); + else if (object instanceof Iterator) array((Iterator) object); + else if (object instanceof Collection) array(((Collection) object).iterator()); + else bean(object); + calls.pop(); + } + } + + private boolean cyclic(Object object) { + Iterator it = calls.iterator(); + while (it.hasNext()) { + Object called = it.next(); + if (object == called) return true; + } + return false; + } + + private void bean(Object object) { + add("{"); + BeanInfo info; + boolean addedSomething = false; + try { + info = Introspector.getBeanInfo(object.getClass()); + PropertyDescriptor[] props = info.getPropertyDescriptors(); + for (int i = 0; i < props.length; ++i) { + PropertyDescriptor prop = props[i]; + String name = prop.getName(); + // ignore stacktraces + if ( object instanceof Throwable && "stackTrace".equals(name) ) continue; + // ignore class element of JSONRPCErrorBean + if ( object instanceof JsonRpcErrorBean && "class".equals(name) ) continue; + // for JSONRPCBean ignore result or error depending on weather error present + if ( object instanceof JsonRpcBean) { + if ("class".equals(name) ) continue; + JsonRpcBean rpcBean = (JsonRpcBean) object; + if (rpcBean.getError() == null && "error".equals(name) ) continue; + if (rpcBean.getError() != null && "result".equals(name) ) continue; + } + Method accessor = prop.getReadMethod(); + if ((emitClassName || !"class".equals(name)) && accessor != null) { + if (!accessor.isAccessible()) accessor.setAccessible(true); + Object value = accessor.invoke(object, (Object[]) null); + if (addedSomething) add(','); + add(name, value); + addedSomething = true; + } + } + Field[] ff = object.getClass().getFields(); + for (int i = 0; i < ff.length; ++i) { + Field field = ff[i]; + if (addedSomething) add(','); + add(field.getName(), field.get(object)); + addedSomething = true; + } + } catch (IllegalAccessException iae) { + iae.printStackTrace(); + } catch (InvocationTargetException ite) { + ite.getCause().printStackTrace(); + ite.printStackTrace(); + } catch (IntrospectionException ie) { + ie.printStackTrace(); + } + add("}"); + } + + private void add(String name, Object value) { + add('"'); + add(name); + add("\":"); + value(value); + } + + private void map(Map map) { + add("{"); + Iterator it = map.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + value(e.getKey()); + add(":"); + value(e.getValue()); + if (it.hasNext()) add(','); + } + add("}"); + } + + private void array(Iterator it) { + add("["); + while (it.hasNext()) { + value(it.next()); + if (it.hasNext()) add(","); + } + add("]"); + } + + private void array(Object object) { + add("["); + int length = Array.getLength(object); + for (int i = 0; i < length; ++i) { + value(Array.get(object, i)); + if (i < length - 1) add(','); + } + add("]"); + } + + private void bool(boolean b) { + add(b ? "true" : "false"); + } + + private void string(Object obj) { + add('"'); + CharacterIterator it = new StringCharacterIterator(obj.toString()); + for (char c = it.first(); c != CharacterIterator.DONE; c = it.next()) { + if (c == '"') add("\\\""); + else if (c == '\\') add("\\\\"); + else if (c == '/') add("\\/"); + else if (c == '\b') add("\\b"); + else if (c == '\f') add("\\f"); + else if (c == '\n') add("\\n"); + else if (c == '\r') add("\\r"); + else if (c == '\t') add("\\t"); + else if (Character.isISOControl(c)) { + unicode(c); + } else { + add(c); + } + } + add('"'); + } + + private void add(Object obj) { + buf.append(obj); + } + + private void add(char c) { + buf.append(c); + } + + static char[] hex = "0123456789ABCDEF".toCharArray(); + + private void unicode(char c) { + add("\\u"); + int n = c; + for (int i = 0; i < 4; ++i) { + int digit = (n & 0xf000) >> 12; + add(hex[digit]); + n <<= 4; + } + } + + +} diff --git a/src/main/resources/org/tuckey/web/filters/urlrewrite/build.number.properties b/src/main/resources/org/tuckey/web/filters/urlrewrite/build.number.properties index 801107b3..8fd0c45a 100644 --- a/src/main/resources/org/tuckey/web/filters/urlrewrite/build.number.properties +++ b/src/main/resources/org/tuckey/web/filters/urlrewrite/build.number.properties @@ -1,2 +1,2 @@ -project.version=${project.version} +project.version=${project.version} build.number=${buildNumber} \ No newline at end of file diff --git a/src/main/resources/org/tuckey/web/filters/urlrewrite/doc/doc.css b/src/main/resources/org/tuckey/web/filters/urlrewrite/doc/doc.css index 105c6476..4d5043a6 100644 --- a/src/main/resources/org/tuckey/web/filters/urlrewrite/doc/doc.css +++ b/src/main/resources/org/tuckey/web/filters/urlrewrite/doc/doc.css @@ -1,46 +1,46 @@ - -body { - background: #ffffff; -} - -h1 { - font-family: Arial, Helvetica, sans-serif; color:#000000; - font-size: medium; -} - -h2 { - border: 1px solid #c0c0c0; - background-color: #ccccff; - padding: 5px; -} - -h3 { - border-top: 1px solid #c0c0c0; - margin-top: 1em; - padding-top: 0.25em; -} - -code { - background-color: #eeeeee; -} - -hr { - border: 0; - background-color: #c0c0c0; -} - -.err { - color: #ff0000; -} - -a:link, a:visited { - color: blue; -} - -a:active, a:hover, { - color: #f30 !important; -} - -a:link, a:visited { - color: #555 !important; -} + +body { + background: #ffffff; +} + +h1 { + font-family: Arial, Helvetica, sans-serif; color:#000000; + font-size: medium; +} + +h2 { + border: 1px solid #c0c0c0; + background-color: #ccccff; + padding: 5px; +} + +h3 { + border-top: 1px solid #c0c0c0; + margin-top: 1em; + padding-top: 0.25em; +} + +code { + background-color: #eeeeee; +} + +hr { + border: 0; + background-color: #c0c0c0; +} + +.err { + color: #ff0000; +} + +a:link, a:visited { + color: blue; +} + +a:active, a:hover, { + color: #f30 !important; +} + +a:link, a:visited { + color: #555 !important; +} diff --git a/src/test/java/org/tuckey/web/filters/urlrewrite/PerformanceTest.java b/src/test/java/org/tuckey/web/filters/urlrewrite/PerformanceTest.java index 8ac84f3a..4429f511 100644 --- a/src/test/java/org/tuckey/web/filters/urlrewrite/PerformanceTest.java +++ b/src/test/java/org/tuckey/web/filters/urlrewrite/PerformanceTest.java @@ -1,118 +1,118 @@ -package org.tuckey.web.filters.urlrewrite; - -import junit.framework.TestCase; -import org.tuckey.web.filters.urlrewrite.test.TestRunObj; -import org.tuckey.web.filters.urlrewrite.utils.Log; -import org.tuckey.web.testhelper.*; - -import jakarta.servlet.ServletException; -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; - -/** - * A quick way to check the performance of the engine. Should not be a repleacement for proper performance testing! - */ -public class PerformanceTest extends TestCase { - - MockResponse response; - MockRequest request; - MockServletContext servletContext; - MockFilterChain chain; - - public void setUp() { - Log.setLevel("DEBUG"); - response = new MockResponse(); - request = new MockRequest("/"); - servletContext = new MockServletContext(); - chain = new MockFilterChain(); - TestRunObj.resetTestFlags(); - } - - - /** - * Goal is to be able to process 2000 reqs a second for a simple rule set of 10000. - * Performance is obviously very CPU dependant, so we establish a benchmark for the machine the - * test is running on then base performance on that. This is a horribly rough way of determining - * performance, but it is good enough for this simple test case. - */ - public void testLoadsOfRules() throws IOException, ServletException, InvocationTargetException { - // turn off logging - Log.setLevel("ERROR"); - - // benchmark this machine to see what it can do... - float bench = new BenchmarkRunner().establishBenchmark(); - float timePerRule = bench * (float) 0.0003; // ms per rule... 0.03% of the benchmark - System.out.println("using " + timePerRule + "ms per rule as the standard"); - - float testAmount = 10000; // number of times to run test - - // test with 1000 rules, more than anybody would normally have - Conf conf = new Conf(); - for (int i = 0; i < 1000; i++) { - NormalRule rule = new NormalRule(); - rule.setFrom("^/([a-z]+)/([0-9]+)/" + i + "/$"); - rule.setTo("/blah/a/$2/"); - conf.addRule(rule); - } - conf.initialise(); - UrlRewriter urlRewriter = new UrlRewriter(conf); - - MockRequest request = new MockRequest("/dir/999/45/"); - // warm up - urlRewriter.processRequest(request, response); - - long timeStart = System.currentTimeMillis(); - for (float i = 0; i < testAmount; i++) { - urlRewriter.processRequest(request, response); - if (i % 500 == 0 && i > 0) { - System.out.println("avg so far " + ((System.currentTimeMillis() - timeStart) / i) + "ms per rule"); - } - } - long took = System.currentTimeMillis() - timeStart; - System.out.println("took " + took + "ms " + (took / testAmount) + "ms per rule"); - assertTrue("should take less than " + timePerRule + "ms per rule", (took / testAmount) < timePerRule); - } - - - - /** - * Goal is to be able to process 1000 urls a second for a simple rule set of 1000. - */ - public void testLoadsOfOutboundRules() { - // turn off logging - Log.setLevel("ERROR"); - - float testAmount = 10000; // number of times to run test - float timePerRule = 3; // ms per rule - - // test with 1000 rules - Conf conf = new Conf(); - for (int i = 0; i < 1000; i++) { - OutboundRule rule = new OutboundRule(); - rule.setFrom("^/([a-z]+)/([0-9]+)/" + i + "/$"); - rule.setTo("/blah/a/$2/"); - conf.addOutboundRule(rule); - } - conf.initialise(); - UrlRewriter urlRewriter = new UrlRewriter(conf); - - MockRequest request = new MockRequest("/dir/999/45/"); - // warm up - UrlRewriteWrappedResponse urlRewriteWrappedResponse = new UrlRewriteWrappedResponse(response, request, urlRewriter); - urlRewriteWrappedResponse.encodeURL("/aaa"); - - long timeStart = System.currentTimeMillis(); - for (float i = 0; i < testAmount; i++) { - urlRewriteWrappedResponse.encodeURL("/sdasd/asdasd/asdasd"); - if (i % 500 == 0 && i > 0) { - System.out.println("avg so far " + ((System.currentTimeMillis() - timeStart) / i) + "ms per rule"); - } - } - long took = System.currentTimeMillis() - timeStart; - System.out.println("took " + took + "ms " + (took / testAmount) + "ms per rule"); - assertTrue("should take less than " + timePerRule + "ms per rule", (took / testAmount) < timePerRule); - } - - - -} +package org.tuckey.web.filters.urlrewrite; + +import junit.framework.TestCase; +import org.tuckey.web.filters.urlrewrite.test.TestRunObj; +import org.tuckey.web.filters.urlrewrite.utils.Log; +import org.tuckey.web.testhelper.*; + +import jakarta.servlet.ServletException; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; + +/** + * A quick way to check the performance of the engine. Should not be a repleacement for proper performance testing! + */ +public class PerformanceTest extends TestCase { + + MockResponse response; + MockRequest request; + MockServletContext servletContext; + MockFilterChain chain; + + public void setUp() { + Log.setLevel("DEBUG"); + response = new MockResponse(); + request = new MockRequest("/"); + servletContext = new MockServletContext(); + chain = new MockFilterChain(); + TestRunObj.resetTestFlags(); + } + + + /** + * Goal is to be able to process 2000 reqs a second for a simple rule set of 10000. + * Performance is obviously very CPU dependant, so we establish a benchmark for the machine the + * test is running on then base performance on that. This is a horribly rough way of determining + * performance, but it is good enough for this simple test case. + */ + public void testLoadsOfRules() throws IOException, ServletException, InvocationTargetException { + // turn off logging + Log.setLevel("ERROR"); + + // benchmark this machine to see what it can do... + float bench = new BenchmarkRunner().establishBenchmark(); + float timePerRule = bench * (float) 0.0003; // ms per rule... 0.03% of the benchmark + System.out.println("using " + timePerRule + "ms per rule as the standard"); + + float testAmount = 10000; // number of times to run test + + // test with 1000 rules, more than anybody would normally have + Conf conf = new Conf(); + for (int i = 0; i < 1000; i++) { + NormalRule rule = new NormalRule(); + rule.setFrom("^/([a-z]+)/([0-9]+)/" + i + "/$"); + rule.setTo("/blah/a/$2/"); + conf.addRule(rule); + } + conf.initialise(); + UrlRewriter urlRewriter = new UrlRewriter(conf); + + MockRequest request = new MockRequest("/dir/999/45/"); + // warm up + urlRewriter.processRequest(request, response); + + long timeStart = System.currentTimeMillis(); + for (float i = 0; i < testAmount; i++) { + urlRewriter.processRequest(request, response); + if (i % 500 == 0 && i > 0) { + System.out.println("avg so far " + ((System.currentTimeMillis() - timeStart) / i) + "ms per rule"); + } + } + long took = System.currentTimeMillis() - timeStart; + System.out.println("took " + took + "ms " + (took / testAmount) + "ms per rule"); + assertTrue("should take less than " + timePerRule + "ms per rule", (took / testAmount) < timePerRule); + } + + + + /** + * Goal is to be able to process 1000 urls a second for a simple rule set of 1000. + */ + public void testLoadsOfOutboundRules() { + // turn off logging + Log.setLevel("ERROR"); + + float testAmount = 10000; // number of times to run test + float timePerRule = 3; // ms per rule + + // test with 1000 rules + Conf conf = new Conf(); + for (int i = 0; i < 1000; i++) { + OutboundRule rule = new OutboundRule(); + rule.setFrom("^/([a-z]+)/([0-9]+)/" + i + "/$"); + rule.setTo("/blah/a/$2/"); + conf.addOutboundRule(rule); + } + conf.initialise(); + UrlRewriter urlRewriter = new UrlRewriter(conf); + + MockRequest request = new MockRequest("/dir/999/45/"); + // warm up + UrlRewriteWrappedResponse urlRewriteWrappedResponse = new UrlRewriteWrappedResponse(response, request, urlRewriter); + urlRewriteWrappedResponse.encodeURL("/aaa"); + + long timeStart = System.currentTimeMillis(); + for (float i = 0; i < testAmount; i++) { + urlRewriteWrappedResponse.encodeURL("/sdasd/asdasd/asdasd"); + if (i % 500 == 0 && i > 0) { + System.out.println("avg so far " + ((System.currentTimeMillis() - timeStart) / i) + "ms per rule"); + } + } + long took = System.currentTimeMillis() - timeStart; + System.out.println("took " + took + "ms " + (took / testAmount) + "ms per rule"); + assertTrue("should take less than " + timePerRule + "ms per rule", (took / testAmount) < timePerRule); + } + + + +} diff --git a/src/test/java/org/tuckey/web/filters/urlrewrite/RequestProxyTest.java b/src/test/java/org/tuckey/web/filters/urlrewrite/RequestProxyTest.java index 951568c2..83c43a21 100644 --- a/src/test/java/org/tuckey/web/filters/urlrewrite/RequestProxyTest.java +++ b/src/test/java/org/tuckey/web/filters/urlrewrite/RequestProxyTest.java @@ -1,22 +1,22 @@ -package org.tuckey.web.filters.urlrewrite; - -import junit.framework.TestCase; - -import jakarta.servlet.ServletException; -import java.io.IOException; - -/** - * @author Paul Tuckey - * @version $Revision: 40 $ $Date: 2006-10-27 15:12:37 +1300 (Fri, 27 Oct 2006) $ - */ -public class RequestProxyTest extends TestCase { - - - public void testUseProxyServer() throws IOException, ServletException { - assertEquals(3128, RequestProxy.getUseProxyServer("myproxyserver:3128").getPort()); - assertEquals(80, RequestProxy.getUseProxyServer("myproxyserver:A3128").getPort()); - assertEquals("myproxyserver", RequestProxy.getUseProxyServer("myproxyserver:A3128").getHostName()); - } - - -} +package org.tuckey.web.filters.urlrewrite; + +import junit.framework.TestCase; + +import jakarta.servlet.ServletException; +import java.io.IOException; + +/** + * @author Paul Tuckey + * @version $Revision: 40 $ $Date: 2006-10-27 15:12:37 +1300 (Fri, 27 Oct 2006) $ + */ +public class RequestProxyTest extends TestCase { + + + public void testUseProxyServer() throws IOException, ServletException { + assertEquals(3128, RequestProxy.getUseProxyServer("myproxyserver:3128").getPort()); + assertEquals(80, RequestProxy.getUseProxyServer("myproxyserver:A3128").getPort()); + assertEquals("myproxyserver", RequestProxy.getUseProxyServer("myproxyserver:A3128").getHostName()); + } + + +} diff --git a/src/test/java/org/tuckey/web/filters/urlrewrite/VariableReplacerTest.java b/src/test/java/org/tuckey/web/filters/urlrewrite/VariableReplacerTest.java index 26d38668..d5a9aff7 100644 --- a/src/test/java/org/tuckey/web/filters/urlrewrite/VariableReplacerTest.java +++ b/src/test/java/org/tuckey/web/filters/urlrewrite/VariableReplacerTest.java @@ -1,98 +1,98 @@ -package org.tuckey.web.filters.urlrewrite; - -import junit.framework.TestCase; -import org.tuckey.web.filters.urlrewrite.substitution.VariableReplacer; -import org.tuckey.web.testhelper.MockRequest; - -import jakarta.servlet.ServletContext; - -/** - * @author Tim Morrow - * @since Dec 4, 2007 - */ -public class VariableReplacerTest extends TestCase { - - private MockRequest request; - - protected void setUp() { - request = new MockRequest(); - } - - public final void testReplaceNullValue() { - request.getSession(true); - final String result = VariableReplacer.replace("%{session-attribute:color}", request); - - assertEquals("", result); - } - - public final void testQueryStringValue() { - request.setQueryString("keyword=$2"); - final String result = VariableReplacer.replace("%{query-string}", request); - assertEquals("keyword=$2", result); - } - - public final void testNonRecursiveSubstitution() { - request.setQueryString("keyword=%{query-string}"); - final String result = VariableReplacer.replace("%{query-string}", request); - assertEquals("keyword=%{query-string}", result); - } - - public final void testReplace() { - request.getSession(true).setAttribute("color", "red"); - final String result = VariableReplacer.replace("%{session-attribute:color}", request); - - assertEquals("red", result); - } - - public final void testReplace2() { - request.getSession(true).setAttribute("color", "red"); - final String result = VariableReplacer.replace("abcd$s%{session-attribute:color}efg", request); - - assertEquals("abcd$sredefg", result); - } - - public final void testReplaceWithDollar() { - request.getSession(true).setAttribute("color", "ab$cd"); - final String result = VariableReplacer.replace("%{session-attribute:color}", request); - - assertEquals("ab$cd", result); - } - - public final void testReplaceWithBackslash() { - request.getSession(true).setAttribute("color", "ab\\cd"); - final String result = VariableReplacer.replace("%{session-attribute:color}", request); - - assertEquals("ab\\cd", result); - } - - public final void testReplaceContextVars() { - ServletContext servletContext = request.getSession(true).getServletContext(); - servletContext.setAttribute("host", "http://testurl"); - //request.getMockSession().setServletContext(servletContext); - - final String result = VariableReplacer.replaceWithServletContext("%{context:host}", request, servletContext); - - assertEquals("http://testurl", result); - } - - public final void testReplaceWithUnderscore() { - request.getSession(true).setAttribute("_type", "html"); - final String result = VariableReplacer.replace("%{session-attribute:_type}", request); - - assertEquals("html", result); - } - - public final void testReplaceWithPeriods() { - request.getSession(true).setAttribute("s3.static.bucket", "fizz"); - final String result = VariableReplacer.replace("%{session-attribute:s3.static.bucket}", request); - - assertEquals("fizz", result); - } - - public final void testReplaceWithNumbers() { - request.getSession(true).setAttribute("com.foo1.bar2", "fizz"); - final String result = VariableReplacer.replace("%{session-attribute:com.foo1.bar2}", request); - - assertEquals("fizz", result); - } -} +package org.tuckey.web.filters.urlrewrite; + +import junit.framework.TestCase; +import org.tuckey.web.filters.urlrewrite.substitution.VariableReplacer; +import org.tuckey.web.testhelper.MockRequest; + +import jakarta.servlet.ServletContext; + +/** + * @author Tim Morrow + * @since Dec 4, 2007 + */ +public class VariableReplacerTest extends TestCase { + + private MockRequest request; + + protected void setUp() { + request = new MockRequest(); + } + + public final void testReplaceNullValue() { + request.getSession(true); + final String result = VariableReplacer.replace("%{session-attribute:color}", request); + + assertEquals("", result); + } + + public final void testQueryStringValue() { + request.setQueryString("keyword=$2"); + final String result = VariableReplacer.replace("%{query-string}", request); + assertEquals("keyword=$2", result); + } + + public final void testNonRecursiveSubstitution() { + request.setQueryString("keyword=%{query-string}"); + final String result = VariableReplacer.replace("%{query-string}", request); + assertEquals("keyword=%{query-string}", result); + } + + public final void testReplace() { + request.getSession(true).setAttribute("color", "red"); + final String result = VariableReplacer.replace("%{session-attribute:color}", request); + + assertEquals("red", result); + } + + public final void testReplace2() { + request.getSession(true).setAttribute("color", "red"); + final String result = VariableReplacer.replace("abcd$s%{session-attribute:color}efg", request); + + assertEquals("abcd$sredefg", result); + } + + public final void testReplaceWithDollar() { + request.getSession(true).setAttribute("color", "ab$cd"); + final String result = VariableReplacer.replace("%{session-attribute:color}", request); + + assertEquals("ab$cd", result); + } + + public final void testReplaceWithBackslash() { + request.getSession(true).setAttribute("color", "ab\\cd"); + final String result = VariableReplacer.replace("%{session-attribute:color}", request); + + assertEquals("ab\\cd", result); + } + + public final void testReplaceContextVars() { + ServletContext servletContext = request.getSession(true).getServletContext(); + servletContext.setAttribute("host", "http://testurl"); + //request.getMockSession().setServletContext(servletContext); + + final String result = VariableReplacer.replaceWithServletContext("%{context:host}", request, servletContext); + + assertEquals("http://testurl", result); + } + + public final void testReplaceWithUnderscore() { + request.getSession(true).setAttribute("_type", "html"); + final String result = VariableReplacer.replace("%{session-attribute:_type}", request); + + assertEquals("html", result); + } + + public final void testReplaceWithPeriods() { + request.getSession(true).setAttribute("s3.static.bucket", "fizz"); + final String result = VariableReplacer.replace("%{session-attribute:s3.static.bucket}", request); + + assertEquals("fizz", result); + } + + public final void testReplaceWithNumbers() { + request.getSession(true).setAttribute("com.foo1.bar2", "fizz"); + final String result = VariableReplacer.replace("%{session-attribute:com.foo1.bar2}", request); + + assertEquals("fizz", result); + } +} diff --git a/src/test/java/org/tuckey/web/filters/urlrewrite/functions/CssVarFunctionTest.java b/src/test/java/org/tuckey/web/filters/urlrewrite/functions/CssVarFunctionTest.java index f76f5fe3..3dd71a49 100644 --- a/src/test/java/org/tuckey/web/filters/urlrewrite/functions/CssVarFunctionTest.java +++ b/src/test/java/org/tuckey/web/filters/urlrewrite/functions/CssVarFunctionTest.java @@ -1,62 +1,62 @@ -package org.tuckey.web.filters.urlrewrite.functions; - -import junit.framework.TestCase; - -import java.util.HashMap; -import java.util.Map; - - -public class CssVarFunctionTest extends TestCase { - - String nl = System.getProperty("line.separator"); - - String css = "" + - "@variables {" + nl + - " gadgetBodyLinkColor: #c0c0c0;" + nl + - "}" + nl + - "" + nl + - "h1 {" + nl + - " border-color: var(gadgetBodyLinkColor);" + nl + - "}"; - - String css2 = "" + - "@variables {" + nl + - " gadgetBodyLinkColor: #c0c0c0;" + nl + - " gadgetBodyLinkColor2: #f0c0c0;" + nl + - "}" + nl + - "" + nl + - "h1 {" + nl + - " color: var(gadgetBodyLinkColor2);" + nl + - " border-color: var(gadgetBodyLinkColor);" + nl + - "}"; - - - public void testSimple() { - assertEquals(nl + - "h1 {" + nl + - " border-color: #c0c0c0;" + nl + - "}", - CssVarFunction.parse(css, null)); - } - - public void testSimpleMap() { - Map in = new HashMap(); - in.put("gadgetBodyLinkColor", "blue"); - assertEquals(nl + - "h1 {" + nl + - " border-color: blue;" + nl + - "}", - CssVarFunction.parse(css, in)); - } - - public void testSimple2() { - assertEquals(nl + - "h1 {" + nl + - " color: #f0c0c0;" + nl + - " border-color: #c0c0c0;" + nl + - "}", - CssVarFunction.parse(css2, null)); - } - - -} +package org.tuckey.web.filters.urlrewrite.functions; + +import junit.framework.TestCase; + +import java.util.HashMap; +import java.util.Map; + + +public class CssVarFunctionTest extends TestCase { + + String nl = System.getProperty("line.separator"); + + String css = "" + + "@variables {" + nl + + " gadgetBodyLinkColor: #c0c0c0;" + nl + + "}" + nl + + "" + nl + + "h1 {" + nl + + " border-color: var(gadgetBodyLinkColor);" + nl + + "}"; + + String css2 = "" + + "@variables {" + nl + + " gadgetBodyLinkColor: #c0c0c0;" + nl + + " gadgetBodyLinkColor2: #f0c0c0;" + nl + + "}" + nl + + "" + nl + + "h1 {" + nl + + " color: var(gadgetBodyLinkColor2);" + nl + + " border-color: var(gadgetBodyLinkColor);" + nl + + "}"; + + + public void testSimple() { + assertEquals(nl + + "h1 {" + nl + + " border-color: #c0c0c0;" + nl + + "}", + CssVarFunction.parse(css, null)); + } + + public void testSimpleMap() { + Map in = new HashMap(); + in.put("gadgetBodyLinkColor", "blue"); + assertEquals(nl + + "h1 {" + nl + + " border-color: blue;" + nl + + "}", + CssVarFunction.parse(css, in)); + } + + public void testSimple2() { + assertEquals(nl + + "h1 {" + nl + + " color: #f0c0c0;" + nl + + " border-color: #c0c0c0;" + nl + + "}", + CssVarFunction.parse(css2, null)); + } + + +} diff --git a/src/test/java/org/tuckey/web/filters/urlrewrite/test/MockRequestParserTest.java b/src/test/java/org/tuckey/web/filters/urlrewrite/test/MockRequestParserTest.java index 64188838..2df92084 100644 --- a/src/test/java/org/tuckey/web/filters/urlrewrite/test/MockRequestParserTest.java +++ b/src/test/java/org/tuckey/web/filters/urlrewrite/test/MockRequestParserTest.java @@ -1,68 +1,68 @@ -package org.tuckey.web.filters.urlrewrite.test; - -import junit.framework.TestCase; -import org.tuckey.web.filters.urlrewrite.utils.Log; - -import jakarta.servlet.http.HttpServletRequest; - -public class MockRequestParserTest extends TestCase { - - private MockRequestParser parser = new MockRequestParser(); - - public void setUp() { - Log.setLevel("DEBUG"); - } - - - public void testSimpleOneLine() { - HttpServletRequest request = parser.decodeRequest("/test/uri"); - assertEquals("/test/uri", request.getRequestURI()); - } - - public void testOneLineSessionId() { - HttpServletRequest request = parser.decodeRequest("/test/uri;jsessionid=asdf"); - assertEquals("/test/uri", request.getRequestURI()); - assertEquals("asdf", request.getRequestedSessionId()); - } - - public void testOneLineSessionIdAndQueryString() { - HttpServletRequest request = parser.decodeRequest("/test/uri;jsessionid=asdf?abc=123"); - assertEquals("/test/uri", request.getRequestURI()); - assertEquals("asdf", request.getRequestedSessionId()); - assertEquals("123", request.getParameter("abc")); - } - - public void testSimpleOneLine2() { - HttpServletRequest request = parser.decodeRequest("/test/uri?abc=123&asd=345"); - assertEquals("/test/uri", request.getRequestURI()); - assertEquals("abc=123&asd=345", request.getQueryString()); - assertEquals("123", request.getParameter("abc")); - assertEquals("345", request.getParameter("asd")); - } - - public void testSimpleTwoLine() { - HttpServletRequest request = parser.decodeRequest("POST /pub/WWW/TheProject.html HTTP/1.1\n" + - "Host: www.w3.org\n" + - "user-agent: Mozburger"); - assertEquals("/pub/WWW/TheProject.html", request.getRequestURI()); - assertEquals("POST", request.getMethod()); - assertEquals("HTTP/1.1", request.getScheme()); - assertEquals("www.w3.org", request.getServerName()); - assertEquals("Mozburger", request.getHeader("user-agent")); - } - - public void testPost() { - HttpServletRequest request = parser.decodeRequest("POST /pub/WWW/TheProject.html HTTP/1.1\n" + - "Host: www.w3.org\n" + - "\n" + - "id=23&fast&name=bert"); - assertEquals("/pub/WWW/TheProject.html", request.getRequestURI()); - assertEquals("POST", request.getMethod()); - assertEquals("HTTP/1.1", request.getScheme()); - assertEquals("www.w3.org", request.getServerName()); - assertEquals("23", request.getParameter("id")); - assertEquals("bert", request.getParameter("name")); - } - - -} +package org.tuckey.web.filters.urlrewrite.test; + +import junit.framework.TestCase; +import org.tuckey.web.filters.urlrewrite.utils.Log; + +import jakarta.servlet.http.HttpServletRequest; + +public class MockRequestParserTest extends TestCase { + + private MockRequestParser parser = new MockRequestParser(); + + public void setUp() { + Log.setLevel("DEBUG"); + } + + + public void testSimpleOneLine() { + HttpServletRequest request = parser.decodeRequest("/test/uri"); + assertEquals("/test/uri", request.getRequestURI()); + } + + public void testOneLineSessionId() { + HttpServletRequest request = parser.decodeRequest("/test/uri;jsessionid=asdf"); + assertEquals("/test/uri", request.getRequestURI()); + assertEquals("asdf", request.getRequestedSessionId()); + } + + public void testOneLineSessionIdAndQueryString() { + HttpServletRequest request = parser.decodeRequest("/test/uri;jsessionid=asdf?abc=123"); + assertEquals("/test/uri", request.getRequestURI()); + assertEquals("asdf", request.getRequestedSessionId()); + assertEquals("123", request.getParameter("abc")); + } + + public void testSimpleOneLine2() { + HttpServletRequest request = parser.decodeRequest("/test/uri?abc=123&asd=345"); + assertEquals("/test/uri", request.getRequestURI()); + assertEquals("abc=123&asd=345", request.getQueryString()); + assertEquals("123", request.getParameter("abc")); + assertEquals("345", request.getParameter("asd")); + } + + public void testSimpleTwoLine() { + HttpServletRequest request = parser.decodeRequest("POST /pub/WWW/TheProject.html HTTP/1.1\n" + + "Host: www.w3.org\n" + + "user-agent: Mozburger"); + assertEquals("/pub/WWW/TheProject.html", request.getRequestURI()); + assertEquals("POST", request.getMethod()); + assertEquals("HTTP/1.1", request.getScheme()); + assertEquals("www.w3.org", request.getServerName()); + assertEquals("Mozburger", request.getHeader("user-agent")); + } + + public void testPost() { + HttpServletRequest request = parser.decodeRequest("POST /pub/WWW/TheProject.html HTTP/1.1\n" + + "Host: www.w3.org\n" + + "\n" + + "id=23&fast&name=bert"); + assertEquals("/pub/WWW/TheProject.html", request.getRequestURI()); + assertEquals("POST", request.getMethod()); + assertEquals("HTTP/1.1", request.getScheme()); + assertEquals("www.w3.org", request.getServerName()); + assertEquals("23", request.getParameter("id")); + assertEquals("bert", request.getParameter("name")); + } + + +} diff --git a/src/test/java/org/tuckey/web/filters/urlrewrite/utils/FunctionReplacerTest.java b/src/test/java/org/tuckey/web/filters/urlrewrite/utils/FunctionReplacerTest.java index 93a8cebc..890bed29 100644 --- a/src/test/java/org/tuckey/web/filters/urlrewrite/utils/FunctionReplacerTest.java +++ b/src/test/java/org/tuckey/web/filters/urlrewrite/utils/FunctionReplacerTest.java @@ -1,98 +1,98 @@ -package org.tuckey.web.filters.urlrewrite.utils; - -import junit.framework.TestCase; -import org.tuckey.web.filters.urlrewrite.substitution.FunctionReplacer; - -import jakarta.servlet.ServletException; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.InvocationTargetException; - - -public class FunctionReplacerTest extends TestCase { - - private final static String UNICODE_VALUE = "\u0131"; // Turkish dotless i - private final static String UTF16ESCAPED_UNICODE_VALUE = "%FE%FF%01%31"; - - public void setUp() { - Log.setLevel("DEBUG"); - } - - public void testDefaultEscape() throws UnsupportedEncodingException { - assertEquals("a%20b%20c%20:%20other%20%2f%20path", - FunctionReplacer.replace("${escapePath:UTF-8:a b c : other / path}")); - assertEquals("a+b+c+%3A+other+%2F+path", - FunctionReplacer.replace("${escape:UTF-8:a b c : other / path}")); - assertEquals("a+b c/", - FunctionReplacer.replace("${unescapePath:UTF-8:a+b c%2F}")); - assertEquals("a b c/", - FunctionReplacer.replace("${unescape:UTF-8:a+b c%2F}")); - assertEquals("a+b+c%FE%FF%00%3Aotherstr", - FunctionReplacer.replace("${escape:UTF-16:a b c:otherstr}")); - assertEquals("a+b+c%3Aotherstr", - FunctionReplacer.replace("${escape:utf8:a b c:otherstr}")); - assertEquals("a+b+c", - FunctionReplacer.replace("${escape:UTF-16:a b c}")); - assertEquals("a b c", - FunctionReplacer.replace("${unescape:UTF-16:a+b+c}")); - assertEquals(java.net.URLEncoder.encode(UNICODE_VALUE, "UTF-8"), - FunctionReplacer.replace("${escape:unknown:" + UNICODE_VALUE + "}")); - } - - public void testEncodingEscape() { - assertEquals(UTF16ESCAPED_UNICODE_VALUE, - FunctionReplacer.replace("${escape:UTF-16:" + UNICODE_VALUE + "}")); - } - - public void testDefaultUnescape() throws java.io.UnsupportedEncodingException { - String testString = "unknown:" + UNICODE_VALUE; - assertEquals(testString, FunctionReplacer.replace( - "${unescape:" + java.net.URLEncoder.encode(testString, "UTF-8") + "}")); - } - - public void testEncodingUnescape() { - assertEquals(UNICODE_VALUE, FunctionReplacer.replace( - "${unescape:UTF-16:" + UTF16ESCAPED_UNICODE_VALUE + "}")); - } - - public void testSimple1() throws InvocationTargetException, IOException, ServletException { - assertTrue(FunctionReplacer.containsFunction("a${lower:HEllo}b")); - assertEquals("ahellob", FunctionReplacer.replace("a${lower:HElLO}b")); - } - - public void testSimple2() throws InvocationTargetException, IOException, ServletException { - assertTrue(FunctionReplacer.containsFunction("a${upper:HEllo}b")); - assertEquals("aHELLOb", FunctionReplacer.replace("a${upper:hellO}b")); - } - - public void testSimple3() throws InvocationTargetException, IOException, ServletException { - assertTrue(FunctionReplacer.containsFunction("a${replace:a b c: :_}b")); - assertEquals("aa_b_cb", FunctionReplacer.replace("a${replace:a b c: :_}b")); - } - - public void testSimple4() throws InvocationTargetException, IOException, ServletException { - assertTrue(FunctionReplacer.containsFunction("a${replaceFirst:a b c: :_}b")); - assertEquals("aa_b cb", FunctionReplacer.replace("a${replaceFirst:a b c: :_}b")); - } - - public void testSimple5() throws InvocationTargetException, IOException, ServletException { - assertTrue(FunctionReplacer.containsFunction("a${escape:a b c} b")); - assertEquals("aa+b+c b", FunctionReplacer.replace("a${escape:a b c} b")); - } - - public void testSimple6() throws InvocationTargetException, IOException, ServletException { - assertTrue(FunctionReplacer.containsFunction("a${trim: b } b")); - assertEquals("ab b", FunctionReplacer.replace("a${trim: b } b")); - } - - public void testSimple7() throws InvocationTargetException, IOException, ServletException { - assertTrue(FunctionReplacer.containsFunction("a${length:asdf} b")); - assertEquals("a4 b", FunctionReplacer.replace("a${length:asdf} b")); - } - - public void testRecursive() throws InvocationTargetException, IOException, ServletException { - assertTrue(FunctionReplacer.containsFunction("a${upper:${lower:fOObAR}} b")); - assertEquals("aFOOBAR b", FunctionReplacer.replace("a${upper:${lower:fOObAR}} b")); - } - -} +package org.tuckey.web.filters.urlrewrite.utils; + +import junit.framework.TestCase; +import org.tuckey.web.filters.urlrewrite.substitution.FunctionReplacer; + +import jakarta.servlet.ServletException; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.InvocationTargetException; + + +public class FunctionReplacerTest extends TestCase { + + private final static String UNICODE_VALUE = "\u0131"; // Turkish dotless i + private final static String UTF16ESCAPED_UNICODE_VALUE = "%FE%FF%01%31"; + + public void setUp() { + Log.setLevel("DEBUG"); + } + + public void testDefaultEscape() throws UnsupportedEncodingException { + assertEquals("a%20b%20c%20:%20other%20%2f%20path", + FunctionReplacer.replace("${escapePath:UTF-8:a b c : other / path}")); + assertEquals("a+b+c+%3A+other+%2F+path", + FunctionReplacer.replace("${escape:UTF-8:a b c : other / path}")); + assertEquals("a+b c/", + FunctionReplacer.replace("${unescapePath:UTF-8:a+b c%2F}")); + assertEquals("a b c/", + FunctionReplacer.replace("${unescape:UTF-8:a+b c%2F}")); + assertEquals("a+b+c%FE%FF%00%3Aotherstr", + FunctionReplacer.replace("${escape:UTF-16:a b c:otherstr}")); + assertEquals("a+b+c%3Aotherstr", + FunctionReplacer.replace("${escape:utf8:a b c:otherstr}")); + assertEquals("a+b+c", + FunctionReplacer.replace("${escape:UTF-16:a b c}")); + assertEquals("a b c", + FunctionReplacer.replace("${unescape:UTF-16:a+b+c}")); + assertEquals(java.net.URLEncoder.encode(UNICODE_VALUE, "UTF-8"), + FunctionReplacer.replace("${escape:unknown:" + UNICODE_VALUE + "}")); + } + + public void testEncodingEscape() { + assertEquals(UTF16ESCAPED_UNICODE_VALUE, + FunctionReplacer.replace("${escape:UTF-16:" + UNICODE_VALUE + "}")); + } + + public void testDefaultUnescape() throws java.io.UnsupportedEncodingException { + String testString = "unknown:" + UNICODE_VALUE; + assertEquals(testString, FunctionReplacer.replace( + "${unescape:" + java.net.URLEncoder.encode(testString, "UTF-8") + "}")); + } + + public void testEncodingUnescape() { + assertEquals(UNICODE_VALUE, FunctionReplacer.replace( + "${unescape:UTF-16:" + UTF16ESCAPED_UNICODE_VALUE + "}")); + } + + public void testSimple1() throws InvocationTargetException, IOException, ServletException { + assertTrue(FunctionReplacer.containsFunction("a${lower:HEllo}b")); + assertEquals("ahellob", FunctionReplacer.replace("a${lower:HElLO}b")); + } + + public void testSimple2() throws InvocationTargetException, IOException, ServletException { + assertTrue(FunctionReplacer.containsFunction("a${upper:HEllo}b")); + assertEquals("aHELLOb", FunctionReplacer.replace("a${upper:hellO}b")); + } + + public void testSimple3() throws InvocationTargetException, IOException, ServletException { + assertTrue(FunctionReplacer.containsFunction("a${replace:a b c: :_}b")); + assertEquals("aa_b_cb", FunctionReplacer.replace("a${replace:a b c: :_}b")); + } + + public void testSimple4() throws InvocationTargetException, IOException, ServletException { + assertTrue(FunctionReplacer.containsFunction("a${replaceFirst:a b c: :_}b")); + assertEquals("aa_b cb", FunctionReplacer.replace("a${replaceFirst:a b c: :_}b")); + } + + public void testSimple5() throws InvocationTargetException, IOException, ServletException { + assertTrue(FunctionReplacer.containsFunction("a${escape:a b c} b")); + assertEquals("aa+b+c b", FunctionReplacer.replace("a${escape:a b c} b")); + } + + public void testSimple6() throws InvocationTargetException, IOException, ServletException { + assertTrue(FunctionReplacer.containsFunction("a${trim: b } b")); + assertEquals("ab b", FunctionReplacer.replace("a${trim: b } b")); + } + + public void testSimple7() throws InvocationTargetException, IOException, ServletException { + assertTrue(FunctionReplacer.containsFunction("a${length:asdf} b")); + assertEquals("a4 b", FunctionReplacer.replace("a${length:asdf} b")); + } + + public void testRecursive() throws InvocationTargetException, IOException, ServletException { + assertTrue(FunctionReplacer.containsFunction("a${upper:${lower:fOObAR}} b")); + assertEquals("aFOOBAR b", FunctionReplacer.replace("a${upper:${lower:fOObAR}} b")); + } + +} diff --git a/src/test/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoaderTest.java b/src/test/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoaderTest.java index 7e689fd9..7100c184 100644 --- a/src/test/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoaderTest.java +++ b/src/test/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoaderTest.java @@ -1,241 +1,241 @@ -package org.tuckey.web.filters.urlrewrite.utils; - -import junit.framework.TestCase; -import org.tuckey.web.filters.urlrewrite.Condition; -import org.tuckey.web.filters.urlrewrite.Conf; -import org.tuckey.web.filters.urlrewrite.NormalRule; - -import java.io.IOException; -import java.io.InputStream; - -public class ModRewriteConfLoaderTest extends TestCase { - - ModRewriteConfLoader loader = new ModRewriteConfLoader(); - Conf conf; - - public static final String BASE_PATH = "/org/tuckey/web/filters/urlrewrite/utils/"; - - public void setUp() { - Log.setLevel("DEBUG"); - conf = new Conf(); - } - - public void testEngine() { - loader.process("RewriteEngine on", conf); - assertTrue(conf.isEngineEnabled()); - } - - public void testEngine2() { - loader.process("RewriteEngine off", conf); - assertFalse(conf.isEngineEnabled()); - } - - public void testLoadFromFile() throws IOException { - InputStream is = ModRewriteConfLoaderTest.class.getResourceAsStream(BASE_PATH + "htaccess-test1.txt"); - loader.process(is, conf); - assertTrue(conf.isEngineEnabled()); - assertEquals(1, conf.getRules().size()); - } - - public void testLoadFromFile2() throws IOException { - InputStream is = ModRewriteConfLoaderTest.class.getResourceAsStream(BASE_PATH + "htaccess-test1.txt"); - Conf conf = new Conf(null, is, "htaccess-test1.txt", null, true); - assertTrue(conf.isEngineEnabled()); - assertTrue(conf.isOk()); - assertEquals(1, conf.getRules().size()); - } - - public void testSimple2() { - loader.process("\n" + - " # redirect mozilla to another area \n" + - " RewriteCond %{HTTP_USER_AGENT} ^Mozilla.* \n" + - " RewriteRule ^/$ /homepage.max.html [L] ", conf); - assertEquals(1, conf.getRules().size()); - assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); - assertEquals("header", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("user-agent", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getName()); - assertEquals("^Mozilla.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); - assertEquals("redirect mozilla to another area", ((NormalRule) conf.getRules().get(0)).getNote()); - assertEquals("^/$", ((NormalRule) conf.getRules().get(0)).getFrom()); - assertEquals("/homepage.max.html", ((NormalRule) conf.getRules().get(0)).getTo()); - assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); - } - - public void testSimpleRedirect() { - loader.process("\n" + - " RewriteRule ^/$ http://www.foo.com [R] \n" + - "", conf); - - assertNotNull(conf.getRules()); - assertEquals(1, conf.getRules().size()); - - NormalRule rule = (NormalRule) conf.getRules().get(0); - assertNotNull(rule); - assertEquals("redirect", rule.getToType()); - assertEquals("^/$", rule.getFrom()); - assertEquals("http://www.foo.com", rule.getTo()); - } - - public void testPermanentRedirect() { - loader.process("\n" + - " RewriteRule ^/$ http://www.foo.com [R=301] \n" + - "", conf); - - assertNotNull(conf.getRules()); - assertEquals(1, conf.getRules().size()); - - NormalRule rule = (NormalRule) conf.getRules().get(0); - assertNotNull(rule); - assertEquals("permanent-redirect", rule.getToType()); - assertEquals("^/$", rule.getFrom()); - assertEquals("http://www.foo.com", rule.getTo()); - } - - public void testMobile() { - loader.process("\n" + - " # mobile redirect\n" + - "RewriteCond %{HTTP_HOST} from.com\n" + - "RewriteCond %{HTTP:accept} (hdml|wml|xhtml-mp|vnd\\.wap\\.) [OR]\n" + - "RewriteCond %{HTTP:x-wap-profile} .+ [OR]\n" + - "RewriteCond %{HTTP:user-agent} (Windows\\ CE) [OR]\n" + - "RewriteCond %{HTTP:user-agent} (iPhone) [OR]\n" + - "RewriteCond %{HTTP:user-agent} (iPod) [OR]\n" + - "RewriteRule ^(.*)$ http://to.com [L,R]" + - "", conf); - - assertNotNull(conf.getRules()); - assertEquals(1, conf.getRules().size()); - - NormalRule rule = (NormalRule) conf.getRules().get(0); - assertNotNull(rule); - assertEquals("redirect", rule.getToType()); - assertEquals("^(.*)$", rule.getFrom()); - assertTrue(rule.isLast()); - assertEquals("http://to.com", rule.getTo()); - } - - public void testTemporaryRedirect() { - loader.process("\n" + - " RewriteRule ^/$ http://www.foo.com [R=302] \n" + - "", conf); - - assertNotNull(conf.getRules()); - assertEquals(1, conf.getRules().size()); - - NormalRule rule = (NormalRule) conf.getRules().get(0); - assertNotNull(rule); - assertEquals("temporary-redirect", rule.getToType()); - assertEquals("^/$", rule.getFrom()); - assertEquals("http://www.foo.com", rule.getTo()); - } - - public void testReqUri() { - loader.process("\n" + - " RewriteCond %{REQUEST_URI} ^somepage.* \n" + - " RewriteRule ^/$ /homepage.max.html [L] ", conf); - assertEquals(1, conf.getRules().size()); - assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); - assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("^somepage.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); - assertEquals("^/$", ((NormalRule) conf.getRules().get(0)).getFrom()); - assertEquals("/homepage.max.html", ((NormalRule) conf.getRules().get(0)).getTo()); - assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); - } - - public void testReqFilename() { - loader.process(" RewriteCond %{REQUEST_FILENAME} -f \n" + - " RewriteRule ^/conf-test1.xml$ /homepage.max.html [L] ", conf); - assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("isfile", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); - } - - public void testReqFilename2() { - loader.process(" RewriteCond %{REQUEST_FILENAME} -F \n" + - " RewriteRule ^/conf-test1.xml$ /homepage.max.html [L] ", conf); - assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("isfile", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); - } - - public void testReqIsDir() { - loader.process(" RewriteCond %{REQUEST_FILENAME} -d \n" + - " RewriteRule ^/conf-test1.xml$ /homepage.max.html [L] ", conf); - assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("isdir", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); - } - - public void testReqNotDir() { - loader.process(" RewriteCond %{REQUEST_FILENAME} !-d \n" + - " RewriteRule ^/conf-test1.xml$ /homepage.max.html [L] ", conf); - assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("notdir", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); - } - - public void testReqUriNotEqual() { - loader.process("\n" + - " RewriteCond %{REQUEST_URI} !^/index.html.*$\n" + - " RewriteRule ^/$ /homepage.max.html [L] ", conf); - assertEquals(1, conf.getRules().size()); - assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); - assertEquals("notequal", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); - assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("^/index.html.*$", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); - assertEquals("^/$", ((NormalRule) conf.getRules().get(0)).getFrom()); - assertEquals("/homepage.max.html", ((NormalRule) conf.getRules().get(0)).getTo()); - assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); - } - - - public void testReplaceToVariables() { - loader.process("\n" + - " RewriteCond %{REQUEST_FILENAME} !-f\n" + - " RewriteCond %{REQUEST_FILENAME} !-d\n" + - " RewriteRule ^(.*)$ index.cfm%{REQUEST_URI} [QSA,L]", conf); - assertEquals(1, conf.getRules().size()); - assertEquals(2, ((NormalRule) conf.getRules().get(0)).getConditions().size()); - assertEquals("notfile", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); - assertEquals("notdir", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(1)).getOperator()); - assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("^(.*)$", ((NormalRule) conf.getRules().get(0)).getFrom()); - assertEquals("index.cfm%{request-uri}", ((NormalRule) conf.getRules().get(0)).getTo()); - assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); - } - - public void testReqUriShortcut() { - loader.process("\n" + - " RewriteCond $1 ^somepage.* \n" + - " RewriteRule ^/$ /homepage.max.html [L] ", conf); - assertEquals(1, conf.getRules().size()); - assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); - assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("^somepage.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); - assertEquals("^/$", ((NormalRule) conf.getRules().get(0)).getFrom()); - assertEquals("/homepage.max.html", ((NormalRule) conf.getRules().get(0)).getTo()); - assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); - } - - public void testNoSubstitution() { - loader.process("\n" + - " RewriteCond $1 ^somepage.* \n" + - " RewriteRule ^.*$ - [NC,L] ", conf); - assertEquals(1, conf.getRules().size()); - assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); - assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("^somepage.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); - assertEquals("^.*$", ((NormalRule) conf.getRules().get(0)).getFrom()); - assertEquals("-", ((NormalRule) conf.getRules().get(0)).getTo()); - assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); - } - - public void testTabOnly() { - loader.process("\n" + - " RewriteCond $1 ^somepage.* \n" + - " RewriteRule ^.*$ - [NC,L] ", conf); - assertEquals(1, conf.getRules().size()); - assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); - assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); - assertEquals("^somepage.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); - assertEquals("^.*$", ((NormalRule) conf.getRules().get(0)).getFrom()); - assertEquals("-", ((NormalRule) conf.getRules().get(0)).getTo()); - assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); - } -} +package org.tuckey.web.filters.urlrewrite.utils; + +import junit.framework.TestCase; +import org.tuckey.web.filters.urlrewrite.Condition; +import org.tuckey.web.filters.urlrewrite.Conf; +import org.tuckey.web.filters.urlrewrite.NormalRule; + +import java.io.IOException; +import java.io.InputStream; + +public class ModRewriteConfLoaderTest extends TestCase { + + ModRewriteConfLoader loader = new ModRewriteConfLoader(); + Conf conf; + + public static final String BASE_PATH = "/org/tuckey/web/filters/urlrewrite/utils/"; + + public void setUp() { + Log.setLevel("DEBUG"); + conf = new Conf(); + } + + public void testEngine() { + loader.process("RewriteEngine on", conf); + assertTrue(conf.isEngineEnabled()); + } + + public void testEngine2() { + loader.process("RewriteEngine off", conf); + assertFalse(conf.isEngineEnabled()); + } + + public void testLoadFromFile() throws IOException { + InputStream is = ModRewriteConfLoaderTest.class.getResourceAsStream(BASE_PATH + "htaccess-test1.txt"); + loader.process(is, conf); + assertTrue(conf.isEngineEnabled()); + assertEquals(1, conf.getRules().size()); + } + + public void testLoadFromFile2() throws IOException { + InputStream is = ModRewriteConfLoaderTest.class.getResourceAsStream(BASE_PATH + "htaccess-test1.txt"); + Conf conf = new Conf(null, is, "htaccess-test1.txt", null, true); + assertTrue(conf.isEngineEnabled()); + assertTrue(conf.isOk()); + assertEquals(1, conf.getRules().size()); + } + + public void testSimple2() { + loader.process("\n" + + " # redirect mozilla to another area \n" + + " RewriteCond %{HTTP_USER_AGENT} ^Mozilla.* \n" + + " RewriteRule ^/$ /homepage.max.html [L] ", conf); + assertEquals(1, conf.getRules().size()); + assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); + assertEquals("header", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("user-agent", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getName()); + assertEquals("^Mozilla.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); + assertEquals("redirect mozilla to another area", ((NormalRule) conf.getRules().get(0)).getNote()); + assertEquals("^/$", ((NormalRule) conf.getRules().get(0)).getFrom()); + assertEquals("/homepage.max.html", ((NormalRule) conf.getRules().get(0)).getTo()); + assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); + } + + public void testSimpleRedirect() { + loader.process("\n" + + " RewriteRule ^/$ http://www.foo.com [R] \n" + + "", conf); + + assertNotNull(conf.getRules()); + assertEquals(1, conf.getRules().size()); + + NormalRule rule = (NormalRule) conf.getRules().get(0); + assertNotNull(rule); + assertEquals("redirect", rule.getToType()); + assertEquals("^/$", rule.getFrom()); + assertEquals("http://www.foo.com", rule.getTo()); + } + + public void testPermanentRedirect() { + loader.process("\n" + + " RewriteRule ^/$ http://www.foo.com [R=301] \n" + + "", conf); + + assertNotNull(conf.getRules()); + assertEquals(1, conf.getRules().size()); + + NormalRule rule = (NormalRule) conf.getRules().get(0); + assertNotNull(rule); + assertEquals("permanent-redirect", rule.getToType()); + assertEquals("^/$", rule.getFrom()); + assertEquals("http://www.foo.com", rule.getTo()); + } + + public void testMobile() { + loader.process("\n" + + " # mobile redirect\n" + + "RewriteCond %{HTTP_HOST} from.com\n" + + "RewriteCond %{HTTP:accept} (hdml|wml|xhtml-mp|vnd\\.wap\\.) [OR]\n" + + "RewriteCond %{HTTP:x-wap-profile} .+ [OR]\n" + + "RewriteCond %{HTTP:user-agent} (Windows\\ CE) [OR]\n" + + "RewriteCond %{HTTP:user-agent} (iPhone) [OR]\n" + + "RewriteCond %{HTTP:user-agent} (iPod) [OR]\n" + + "RewriteRule ^(.*)$ http://to.com [L,R]" + + "", conf); + + assertNotNull(conf.getRules()); + assertEquals(1, conf.getRules().size()); + + NormalRule rule = (NormalRule) conf.getRules().get(0); + assertNotNull(rule); + assertEquals("redirect", rule.getToType()); + assertEquals("^(.*)$", rule.getFrom()); + assertTrue(rule.isLast()); + assertEquals("http://to.com", rule.getTo()); + } + + public void testTemporaryRedirect() { + loader.process("\n" + + " RewriteRule ^/$ http://www.foo.com [R=302] \n" + + "", conf); + + assertNotNull(conf.getRules()); + assertEquals(1, conf.getRules().size()); + + NormalRule rule = (NormalRule) conf.getRules().get(0); + assertNotNull(rule); + assertEquals("temporary-redirect", rule.getToType()); + assertEquals("^/$", rule.getFrom()); + assertEquals("http://www.foo.com", rule.getTo()); + } + + public void testReqUri() { + loader.process("\n" + + " RewriteCond %{REQUEST_URI} ^somepage.* \n" + + " RewriteRule ^/$ /homepage.max.html [L] ", conf); + assertEquals(1, conf.getRules().size()); + assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); + assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("^somepage.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); + assertEquals("^/$", ((NormalRule) conf.getRules().get(0)).getFrom()); + assertEquals("/homepage.max.html", ((NormalRule) conf.getRules().get(0)).getTo()); + assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); + } + + public void testReqFilename() { + loader.process(" RewriteCond %{REQUEST_FILENAME} -f \n" + + " RewriteRule ^/conf-test1.xml$ /homepage.max.html [L] ", conf); + assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("isfile", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); + } + + public void testReqFilename2() { + loader.process(" RewriteCond %{REQUEST_FILENAME} -F \n" + + " RewriteRule ^/conf-test1.xml$ /homepage.max.html [L] ", conf); + assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("isfile", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); + } + + public void testReqIsDir() { + loader.process(" RewriteCond %{REQUEST_FILENAME} -d \n" + + " RewriteRule ^/conf-test1.xml$ /homepage.max.html [L] ", conf); + assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("isdir", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); + } + + public void testReqNotDir() { + loader.process(" RewriteCond %{REQUEST_FILENAME} !-d \n" + + " RewriteRule ^/conf-test1.xml$ /homepage.max.html [L] ", conf); + assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("notdir", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); + } + + public void testReqUriNotEqual() { + loader.process("\n" + + " RewriteCond %{REQUEST_URI} !^/index.html.*$\n" + + " RewriteRule ^/$ /homepage.max.html [L] ", conf); + assertEquals(1, conf.getRules().size()); + assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); + assertEquals("notequal", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); + assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("^/index.html.*$", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); + assertEquals("^/$", ((NormalRule) conf.getRules().get(0)).getFrom()); + assertEquals("/homepage.max.html", ((NormalRule) conf.getRules().get(0)).getTo()); + assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); + } + + + public void testReplaceToVariables() { + loader.process("\n" + + " RewriteCond %{REQUEST_FILENAME} !-f\n" + + " RewriteCond %{REQUEST_FILENAME} !-d\n" + + " RewriteRule ^(.*)$ index.cfm%{REQUEST_URI} [QSA,L]", conf); + assertEquals(1, conf.getRules().size()); + assertEquals(2, ((NormalRule) conf.getRules().get(0)).getConditions().size()); + assertEquals("notfile", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getOperator()); + assertEquals("notdir", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(1)).getOperator()); + assertEquals("request-filename", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("^(.*)$", ((NormalRule) conf.getRules().get(0)).getFrom()); + assertEquals("index.cfm%{request-uri}", ((NormalRule) conf.getRules().get(0)).getTo()); + assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); + } + + public void testReqUriShortcut() { + loader.process("\n" + + " RewriteCond $1 ^somepage.* \n" + + " RewriteRule ^/$ /homepage.max.html [L] ", conf); + assertEquals(1, conf.getRules().size()); + assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); + assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("^somepage.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); + assertEquals("^/$", ((NormalRule) conf.getRules().get(0)).getFrom()); + assertEquals("/homepage.max.html", ((NormalRule) conf.getRules().get(0)).getTo()); + assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); + } + + public void testNoSubstitution() { + loader.process("\n" + + " RewriteCond $1 ^somepage.* \n" + + " RewriteRule ^.*$ - [NC,L] ", conf); + assertEquals(1, conf.getRules().size()); + assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); + assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("^somepage.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); + assertEquals("^.*$", ((NormalRule) conf.getRules().get(0)).getFrom()); + assertEquals("-", ((NormalRule) conf.getRules().get(0)).getTo()); + assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); + } + + public void testTabOnly() { + loader.process("\n" + + " RewriteCond $1 ^somepage.* \n" + + " RewriteRule ^.*$ - [NC,L] ", conf); + assertEquals(1, conf.getRules().size()); + assertEquals(1, ((NormalRule) conf.getRules().get(0)).getConditions().size()); + assertEquals("request-uri", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getType()); + assertEquals("^somepage.*", ((Condition) ((NormalRule) conf.getRules().get(0)).getConditions().get(0)).getValue()); + assertEquals("^.*$", ((NormalRule) conf.getRules().get(0)).getFrom()); + assertEquals("-", ((NormalRule) conf.getRules().get(0)).getTo()); + assertEquals(true, ((NormalRule) conf.getRules().get(0)).isLast()); + } +} diff --git a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test-bad-parse.xml b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test-bad-parse.xml index 84b578db..da0e2138 100644 --- a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test-bad-parse.xml +++ b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test-bad-parse.xml @@ -1,13 +1,13 @@ - - - - - - - basicvalue1 - basicfrom1 - basicto1 - - - + + + + + + + basicvalue1 + basicfrom1 + basicto1 + + + diff --git a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test-no-dtd.xml b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test-no-dtd.xml index 5eadabbe..9cef1251 100644 --- a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test-no-dtd.xml +++ b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test-no-dtd.xml @@ -1,13 +1,13 @@ - - - - - - basicvalue1 - basicfrom1 - basicto1 - - - - - + + + + + + basicvalue1 + basicfrom1 + basicto1 + + + + + diff --git a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test1.xml b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test1.xml index 3383b7aa..5b21ac0a 100644 --- a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test1.xml +++ b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test1.xml @@ -1,86 +1,86 @@ - - - - - - - basicvalue1 - basicfrom1 - - basicto1 - - - Mega Rule - - - This rule is designed to take sdfsdfsdf sdcmdklcmjlkcj lsdc - sdcsdckljsklcj lksjck jkls - - - - 9004 - basicfrom2 - basicto2 - - - /some/olddir/(.*) - $1 - val - val:tuckey.org:96:/asdsad - 201 - en-NZ-bro - UTF-8 - application/spagcodebrowserplugin - - - - 80 - (.*) - https:///very/newdir/$1 - - - - - - - - /run-me - - - testName - testValue - - - - - - - - ^/runWithParam/([0-9])+/$ - - - - - ^/lowerMe/([A-Z])+/$ - /lowerMe/${lower:$1} - - - - default encode on to test - a - b - - - - a - b - - - - - - - - - + + + + + + + basicvalue1 + basicfrom1 + + basicto1 + + + Mega Rule + + + This rule is designed to take sdfsdfsdf sdcmdklcmjlkcj lsdc + sdcsdckljsklcj lksjck jkls + + + + 9004 + basicfrom2 + basicto2 + + + /some/olddir/(.*) + $1 + val + val:tuckey.org:96:/asdsad + 201 + en-NZ-bro + UTF-8 + application/spagcodebrowserplugin + + + + 80 + (.*) + https:///very/newdir/$1 + + + + + + + + /run-me + + + testName + testValue + + + + + + + + ^/runWithParam/([0-9])+/$ + + + + + ^/lowerMe/([A-Z])+/$ + /lowerMe/${lower:$1} + + + + default encode on to test + a + b + + + + a + b + + + + + + + + + diff --git a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test2-incl.xml b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test2-incl.xml index 0f32ec0d..04025d70 100644 --- a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test2-incl.xml +++ b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test2-incl.xml @@ -1,5 +1,5 @@ - - Included Rule - included - somewhere + + Included Rule + included + somewhere \ No newline at end of file diff --git a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test2.xml b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test2.xml index bf392dc2..663cda6f 100644 --- a/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test2.xml +++ b/src/test/resources/org/tuckey/web/filters/urlrewrite/conf-test2.xml @@ -1,35 +1,35 @@ - - -]> - - - - - BasicFrom1 - basicvalue1 - basicfrom1 - - basicto1 - - - - BasicRule2 - basicfrom2 - basicto2 - - - - basicfrom3 - basicto3 - - - &included; - - - + + +]> + + + + + BasicFrom1 + basicvalue1 + basicfrom1 + + basicto1 + + + + BasicRule2 + basicfrom2 + basicto2 + + + + basicfrom3 + basicto3 + + + &included; + + + diff --git a/src/test/resources/org/tuckey/web/filters/urlrewrite/utils/htaccess-test1.txt b/src/test/resources/org/tuckey/web/filters/urlrewrite/utils/htaccess-test1.txt index 72fa15bb..2af67b97 100644 --- a/src/test/resources/org/tuckey/web/filters/urlrewrite/utils/htaccess-test1.txt +++ b/src/test/resources/org/tuckey/web/filters/urlrewrite/utils/htaccess-test1.txt @@ -1,8 +1,8 @@ - -RewriteLog "SYSOUT" -RewriteLogLevel 9 - -# redirect mozilla to another area -RewriteCond %{HTTP_USER_AGENT} ^Mozilla.* -RewriteRule ^/$ /homepage.max.html [L] - + +RewriteLog "SYSOUT" +RewriteLogLevel 9 + +# redirect mozilla to another area +RewriteCond %{HTTP_USER_AGENT} ^Mozilla.* +RewriteRule ^/$ /homepage.max.html [L] + diff --git a/src/test/test-web-adhoc/WEB-INF/urlrewrite.xml b/src/test/test-web-adhoc/WEB-INF/urlrewrite.xml index 1fa1d708..4142d3c4 100644 --- a/src/test/test-web-adhoc/WEB-INF/urlrewrite.xml +++ b/src/test/test-web-adhoc/WEB-INF/urlrewrite.xml @@ -1,21 +1,21 @@ - - - - - - - ^/index.jsp\?t=1$ - hello 111 - /index.jsp - - - - ^/to/(.*)$ - proxy3:8080 - http://www.tuckey.org/$1 - - - - + + + + + + + ^/index.jsp\?t=1$ + hello 111 + /index.jsp + + + + ^/to/(.*)$ + proxy3:8080 + http://www.tuckey.org/$1 + + + + diff --git a/src/test/test-web-adhoc/WEB-INF/web.xml b/src/test/test-web-adhoc/WEB-INF/web.xml index 6086e837..411b0688 100644 --- a/src/test/test-web-adhoc/WEB-INF/web.xml +++ b/src/test/test-web-adhoc/WEB-INF/web.xml @@ -1,22 +1,22 @@ - - - - - - - test - test context - - - - UrlRewriteFilter - org.tuckey.web.filters.urlrewrite.UrlRewriteFilter - - - UrlRewriteFilter - /* - - - + + + + + + + test + test context + + + + UrlRewriteFilter + org.tuckey.web.filters.urlrewrite.UrlRewriteFilter + + + UrlRewriteFilter + /* + + + diff --git a/src/test/test-web-adhoc/index.jsp b/src/test/test-web-adhoc/index.jsp index cbef923e..21ca468a 100644 --- a/src/test/test-web-adhoc/index.jsp +++ b/src/test/test-web-adhoc/index.jsp @@ -1,6 +1,6 @@ -

Simple WebApp used for ad-hoc testing.

- -Hello World - - +

Simple WebApp used for ad-hoc testing.

+ +Hello World + + 1 <%= request.getAttribute("test1") %> 2 \ No newline at end of file diff --git a/src/test/webapp/WEB-INF/urlrewrite.xml b/src/test/webapp/WEB-INF/urlrewrite.xml index 603a1fcc..a1d27c89 100644 --- a/src/test/webapp/WEB-INF/urlrewrite.xml +++ b/src/test/webapp/WEB-INF/urlrewrite.xml @@ -1,202 +1,202 @@ - - - - - - - - Test Rule1 - A test rule to show a simple redirect. - /test/status/ - /rewrite-status - - - - Bild redirect test - logo.gif - http://127.0.0.1:8080/urlrewrite/artifact_type.gif - - - - - - Products - Allows users to type product id's into urls. - ID's published in magazine. - - /products/*/*/ - - yes - /products.jsp - - - - /chairs/*/ - true - /products/chairs.jsp - - - - Test Rule disabled - mac - 14 - utf - admin - /test/disabled/ - /rewrite-status - - - - Test Rule with sets - mac - /test/disabled/ - ass - ass - - - - mac - /test-set/([0-9]+) - - num - - - - - - - - - aParam - 10 - - - - - - - - - someParam - 10 - - - someOtherParam - 20 - - - - /test-set.jsp - - - - - /content/([a-zA-Z]+) - $1 - - - - - POST - /pref/([a-zA-Z]+) - - - - - - /test-redirect-301 - /is-this-301 - - - - /test-redirect-302 - is-this-302 - - - - - - /test-redirect-302 - is-this-302 - - - - filenamecheck - - /check-uw-config-exists.txt - file exists!!! - /test-set.jsp - - - - Out test 1 - - /page-not-for-devils(0-9)? - /devils-page - - - - googlebot.* - ^(.*);jsessionid=.*$ - $1 - - - - googlebot* - *;jsessionid=* - $1 - - - - - - - + + + + + + + + Test Rule1 + A test rule to show a simple redirect. + /test/status/ + /rewrite-status + + + + Bild redirect test + logo.gif + http://127.0.0.1:8080/urlrewrite/artifact_type.gif + + + + + + Products + Allows users to type product id's into urls. + ID's published in magazine. + + /products/*/*/ + + yes + /products.jsp + + + + /chairs/*/ + true + /products/chairs.jsp + + + + Test Rule disabled + mac + 14 + utf + admin + /test/disabled/ + /rewrite-status + + + + Test Rule with sets + mac + /test/disabled/ + ass + ass + + + + mac + /test-set/([0-9]+) + + num + + + + + + + + + aParam + 10 + + + + + + + + + someParam + 10 + + + someOtherParam + 20 + + + + /test-set.jsp + + + + + /content/([a-zA-Z]+) + $1 + + + + + POST + /pref/([a-zA-Z]+) + + + + + + /test-redirect-301 + /is-this-301 + + + + /test-redirect-302 + is-this-302 + + + + + + /test-redirect-302 + is-this-302 + + + + filenamecheck + + /check-uw-config-exists.txt + file exists!!! + /test-set.jsp + + + + Out test 1 + + /page-not-for-devils(0-9)? + /devils-page + + + + googlebot.* + ^(.*);jsessionid=.*$ + $1 + + + + googlebot* + *;jsessionid=* + $1 + + + + + + + diff --git a/src/test/webapp/WEB-INF/web.xml b/src/test/webapp/WEB-INF/web.xml index 55f45684..6232fce3 100644 --- a/src/test/webapp/WEB-INF/web.xml +++ b/src/test/webapp/WEB-INF/web.xml @@ -1,48 +1,48 @@ - - - - - - - url rewrite filter build - build context - - - UrlRewriteFilter - org.tuckey.web.filters.urlrewrite.UrlRewriteFilter - - - confReloadCheckInterval - 30 - - - - logLevel - STDOUT:DEBUG - - - - statusEnabled - true - - - - statusPath - /status - - - - UrlRewriteFilter - /* - - - - + + + + + + + url rewrite filter build + build context + + + UrlRewriteFilter + org.tuckey.web.filters.urlrewrite.UrlRewriteFilter + + + confReloadCheckInterval + 30 + + + + logLevel + STDOUT:DEBUG + + + + statusEnabled + true + + + + statusPath + /status + + + + UrlRewriteFilter + /* + + + + diff --git a/src/test/webapp/test-set.jsp b/src/test/webapp/test-set.jsp index 4fc284e7..5e028e95 100644 --- a/src/test/webapp/test-set.jsp +++ b/src/test/webapp/test-set.jsp @@ -1 +1 @@ -request.getAttribute(test1): <%= request.getAttribute("test1") %> +request.getAttribute(test1): <%= request.getAttribute("test1") %> From db09b6947f0e534b0f1fec484a1445182d215137 Mon Sep 17 00:00:00 2001 From: Paul Tuckey Date: Mon, 3 Jul 2023 10:19:36 +1200 Subject: [PATCH 2/2] progress --- .../filters/urlrewrite/json/JsonWriter.java | 22 ++++++++----------- .../tuckey/web/filters/urlrewrite/doc/doc.css | 2 +- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/org/tuckey/web/filters/urlrewrite/json/JsonWriter.java b/src/main/java/org/tuckey/web/filters/urlrewrite/json/JsonWriter.java index 29994039..23620372 100644 --- a/src/main/java/org/tuckey/web/filters/urlrewrite/json/JsonWriter.java +++ b/src/main/java/org/tuckey/web/filters/urlrewrite/json/JsonWriter.java @@ -75,9 +75,7 @@ private void value(Object object) { } private boolean cyclic(Object object) { - Iterator it = calls.iterator(); - while (it.hasNext()) { - Object called = it.next(); + for (Object called : calls) { if (object == called) return true; } return false; @@ -90,19 +88,18 @@ private void bean(Object object) { try { info = Introspector.getBeanInfo(object.getClass()); PropertyDescriptor[] props = info.getPropertyDescriptors(); - for (int i = 0; i < props.length; ++i) { - PropertyDescriptor prop = props[i]; + for (PropertyDescriptor prop : props) { String name = prop.getName(); // ignore stacktraces - if ( object instanceof Throwable && "stackTrace".equals(name) ) continue; + if (object instanceof Throwable && "stackTrace".equals(name)) continue; // ignore class element of JSONRPCErrorBean - if ( object instanceof JsonRpcErrorBean && "class".equals(name) ) continue; + if (object instanceof JsonRpcErrorBean && "class".equals(name)) continue; // for JSONRPCBean ignore result or error depending on weather error present - if ( object instanceof JsonRpcBean) { - if ("class".equals(name) ) continue; + if (object instanceof JsonRpcBean) { + if ("class".equals(name)) continue; JsonRpcBean rpcBean = (JsonRpcBean) object; - if (rpcBean.getError() == null && "error".equals(name) ) continue; - if (rpcBean.getError() != null && "result".equals(name) ) continue; + if (rpcBean.getError() == null && "error".equals(name)) continue; + if (rpcBean.getError() != null && "result".equals(name)) continue; } Method accessor = prop.getReadMethod(); if ((emitClassName || !"class".equals(name)) && accessor != null) { @@ -114,8 +111,7 @@ private void bean(Object object) { } } Field[] ff = object.getClass().getFields(); - for (int i = 0; i < ff.length; ++i) { - Field field = ff[i]; + for (Field field : ff) { if (addedSomething) add(','); add(field.getName(), field.get(object)); addedSomething = true; diff --git a/src/main/resources/org/tuckey/web/filters/urlrewrite/doc/doc.css b/src/main/resources/org/tuckey/web/filters/urlrewrite/doc/doc.css index 4d5043a6..b9fc567f 100644 --- a/src/main/resources/org/tuckey/web/filters/urlrewrite/doc/doc.css +++ b/src/main/resources/org/tuckey/web/filters/urlrewrite/doc/doc.css @@ -37,7 +37,7 @@ a:link, a:visited { color: blue; } -a:active, a:hover, { +a:active, a:hover { color: #f30 !important; }