fettig.net

XmlHttpRequest subdomain update

Posted by Abe on Wednesday, November 30, 2005 @ 1:16 pm

Firefox 1.5 shipped yesterday, and it brings good news for my work on cross-subdomain XmlHttpRequest calls (I’m going to start using the abbreviation XHR for XmlHttpRequest now, to save on typing). In previous releases of Firefox (and in the other browsers I tested) setting document.domain in an iframe caused the iframe to lose the ability to make XHR calls. But for Firefox 1.5, the Mozilla developers decided this was a bug, and fixed it. So going forward you no longer need to resort to any ugly hacks to make cross-subdomain XHR calls in Firefox: load an iframe from the same server you’ll be making XHR calls to, set document domain in both the original window and iframe, and then proceed to make XHR calls in the iframe. It’s beautiful. Many thanks to Peter Van der Beken and Brendan Eich at Mozilla for taking care of this.

This means that the really hacky part of the cross-subdomain XHR technique I talked about the other day is now only needed for old versions of Mozilla-based browsers. This is great news because it addresses worries about the iframe-bridge hack going away in the future: it may very well not work in future Mozilla releases, but it doesn’t matter because we’ve got a much better solution.

I’ve posted some updated code that does the right thing in Firefox 1.5, while keeping the iframe bridge hack on older versions: test5.html. This works in Firefox 1.07, Firefox 1.5, IE6, Safari 1.3/2.0, and Konqueror 3.4.3. It still doesn’t work on Opera, which is looking like a lost cause unless someone can come up with an Opera-specific hack. Here’s the iframe code:

<html>
  <head>
  <script type="text/javascript" src="xmlhttp.js"></script>
  <script type="text/javascript">
    var AJAX_URL="http://www.fettig.net/playground/ajax-subdomain/ajaxdata.php";
    function getTime(){
      try {
        getUrl(AJAX_URL, gotTime);
      } catch(e) {
        // getUrl failed, probably because we're running in an older
        // Moz/Firefox/Gecko and we we've changed document.domain.
        // switch to the bridge hack (if we haven't already)
        if (window.bridgeGotTime) {
          throw e;
        } else {
          document.location.replace("test5-bridge.html");
        }
      }
    }
    function gotTime(status, headers, result) {
      var oldDomain = document.domain;
      if (window.bridgeGotTime) {
        window.bridgeGotTime(result);
      } else {
        document.domain = "fettig.net";
        window.parent.gotTime(result);
      }
      // try to set document.domain. this is needed for IE/Konq/Safari
      // it will fail in Gecko-based browsers, which is ok in ff > 1.5, but
      // which forces the use of a bridge iframe hack in earlier Geckos.
      try {
        document.domain = oldDomain;
      } catch (e) {}
      setTimeout(getTime, 1000);
 }
    getTime();
  </script>
  </head>
</html>

Note that this doesn’t do any browser sniffing, it just tries different techniques until it finds one that works (or until they all fail).

I’ve also tweaked the bridge code a bit, to clean it up and to avoid the case where it only half works and you end up with a bunch of recursively loaded iframes. Here’s the updated code:

<html>
  <head>
  </head>
  <body>
  <script type="text/javascript">
    function gotTime(result) {
      window.parent.gotTime(result);
    }
    var subframe = document.createElement('iframe');
    document.body.appendChild(subframe);
    function setupBridge() {
      subframe.contentWindow.bridgeGotTime = gotTime;
      document.domain = "fettig.net";
    }
    subframe.src = "test4-iframe.html";
    subframe.contentWindow.onload = setupBridge;
  </script>
  </body>
</html>

How to make XmlHttpRequest calls to another server in your domain

Posted by Abe on Monday, November 28, 2005 @ 1:26 pm

This post is more technical and detailed than what I usually
write on fettig.net. I’m going to talk about a technique I’ve been
working on to work around a limitation in the XmlHttpRequest object
used in Ajax applications. Web geeks, please read on.

Updates to this post

See this post for an updated version of this techinique that works (hack-free) in Firefox 1.5.

The problem

XmlHttpRequest objects are bound by the
same origin security policy
of browsers, which prevents a page from accessing data
from another server. This has put a serious limitation on Ajax
developers: you can use XmlHttpRequests to make background
calls to a server, but it has to be the same server that served up the
current page. Known workarounds for this limitation involve either
server-side reverse proxying
or
bypassing XmlHttpRequest entirely.

