<document>
<header>
<title>URL Rewriting and Dispatching</title>
<description>

<p>Resin comes with powerful and extensible rewrite capabilities that is as
powerful as Apache's mod_rewrite.</p>

</description>
</header>
<body>

<localtoc/>


<s1 title="Dispatch Rules">

<p>Resin's dispatching is based on a list of <a
javadoc="com.caucho.rewrite.DispatchRule">dispatch rules</a>
configured in the resin-web.xml or the resin.xml configuration
files.  Each rule has a regular expression matching request URLs.
The first dispatch rule that matches takes control of the request.
For example, a <a config-tag="resin:Redirect"/> sends a HTTP
redirect, and a <a config-tag="resin:Dispatch"/> dispatches
the request as normal.</p> 

<p>Each matching rule can rewrite the URL using a <em>target</em> attribute that
accepts Java regular expressions.  The following rule flips the first two
segments around, so <code>/foo/bar</code> would become <code>/bar/foo</code>.</p>

<example title="Example: redirect flipping">
&lt;web-app xmlns="http://caucho.com/ns/resin"
            xmlns:resin="urn:java:com.caucho.resin">

  &lt;resin:Redirect regexp="^/([^/]+)/([^/]+)" target="/$2/$1"/>
	    
&lt;/web-app>
</example>

</s1>

<s1 title="Conditions">

<p>Dispatching can be more complicated than just on a regular expression
matching of the URL.  It may depend on request attributes.  In the example below,
Resin will send a 403 Forbidden response if the URL path starts with <em>/secret</em>
AND the child condition evaluates to true.  In this case, the condition
<a config-tag="resin:IfSecure"/>
succeeds if the request is not an SSL request.
</p>

<example title="Example: dispatch on header">
&lt;web-app xmlns="http://caucho.com/ns/resin"
            xmlns:resin="urn:java:com.caucho.resin">

  &lt;resin:Forbidden regexp="^/secret">
    &lt;resin:IfSecure value="false"/>
  &lt;/resin:Forbidden>
	    
&lt;/web-app>
</example>

<s2 title="Basic Conditions">

<p>Basic conditions check the request and return true if the condition
matches.  Conditions can check on authentication
(<a config-tag="resin:IfUserInRole"/>), the remote IP
(<a config-tag="resin:IfNetwork"/>), check for SSL
(<a config-tag="resin:IfSecure"/>), and check for activation time
(<a config-tag="resin:IfCron"/>) or if a file exists
(<a config-tag="resin:IfFileExists"/>).</p>

<p>The rewrite conditions can also be used as security conditions, e.g. for
<a config-tag="resin:Allow"/> or
<a config-tag="resin:Deny"/>.</p>

</s2>

<s2 title="Combining Conditions">

<p>An action tag can have zero condition tags or at most one.  If you want
combine multiple conditions, then you'll need to use composite conditions like
<a config-tag="resin:And"/>,
<a config-tag="resin:Or"/>,
<a config-tag="resin:Not"/>,
<a config-tag="resin:NotAnd"/>, and
<a config-tag="resin:NotOr"/>.</p>

<example title="Example: send 403 Forbidden if port is 80 and user is not admin">
&lt;web-app xmlns="http://caucho.com/ns/resin"
            xmlns:resin="urn:java:com.caucho.resin">

  &lt;resin:Forbidden regexp="^/secret">
    &lt;resin:And>
      &lt;resin:IfLocalPort value="80"/>
      &lt;resin:Not>
        &lt;resin:IfUserInRole role="admin"/>
      &lt;/resin:Not>
    &lt;/resin:And>
  &lt;/resin:Forbidden>
	    
&lt;/web-app>
</example>


</s2>

</s1>

<s1 title="Filter Actions">

<p>The rewrite capability can also add standard predefined filters
to modify the output, e.g. setting a response header.  Filters can
use conditions as restrictions, just like the dispatch rules.</p>

<example title="Example: set header Foo: bar">
&lt;web-app xmlns="http://caucho.com/ns/resin"
            xmlns:resin="urn:java:com.caucho.resin">

  &lt;resin:SetHeader regexp="^/secret" name="Foo" value="bar"/>
	    
&lt;/web-app>
</example>

<s2 title="Servlet Filters">

<p>Standard servlet filters can also be invoked as an action to the dispatch
target.  Your filter is created using Java Injection syntax and will
be applied if the dispatch rule matches.</p>

<example title="Example: dispatching with a custom filter">
&lt;web-app xmlns="http://caucho.com/ns/resin"
            xmlns:resin="urn:java:com.caucho.resin">

  &lt;resin:Dispatch regexp="^/test">
    &lt;mypkg:MyFilter xmlns:my="urn:java:com.foo.mypkg">
      &lt;mypkg:my-param>my-value&lt;/mypkg:my-param>
    &lt;/mypkg:MyFilter>
  &lt;/resin:Dispatch>
	    
&lt;/web-app>
</example>

</s2>
</s1>

<s1 title="Logging and Debugging">
<p>
Logging for the name <code>com.caucho.server.rewrite</code>
at the <em>finer</em> level reveals successful matches.  At the <em>finest</em> level both
successful and unsuccessful matches are logged.
</p>

