GeekLondon.com Help icon Syndication Feed icon 

WebDAV, File Upload, Hibernate and Blobs

My evil scheme for world domination has a web front end that allows file uploads. Unfortunately the standard web browser support for file uploads is as attractive as a monkey's bottom and, unless you have very strange tastes in either area, about as useful. Why doesn't one of the emerging updates to HTML support a humane file upload picker? We may never know.

There are several possible work-arounds.

So I've gone for that last option. The problem is that my application isn't using a filesystem. So I haven't got one I can share. It's storing all the files in an honest to god PostgreSQL database as blobs. So instead of sharing out the filesystem, I'm skipping the middle man and working on an implementation of the WebDAV4 distributed authoring protocol to expose the various table contents directly. This is my world of geeky fun. Inevitably my implementation of the protocol has been dubbed WebDAVE.

I have hit a few problems though. The WebDAV spec is not as clear as, for example, the SMTP5 specification and it makes some fairly heavy use of XML. In some areas it is quite hand wavily vague about quite what content to expect. Still, my application is now able to talk to the Dolphin filemanager, so it's coming together. I have no doubt that it will explode violently on contact with other clients, but some more rigorous testing should take care of the worst deficiencies.

Along the way I encountered two particularly baffling issues, both eventually resolved to errors on my part, but I thought I'd document them here for future reference.

Firstly, after issuing a MKCOL (create folder) request, the Dolphin client complained "A folder named New Folder already exists." If I did a refresh the folder suddenly materialized. It took me ages to spot that I was returning the 200 (OK) response code, instead of the 201 (CREATED) response code as required by the standard.

Secondly, when uploading files with the PUT operation, my files were ending up zero bytes long. Utterly baffling that one, because I already had form based file uploads working absolutely fine and the WebDAV support was invoking most of the same logic. That was caused by my use of Hiberate's methods for creating Blobs. If you call Hibernate.createBlob(InputStream) the input stream's available() method must return the full size of the incoming blob. However, when reading a ServletInputStream from a browser request, that typically returns 0 because the incoming data supply depends upon the client6. The solution is to use the alternative Hibernate.createBlob(InputStream,int) method to specify the number of octets to read from the incoming stream. The incoming PUT request specifies the content length, so this information is available when it's needed.

Once WebDAVE is complete I'll try to resist the temptation to add an FTP client.

Footnotes

1 Why do Java Applets still take a zillion years to load? Hell, I can launch the entirely Java based Tomcat application server quicker than most Java Applets. What on earth do they spend all that time doing? I think we should be told.

2 This may seem intolerant, but in fact, since I discovered Desktop Tower Defence and (of course) Scrabulous, I've mellowed enough that I no longer think that all Flash developers should be put to death. Unless they create Flash based adverts.

3 Actually the Flickr photo hosting site takes the alternative approach of creating a desktop widget to allow you to upload via their website. It's a neat solution, but not one I plan to emulate.

4 If you fancy emulating this act of stupidity, you'll need to brush up on RFC2068 describing the HTTP 1.1 specification and RFC2518 describing the WebDAV distributed authoring extensions to it.

5Which was specified in the beautifully written RFC0821 by the immortal Jon Postel.

6 Why didn't my form based method fail in the same way? Because it was coming in as multipart form data from a POST, rather than the input stream of a PUT request. I was therefore using Spring's CommonsMultipartResolver support class. In my configuration this converts the incoming POST data into a set of temporary files. The logic on this path through the application was therefore supplying a FileInputStream to the Hibernate method, and the available() method on a file normally returns the number of bytes in the file.

Posted at May 16, 2008 1:14:13 PM, and last updated May 16, 2008 1:18:39 PM