Pages

Wednesday, January 1, 2014

Same Origin Policy and JSONP


Some days back, I was developing a mobile application that needed communication with the server. Since I was learning about node.js, I decided to give it a try and make the web app in node. Earlier I used J2EE Servlets, which seems fairly simple, but very heavyweight for my educational projects. So, I thought node.js will be a lightweight substitute. Also, I was not using the native mobile application development to develop the app on android. I was using Phonegap to make a HTML-CSS-JS based app, and used jQuery mobile to do the JS part. So I thought if I opted for node.js on server side, it will be an all Javascript project which seemed like fun.

As I started and tried to do the basic things I always try out first - Send something from client to server, do something with the data, Send back something to the client, display it - I was addressing a new problem that I was not familiar with - Same Origin Policy.



I looked up Wikipedia and got this. The policy makes sure that requests originating from same site (a combination of URI scheme, hostname and portnumber) are allowed and others are not. What I was trying to establish was to send a jQuery ajax call from my client with contained some fields from a form, ( a login form, for example), get it at server, compare against some value, send "yes" or "no" back to client. As simple as that. But whatever I try, I couldn't get the data at the server or back to the client. Because of Same origin policy, and since my requests are originating from a completely different place, my requests are rejected access to DOM. That got me stalled for a while until I got the solution.

JSONP - JavaScript Object Notation with Padding. I was already familiar with JSON, as I used it as a data interchange format for a couple of my projects, and found it quite comfortable. If you want to read more on JSON, give this a try. To keep it simple, It is just the representation of key value pairs. For eg:

{
    "Name": "Foo",
    "Id": 1234,
    "Rank": 7
}

Here, Name, ID and Rank are the keys and Foo,1234 and 7 are their respective values. How JSONP differs from JSON is that there is a function call wrapping up the above data. Like this:
functionCall({"Name": "Foo", "Id": 1234, "Rank": 7});

The term Padding in the JSONP, refers to the name of this callback function. So, the typical use of JSONP provides cross-domain access to an existing JSON API, by wrapping a JSON payload in a function call. If you need to know further, ask the wiki. But it is pretty much you wanna know for the scope of this article.
There is one more thing, I would like to add. JSONP requests are almost always GET, not POST. Even if I specify the method as POST in my ajax call, the server catches it as a GET request. Lemme explain it to you with a piece of code.

This code below is what I fire up when user clicks the submit button on a login forms with fields username and password.
function validate() {
    var uname = $('#username').val() ;
    var pword = $('#password').val() ;
    $.ajax({
     type : "GET",
     dataType: "jsonp",
     jsonpCallback: "responding",
     url : "http://localhost:8888/authenticate",
     data :  { username: uname , password : pword },
     success : function(data) {
      
      alert(data.auth);
      
     },
     error : function(jqXHR, textStatus, errorThrown) {
      alert("Error, status = " + textStatus + ", " + "error thrown: " + errorThrown);
     }
    });
   }

and here is my node server code processing it.
var querystring = require('querystring');
var url = require('url');

function authenticate(request, response) {
 console.log(request);
 var pquery = querystring.parse(url.parse(request.url).query);
 var result = {
   auth : "yes"
 };
 if(pquery.username!="admin"||pquery.password!="pass"){
  result.auth = "no";
 }
 var jstring = JSON.stringify(result);
 console.log(jstring);
 response.writeHead(200, {
  "Content-Type" : "text/plain"
 });
 response.write('responding('+jstring+')');
 response.end();
}

and when I executed both and put in 'admin' and 'pass' in the form, clicked login, a console log of the request was shown in the console, and among a lot of lines was these ..

 url: '/authenticate?callback=responding&username=admin&password=pass&_=1388598347928',
  method: 'GET',
As you can see, the parameters are shown as if they are in the url, but this is not exactly like this, because there is a limit to the URL size but not for the amount of data that can be sent through JSONP. JSONP works by exploiting the fact that there are exceptions to HTML <script> elements in the same origin policy, so it simple adds a <script> element and get its task done.

So, the code works, my username and password gets validated, and it sends an { "auth" : "yes" } back with a responding() function wrapped, the "yes" gets alerted back at my app. Stupid piece of code, ha? Say what, Educational purpose only ;)

So, Thanks for reading my blog, do comment if anything is there, and Happy New Year ! 

No comments:

Post a Comment