diff --git a/INSTALL b/INSTALL index e4df048..74a19a9 100644 --- a/INSTALL +++ b/INSTALL @@ -169,8 +169,8 @@ as per the example configuration file in examples/apache_luminotes. For nginx, if you want a working upload progress bar, build and install a version of nginx with the NginxHttpUploadProgressModule enabled. See: -http://wiki.nginx.org//NginxHttpUploadProgressModule for more information. -Then, configure nginx as per the example configuration file in +http://github.com/masterzen/nginx-upload-progress-module/ for more +information. Then, configure nginx as per the example configuration file in examples/nginx_luminotes. For either web server, you should change the paths in your configuration file diff --git a/controller/Files.py b/controller/Files.py index cd5d6b9..3a0d514 100644 --- a/controller/Files.py +++ b/controller/Files.py @@ -133,7 +133,10 @@ class Upload_file( object ): @staticmethod def delete_file( file_id ): - return os.remove( Upload_file.make_server_filename( file_id ) ) + try: + return os.remove( Upload_file.make_server_filename( file_id ) ) + except OSError: + pass filename = property( lambda self: self.__filename ) @@ -174,7 +177,7 @@ class FieldStorage( cherrypy._cpcgifs.FieldStorage ): # pluck the file id out of the query string. it would be preferable to grab it out of parsed # form variables instead, but at this point in the processing, all the form variables might not # be parsed - file_id = cgi.parse_qs( cherrypy.request.query_string ).get( u"file_id", [ None ] )[ 0 ] + file_id = cgi.parse_qs( cherrypy.request.query_string ).get( u"X-Progress-ID", [ None ] )[ 0 ] try: file_id = Valid_id()( file_id ) except ValueError: @@ -549,13 +552,13 @@ class Files( object ): upload = (), notebook_id = Valid_id(), note_id = Valid_id( none_okay = True ), - file_id = Valid_id(), + x_progress_id = Valid_id(), user_id = Valid_id( none_okay = True ), ) - def upload( self, upload, notebook_id, note_id, file_id, user_id ): + def upload( self, upload, notebook_id, note_id, x_progress_id, user_id ): """ - Upload a file from the client for attachment to a particular note. The file_id must be provided - as part of the query string, even if the other values are submitted as form data. + Upload a file from the client for attachment to a particular note. The x_progress_id must be + provided as part of the query string, even if the other values are submitted as form data. @type upload: cgi.FieldStorage @param upload: file handle to uploaded file @@ -563,8 +566,8 @@ class Files( object ): @param notebook_id: id of the notebook that the upload is to @type note_id: unicode or NoneType @param note_id: id of the note that the upload is to (if any) - @type file_id: unicode - @param file_id: id of the file being uploaded + @type x_progess_id: unicode + @param x_progess_id: id of the file being uploaded @type user_id: unicode or NoneType @param user_id: id of current logged-in user (if any) @rtype: unicode @@ -573,6 +576,7 @@ class Files( object ): @raise Upload_error: the Content-Length header value is invalid """ global current_uploads, current_uploads_lock + file_id = x_progress_id current_uploads_lock.acquire() try: @@ -624,10 +628,10 @@ class Files( object ): @end_transaction @grab_user_id @validate( - file_id = Valid_id(), + x_progress_id = Valid_id(), user_id = Valid_id( none_okay = True ), ) - def progress( self, file_id, user_id = None ): + def progress( self, x_progress_id, user_id = None ): """ Return information on a file that is in the process of being uploaded. This method does not perform any access checks, but the only information revealed is the file's upload progress. @@ -636,8 +640,8 @@ class Files( object ): intended to mimic the API described here: http://wiki.nginx.org//NginxHttpUploadProgressModule - @type file_id: unicode - @param file_id: id of a currently uploading file + @type x_progress_id: unicode + @param x_progress_id: id of a currently uploading file @type user_id: unicode or NoneType @param user_id: id of current logged-in user (if any) @rtype: dict @@ -649,6 +653,7 @@ class Files( object ): 'received': bytes_received, 'size': total_bytes } """ global current_uploads + file_id = x_progress_id uploading_file = current_uploads.get( file_id ) db_file = None diff --git a/controller/Validate.py b/controller/Validate.py index 43e1c17..945bf30 100644 --- a/controller/Validate.py +++ b/controller/Validate.py @@ -221,6 +221,13 @@ def validate( **expected ): args = list( args ) args_index = 1 # skip the self argument + # make sure all kwarg names are lowercase and don't have dashes + for ( kwarg_name, value ) in kwargs.items(): + new_kwarg_name = kwarg_name.replace( "-", "_" ).lower() + if new_kwarg_name != kwarg_name: + del( kwargs[ kwarg_name ] ) + kwargs[ new_kwarg_name ] = value + # determine the expected argument names from the decorated function itself code = function.func_code expected_names = code.co_varnames[ : code.co_argcount ] diff --git a/examples/nginx_luminotes b/examples/nginx_luminotes index 887b69d..348f553 100644 --- a/examples/nginx_luminotes +++ b/examples/nginx_luminotes @@ -2,6 +2,8 @@ gzip_comp_level 4; gzip_min_length 1100; gzip_types text/plain text/html text/css application/x-javascript; +upload_progress luminotes 1m; + upstream luminotes { server 127.0.0.1:8081; } @@ -15,6 +17,11 @@ server { location / { proxy_pass http://luminotes; client_max_body_size 505m; + track_uploads luminotes 30s; + } + + location ^~ /files/progress { + report_uploads luminotes; } location /download/ { diff --git a/static/js/Wiki.js b/static/js/Wiki.js index f939043..0f3ddbd 100644 --- a/static/js/Wiki.js +++ b/static/js/Wiki.js @@ -3641,10 +3641,10 @@ function Upload_pulldown( wiki, notebook_id, invoker, editor, link, anchor, ephe appendChildNodes( this.upload_area, createDOM( "form", { "target": "upload_frame", - "action": "/files/upload?file_id=new", + "action": "/files/upload?X-Progress-ID=new&file_id=new", "method": "post", "enctype": "multipart/form-data", - "id": "upload_form" + "id": "upload_form", }, createDOM( "span", { "class": "field_label" }, this.link ? "attach file: " : "import file: " ), createDOM( "input", { "name": "notebook_id", "id": "notebook_id", "type": "hidden", "value": notebook_id } ), @@ -3681,7 +3681,7 @@ Upload_pulldown.prototype.update_file_id = function ( result ) { var upload_form = getElement( "upload_form" ) if ( upload_form ) - upload_form.action = "/files/upload?file_id=" + this.file_id; + upload_form.action = "/files/upload?X-Progress-ID=" + this.file_id; var file_id_node = getElement( "file_id" ); if ( file_id_node ) @@ -3738,9 +3738,8 @@ Upload_pulldown.prototype.update_progress = function () { var self = this; var BAR_WIDTH_EM = 20.0; - // TODO: send X- HTTP header nginx expects with file_id this.invoker.invoke( "/files/progress", "GET", - { "file_id": this.file_id }, + { "X-Progress-ID": this.file_id }, function( result ) { var fraction_done = 0.0; if ( !self.uploading )