IE XMLHttpRequest, RSS feeds, and fixing it with Apache mod_rewrite

Apr 15 2009

On occasion I have run into a strange problem, both with the RSS JavaScript widget downloadable from aleph-null.tv and with the code I wrote for Drupal 6 JavaScript and jQuery: Under certain conditions, the script simply does not work on IE 6, and IE 7. Firefox, Safari, and such don't seem to have this problem at all.

After a whole lot of digging, I found the problem, and devised a solution that will work out of the box with Apache (and with a little tweaking, it should work with other webservers, too). <!--break-->

The Problem

The problem, in one line, is that IE's XMLHttpRequest object does not treat files served as application/rss+xml as XML files.

How does this manifest itself in applications? Both the widget at Aleph-Null and the Webclips code in Drupal 6 JavaScript and jQuery use jQuery to load an RSS feed over AJAX. They retrieve the feed, parse the contents, and then display RSS data inline.

This does not always work. The symptoms of the failure seem to be something like this: The RSS feed gets fetched from the server, but it is never loaded by the underlying JavaScript. Instead of displaying content, the display area is left blank. The JScript debugger emits no errors (remember: this only happens in IE).

At first, the problem seemed to be unreplicatable with the widget running on http://aleph-null.tv. Others who downloaded it would report problems, but each time I downloaded their feeds, loaded them up to my server, and tested, all was well. Then I tried the feed from Drupal. This feed did not work, while those not served from Drupal worked fine. Why?

It turns out that Drupal correctly serves out its RSS feed with the application/rss+xml MIME type. My server, however, simply spits out RSS files as text/xml. Could that be the problem? A little research confirmed for me that it was. Changing the MIME type back and forth, I could replicate the error reliably.

After a little research, I learned that IE does not follow the common behavior of treating all MIME types ending +xml as XML files. Only explicitly defined XML MIME types are parsed by IE's XMLHTTPRequest object. And application/rss+xml is not one of these MIME types.

The Solution: Apache to the Rescue

So we can refine the problem down to this description:

When the RSS file is requested from an XMLHttpRequest object, the web server must set the Content-type: header to text/xml instead of application/rss+xml.

Now the question is, how do we fix this?

The problem is really between the requesting client (the XMLHttpRequest object) and the webserver, which is ultimately responsible for the content type settings. Is it possible to work out this issue between these two? If you are running Apache 2.x with mod_rewrite, it is, in fact, not that hard to do.

Since AJAX requests (at least through jQuery) send the X-Requested-With: XMLHttpRequest header, we can selectively match those requests on the server. From there, we just need to adjust the MIME type.

Here's the Apache configuration to do it. You can put this in Apache's configuration file or in an .htaccess file.

RewriteEngine on
RewriteCond %{HTTP:x-requested-with} ^XMLHttpRequest$
RewriteRule ^(.*\.(rss|xml|rdf))$ - [L,T=text/xml]

The first line turns on mod_rewrite's rewrite engine.

The second line adds a condition. The rewrite rule (on the third line) will not be executed if this condition is not met. The condition says, in plain English, "If the HTTP header x-requested-with is set to XMLHttpRequest, then..."

The rewrite rule handles the next part. If the request is for a file with the extension rss, xml, or rdf, then serve the file with the MIME type text/xml.

Once this is installed on the webserver (and this might require a server restart if you are not using .htaccess files), the MIME type should be corrected, and RSS data will be served to XMLHttpRequest objects as plain XML.