Friday, August 19, 2011

Tomcat Redirect Valve

Apache Tomcat

⇓ Probably the most important part – "All we need is already here"

added on 2011-11-27

⇓ Another important news – ... now implemented as Tomcat 8 component

added on 2013-03-17

⇓ And the final news – ... now available as standard Tomcat feature

added on 2014-11-16



Background


Every mature web resource eventually realizes that it needs URL redirection.

Leaving aside manual and client-side redirection techniques, and concentrating on server-side redirection, one can see that in the Apache HTTP Server world mod_rewrite is the canonical and powerful tool to do the job.

In the Java world there is also a recognized leader for this task. That is UrlRewriteFilter, also hosted at Google Code. BTW, the front page of that project contains a good list of reasons for one to be interested in URL rewriting (redirection).

There is nothing wrong about UrlRewriteFilter. It is feature rich, and mature, and well supported, and actively developed. Nothing wrong except it is a Filter .

On one hand, being a Filter is not bad. In any case Filter is a standard concept defined by the Servlet specification, so portability across different web application containers may be considered as guaranteed.

On the other hand, having URL rewriting as part of a web application may be not always sufficient. It is not uncommon for a servlet container to host more than one web application, and thus separation of responsibilities may become a concern. Web application belongs to the developer's responsibility domain. Meanwhile the container belongs to the administrator's responsibility domain. And an administrator may have his own ideas on the requirements for redirection. So an administrator may need a separate facility for setting up server-side redirects securely, without risk of being blamed for ruining the developer's masterpiece... And speaking seriously, an administrator may occasionally wish to establish server-wide redirection policies that would be common for all the applications being hosted.

Unfortunately there is no common standard for Java web application containers that we could base upon for this task. Every container seems to have its own specifics. Narrowing our needs to Tomcat as one of the widely used containers we may come to an idea that a Valve may be the right tool. BTW, there is an noteworthy consideration of Valves vs Filters in Nicolas Fränkel's blog.

The idea of a Redirect Valve for Tomcat has been in the air for quite a while already. Curious to note, it was even on the Tomcat 4 TODO list. And deep googling for a "RedirectValve" reveals several in-house implementations of such a Valve being mentioned across various exception logs here and there. Meanwhile it looks like nobody cared to make such a tool publicly available so far...

Implementation


The first draft implementation of a Redirect Valve was suggested in 2002 by Jens Andersen. Unfortunately the implementation was incomplete and thus was not adopted for inclusion into the Tomcat project.

Bringing the existing draft to working state was not a hard job. So the final result:
  • allows configuration of a Valve instance in terms of Java regular expressions and substitutions using capturing groups;
  • for every incoming HTTP request:
    • makes an effort to reconstruct the original request URL from sparse pieces available at the valve level;
    • saves the URL as a request attribute to be used by subsequent RedirectValve instances that may follow in the pipeline;
    • matches the URL against a pre-configured regular expression;
    • in case the match succeeds, sets the response status code as SC_MOVED_PERMANENTLY, sets the response "Location" header as prescribed by a pre-configured expression using capturing groups and gets the request out of the processing pipeline;
Well, nothing fancy at all, but looks like doing the job for standard cases...

This RedirectValve implementation was submitted to the Tomcat project again. The result was the same as for the submission of 2002, the reasons now being that in the times of UrlRewriteFilter there is no need for other tools, and those willing to have a redirection Valve are free to wrap UrlRewriteFilter into a Valve by themselves...

Admitting this may be true, I still dare to offer this Valve to the public. Please feel free to use and modify. The license is Apache 2.0. Both the source and a compiled .jar are available. Still, as the code is not likely to become a part of the Tomcat project, the package name prefix is changed from org.apache to usn.apache .

Usage – HOW-TO


  1. Download the .jar file .
  2. Copy it to the lib folder of your Tomcat installation or to any other appropriate location of your choice. You may also wish to have a look at Tomcat classloader overview at MuleSoft.
  3. Register RedirectValve as a Valve with your Tomcat by adding an appropriate section to the contents of relevant <Host> element in your conf/server.xml file. Say, a task of redirecting/mapping a Tomcat web application to a virtual directory at your front-end server on the same machine might be configured like this:
    <Valve
        className="usn.apache.catalina.valves.RedirectValve"
        from="^http://([^:]+):8080/my-web-app/(.*)$"
        to="http://{1}/my-virtual-dir-at-the-front-end-server/{2}"
        />
    
    Feel free to add as many RedirectValve elements in a series as you wish.
  4. Restart Tomcat.
  5. Enjoy .



"All we need is already here"

added on 2011-08-24

Being curious about when Google gets my blog indexed and listed , I have occasionally found somewhere in the third dozen of search result pages that a "Redirect Valve" for Tomcat already exists as RewriteValve, a component of JBoss Web Server. Looks like the code does not have any dependencies on JBoss internals, and the license is LGPLv2.1 or later. The functionality looks really rich and closely resembles mod_rewrite.

I wish I knew it before starting off with my simplistic implementation... Well, one more great tool to enjoy!



... now implemented as Tomcat 8 component

added on 2013-03-17

It recently appeared that a new rewrite valve implementation is being developed as a component of Tomcat 8. The docs say that the capabilities and configuration facilities resemble Apache HTTP Server mode_rewrite closely. This is good news for all of us IMHO...



... now available as standard Tomcat feature

added on 2014-11-16

The latest and probably the final news on this topic is that as of June 2014 Tomcat 8 has reached release status, with rewrite valve as a standard component. Nothing more left to be desired...

2 comments:

  1. Hi.
    I setup the redirect as below:
    ========
    Valve
    className="usn.apache.catalina.valves.RedirectValve"
    from="^http://([^:]+):8181/ACS"
    to="http://corp1280:9080/ACS/servlet/ACS"
    ==========
    When I call "http://localhost:8181/ACS", the redirect address
    is "http//corp1280:9080/ACS/servlet/ACS" without ":" of "http://"

    Do you know why ?

    ReplyDelete
    Replies
    1. Hi João Clemente, and the problem you describe is really amazing :)
      Do you feel like modifying the source and recompiling the module, so to add a couple of debug log statements and see what's happening?
      If yes, I'll make suggestions on the statements to add.
      If not, I'll do that myself, but that may require a bit more time... :)
      So you are welcome to share your ideas on the approach for us to follow...
      And the first thing I would suggest for debugging is logging 'sTarget' and 'sTargetTemplate' after the statement
      String sTarget = MessageFormat.format (sTargetTemplate, asGroups);

      Delete