Tuesday, May 3, 2011

How do you open and transfer a file on the filesystem in mod_python?

I'm new to mod_python and Apache, and I'm having trouble returning a file to a user after a GET request. I've got a very simple setup right now, and was hoping to simply open the file and write it to the response:

from mod_python import apache

def handler(req):
    req.content_type = 'application/octet-stream'
    fIn = open('response.bin', 'rb')
    req.write(fIn.read())
    fIn.close()
    return apache.OK

However, I'm getting errors when I use open(), saying that the file doesn't exist (even though I've checked a dozen times that it does). This happens when using relative and absolute filepaths.

I've got two questions:

  • Why isn't open() finding the right files?
  • What is the best way to return a file from the filesystem? (I ask to make sure I'm not missing some better way to use mod_python to return a file.)

Thanks

Edit: After finding this thread: http://www.programmingforums.org/thread12384.html I discovered that open() works for me if I move the file to another directory outside of home (I was aliasing out of /home/myname/httpdocs, but it works if I use /data). Any ideas why that works?

Edit 2: Part of my debug error, as requested:

MOD_PYTHON ERROR

ProcessId:      13642
Interpreter:    '127.0.1.1'

ServerName:     '127.0.1.1'
DocumentRoot:   '/var/www'

URI:            '/test/mptest.py'
Location:       None
Directory:      '/home/myname/httpdocs/'
Filename:       '/home/myname/httpdocs/mptest.py'
PathInfo:       ''

Phase:          'PythonHandler'
Handler:        'mptest'

Traceback (most recent call last):

  File "/usr/lib/python2.5/site-packages/mod_python/importer.py", line 1537, in HandlerDispatch
    default=default_handler, arg=req, silent=hlist.silent)

  File "/usr/lib/python2.5/site-packages/mod_python/importer.py", line 1229, in _process_target
    result = _execute_target(config, req, object, arg)

  File "/usr/lib/python2.5/site-packages/mod_python/importer.py", line 1128, in _execute_target
    result = object(arg)

  File "/home/myname/httpdocs/mptest.py", line 13, in handler
    fIn = open('/home/myname/httpdocs/files/response.bin', 'rb')

IOError: [Errno 2] No such file or directory: '/home/myname/httpdocs/files/response.bin'
From stackoverflow
  • To debug this kind of thing, you need to gather all information from the running mod_python instance.

    Stop messing with "checking a dozen times that it [exists]". Some assumption isn't correct.

    Do something like this to get some debugging information.

    def handler(req):
        req.content_type = 'text/plain'
        req.write(os.environ)
        req.write(os.getcwd())
        # etc.
        return apache.OK
    


    Edit

    Now you have a glimpse of the Important Stuff. In this case it might be permissions -- you'll need to use os.filestat to be sure. Apache runs mod_python as a user who has almost no usable permissions. Apache does not like links, either, but this shouldn't affect mod_python. If your file doesn't have read-by-everybody and isn't in the right directory you'll have problems.

    You might want to switch to mod_wsgi.

  • Could you paste the error(s) you get?

    It's likely to be a permission error (if you tried using the full path to the file). Remember the script runs as the user running the web-server process - so you will be accessing the file as "www-data", or "nobody" usually.

    Check the permissions of the folder /home/myname/httpdocs/files/ also. The folder should be +x for the www-data user:

    $ mkdir blah
    $ echo works > blah/response.bin
    $ chmod 000 blah/
    $ cat blah/response.bin
    cat: blah/response.bin: Permission denied
    $ chmod +x blah/
    $ cat blah/response.bin
    works
    

    You could eliminate Apache/your-script from the equation by doing the following:

    you:~$ sudo su - www-data
    www-data:~$ file /home/myname/httpdocs/files/response.bin
    

    (the su may not work, depending on what OS/distribution you are using, for example OS X prevents you logging in as it's www user)

    File permissions aside, why is the script dependant on a file in your home folder anyway? Can response.bin be moved to the same folder as your Python script? Or possibly even moved into a database? (perhaps SQLite? Might be unnecessary/excessive, depending on what is in response.bin and how much it changes)

0 comments:

Post a Comment