<example title="Example: Logging example">
&lt;logger name="com.caucho.server.rewrite" level="finest"/&gt;
</example>

<results>
[1998/05/08 02:51:31.000] forward ^/foo: '/baz/test.jsp'  no match
[1998/05/08 02:51:31.000] forward ^/bar: '/baz/test.jsp'  no match
[1998/05/08 02:51:31.000] forward ^/baz: '/baz/test.jsp'  -->  '/hogwarts/test.jsp'
</results>

</s1>

<s1 title="Examples">
<s2 title="Redirect HTTP requests to HTTPS requests">
<p>The desired behaviour is to redirect plain connections to SSL connections.</p>

<example title="Desired behaviour">
  http://anything.com/anything.html
    redirect => https://anything.com/anything.html
</example>

<example title="Example: resin.xml configuration">
&lt;resin xmlns="http://caucho.com/ns/resin"
    xmlns:resin="urn:java:com.caucho.resin">
    
  &lt;cluster ...&gt;
  &lt;host ...&gt;
    ...
    &lt;resin:Redirect regexp="^" target="https://${host.name}"&gt;
      &lt;resin:IfSecure value="false"/>
    &lt;/resin:Redirect>
    ...
  &lt;/host&gt;
&lt;/resin&gt;
</example>
</s2>

<s2 title="Make an alias for a web-app">
  <p>
  The desired behaviour is to make it so that a web-app will match more than
  one url pattern.  For example, a web-app is deployed in
  <code>webapps/physics</code> and available at
  <code>http://hostname/physics/</code>, the desired behaviour is to allow a
  request to <code>http://hostname/classroom/physics</code> to end up at the
  <code>/physics</code> web-app.

  </p>

  <example title="Desired behaviour">
    http://hostname/classroom/physics
      forward => http://hostname/physics 

    http://hostname/classroom/physics/anything
      forward => http://hostname/physics/anything
  </example>

  <p>
  The rewrite-dispatch tag is used at the <code>&lt;host&gt;</code> level.  If it was placed in a 
  <code>&lt;web-app&gt;</code> then it would be too late to forward to a different web-app
  because Resin would have already resolved the web-app.
  </p>

  <example title="Example: resin.xml configuration">
&lt;resin xmlns="http://caucho.com/ns/resin"
  xmlns:resin="urn:java:com.caucho.resin">

&lt;cluster id=""&gt;
&lt;host id=""&gt;

  &lt;resin:Forward regexp="^/classroom/physics" target="/physics"/&gt;

</example>
</s2>

