Making cross-sub-domain ajax (XHR) requests using mod_proxy and iframes

One of the restrictions imposed by all browser side programming languages is that one cannot make cross-domain ajax requests. This restriction comes because of the same origin policy and even sub-domain ajax calls are not allowed. In this blog post, I will demo two methods of making cross-sub-domain ajax requests. First demo will use mod_proxy module of Apache. While the second demo will use iframe and javascript tricks for making sub-domain ajax requests.

Using mod_proxy for cross-domain ajax requests
By enabling mod_proxy module of apache2, we can configure apache in reverse proxy mode. In reverse proxy mode, apache2 appears be like an ordinary web server to the browser. However depending upon the proxy rules defined, apache2 can make cross-domain request and serve data back to the browser.

Demo Link for Cross Domain Ajax using Apache mod_proxy

In this demo, I will make cross-domain request to http://gtalkbots.com/reverse-proxy-data.php. To make this cross-domain request successful, I have configured apache2 as shown below:

  1. Enable mod_proxy module.
    $ a2enmod proxy
    $ a2enmod proxy_http
    $ a2enmod proxy_connect
  2. Add the following lines to httpd.conf:
    $ cat /private/etc/apache2/httpd.conf | grep mod_proxy
    
    LoadModule proxy_module libexec/apache2/mod_proxy.so
    LoadModule proxy_connect_module libexec/apache2/mod_proxy_connect.so
    LoadModule proxy_http_module libexec/apache2/mod_proxy_http.so
  3. Create a file reverse-proxy.conf and add the following config:
    $ cat /private/etc/apache2/other/reverse-proxy.conf
    
    ProxyRequests Off
    
    <Proxy *>
    Order deny,allow
    Deny from all
    Allow from .abhinavsingh.com
    </Proxy>
    
    ProxyPass /webdemos/crossdomainajax/reverse-proxy-get.php http://gtalkbots.com/reverse-proxy-data.php
    ProxyPassReverse /webdemos/crossdomainajax/reverse-proxy-get.php http://gtalkbots.com/reverse-proxy-data.php

In brief, when Apache sees an incoming ajax request to /webdemos/crossdomainajax/reverse-proxy-get.php , it simply proxy pass it to http://gtalkbots.com/reverse-proxy-data.php and return back the response. The whole process is hidden from the users on the demo page.

Using iframes for cross-domain ajax requests
Another method of achieving sub-domain ajax requests is by using iframes. However, javascript does not allow communication between two frames if they don’t have same document.domain. The simplest of the hacks to make this communication possible is to set document.domain of the iframe same as that of the parent frame.

Demo Link for Sub-Domain Ajax using iFrames

In this demo, I will make a sub-domain request to http://img1.abhinavsingh.com/iframe-data.php. To make this possible, I load an iframe with src="http://img1.abhinavsingh.com/iframe-demo.php" and set document.domain="abhinavsingh.com"; for the iframe.

iframe-demo.php

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript">
	jQuery(function($) {
		function getTimestamp() {
			$.get(ajax_url,
				{},
				function(data) {
					$('#iframe_ajax_data', top.document).html('Server time received through iframe ajax: '+data);
				}
			);
		}

		document.domain = "abhinavsingh.com";
		$('#link', top.document).click(function() {
			getTimestamp();
		});
	});
</script>

In brief, iframe-demo.php sets an onclick event on $('#link' top.document) , which makes a sub-domain ajax request to http://img1.abhinavsingh.com/iframe-data.php

Enjoy!

Caching problem in IE with Ajax : A Solution

Hello All,

Problem Definition:
I made my first browser based chat messenger way back in January this year, and I tried making a improved version of it yesterday again. But unfortunately Microsoft continues to give 1000 reasons for a web developer to suicide. They continue to serve the same old buggy browser way back in 2000 and even now.

The problem I was facing with IE7 (I haven’t tested on IE6), while trying to make a browser based chat messenger was that the chat application loads the chat messages from the server successfully only for the first time i.e. when you load the site for the first time. However, after that it continues showing the same old loaded data, even as new messages keep coming in the server. My chat application always worked fine in Firefox, Netscape, Safari and Flock. So what the hell with Internet Explorer.

The Real Problem:
I faced the same problem 6 months back and was facing it again now. Frustrating enough! As a web developer its a reason enough to die. Anyways, I finally tried analyzing the things. I went around installing Wireshark , which lets you see each and every http request made from your computer. Unfortunately, It was just not showing any ajax request being made by my site (opened on IE). What the hell? However, it showed successful ajax requests being made by my site opened on Firefox.

