Flash 10 Breaks Local File Browsing
People, people, people! Just when I fix other people's bugs enough that I can start innovating again, people start screwing with their code so that I have to start from base 1 again. Adobe's Flash 10 is a case in point. With the latest release, Flash 10, Adobe purposely breaks functionality that has been around for years, motivated by some amorphous hypothetical "security issue." This breaks the innovating Guise™ upload capabilities, which means I'll have to abandon Flash.
First a little background. Traditionally the only way to upload content on the web was to use an HTML input control. This control made the browser show a button that, which pressed, would allow the user to browse the local file system and choose files for upload. Then, when the user pressed a button to submit the results to the server, the browser would collect the contents of the file and post them to the server.
This HTML-based solution was very tedious. The style of the button couldn't be changed reliably across browsers. More importantly, there was no way to allow the user to select multiple files. This resulted in many pages with several upload buttons, requiring the user to press a separate button for each file that needed to be uploaded. Lastly, the resulting HTTP POST caused the whole page to be reloaded, freezing the browser until the upload finished, with no way to monitor the upload progress. Obviously, a content management system that wants to upload even a handful of images (each around 3MB in size, for example) will soon loose customers from all this tediousness.
In today's age of web-based applications using Ajax technology, HTML file upload doesn't cut it. Some Ajax solutions, including an early version of my Guise™ Framework, used JavaScript to dynamically add HTML upload buttons and have the results posted to an IFrame in the background so that upload process could be monitored. It was all very clever stuff, if I say so myself, but selecting files was still tedious, requiring files to be chosen one at a time.
Because of the ubiquity of Adobe Flash (by September 2008 Flash 9 had reached over 97% penetration in mature markets), it seemed like an ideal go-between for some server-based Ajax technology such as Guise and the user's local file system. Guise uses Flash both to stream and play MP3s and to choose and upload files, all transparently to the server-based software within the framework. Let me explain a bit about how Guise (which this very site uses) works.
Guise is a Java-based application framework, inspired in part by Java Swing, which allows you to create an entire user interface using server-based, client agnostic components such as buttons, windows, sliders, etc. When I say "server-based, client-agnostic" I mean that the developer creates these components and assigns actions to them without knowing or caring where the user interface will be displayed. I can create a button, add a listener to it, and when the button is pressed I can modify the value of a slider. A system of Guise depictors will translate all this in real time into whatever HTML or JavaScript magic needs to happen for this to be displayed on a browser, but I as the developer never write a line of HTML or JavaScript. When a button is pressed on the browser, a message is sent to the server in the background that knows to call the event-handling code that I have attached to the button. Theoretically one could write depictors to make my application run on Swing or SWT with essentially no application code modifications.
The way Guise depictors handle file uploads is clever but intricate. There is a server side object for requesting a list of files from the user. This component talks to a small Flash application that gets loaded in the browser. When the user presses a "browse" button (a Guise button), the button sends a message to the server, and the server asks the file list object to gather files; the web platform depictor then sends a message back to the hidden Flash application, asking it to pop up a dialog to browse for files. Importantly, the message coming back from the server to the Flash application occurs asynchronously—the button, when pressed, does not wait for the message to come back from the server right away.
In Flash 10 Adobe decided that they would not allow Flash applications to pop up browse dialogs unless they happen directly in response to some button being pressed—that is, within the same event call from the button. This breaks the whole asynchronous, client-agnostic model of Guise. It also breaks WordPress, Flickr, and Yahoo.
So why did Adobe take such drastic measures, breaking so many applications? According to Adobe's Justin Everett-Church, this was to prevent some rogue site from repeatedly popping up a browse dialog using Flash, even though the user hadn't requested it. When asked if this sort of thing had actually been seen in the wild or if it were more of a theoretical risk, he hemmed and hawed a bit and never really answered the question.
But can't a JavaScript application pop up an alert dialog any time it wants? I could write a JavaScript application that essentially freezes your browser with an alert popup that appears every time you close it. How is this different from a file browse dialog? Does Justin think that, if a rogue site keeps popping up a browse dialog, that a user will become so frustrated that he/she says to him/herself, "maybe I can make this go away if I browse to my personal folder and upload the my-secret-passwords.txt
file?"
This is insane. If a rogue site has access to Flash and can present a file browse dialog in the first place, the security risk of a user uploading personal files to the rogue site has not been diminished in the least. All this change does is remove a source of irritation highly unlikely to happen in the wild, in the process breaking legitimate use cases on my site and on a number of high-profile sites. But removing a hypothetical irritation does not introduce security; no security has been added by this ill-thought-out change.
My only choice now is to switch to a Java applet (which is still slow and cumbersome, regardless of the new improvements in Java 6 update 10), or switch to Google Gears, which as luck would have it recently added an openFiles() method to its Desktop API. I'll check that out; if that doesn't work I may just have to do the tried and true method of writing the plugin myself.