<s2 title="Forward based on host name">
  <p>
  The desired behaviour is to forward requests internally based on the host name.
  </p>

  <example title="Desired behaviour">
    http://gryffindor.hogwarts.com/anything.html
      forward => /gryffindor/*

    http://slytherin.hogwarts.com/anything.html
      forward => /slytherin/anything.html

    http://hogwarts.com/anything.html
      forward => /anything.html
  </example>

  <p>
  The rewrite-dispatch tag is used at the <code>&lt;cluster&gt;</code> level.
  If it was placed in the <code>&lt;host&gt;</code> or the
  <code>&lt;web-app&gt;</code> then it would be too late to forward to a
  different host because Resin would have already resolved the host.
  </p>

<example title="Example: resin.xml Configuration">
&lt;resin xmlns="http://caucho.com/ns/resin"
    xmlns:resin="urn:java:com.caucho.resin">
    
  &lt;cluster&gt;
      ...
    &lt;resin:Forward regexp="http://gryffindor\.[^/]+" target="/gryffindor/"/&gt;
    &lt;resin:Forward regexp="http://slytherin\.[^/]+" target="/slytherin/"/&gt;
   ...
&lt;/cluster&gt;
&lt;/resin&gt;
  </example>
</s2>

<s2 title="Proxy requests to PHP/Ruby using FastCGI">

<example>
&lt;web-app xmlns="http://caucho.com/ns/resin"
         xmlns:resin="urn:java:com.caucho.resin"&gt;

   &lt;resin:FastCgiProxy regexp="\.php$"&gt;
     &lt;address>127.0.0.1:12345&lt;/address&gt;
   &lt;/resin:FastCgiProxy&gt;
   
   &lt;resin:FastCgiProxy regexp="\.rb$"&gt;
     &lt;address>127.0.0.1:67890&lt;/address&gt;
   &lt;/resin:FastCgiProxy&gt;

&lt;/web-app&gt;

</example>

</s2>


</s1>

<s1 title="Tag listing by function">

<deftable title="Dispatch rules">
<tr>
  <th>name</th>
  <th>description</th>
</tr>
<tr>
  <td><a config-tag="resin:Dispatch"/></td>
  <td>Normal servlet dispatching with optional <em>target</em> rewriting.</td>
</tr>
<tr>
  <td><a config-tag="resin:FastCgiProxy"/></td>
  <td>Proxies the request to a backend server using FastCGI as a proxy protocol.</td>
</tr>
<tr>
  <td><a config-tag="resin:Forbidden"/></td>
  <td>Send a HTTP forbidden response.</td>
</tr>
<tr>
  <td><a config-tag="resin:Forward"/></td>
  <td>Forwards to the new URL using RequestDispatcher.forward with the <em>target</em> URL.</td>
</tr>
<tr>
  <td><a config-tag="resin:HttpProxy"/></td>
  <td>Proxies the request to a backend server using HTTP as a proxy protocol.</td>
</tr>
<tr>
  <td><a config-tag="resin:LoadBalance"/></td>
  <td>Load balance to a cluster of backend Resin servers.</td>
</tr>
<tr>
  <td><a config-tag="resin:MovedPermanently"/></td>
  <td>Send a HTTP redirect to a new URL specified by <em>target</em>.</td>
</tr>
<tr>
  <td><a config-tag="resin:Redirect"/></td>
  <td>Send a HTTP redirect to a new URL specified by <em>target</em>.</td>
</tr>
<tr>
  <td><a config-tag="resin:SendError"/></td>
  <td>Send a HTTP error response.</td>
</tr>
<tr>
  <td><a javadoc="com.caucho.rewrite.AbstractTargetDispatchRule">AbstractTargetDispatchRule</a></td>
  <td>Base class for custom dispatch rules.</td>
</tr>
</deftable>

<deftable title="Basic conditions">
<tr>
  <th>name</th>
  <th>description</th>
</tr>
<tr>
  <td><a config-tag="resin:IfAuthType"/></td>
  <td>Checks for the authentication type, request.getAuthType().</td>
</tr>
<tr>
  <td><a config-tag="resin:IfCookie"/></td>
  <td>Checks for the presence of a named HTTP cookie from request.getCookies().</td>
</tr>
<tr>
  <td><a config-tag="resin:IfCron"/></td>
  <td>Matches if the current time is in an active range configured by cron-style times.</td>
</tr>
<tr>
  <td><a config-tag="resin:IfFileExists"/></td>
  <td>Matches if the URL corresponds to an actual file.</td>
</tr>
<tr>
  <td><a config-tag="resin:IfHeader"/></td>
  <td>Tests for a HTTP header and value match.</td>
</tr>
<tr>
  <td><a config-tag="resin:IfLocale"/></td>
  <td>Tests for a Locale match from the HTTP request.</td>
</tr>
<tr>
  <td><a config-tag="resin:IfLocalPort"/></td>
  <td>Compares the local port of the request, request.getLocalPort().</td>
</tr>
<tr>
  <td><a config-tag="resin:IfMethod"/></td>
  <td>Compares the HTTP method, request.getMethod().</td>
</tr>
<tr>
  <td><a config-tag="resin:IfNetwork"/></td>
  <td>Compares the remote IP address to a network pattern like 192.168/16.</td>
</tr>
<tr>
  <td><a config-tag="resin:IfQueryParam"/></td>
  <td>Tests for a HTTP query parameger, request.getParameter().</td>
</tr>
<tr>
  <td><a config-tag="resin:IfRemoteUser"/></td>
  <td>Tests against the remote user, request.getRemoteUser().</td>
</tr>
<tr>
  <td><a config-tag="resin:IfSecure"/></td>
  <td>True for SSL requests, i.e. if request.isSecure() is true.</td>
</tr>
<tr>
  <td><a config-tag="resin:IfUserInRole"/></td>
  <td>Tests is the user is in the servlet security role.</td>
</tr>
<tr>
  <td><a javadoc="com.caucho.rewrite.RequestPredicate">RequestPredicate</a></td>
  <td>Interface for custom request predicates.</td>
</tr>
</deftable>

<deftable title="Combining conditions">
<tr>
  <th>name</th>
  <th>description</th>
</tr>
<tr>
  <td><a config-tag="resin:And"/></td>
  <td>Matches if all children match.</td>
</tr>
<tr>
  <td><a config-tag="resin:Or"/></td>
  <td>Matches if any children match.</td>
</tr>
<tr>
  <td><a config-tag="resin:Not"/></td>
  <td>Matches if the child does not match.</td>
</tr>
<tr>
  <td><a config-tag="resin:NotAnd"/></td>
  <td>Matches if any child does not match.</td>
</tr>
<tr>
  <td><a config-tag="resin:NotOr"/></td>
  <td>Matches if all the children do not match.</td>
</tr>
</deftable>

<deftable title="Rewrite filters">
<tr>
  <th>name</th>
  <th>description</th>
</tr>
<tr>
  <td><a config-tag="resin:SetHeader"/></td>
  <td>Sets a response header.</td>
</tr>
<tr>
  <td><a config-tag="resin:SetRequestCharacterEncoding"/></td>
  <td>Sets the character encoding of the request parameters.</td>
</tr>
<tr>
  <td><a config-tag="resin:SetRequestSecure"/></td>
  <td>Marks the request as secure.</td>
</tr>
<tr>
  <td><a config-tag="resin:SetVary"/></td>
  <td>Sets the Vary header.</td>
</tr>
<tr>
  <td>&lt;mypkg:MyFilter></td>
  <td>Regular Servlet filters can be used as rewrite filters.</td>
</tr>
</deftable>

</s1>

</body>

</document>

