2

My file upload was working perfectly on the built in Flask server, but the file upload broke when I deployed it (Apache2).

Flask python code:

@app.route('/uploadajax', methods=['POST', 'GET'])
def upload():
    file = request.files['file']

    if file and allowed_file(file.filename):
        filename = secure_filename(file.filename)
        file.save('TEST.pdf')

    return jsonify({'filename':'http://www.michigan.gov/documents/sprsConnectionsVol5No1_15852_7.pdf'})

Javascript:

$(function() {
    $('#upload-file-btn').click(function() {
        var form_data = new FormData($('#upload-file')[0])
        $.ajax({
            type: 'POST',
            url: SCRIPT_ROOT + '/uploadajax',
            data: form_data,
            contentType: false,
            cache: false,
            processData: false,
            async: false,
            success: function(data) {
                console.log('Loaded questions successfully.')
                packet_frame = '<iframe src="http://docs.google.com/viewer?url=' + encodeURI(data['filename']) + '&embedded=true" width="100%" height="260" style="border: none;"></iframe>'
            }
        })
    })
})

There's no error if I comment out the file.save('...') line. The specific error is

[Sat Nov 30 20:43:21 2013] [error] [client 66.75.0.4]     file.save('TEST.pdf'), referer: http://mydomain.com/
[Sat Nov 30 20:43:21 2013] [error] [client 66.75.0.4]   File "/usr/local/lib/python2.6/dist-packages/werkzeug/datastructures.py", line 2576, in save, referer: http://mydomain.com/
[Sat Nov 30 20:43:21 2013] [error] [client 66.75.0.4]     dst = open(dst, 'wb'), referer: http://mydomain.com/
[Sat Nov 30 20:43:21 2013] [error] [client 66.75.0.4] IOError: [Errno 13] Permission denied: 'TEST.pdf', referer: http://mydomain.com/

I thought that this wouldn't happen because I'm only writing to a subdirectory and not root, but there's still the permission denied error. Any help?

quantumtremor
  • 3,787
  • 2
  • 17
  • 20

2 Answers2

7

You are saving a file with no path information. This means it'll be saved in the current working directory, wherever that may be for the Apache process. You do not have write permissions there. This working directory is almost certainly not the same place as where your project code is stored.

Specify a path for the file. You could use a directory based on the current module (os.path.dirname(__file__) is the directory of the current module), or configure a destination path for your application.

You may want to study the Uploading Files pattern in this context.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • I changed it to match the structure at that website; the same thing happens. http://pastebin.com/dLUG88jt for the errorlog – quantumtremor Dec 01 '13 at 07:38
  • Will http://stackoverflow.com/questions/7645974/file-writing-permission-denied-in-mod-wsgi-deployed-app help? I don't want to mess any permissions up permanently. – quantumtremor Dec 01 '13 at 08:05
  • Right, yes, you'll have to give the `www-data` user write access, *or* configure the WSGI setup to use separate processes and a specific user. – Martijn Pieters Dec 01 '13 at 08:45
  • Thank you, that worked. Now I need to get the link for my uploaded file (for Google Docs Viewer), but I'm not sure exactly where my application root is. I have 'DocumentRoot /var/www' in my apache2 config, but when I try www.mydomain.com/html/myapp/myapp.py (/var/www/html/myapp/myapp.py is an existing file), I get a 404. Is there a way I can get the URL for my uploaded file? – quantumtremor Dec 01 '13 at 09:21
  • @user3024025: what does `os.getcwd()` tell you the current working dir is? – Martijn Pieters Dec 01 '13 at 09:51
  • When I return os.getcwd() from within the Flask file, I get '/' in my console. Does this mean DocumentRoot didn't work in the apache2 config? Also, when I try mydomain.com/var/www/html/myapp/myapp.py, it still returns a 404. Here is my /etc/apache2/sites-available/myapp file - http://pastebin.com/UZ5WQgWq (Debian) – quantumtremor Dec 01 '13 at 10:06
  • Same thing happens if I remove the Options and AllowOverride lines. – quantumtremor Dec 01 '13 at 10:13
  • @user3024025: You should not rely on the working directory **at all**. See https://code.google.com/p/modwsgi/wiki/ApplicationIssues#Application_Working_Directory. Use an absolute path instead. Hardcode the document directory if you have to. – Martijn Pieters Dec 01 '13 at 10:15
  • Thank you for your help, but I'm still not sure what to do. Are you saying that I can't access the file from http://mydomain.com/.../test.pdf? If not, then how do I input the link into Google PDF viewer? – quantumtremor Dec 01 '13 at 11:35
0

I solved it by giving relative path rather than giving absolute path in the filepath.

charchit
  • 1,492
  • 2
  • 6
  • 17