Fire and Forget

...or, 'How to Make One-Way Cross-Domain POST Requests with XmlHttpRequest'.


Most developers know about the same-origin policy when it comes to Ajax requests using XmlHttpRequest (XHR). Essentially, it means that an XHR request from the hosting domain cannot be made to any other domain. In fact, it is even more strict than other scripting and cookie policies in that it cant even be used across subdomains of the same domain.


However, I recently stumbled onto a loophole that proves quite interesting. If you run Fiddler or your favorite proxy and try this sample, you can clearly see that the request (from my domain) to another domain (yahoo.com*) is being made just fine. At first I thought it was some kind of browser bug so I tried a few others with the same result. A quick 'View Source' of the sample page will show that it is straight-up Javascript; no client libraries or other trickery to confuse the issue. It took me a minute, but then I realized what was going on.


Turns out the same-origin policy specifically disallows *reading responses* from other domains. Since the responses contain HTTP headers (which in turn could contain cookie information), that is the data that is marked as off-limits. However, the request is sent and processed on the server just as it normally would. The only difference is that the client (the Javascript making the XHR request) just can see the response that comes back.


"Great" I hear you say, "what good is it if we cant read the response?". Well, for plain-jane Ajax stuff where you are making requests to return JSON or HTML to update the page dynamically, it really isn’t useful at all. "And besides, we can already use JSONP and <iframes> and dynamic <script> tags to do cross-domain requests" you argue. True, but those techniques only allow GET requests – this cross-domain XHR request allows the full set of HTTP methods, including POST, so you can post form data using this technique.


And although the response is off-limits, we *can* get some indication of the result of the request. The .status property is not allowed, but the .statusText property is, sometimes, allowed. Why sometimes? I don’t know for sure, but in Firefox, if the request succeeds and returns a 200 OK response, the .statusText can be read and returns 'OK'. (Conversely, if a 404 response is generated, the .statusText property cannot even be read and throws an exception). So you can at least determine if your request made it to its destination and was successfully processed or not.


So what is it all good for? You can make fire-and-forget requests (a sort of web-based UDP protocol) where the responses don’t matter. Or you could have a backend system or API that only accepts data (think: analytics tracking service or notification service like notify.io). These might not be earth-shattering ideas, but I thought it was an interesting scenario to consider.


Anyway, maybe everybody already knew this except me and I am just years behind the times. But if not, maybe this will help someone out there who is looking for a creative solution to their problem.


* - Why yahoo.com? google.com doesn't allow POST requests and I didn’t want the 405 Method Not Allowed response to confuse people

 

0 comments