In my case neither of these approaches was
going to work. I wanted to use
LivePage, the live-update framework
developed by Donovan Preston and other brilliant hackers at
Divmod. LivePage
works because it uses Twisted,
which is good at handling lots of long-lasting network connections at
the same time. Since Apache isn’t good at handling lots of long-lasting
connections, putting an Apache reverse proxy in front of the Twisted
server would put a major hurt on performance and scalability. And
since LivePage is bound to XmlHttpRequest, I couldn’t use a
non-XmlHttpRequest alternative.

Our approach with JotSpot Live has been to let a Twisted server
handle all page requests and XmlHttpRequest calls. That’s fine as
long as JotSpot Live is a standalone, dedicated web site. But what our
customers are asking for (and what we want) is the ability to
have Live-style realtime updates in ordinary xxx.jot.com sites. And we
don’t want to put a Twisted server in front of every site in our
domain. So I’ve been trying to find a way to let any page in our domain
communicate with live.jot.com through XmlHttpRequests. As it turns out, it is
possible, but you have to jump through some hoops.

(more…)

New Camera

Posted by Abe on Friday, November 11, 2005 @ 11:42 pm

I just ordered a new digital camera, a Panasonic Lumix DMC-FZ5. I got a great deal on Amazon.com - they had a very competitive price, plus they’re running a special where you get $23 off a memory card with the camera purchase, plus at checkout they gave me a free trial membership to Amazon Prime so I got next business day shipping for cheap. The link is to the right if you want to buy one of your own.

After a couple years of taking fairly low-quaility snapshots with my old Casio Exlim EX-S2, and then a year of extremely low quality snapshots with my mobile phone I’m stepping up to a “real” camera. I did a lot of research on cameras, but what finally pushed me over the edge to the DMC-FZ5 was a Google search for “DMC-FZ5 site:flickr.com“, which let me see a sampling of all the pictures DMC-FZ5 users have posted to Flickr. The sample photos show that this camera either naturally takes great pictures or it attracts a lot of good photographers, and one way or the other I feel good about choosing it.

Unlike previous cameras I’ve owned this one isn’t pocketable, so I won’t have it with me all the time, but at least when I do choose to bring it I’ll be able to take the pictures I want. Or, more accurately, it will be my own lack of skill holding me back rather than the camera.
Look for some action in my Flickr stream starting Monday.


Managing Mail

Posted by Abe on Thursday, November 3, 2005 @ 11:11 pm

Today I finally got my email working exactly the way I want:

  • Both my main addresses (jot.com and fettig.net) get forwarded to a gmail account.
  • I download mail into Thunderbird from gmail via POP
  • I send mail through gmail using SMTP. Until recently any mail sent through Google appeared to come from your gmail address, so I had to use my own SMTP server in order to preserve the my From: address. But now Gmail lets you set up alternative From: addresses. I like using Google’s SMTP service because my sent mail gets archived online with my received mail.
  • I use the Gmail philosophy of “search, don’t sort” in Thunderbird. New mail comes into my Inbox, and when I’ve read/responded to it I put it into a folder called Archive. I also configured Thunderbird to put my sent mail in Archive, so both sides of my email conversations are in one folder.
  • Dragging and dropping mail from Inbox into Archive gets old fast. Today I finally found a solution: the GmailUI extension. It adds some Gmail-inspired features to Thunderbird, making the “Y” key a shortcut for “Move this message to my Archive folder”. Now I can push messages out of my Inbox without having to use the mouse.
  • That just left one problem: I want to use my jot.com address to respond to jot email, and my fettig.net address for personal email. That too was solved with a Thunderbird extension: Correct Identity. This automatically picks the right account to use when replying to mail, based on the address the original message was sent to. I did have to create a dummy account just so Thunderbird would know about my jot.com email address, but that’s a small price to pay. (Update: not actually necessary - see comments)

Benefits of this setup:

  • All my mail flows through Gmail. Gmail is essentially acting as a free mail host with all the goodies: Excellent spam filtering, a nice web UI, archiving/backup, search, SSL connections.
  • My Gmail address isn’t used for sending or receiving mail. I like Gmail’s service, but I’m not going to let myself get bound to an email address at a domain I don’t control. This way I can switch off Gmail at any time in the future, and it will be completely transparent to other people.
  • I have my mail locally in Thunderbird, so I don’t have to be online to read old mail.
  • I have multiple accounts flowing into a single POP mailbox, but I still get the correct From: address when replying to mail.