File Upload Progress with mod_python
Now that Gmail has added a progress bar for attachment uploads, everybody wants to do the same including myself
So, with the same method that everybody uses consisting in an upload form with a hidden <iframe> as target, and then a periodic Ajax request to update the progress, I made a simple implementation using mod_python on the server side… This is a veeery simple example, like everything that you do with Python.
Additionally I’ve added an upload size limit control based in examples that can be found in the mod_python forum site. Use the source Luke!
See LIVE DEMO!
Libraries that I used for this example
Prototype.js: this well known library to avoid cross-browser compatibility issues, is small and practical. I use it in almost all my web projects. Also Bramus requires this library. If you don’t like it for some reason you will need to replace many many many functions like $() which is an improved getElementById(), or the Hash class that I use to track in-progress uploads, JSON encoding, etc. etc. You don’t want to remove it, seriously.
simplejson: A python library to encode/decode JSON objects. I use this one for the messaging between the server and the page. In my opinion JSON is more efficient than XML because it generates more compact and still human-readable outputs. But you can use XML or any other method by modifying the example as you like.
Start by downloading the source code for this example. I decided to release the code under BSD license, so you can use it for whatever you want.
The source is organized like the following illustration:
/src/temp: directory where the uploaded files will be stored. IMPORTANT: in unix like environments the group and permission of this folder must be configured properly in order to Apache to have write access on it.
/src/_upload_limit.py: mod_python fixup handler that controls the file upload size limit, verifies if the file already exist in the server, stores file size and location information on the session and does the actual file upload after all the verifications.
/src/index.py: The main python publisher handler. Exposed URLs are the main / “index” page that loads the test.html and /get_upload_progress function that returns the current % progress of the files being uploaded.
/lib/simplejson: simplejson python library to encode / decode JSON messages.
I’m assuming that you already have mod_python installed on your Apache. Take a look to the sample configuration:
Alias / "/Users/fvicente/workspace/uprogress/src/" <Directory "/Users/fvicente/workspace/uprogress/src/"> SetHandler python-program PythonHandler mod_python.publisher PythonDebug On PythonFixupHandler _upload_limit <Files ~ "\.(gif|jpg|png|ico|js|css)$"> SetHandler default-handler </Files> Order allow,deny Allow from all </Directory>
mod_python manual has a lot of information about the configuration options, so I’m not going to describe this in too much depth, just remark that I’m using the very useful mod_python publisher, and more “unusual” option PythonFixupHandler pointing to the _upload_limit.py file.
Interesting parts of the code
The fixuphandler function contained in this file does the checking for the size limit of the file being uploaded by reading the http header Content-Length sent by the browser allowing you to reject an upload even before starting the actual transfer… very clever!. I found _upload_limit.py example in the mod_python forum, and used it as a based adding the specific code for the upload progress handling. _upload_limit.py also stores the file size and name in the current session to be used later by the get_upload_progress function defined in index.py. Note that every time that the Session is used it will be accessed with the option lock=False thus using the session.lock() and session.unlock() methods manually when necessary, if you don’t do this that way all the parallel requests will be held until the upload finishes making impossible to monitor the progress via parallel Ajax request.
addUploadSlot(): creates an HTML code dynamically with an “upload slot” which is a form with the file to upload, the hidden <iframe> that is the form target, the progress bar control, and the “Upload” button. It uses a global counter called slotCnt to give a unique id to each slot. This id will be the “key” in the get_upload_progress dictionary (see index.py description).
updateProgressBars(): This is the function called by setInterval() while the files are uploading that does the actual Ajax.Request to /get_upload_progress in order to get the % progress for each file. The parameter sent with the request is a dictionary where the keys are the slots Id’s and the values the file names stored in the hash table.
uploadDone(slot): Will be called by the <iframe> when the upload finishes (successfully or not). Here I remove the file from the hash and stop the interval if no longer necessary.
Remember that this is just an example and may contain errors. Use it at your own risk, I’m not responsable of any possible damage or data lost, blah, blah, etc. etc. etc.
The code is poorly commented, but at least is well formatted . I recommend you to read it, it is very short and you may find interesting chunks.