CORS

CORS – Cross Origin Resource Sharing

This is a sequel to my post on cURL.

“Cross-origin resource sharing (CORS) is a mechanism that allows restricted resources (e.g. fonts, JavaScript, etc.) on a web page to be requested from another domain outside the domain from which the resource originated” from wiki.

The above explanation is self explanatory. For instance, a resource loaded from Domain A (http://A:3000) such as an HTML web page, makes a request for a resource on Domain B (http://B:4000). The Same-Origin Policy restricts the browser from performing certain actions by scripts or documents based on the origin. The origin is everything in the URL before the path (e.g., in http://A:3000/images/bg.png, http://A:3000 is the origin and /images/bg.png is the path). For certain actions, the browser will compare origins and, if they don’t match, won’t allow things to proceed.

We kept getting CORS error, when we were trying to test our REST API. The server sided REST API logic was written on Node.js and was running on port 3000 on one system. The client side logic was also written on Node.js and was also running on port 3000, but on another system. I had initially tested the API using POSTMAN, and it worked great. But, when we tried integrating the front-end with the back-end, it was erroneous. And it was CORS. I had encountered something similar related to CORS, way back in 2011, during my first job, but it was resolved in few minutes. I cannot recall the exact issue, all I remember is that it had to do only with JQuery (front-end only).

This time, I tried understanding CORS in more detail.

Let’s assume, the server-side code was running on http://A:3000 and the client-side code was running on http://B:3000. We were trying to test the login api, i.e. front-end accepts username/password through a form and on button click, submits the values (HTTP POST) to the server. The server then validates the username/password combination. If successful, server returns the user id, else, returns appropriate error messages. We had agreed upon both the input and output to be JSON only.

Things looked alright, when the input type was x-www-form-urlencoded, i.e. normal form data being passed through JQuery AJAX request. But things went awry, when we restricted it to JSON only (POSTMAN still had no issues).

Following is the list of errors when we tried with JSON input, and how I went about solving each one of them.

1. http://B:3000 made a POST request to http://A:3000/login. But instead of POST, it always made a OPTIONS request.

Now the first thing to wonder about was why did this happen. To be honest, I wasn’t sure about the HTTP OPTIONS method until then. But this is what it is. “This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.”
Nobody uses this OPTIONS method, but it is used for CORS access to API’s. When doing a CORS request, the browser will do a ‘preflight’ OPTIONS request to discover if the server will answer the real request.

The next thing to wonder was what is this preflight.

CORS requests are usually preflighted. This request is basically there to ask the server if the full request is permissible. If POST is used to send request data with a Content-Type other than application/x-www-form-urlencoded, multipart/form-data, or text/plain, e.g. if the POST request sends an XML/JSON payload to the server using application/xml or text/xml or application/json, then the request is preflighted. Only if the server responds positive to this preflight request, the actual POST request will be sent to the server.

At this point it was clear why the POST request always came as an OPTIONS request for JSON input and not for x-www-form-urlencoded.

2. After I understood about OPTIONS method and the preflight request, following was the next error. XMLHttpRequest cannot load http://A:3000/login. The ‘Access-Control-Allow-Origin’ header has a value that is not equal to the supplied origin. Origin ‘null’ is therefore not allowed access.

I was running test.html locally on the browser as file:///E:test.html. Running it this way, always sets the Origin to Null in the request header. This took quite some time for me to understand and resolve. I then created another local Node.js server running on port 4000 to serve test.html. Alternative to this could have been serving test.html through WAMP Server/Apache on port 80. This resolved the null origin issue. The origin was now set to http://localhost:4000.

3. Following was the third error. XMLHttpRequest cannot load http://A:3000/login. The ‘Access-Control-Allow-Origin’ header has a value http://B:3000 that is not equal to the supplied origin. Origin http://B:3000 is therefore not allowed access.

This wasn’t scary, like the earlier one. I could make sense, what was happening here. On my server sided logic in Node.js, I had restricted “Access-Control-Allow-Origin” to http://B:3000 only. res.header("Access-Control-Allow-Origin", "http://B:3000");
On the client side code, I had to add the below line to JQuery AJAX method. When the CORS makes a preflight request, both the client and server should have the same headers set.
beforeSend: function (request) { request.setRequestHeader("Access-Control-Allow-Origin", "http://B:3000"); }

This is the full JavaScript working code after understanding about CORS, OPTIONS, preflight and setting headers through AJAX.

var login = {username: "sadmin", password: "sadminasd"}; $.ajax({ dataType: "json", beforeSend: function (request) { request.setRequestHeader("Access-Control-Allow-Origin", "http://B:3000"); }, contentType: "application/json", type: "POST", data: JSON.stringify(login), url: 'http://A:3000/login', success: function(data) { console.log("Success", data); //alert("Success "+data); }, error: function(err) { console.log("Error", err); //alert("Error "+err) } });

At one point, we took the approach of solving this problem using JSONP. JSONP was initially the solution prior to CORS for making cross domain requests. But JSONP supports only GET and not POST.

In my next blog, I shall talk more about JSONP and also about JSONP vs CORS.

Node.js EACCESS

Yesterday, I tried running a Node.js server on port 80 on Ubuntu. I normally run Node.js server on ports > 3000.

First time when I tried running the server, I was expecting an error, because Apache2 was running on Ubuntu on port 80(default port for Apache2). I stopped Apache2 sudo service apache2 stop.

I tried running Node.js server again, and now it gave me EACCESS error. I was clueless about this.

When I tried to search for this error on Google, I found the answer on stackoverflow.com.

“Non-privileged user (not root) can’t open a listening socket on ports below 1024.” from stackoverflow

I then ran Node.js server using sudo node app. Bingo, it worked.

Also, when I was talking to my colleague Shiv (Guru-g Learning Labs), I learned that if applications run on port 80, then we can access them without the port number.

Eg: http://localhost/ instead of http://localhost:80. The latter option works too, it’s just that, we don’t have to explicitly specify the port numbers for port 80.

P.S: I haven’t tried running Node.js server on port 80 on Windows. Will document my results soon.

cURL

We were trying to test our new Node.js app. I was building a REST API and it worked fine with JSON input. I used POSTMAN (which I heard just a week ago from my colleague Shiv). I must tell you, it is really great. POSTMAN could have been a new topic under #LearningItMyWay. But anyways, it has got a mention here.

When our Front End Engineer Sanjeet tried calling my REST API through JQuery AJAX, we kept getting CORS (cross origin resource sharing) errors. This part is yet to be resolved, and I shall blog on it soon (Insha Allah). Read More

Shiv came and tested using curl on PHP. This wasn’t the first time I had heard about curl, but I had never used it earlier. So this becomes a good topic for #LearningItMyWay.

“curl is a tool to transfer data from or to a server, using one of the supported protocols (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET and TFTP). The command is designed to work without user interaction.

curl offers a busload of useful tricks like proxy support, user authentication, FTP upload, HTTP post, SSL connections, cookies, file transfer resume, Metalink, and more.”
(from this link)

So, basically, cURL is a command line tool for getting or sending files using URL syntax. curl url

There are various options for this command, but I haven’t bothered to know all of them for now. I only tried finding about this -L option. curl -L url

The -L option, allows to follow redirects with curl.

In my REST API written using Express on Node.js, I was using passport module for authentication. Passport does appropriate redirects based on login success or failure. When Shiv tested this API using curl, the redirects weren’t working as expected, and for once we were trying to find if Express redirects were working fine or not. Later, I found about this -L option for curl, and that was #LearningItMyWay.

Blogging has been fun so far, happy two days of blogging for me πŸ™‚

Npm install – – save

I have been working on with Node.js and Express for almost a year now. Thanks to Sreeram (istarindia.com) who wanted Talentify (talentify.in) to be built using Node.js.

There is this package.json file in Express, wherein you can specify all the dependent node modules. Once the dependencies have been listed, you have to give the command npm install before launching your Express app. This loads all the dependent node modules.

This is a code snippet from package.json

"dependencies": {
"primus": "*",
"async": "~0.8.0",
"express": "4.2.x"
}


Often I used to wonder, how to get the exact version number for a node module. I started with a “*” next to each node module, just to ensure that the latest version of the node module gets installed.

Few days back, it so happened that I was looking for a particular version of Express, and Ubuntu never installed the right(latest) version for me. I then learned about this command npm install --save express@4.x.x. This command installed the right version of express which I was looking for.

The --save option was so handy. I then learned that issuing this command npm install --save would also create an entry in package.json file with the appropriate version.

I don’t have to bother about the version numbers for node modules henceforth, --save option does that for me. NPM sounds so simpler after that.

Ambigram

I was just done posting an intro to #LearningItMyWay and I was checking yourstory.com. The following headline caught my eyes.

“This two-year-old Jaipur-based startup is a preferred gifting destination for the Bachchans and Anna Hazare” (from yourstory). The start-up’s name was “Indibni” (quite a rare name, and I like it already). “Indibni is actually a very interesting word. It is an ambigram (mirror image) of the word β€˜indi’” (from yourstory).

And that’s when I decided to remind myself the meaning of the word Ambigram, which means Mirror Image.

“An ambigram is a word, art form or other symbolic representation, whose elements retain meaning when viewed or interpreted from a different direction, perspective, or orientation. The meaning of the ambigram may either change, or remain the same, when viewed or interpreted from different perspectives.” (from Wikipedia)

I have noticed often that I do come across numerous words, but it’s hard for me to recall their meanings later. I hope blogging helps me overcome this problem of mine. Let me experiment on this, and I shall document my results on a weekly basis :).

Learning It My Way

Starting today, I have decided to blog on the new thing(s) I learn daily. I have been coding full time now, since 2011, and there have been numerous new things which I have learned/come across.

I started my career as a Lecturer in 2009. Although I liked my work initially, I felt there was no motivation to learn anything new. I moved to Bangalore in 2011 and from then on there has been no looking back :).

I shall try to recall and blog about all the new things I learned over these years too, if I get the time. But other than that, I will definitely document my day to day new learning (Insha Allah). So let me call all the posts which come under this category as #LearningItMyWay. Happy blogging to me πŸ™‚