To fight XSS attacks, the web browser imposes the same origin policy for HTTP requests made by JavaScript code:

But there are a lot of use cases where this kind of cross domain HTTP request is desired, so developers came up with some workarounds:

  • Server side proxy: the idea is to avoid cross domain requests in the browser by doing them on the server:To do that in Mule you can use the HTTP proxy pattern as explained in this post.
  • JSONP: it consists of adding a <SCRIPT> tag dynamically. The src attribute of the script tag can point to another domain, and the browser will load and execute the JavaScript code that comes from it. But here is the twist: since the script can be generated dynamically on the server, you can use it to pass data to the JavaScript program in the browser.
    The suffix means padding, because the server needs to pad the returned JSON with a function call to make it a executable JavaScript code.Then your JavaScript code provides the definition of the function that gets called with the data.
    Clever trick right? But it has some limitations: only GET requests can be done in this way.

Is there another option?

Fortunately, yes. Modern browsers supports a W3C Working Draft  called CORS: Cross-Origin Resource Sharing, and probably the browser that you are using to see this page already supports it.

How CORS works?

The browser sends the request adding the Origin header:

If the origin is accepted by the  HTTP server it adds the Access-Control-Allow-Origin header to the response:

When the browser receives this header it continues reading the payload of the HTTP response, if not the request is rejected.

How it looks in your JavaScript code? If you use jQuery is business as usual:

jQuery is smart enough to detect the kind of CORS support that your browser has and uses XMLHttpRequest or XDomainRequest if the page is running in IE8.

“You’re allowed a wand…”

In Harry Potter and the Goblet of Fire movie, there is an scene were Harry is about to fight a dragon, and he best chance to win is to flight with the broom:

Harry: – But I’m not allowed a broom.
Professor Moody: – You’re allowed a wand…

Having access to an external domain in your JavaScript code, is like having a wand. Even if your web server is limited to deliver static HTML content, you can create powerful web applications using JavaScript and APIs located elsewhere.

I’m going to show you that with a simple example. It consist of a HTML file shared on Dropbox, which is not a hosting service but allows you to share static content. And from that file we are going to call a service hosted in Cloudhub.

Create a Cloudhub application using MuleStudio

Create a new project with MuleStudio and add a flow with a HTTP endpoint. To make it work with Cloudhub you have to use ${http.port} as port number for the endpoint:

Expose your REST API

In this example I’m going to use a JAX-RS, just because I’ve a background on Java programming and I’ve used JAX-RS services before. But, a good alternative to try is the REST module from MuleForge.

Following the JAX-RS way of things, we need a Java class to define the resources:

Then we need to wire it into the flow using a REST component:

Add Access-Control-Allow-Origin header to the response

An here comes the most important part, we need to add the Access-Control-Allow-Origin header to the response. To do that we are going to use a HTTP Response Builder:

In this case we are using https://dl.dropbox.com. Take account that: you can put multiple origins separated by space, and that http is a different origin than https.

Deploy to Cloudhub

On MuleStudio, right click into the project and choose “Deploy to Cloudhub…”

 

 

Fill up the credentials, and we are done with the service. Next step the client code.

Client code

The client code is straight forward:

This example takes the list returned by the server and shows a list from it.

You can see the running example here. That’s all folks!

Related posts:

  1. Extending Mule with DevKit – the LDAPConnector

5 Responses to “Cross domain REST calls using CORS”

Distributed Weekly 181 — Scott Banwart's Blog November 16th, 2012, 1:04 am

[...] Cross domain REST calls using CORS [...]

Antonio Santiago November 16th, 2012, 12:51 pm

Hi Diego,
nice article !!!

Only I would like to remeber there are other important properties to set in the header, like the Access-Control-Allow-Methods (see https://developer.mozilla.org/en/docs/HTTP_access_control#Access-Control-Allow-Methods).

CORS implies when the client makes a request, for example a GET request, a call to the server is made using the HTTP OPTION method to check if the call is available for the domain and for the GET mehotd, if so then the real GET method call is made, otherwise we don’t get nothing.

I wrote a similar one some time ago: http://acuriousanimal.com/blog/2011/01/27/working-with-the-javascript-xmlhttprequest-object/

Again, great post.

diego.fernandez November 17th, 2012, 4:20 am

Antonio, thanks for the comment!

I’ve shown only one of the CORS headers just for brevity, but you are right that Allow-Methods is another useful one, so thanks for the link!

About the OPTIONS request. At first, based on the spec, I took that request into account. But then when I tested my app, I saw that the OPTIONS request wasn’t sent. So after debugging a little bit it seems that Chrome (didn’t try on Firefox) doesn’t send the OPTIONS request, it just tries with the GET request and ignores the response payload if the allow header doesn’t match.
Maybe asking to the Chrome or Firefox devs could clarify that behavior.

Thanks!

David Dossot November 17th, 2012, 10:33 am

According to the spec (see: http://www.w3.org/TR/cors/#user-agent-processing-model ), pre-flight (ie the OPTIONS request) occurs only under certain circumstances.

For example, as soon as you use a non-simple header in your request (see: http://www.w3.org/TR/cors/#simple-header), pre-flight will occur.

Handling pre-flight requests indeed implies dealing with allow methods and headers, as explained in http://www.w3.org/TR/cors/#cross-origin-request-with-preflight-0

Bernard Lin December 4th, 2013, 7:57 pm

I have trouble making JSONP work with Mule Cloudhub. Is configuring CORS the only way?

Leave a Comment