Yes, it is possible using mod_rewrite and an 'escape' rewrite map. See http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritemap
First, you need to define the rewrite map in your server or virtual host config, like this:
RewriteMap escaped int:escape
This creates a rewrite map named "escaped" that will translate special chars in the string to their hex encodings. You can use it like this ${escaped:text to escape}.
Next, you need to work up an appropriate set of rewrite rules to pass the information to your handler:
RewriteRule .* - [E=HT:http]
RewriteCond %{HTTPS} =on
RewriteRule .* - [E=HT:https]
RewriteRule .* %{ENV:HT}://myhost.com/app2/controller/?TARGET_URL=${escaped:%{ENV:HT}://%{HTTP_HOST}%{REQUEST_URI}?%{QUERY_STRING}}
The first three lines figure out whether you should use 'http' or 'https' in your final rewrite. The last line makes a go at putting the original URL through the escape rewrite map and sending it along to your servlet/handler.
This is a little complicated, since it tries to handle http and https. One problem is that it will always include the ?
char, even if the original request does not have a query string.
The last comment I have would be to suggest that you think about just proxying or using AJP to your servlet controller, which would make all this URL parameter manipulation unnecessary.
Turned out that mod_rewrite was not enabled.
In /etc/httpd/conf/httpd.conf
, uncomment:
#LoadModule rewrite_module modules/mod_rewrite.so
Why did I not find this at first? Because all the url rewriting seemed to work fine, except for the 404 header.
Best Answer
You can do it like the following using mod_rewrite:
The first condition captures the value of
p1
and passes this to the second condition that also captures the value ofp2
. These are then used in the substitution string as%1
and%2
backreferences respectively.The URL parameters can occur in any order.
@
(in the second condition) is just an arbitrary character that does not occur inv1
and so is used as a delimiter betweenv1
and the query string when searching forp2
.All other URL parameters (ie.
p3
..pN
) are ignored (and discarded).Bothp1
andp2
must exist with a non-empty value for the redirect to occur.UPDATE:
p1
must exist with a non-empty value (otherwise the resulting redirect will be ambiguous).p2
must also exist, but the value can be empty. I've also updated the regex so that it would also allow an arguably malformed (but still valid) query string where the URL parameter delimiter (&
) occurs beforep2
at the very start of the query string. eg./my-page?&p2=&p1=v1
would still be redirected to/my-page/v1/
.The
QSD
flag discards the original query string from the request.Depending on where these directives are being used (eg. directory or server context) and how the URL is ultimately being routed, you may need to add an initial condition to ensure that only direct requests (as opposed to rewritten requests) are processed.
For example, add the following as the first condition if required:
UPDATE:
You could change the above as follows:
The 2nd condition now ensures there is a value for the
p2
parameter (ie.v2
) - it cannot be empty.Then either the 3rd condition checks for a non-empty
p3
parameter OR the 4th condition simply captures the values when thep3
parameter is either empty or omitted altogether.The resulting redirect omits the trailing slash when
p3
is not present. For example, the resulting redirect is either/mypage/v1/v2
or/mypage/v1/v2/v3
. (The trailing slash that might otherwise occur on/mypage/v1/v2/
is avoided.)In the final substitution string, the values of the
%1
and%2
backreferences are a little different to before. These no longer contain each value (ie.v1
andv2
). Instead%1
containsv1/v2
and%2
contains either/v3
(including the slash prefix) or is empty (whenp3
is empty or omitted).