2012-12-29

Camel 2.11 - HTTP proxy routes with url rewriting functionality

In the upcoming Apache Camel 2.11 release I have recently added support for plugging in custom url rewrite implementations to HTTP based routes (http, http4, jetty). This allows people to control the url mappings, when you use Camel to proxy/bridge HTTP routes.

For example suppose you need to proxy a legacy HTTP service and plugin a strategy for mapping the urls. This is now much easier with Camel 2.11. There is a new option urlRewrite added to the various HTTP components, to plugin a custom url rewriter.

For example having a http proxy route as shown, where we use the new urlRewrite option on the http producer endpoint.


from("jetty:http://localhost:{{port}}/myapp?matchOnUriPrefix=true")
    .to("jetty:http://somewhere:{{port2}}/myapp2?bridgeEndpoint=true&throwExceptionOnFailure=false&urlRewrite=#myRewrite");


In a nutshell you can implement a custom strategy by implementing the UrlRewrite interface, as shown below. As this is from an unit test, we just replace yahoo to google in the url (yes its not a real-life applicable example).


public class GoogleUrlRewrite implements UrlRewrite {

  @Override
  public String rewrite(String url, String relativeUrl, Producer producer) {
      return url.replaceAll("yahoo", "google");
  }
}

In the rewrite method Camel provides you with the absolute url (eg including scheme:host:port/path?query) or a relative url which is the offset from the uri configured in the route (see further below).

However it all gives you the full power to control the url mappings, and even return a new absolute url. If you return null, then the default strategy is used, which is a 1:1 url mapping.

That is not all there is also a new component

Introducing the new camel-urlrewrite component

The new camel-urlrewrite component is a implementation of the new url rewrite plugin based on the UrlRewriteFilter project. This project has strong support for specifying your rewrite strategies as rules, and have its engine evaluate the rules.

For example we can have N+ rules in the url rewrite XML configuration file. In the example below we have a rule to rewrite urls to adapt to a legacy system which is using JSP.


<urlrewrite>

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

</urlrewrite>


This project has even support for Apache mod_rewrite styles which allow you to define rules as you would do with the Apache HTTP server. Though if you are not familiar with the mod_rewrite style then its dense and takes some time to understand - but very powerful.

All this is documented at the camel-urlrewrite component page with examples. And if you want to look for more, then checking the unit tests source code is also a good way to learn more.

I encourage you to take a look at the new camel-urlrewrite page as it has full examples and more details, that what I have outlined in this short blog.


Happy new-year and see you in 2013.

3 comments:

Ximon Eighteen said...

Hi Claus,

I've tried the shiny new 2.11-SNAPSHOT urlrewrite functionality and I think it's working fine and looks great! However, I encountered a couple of issues:

Firstly, after upgrading my Camel Maven dependency versions from 2.10.3 to 2.11-SNAPSHOT I can no longer start my Maven Shaded JAR as I encounter java.lang.SecurityException: Invalid signature file digest for Manifest main attributes at sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:240). Instructing Maven Shade to exclude .SF files from the result JAR allowed me to start my application.

Secondly, I have discovered that when using the functionality with load balancing, <failover/> causes java.lang.IllegalArgumentException: UrlRewrite org.apache.camel.component.urlrewrite.http.HttpUrlRewrite@479cdb17 requires the message body to be aHttpServletRequest instance, but was: null at org.apache.camel.component.http.helper.HttpHelper.urlRewrite(HttpHelper.java:381), but it works fine if I replace <failover> with <roundRobin/>.

I assume that these are my mistakes, but if I can help by providing more details please let me know.

Cheers,

Ximon

Claus Ibsen said...

Hi Ximon

Thanks for sharing this findings.
I will take a look at the load balancing thing. There is possible a bug or something we can improved to make this work. Though when you use failover it gets tricky as in case of a failure you would need to re-read the request, and usually reading a input stream is only possible once. And thus Camel would need to use stream caching to guard against that.

Fell free to contact the Camel community at our mailing list or forums. And as well log issues etc.
http://camel.apache.org/support

For example about the shade thing. I am not sure if you refer to an issue in Camel or on your side. Posting more details on our mailing list / forum is a better way to get support / help.

Claus

Claus Ibsen said...

I added some unit tests with load balancer. Notice for the failover load balancer you need let an exception be thrown so it can react. See the comments in the source code of that commit

http://svn.apache.org/viewvc?rev=1438914&view=rev