Enough! The problem was clear that, for some reason IE was not allowing the Ajax request being made. Then I went around installing IE Debug Bar, there in the HTTP(S) section you can see each and every single request being made by IE. I restarted IE and opened my site again. There in the HTTP(S) section, I could see ajax request being made successfully every 15 seconds as intended (a live chat application will set that to about 2 seconds). Then why the hell was wireshark not showing the same.On further investigation with DebugBar I found this was what was not allowing my site to make a successful ajax request the second time:

  • In the Headers section of HTTP(S) I could see:
    GET /ajax.php?getchatmessage=true&id=36&username=imoracle HTTP/1.1
    Accept: */*
    Accept-Language: en-in
    Referer: http://altertunes.com/home.php
    UA-CPU: x86
    Accept-Encoding: gzip, deflate
    HTTP/1.1 200 OK
    X-Powered-By: PHP/5.2.5
    Keep-Alive: timeout=5, max=100
    Transfer-Encoding: chunked
    Content-Type: text/html

  • In the Timing section of HTTP(S) I could see:
    Request start time: Thu, 05 Jun 2008 22:29:55
    All request retrieved from cache (no server request)

  • Further, in the Info & Cache section of HTTP(S) I could see:
    URL: http://altertunes.com/ajax.php?getchatmessage=true&id=36&username=imoracle
    Content Type: text/html
    Headers size (bytes): 336
    Data size (bytes): 3
    Total size (bytes): 339
    Transferred data size (bytes): 0
    Cached data: Yes
    Cache File: C:UsersabhiAppDataLocalMicrosoftWindowsTemporary Internet FilesLowContent.IE5O184DNELajax[1].htm
    Cache expires: Thu, 01 Jan 1970 05:30:00
    Cache last modified: Thu, 01 Jan 1970 05:30:00

Hence the conclusion was, IE do make an ajax request every 15 seconds as intended. But as it always reads the content from the the browser cache, it never gets the new messages from the server. And hence, Wireshark was unable to show any request being made from IE browser, as the request never goes out of the computer.

Solution to this disaster:
I tried looking for many solutions available over internet. A few of them asks to set some settings in your browser, which will force browser to read all the data from server directly. But for two reasons you surely won’t like to do this:

  1. You surely would like to cache your various images, css and other files for faster loading of your website.
  2. Next, You simply can’t expect your users to do the settings, just to make sure that your ajax runs on IE.

A few other sites asked to set a header information at the top of the php page. Probably something like this:

header(“Last-Modified: ” . gmdate(“D, d M Y H:i:s”) . ” GMT”);
header(“Cache-Control: no-store, no-cache, must-revalidate”);
header(“Cache-Control: post-check=0, pre-check=0”,false);
header(“Pragma: no-cache”);

But even after setting the following header IE was not allowing the ajax requests to fetch the data from the server.

Working Solution:
Then I thought of why not make my ajax requests look unique every time it is fired. i.e. if my ajax request seems like this in the firebug:
http://altertunes.com/ajax.php?getchatmessage=true&id=36&name=imoracle

why not make it look like this the next time:
http://altertunes.com/ajax.php?getchatmessage=true&id=36&name=imoracle&timeid=1234.4323

and like this the very next time:
http://altertunes.com/ajax.php?getchatmessage=true&id=36&name=imoracle&timeid=4324.3589

I tried this up and Bingo! My ajax was working just as great, as it was in any other browser.

I simply changed the url in my ajax request from:
http://altertunes.com/ajax.php?getchatmessage=true&id=36&name=imoracle to
http://altertunes.com/ajax.php?getchatmessage=true&id=36&name=imoracle&timeid=(Math.random()*100000)

and yes, I have my chat messenger working great now.

Try out this solution if you are facing a similar problem with your Ajax requests. I will try to test the same in IE6 if I can find one, but I am pretty sure it will work great there too.

Feel free to post your comments and modified solutions if any.

Happy Ajaxing.

Gmail Type Attachment – How to make one?

Google and its wide range of web applications have simple changed the way we used to look at internet. Be it the revolutionary fast Google search engine or mail by Google i.e Gmail. You will find enormous amount of threads and forums discussing How do google achieve doing XYZ? or How do they make it happen fast and efficiently?.

One of the most talked about thing about Gmail is probably how do they achieve making Gmail so simple, convinient, sober, fast and easy. One of the Gmail’s feature which contribute hugely in making it easier and faster for users is: Its ability to attach your files while you are writing your mail.

I have tried to come up with an exact clone for gmail attachment. Kindly click here for the demo and the source files.

This is achieved by using an iframe which contains your server side script responsible for handling uploads. As soon as the user select a file to upload, the upload form gets submitted to upload.php, which lies in an iframe. Hence at no point does the user leaves the page and still he gets his file uploaded. Find attached below all the files you need to implement this on your server. Just unzip the file on your server, and you are ready. All the uploaded files will go in th upload folder by default. You may change that in upload.php.

Feel free to post a comment back here for any queries etc.

Cheers !