The rewrite valve implements URL rewrite functionality in a way that is very similar to mod_rewrite from Apache HTTP Server.

The rewrite valve implements URL rewrite functionality in a way that is very similar to mod_rewrite from Apache HTTP Server.
The rewrite valve is configured as a valve using the org.apache.catalina.valves.rewrite.RewriteValve
class name.
The rewrite valve can be configured as a valve added in a Host.
See virtual-server documentation for
information on how to configure it. It will use a rewrite.config file
containing the rewrite directives, it must be placed in the Host configuration
folder.
It can also be in the context.xml of a webapp.
The valve will then use a rewrite.config file containing the
rewrite directives, it must be placed in the WEB-INF folder of the web application
The URL presented to the rewrite valve is the same URL used for request
mapping with any literal '%', ';' and/or
'?' characters encoded in %nn form.
A rewrite rule that wishes to insert a literal '%',
';', '?', '&' or '='
character should do so in %nn form. Other characters maybe
inserted in either literal or %nn form.
This enables the rewrite rules to:
'?' characters;'%' character without it being confused with
%nn encoding.The rewrite.config file contains a list of directives which closely
resemble the directives used by mod_rewrite, in particular the central
RewriteRule and RewriteCond directives. Lines that start with a
# character are treated as comments and will be ignored.
Note: This section is a modified version of the mod_rewrite documentation, which is Copyright 1995-2006 The Apache Software Foundation, and licensed under the under the Apache License, Version 2.0.
Syntax: RewriteCond TestString CondPattern
The RewriteCond directive defines a rule condition. One or more RewriteCond can precede a RewriteRule directive. The following rule is then only used if both the current state of the URI matches its pattern, and if these conditions are met.
TestString is a string which can contain the following expanded constructs in addition to plain text:
$N
(0 <= N <= 9), which provide access to the grouped
parts (in parentheses) of the pattern, from the
RewriteRule which is subject to the current
set of RewriteCond conditions..
%N
(1 <= N <= 9), which provide access to the grouped
parts (again, in parentheses) of the pattern, from the last matched
RewriteCond in the current set
of conditions.
${mapname:key|default}.
See the documentation for
RewriteMap for more details.
%{ NAME_OF_VARIABLE
}
where NAME_OF_VARIABLE can be a string taken
from the following list:
HTTP headers:
HTTP_USER_AGENT
HTTP_REFERER
HTTP_COOKIE
HTTP_FORWARDED
HTTP_HOST
HTTP_PROXY_CONNECTION
HTTP_ACCEPT
connection & request:
REMOTE_ADDR
REMOTE_HOST
REMOTE_PORT
REMOTE_USER
REMOTE_IDENT
REQUEST_METHOD
SCRIPT_FILENAME
REQUEST_PATH
CONTEXT_PATH
SERVLET_PATH
PATH_INFO
QUERY_STRING
AUTH_TYPE
server internals:
DOCUMENT_ROOT
SERVER_NAME
SERVER_ADDR
SERVER_PORT
SERVER_PROTOCOL
SERVER_SOFTWARE
date and time:
TIME_YEAR
TIME_MON
TIME_DAY
TIME_HOUR
TIME_MIN
TIME_SEC
TIME_WDAY
TIME
specials:
THE_REQUEST
REQUEST_URI
REQUEST_FILENAME
HTTPS
These variables all correspond to the similarly named HTTP MIME-headers and Servlet API methods. Most are documented elsewhere in the Manual or in the CGI specification. Those that are special to the rewrite valve include those below.
REQUEST_PATHCONTEXT_PATHSERVLET_PATHTHE_REQUESTGET
/index.html HTTP/1.1"). This does not
include any additional headers sent by the
browser.REQUEST_URIREQUEST_FILENAMEHTTPSOther things you should be aware of:
filename field of the internal
request_rec structure of the Apache server.
The first name is the commonly known CGI variable name
while the second is the appropriate counterpart of
REQUEST_URI (which contains the value of the
uri field of request_rec).%{ENV:variable}, where variable can be
any Java system property, is also available.%{SSL:variable}, where variable is the
name of an SSL environment
variable, are implemented, except
SSL_SESSION_RESUMED, SSL_SECURE_RENEG,
SSL_COMPRESS_METHOD, SSL_TLS_SNI,
SSL_SRP_USER, SSL_SRP_USERINFO,
SSL_CLIENT_VERIFY,
SSL_CLIENT_SAN_OTHER_msUPN_n,
SSL_CLIENT_CERT_RFC4523_CEA,
SSL_SERVER_SAN_OTHER_dnsSRV_n.
When OpenSSL is used, the variables related to the server
certificate, prefixed by SSL_SERVER_ are not available.
Example:
%{SSL:SSL_CIPHER_USEKEYSIZE} may expand to
128.%{HTTP:header}, where header can be
any HTTP MIME-header name, can always be used to obtain the
value of a header sent in the HTTP request.
Example: %{HTTP:Proxy-Connection} is
the value of the HTTP header
'Proxy-Connection:'.CondPattern is the condition pattern, a regular expression which is applied to the current instance of the TestString. TestString is first evaluated, before being matched against CondPattern.
Remember: CondPattern is a perl compatible regular expression with some additions:
!' character (exclamation mark) to specify a
non-matching pattern."" (two quotation marks) this
compares TestString to the empty string.[flags]
as the third argument to the RewriteCond
directive, where flags is a comma-separated list of any of the
following flags:
nocase|NC'
(no case)ornext|OR'
(or next condition)RewriteCond %{REMOTE_HOST} ^host1.* [OR]
RewriteCond %{REMOTE_HOST} ^host2.* [OR]
RewriteCond %{REMOTE_HOST} ^host3.*
RewriteRule ...some special stuff for any of these hosts...Example:
To rewrite the Homepage of a site according to the
'User-Agent:' header of the request, you can
use the following:
RewriteCond %{HTTP_USER_AGENT} ^Mozilla.*
RewriteRule ^/$ /homepage.max.html [L]
RewriteCond %{HTTP_USER_AGENT} ^Lynx.*
RewriteRule ^/$ /homepage.min.html [L]
RewriteRule ^/$ /homepage.std.html [L]Explanation: If you use a browser which identifies itself as 'Mozilla' (including Netscape Navigator, Mozilla etc), then you get the max homepage (which could include frames, or other special features). If you use the Lynx browser (which is terminal-based), then you get the min homepage (which could be a version designed for easy, text-only browsing). If neither of these conditions apply (you use any other browser, or your browser identifies itself as something non-standard), you get the std (standard) homepage.
Syntax: RewriteMap name rewriteMapClassName optionalParameters
The rewriteMapClassName value also allows special values:
int:toupper: Special map converting passed values to upper caseint:tolower: Special map converting passed values to lower caseint:escape: URL escape the passed valueint:unescape: URL unescape the passed valueThe maps are implemented using an interface that users must implement. Its class
name is org.apache.catalina.valves.rewrite.RewriteMap, and its code is:
package org.apache.catalina.valves.rewrite;
public interface RewriteMap {
default String setParameters(String params...); // calls setParameters(String) with the first parameter if there is only one
public String setParameters(String params);
public String lookup(String key);
}The referenced implementation of such a class – in our example rewriteMapClassName –
will be instantiated and initialized with the optional parameter – optionalParameters from above
(be careful with whitespace) – by calling setParameters(String). That instance
will then be registered under the name given as the first parameter of RewriteMap rule.
Note: Starting with Tomcat 9 you can use more than one parameter. These have to be separated by spaces. Parameters can be quoted with ". This enables space characters inside parameters.
That map instance will be given the lookup value that is configured in the corresponding RewriteRule by
calling lookup(String). Your implementation is free to return null to indicate,
that the given default should be used, or to return a replacement value.
Say, you want to implement a rewrite map function that converts all lookup keys to uppercase. You
would start by implementing a class that implements the RewriteMap interface.
package example.maps;
import org.apache.catalina.valves.rewrite.RewriteMap;
public class UpperCaseMap implements RewriteMap {
@Override
public String setParameters(String params) {
// nothing to be done here
return null;
}
@Override
public String lookup(String key) {
if (key == null) {
return null;
}
return key.toUpperCase(Locale.ENGLISH);
}
}Compile this class, put it into a jar and place that jar in ${CATALINA_BASE}/lib.
Having done that, you can now define a map with the RewriteMap directive
and further on use that map in a RewriteRule.
RewriteMap uc example.maps.UpperCaseMap
RewriteRule ^/(.*)$ ${uc:$1}
With this setup a request to the url path /index.html would get routed
to /INDEX.HTML.
Syntax: RewriteRule Pattern Substitution
The RewriteRule directive is the real rewriting workhorse. The directive can occur more than once, with each instance defining a single rewrite rule. The order in which these rules are defined is important - this is the order in which they will be applied at run-time.
Pattern is a perl compatible regular expression, which is applied to the current URL. 'Current' means the value of the URL when this rule is applied. This may not be the originally requested URL, which may already have matched a previous rule, and have been altered.
Security warning: Due to the way Java's regex matching is done, poorly formed regex patterns are vulnerable to "catastrophic backtracking", also known as "regular expression denial of service" or ReDoS. Therefore, extra caution should be used for RewriteRule patterns. In general it is difficult to automatically detect such vulnerable regex, and so a good defense is to read a bit on the subject of catastrophic backtracking. A good reference is the OWASP ReDoS guide.
Some hints on the syntax of regular expressions:
Text:.Any single character[chars]Character class: Any character of the class 'chars'[^chars]Character class: Not a character of the class 'chars' text1|text2 Alternative: text1 or text2 Quantifiers:?0 or 1 occurrences of the preceding text*0 or N occurrences of the preceding text (N > 0)+1 or N occurrences of the preceding text (N > 1) Grouping:(text)Grouping of text (used either to set the borders of an alternative as above, or to make backreferences, where the Nth group can be referred to on the RHS of a RewriteRule as$N) Anchors:^Start-of-line anchor$End-of-line anchor Escaping:\char escape the given char (for instance, to specify the chars ".[]()" etc.)
For more information about regular expressions, have a look at the perl regular expression manpage ("perldoc perlre"). If you are interested in more detailed information about regular expressions and their variants (POSIX regex etc.) the following book is dedicated to this topic:
Mastering Regular Expressions, 2nd Edition
Jeffrey E.F. Friedl
O'Reilly & Associates, Inc. 2002
ISBN 978-0-596-00289-3
In the rules, the NOT character
('!') is also available as a possible pattern
prefix. This enables you to negate a pattern; to say, for instance:
'if the current URL does NOT match this
pattern'. This can be used for exceptional cases, where
it is easier to match the negative pattern, or as a last
default rule.
Note: When using the NOT character to negate a pattern, you cannot include
grouped wildcard parts in that pattern. This is because, when the
pattern does NOT match (i.e., the negation matches), there are no
contents for the groups. Thus, if negated patterns are used, you
cannot use $N in the substitution string!
The substitution of a rewrite rule is the string which is substituted for (or replaces) the original URL which Pattern matched. In addition to plain text, it can include
$N) to the RewriteRule
pattern%N) to the last matched
RewriteCond pattern%{VARNAME})${mapname:key|default})Back-references are identifiers of the form
$N
(N=0..9), which will be replaced
by the contents of the Nth group of the
matched Pattern. The server-variables are the same
as for the TestString of a RewriteCond
directive. The mapping-functions come from the
RewriteMap directive and are explained there.
These three types of variables are expanded in the order above.
As already mentioned, all rewrite rules are
applied to the Substitution (in the order in which
they are defined
in the config file). The URL is completely
replaced by the Substitution and the
rewriting process continues until all rules have been applied,
or it is explicitly terminated by a
L flag.
The special characters $ and % can
be quoted by prepending them with a backslash character
\.
There is a special substitution string named
'-' which means: NO
substitution! This is useful in providing
rewriting rules which only match
URLs but do not substitute anything for them. It is commonly used
in conjunction with the C (chain) flag, in order
to apply more than one pattern before substitution occurs.
Unlike newer mod_rewrite versions, the Tomcat rewrite valve does not automatically support absolute URLs (the specific redirect flag must be used to be able to specify an absolute URLs, see below) or direct file serving.
Additionally you can set special flags for Substitution by
appending [flags]
as the third argument to the RewriteRule
directive. Flags is a comma-separated list of any of the
following flags:
chain|C'
(chained with next rule).www' part, inside a per-directory rule set,
when you let an external redirect happen (where the
'.www' part should not occur!).cookie|CO=NAME:VAL:domain[:lifetime[:path]]'
(set cookie)env|E=VAR:VAL'
(set environment variable)$N and
%N) which will be expanded. You can use this
flag more than once, to set more than one variable.forbidden|F' (force URL
to be forbidden)gone|G' (force URL to be
gone)host|H=Host'
(apply rewriting to host)last|L'
(last rule)last command or the break command
in C. Use this flag to prevent the currently
rewritten URL from being rewritten further by following
rules. For example, use it to rewrite the root-path URL
('/') to a real one, e.g.,
'/e/www/'.next|N'
(next round)next command or
the continue command in C. Use
this flag to restart the rewriting process -
to immediately go to the top of the loop.nocase|NC'
(no case)noescape|NE'
(no URI escaping of
output)RewriteRule /foo/(.*) /bar?arg=P1\%3d$1 [R,NE]/foo/zed' into a safe
request for '/bar?arg=P1=zed'.
qsappend|QSA'
(query string
append)redirect|R
[=code]' (force
redirect)http://thishost[:thisport]/ (which makes the
new URL a URI) to force an external redirection. If no
code is given, an HTTP response of 302 (FOUND, previously MOVED
TEMPORARILY) will be returned. If you want to use other response
codes in the range 300-399, simply specify the appropriate number
or use one of the following symbolic names:
temp (default), permanent,
seeother. Use this for rules to
canonicalize the URL and return it to the client - to
translate '/~' into
'/u/', or to always append a slash to
/u/user, etc.http://thishost[:thisport]/ to the URL, and rewriting
will continue. Usually, you will want to stop rewriting at this point,
and redirect immediately. To stop rewriting, you should add
the 'L' flag.
skip|S=num'
(skip next rule(s))skip=N, where N is the number of rules in the
else-clause. (This is not the same as the
'chain|C' flag!)type|T=MIME-type'
(force MIME type).php files to
be displayed by mod_php if they are called with
the .phps extension:
RewriteRule ^(.+\.php)s$ $1 [T=application/x-httpd-php-source]valveSkip|VS'
(skip valve)