Google Gears File Upload Incorporated into Guise™, Replacing Broken Flash 10

Two days ago I explained the ridiculous decision of Adobe to break Flash 10 file uploads. As file uploads are an essential part of the Guise™ Framework and the Marmox™ Network, on which this blog is running, I had to have a replacement, and Java is still way too bulky. Luckily Google Gears has just added file upload capabilities, and I've spent the last couple of days integrating into Guise. Google Gears does the job, and even in beta isn't plagued by all the bugs Flash has had over the past few years.

Flash has had local file upload capabilities for a long time, but the implementation has been buggy from the start. First Flash file upload would fail on Firefox when using SSL. Then this was apparently fixed, but Flash still won't send the correct cookies for SSL on Firefox, forcing me to add a workaround involving a manual cookie indication as a URL query parameter, just to keep the session. Furthermore Flash is very sensitive to SSL certificates (even if the browser has been configured to accept the certificate). Lastly, the upload approach isn't very RESTful—Flash uses POST with a proprietary multipart/form-data form field of Filedata.

But the last straw came this year when Adobe intentionally broke file browsing capabilities except in certain highly constrained situations in a poorly designed attempt at "security". (Adobe ignored the fact that, if a rogue site wants to irritate the user, it's not going to browse for files—it's just going to throw up alert messages all day.) Adobe basically forced me to abandon Flash.

But luckily Google Gears had just integrated local file upload. My friend Brad Neuberg had indicated that this functionality was coming, and it came just in time. Unfortunately Google Gears requires a manual installation (just like Flash) and it isn't yet as ubiquitous as Flash, but I trust Google more than Adobe to have the competence to implement the HTTP protocol correctly.

I present below an explanation on how to perform a file upload using Google Gears as implemented in Guise. You can see the full source in the Guise JavaScript file in the GlobalMentor Subversion repository. Google also has Desktop API documentation.

You'll first need to include Google's gears_init.js in your web page, which prepares your JavaScript for accessing the Guise plugin. Rather than relying on Gears to be installed on ever user's machine, you should check for its presence. Guise does this in the following manner:

/**Checks to see if Google Gears is installed.
If Google Gears is installed, this method returns <code>true</code>.
Otherwise, the user is asked if Google Gears should be installed.
If so, the user is redirected to the Google Gears installation page.
If the user elects not to install Google Gears, this method returns <code>false</code>.
@param askInstall If the user should be asked to install Google Gears if it isn't already installed.
@return <code>true</code> if Google Gears is installed, else <code>false</code> if Google Gears
is not installed and the user has not been asked to install or the user declines.
*/
verifyGoogleGears=function(askInstall)
{
if(window.google && google.gears)    //if Google Gears is installed
{
return true;
}
else    //if Google Gears is not installed
{
if(askInstall && confirm("Install Google Gears?"))    //TODO i18n
{
location.href="http://gears.google.com/?action=install&message=Hello%20Google%20Gears&return="+location.href;
}
else    //if we shouldn't ask to install, or the user declined to install
{
return false;
}
}
};

When you're satisfied that Google is installed, you can allow the user to browse the local file system for one or more files to upload:

var desktop = google.gears.factory.create("beta.desktop");
desktop.openFiles(_onGearsOpenFiles, {singleFile:false});

(Guise actually uses some fancier binding and such to use class methods, but this is the basic idea.) The option to allow for multiple files is shown for completeness. the _onGearsOpenFiles(files) method passes a list of the files selected by the user. You can upload one of them like this:

var httpUploadRequest=google.gears.factory.create("beta.httprequest");
httpUploadRequest.open("PUT", fileURI);
httpUploadRequest.upload.onprogress = _onprogress();
httpUploadRequest.onreadystatechange = function()
{
switch(httpUploadRequest.readyState)
{
case 4:    //complete
alert("Done");
break;
}
};
httpUploadRequest.send(file.blob);

From discussions on the Google Gears users list it seems that error handling is less than straightforward, though. If a network error occurs, there is no callback function to indicate this. Similarly, canceling doesn't seem to change the ready state. But canceling is possible—just keep the HTTP request around and call its abort() method.

Whatever function you use for _onprogress() will be called as the upload occurs; this works well. Overall, although the documentation is a bit sparse and error handling and canceling is a little rough and/or incomplete, Google Gears easily beats Flash. I suppose it's a good thing that Adobe broke Flash so that I would have the motivation to try Google Gears. Here's hoping Google Gears gains the ubuquity that Flash has achieved.

Fulfilling the promise made by Guise, all the application-level code I wrote for file uploads in Guise still work unchanged, even though Guise now uses Google Gears (or falls back to Flash if the user doesn't want to install Google Gears) using Ajax, all transparently. You can find out more on the Guise site.

Update 2008-11-12: Google Gears support is now available in the current release of the Marmox Network; you can create an account and try it out for yourself.