witten
/
luminotes
Archived
1
0
Fork 0

Switched file upload and progress methods to expect nginx-style "X-Progress-ID" instead of "file_id" parameter.

Also updated example nginx config file to include directives for nginx's upload progress module.
This commit is contained in:
Dan Helfman 2009-03-19 21:38:42 -07:00
parent 92b7cf1084
commit 4f3b478509
5 changed files with 37 additions and 19 deletions

View File

@ -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 For nginx, if you want a working upload progress bar, build and install a
version of nginx with the NginxHttpUploadProgressModule enabled. See: version of nginx with the NginxHttpUploadProgressModule enabled. See:
http://wiki.nginx.org//NginxHttpUploadProgressModule for more information. http://github.com/masterzen/nginx-upload-progress-module/ for more
Then, configure nginx as per the example configuration file in information. Then, configure nginx as per the example configuration file in
examples/nginx_luminotes. examples/nginx_luminotes.
For either web server, you should change the paths in your configuration file For either web server, you should change the paths in your configuration file

View File

@ -133,7 +133,10 @@ class Upload_file( object ):
@staticmethod @staticmethod
def delete_file( file_id ): 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 ) 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 # 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 # form variables instead, but at this point in the processing, all the form variables might not
# be parsed # 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: try:
file_id = Valid_id()( file_id ) file_id = Valid_id()( file_id )
except ValueError: except ValueError:
@ -549,13 +552,13 @@ class Files( object ):
upload = (), upload = (),
notebook_id = Valid_id(), notebook_id = Valid_id(),
note_id = Valid_id( none_okay = True ), note_id = Valid_id( none_okay = True ),
file_id = Valid_id(), x_progress_id = Valid_id(),
user_id = Valid_id( none_okay = True ), 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 Upload a file from the client for attachment to a particular note. The x_progress_id must be
as part of the query string, even if the other values are submitted as form data. provided as part of the query string, even if the other values are submitted as form data.
@type upload: cgi.FieldStorage @type upload: cgi.FieldStorage
@param upload: file handle to uploaded file @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 @param notebook_id: id of the notebook that the upload is to
@type note_id: unicode or NoneType @type note_id: unicode or NoneType
@param note_id: id of the note that the upload is to (if any) @param note_id: id of the note that the upload is to (if any)
@type file_id: unicode @type x_progess_id: unicode
@param file_id: id of the file being uploaded @param x_progess_id: id of the file being uploaded
@type user_id: unicode or NoneType @type user_id: unicode or NoneType
@param user_id: id of current logged-in user (if any) @param user_id: id of current logged-in user (if any)
@rtype: unicode @rtype: unicode
@ -573,6 +576,7 @@ class Files( object ):
@raise Upload_error: the Content-Length header value is invalid @raise Upload_error: the Content-Length header value is invalid
""" """
global current_uploads, current_uploads_lock global current_uploads, current_uploads_lock
file_id = x_progress_id
current_uploads_lock.acquire() current_uploads_lock.acquire()
try: try:
@ -624,10 +628,10 @@ class Files( object ):
@end_transaction @end_transaction
@grab_user_id @grab_user_id
@validate( @validate(
file_id = Valid_id(), x_progress_id = Valid_id(),
user_id = Valid_id( none_okay = True ), 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 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. 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: intended to mimic the API described here:
http://wiki.nginx.org//NginxHttpUploadProgressModule http://wiki.nginx.org//NginxHttpUploadProgressModule
@type file_id: unicode @type x_progress_id: unicode
@param file_id: id of a currently uploading file @param x_progress_id: id of a currently uploading file
@type user_id: unicode or NoneType @type user_id: unicode or NoneType
@param user_id: id of current logged-in user (if any) @param user_id: id of current logged-in user (if any)
@rtype: dict @rtype: dict
@ -649,6 +653,7 @@ class Files( object ):
'received': bytes_received, 'size': total_bytes } 'received': bytes_received, 'size': total_bytes }
""" """
global current_uploads global current_uploads
file_id = x_progress_id
uploading_file = current_uploads.get( file_id ) uploading_file = current_uploads.get( file_id )
db_file = None db_file = None

View File

@ -221,6 +221,13 @@ def validate( **expected ):
args = list( args ) args = list( args )
args_index = 1 # skip the self argument 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 # determine the expected argument names from the decorated function itself
code = function.func_code code = function.func_code
expected_names = code.co_varnames[ : code.co_argcount ] expected_names = code.co_varnames[ : code.co_argcount ]

View File

@ -2,6 +2,8 @@ gzip_comp_level 4;
gzip_min_length 1100; gzip_min_length 1100;
gzip_types text/plain text/html text/css application/x-javascript; gzip_types text/plain text/html text/css application/x-javascript;
upload_progress luminotes 1m;
upstream luminotes { upstream luminotes {
server 127.0.0.1:8081; server 127.0.0.1:8081;
} }
@ -15,6 +17,11 @@ server {
location / { location / {
proxy_pass http://luminotes; proxy_pass http://luminotes;
client_max_body_size 505m; client_max_body_size 505m;
track_uploads luminotes 30s;
}
location ^~ /files/progress {
report_uploads luminotes;
} }
location /download/ { location /download/ {

View File

@ -3641,10 +3641,10 @@ function Upload_pulldown( wiki, notebook_id, invoker, editor, link, anchor, ephe
appendChildNodes( this.upload_area, createDOM( "form", appendChildNodes( this.upload_area, createDOM( "form",
{ {
"target": "upload_frame", "target": "upload_frame",
"action": "/files/upload?file_id=new", "action": "/files/upload?X-Progress-ID=new&file_id=new",
"method": "post", "method": "post",
"enctype": "multipart/form-data", "enctype": "multipart/form-data",
"id": "upload_form" "id": "upload_form",
}, },
createDOM( "span", { "class": "field_label" }, this.link ? "attach file: " : "import file: " ), createDOM( "span", { "class": "field_label" }, this.link ? "attach file: " : "import file: " ),
createDOM( "input", { "name": "notebook_id", "id": "notebook_id", "type": "hidden", "value": notebook_id } ), 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" ) var upload_form = getElement( "upload_form" )
if ( 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" ); var file_id_node = getElement( "file_id" );
if ( file_id_node ) if ( file_id_node )
@ -3738,9 +3738,8 @@ Upload_pulldown.prototype.update_progress = function () {
var self = this; var self = this;
var BAR_WIDTH_EM = 20.0; var BAR_WIDTH_EM = 20.0;
// TODO: send X- HTTP header nginx expects with file_id
this.invoker.invoke( "/files/progress", "GET", this.invoker.invoke( "/files/progress", "GET",
{ "file_id": this.file_id }, { "X-Progress-ID": this.file_id },
function( result ) { function( result ) {
var fraction_done = 0.0; var fraction_done = 0.0;
if ( !self.uploading ) if ( !self.uploading )