“AJAX is for asynchronous calls within same origin whereas HTML5 CORS is for asynchronous calls across origins”. This is a popular comparison of AJAX vs CORS which many web developers do, but there is a lot beyond this!
Similar to the above response header, there are a bunch of response headers which help browsers in checking various access permissions. If you are new to CORS, I suggest you to visit HTML5 rocks, which has a detailed tutorial. In this post, I would like to focus on browser security checks.
Browser security checks – AJAX vs CORS:
Let us say you are using a browser which does not support HTML5 CORS and your application is hosted at http://localhost:81. If you open http://localhost and try to make an AJAX call to your app, you will get this security error message:
"Access to restricted URI denied" (message text varies across browsers, essentially conveying SOP violation).
var xhr = new XMLHttpRequest();
xhr.open("POST", "http://localhost:81/handler.ashx", true);
var params = 'name=AJAX';
Browsers do this Same Origin Policy check even before they trigger a network call.
Now if you install a browser which supports CORS and try the same (without configuring any response headers), you will get the message:
“XMLHttpRequest cannot load http://localhost:81/. Origin http://localhost is not allowed by Access-Control-Allow-Origin”.
The message clearly conveys that the check happened after making a call to the remote server. This is obvious, since CORS is based on response headers and browsers do not have any clue whether the remote server allowed the call or not without checking the response. In this context, browser developer tools sort of confuse developers by saying that “the request is cancelled”. In reality, browsers “do the request but just do not render the response” in case CORS headers are not found. To test this, you can simply log the call on your server and you will have log entries.
<%@ WebHandler Language="VB" Class="Handler" %>
Public Class Handler : Implements IHttpHandler
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim str As String = context.Request.Params("name")
Dim sw As StreamWriter
Dim strDate As String
strDate = context.Timestamp
sw = New StreamWriter(context.Server.MapPath("logs.txt"), True)
sw.WriteLine(strDate + " : " + str)
context.Response.ContentType = "text/plain"
context.Response.Write("Hello " + str)
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
The above code is the content of my remote .ashx handler hosted on http://localhost:81 (okay, I’ve written the above code in VB but who cares! As long as you understand what it does, language doesn’t matter. My next demos will be using Java Servlets/PHP..yes, I’m coding in these recently..yay!)
So web developers who have used AJAX and are moving towards HTML5 should know this subtle but important difference.
Cross origin form submission now AJAXified in CORS!
Not sure if you have observed or not, the first code snippet in this post uses a content-type “application/x-www-form-urlencoded”. If you haven’t figured it out, there is a more familiar version of it which you already know:
<form method="post" action="http://localhost:81/handler.ashx">
<input type="text" name="name" value="fake form">
<input type="submit" value="Submit">
When HTML forms are submitted, they use “application/x-www-form-urlencoded” as the default content type. Since forms anyways do cross origin posts inherently, this “feature” was also included in HTML5 CORS specifications. This is the reason why we were able to log the CORS message in the second snippet. So all the three content types which are supported by HTML forms (“application/x-www-form-urlencoded”, “multipart/form-data”, “text/plain”) can be used in CORS to do a cross origin request (Don't you smell attack scenarios here? Stealth mode attacks? Yeah!)
No preflight request for CORS POST request?
The HTTP methods GET and HEAD are called “safe methods” since they should not cause any state changes on the server. POST requests are me