Serving file download with python
Question: Hey gang, I'm trying to convert a legacy php script over to python and not
having much luck.

The intent of the script is to serve up a file while concealing it's origin.
Here's what's working in php:

    
    
    <?php
    $filepath = "foo.mp3";
    
    $filesize = filesize($filepath);
    
    header("Pragma: no-cache");
    header("Expires: 0");
    header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
    
    // force download dialog
    //header("Content-Type: application/force-download");
    header("Content-Type: application/octet-stream");
    header("Content-Type: application/download");
    
    header('Content-Disposition: attachment;filename="'.$filepath.'"');
    
    header("Content-Transfer-Encoding: binary");
    
    #header('Content-Type: audio/mpeg3');
    header('Content-Length: '.$filesize);
    
    @readfile($filepath);
    exit(0);
    ?>
    

When I do the equivilent in Python, I get a download that is zero bytes.
Here's what I'm trying:

    
    
    #!/usr/bin/env python
    # encoding: utf-8
    
    import sys
    import os
    import cgitb; cgitb.enable()
    
    filepath = "foo.mp3" 
    filesize = os.path.getsize(filepath)
    
    print "Prama: no-cache"
    print "Expires: 0"
    print "Cache-Control: must-revalidate, post-check=0, pre-check=0"
    
    print "Content-Type: application/octet-stream"
    print "Content-Type: application/download"
    
    print 'Content-Disposition: attachment;filename="'+filepath+'"'
    
    print "Content-Transfer-Encoding: binary"
    
    print 'Content-Length: '+str(filesize)
    
    print  #required blank line
    
    open(filepath,"rb").read()
    

Can anyone please help me?


Answer: Well, maybe it's just me missing something, but... You are actually not
writing the contents of the file to stdout. You are just reading it into
memory, so it will never show up on the other side of the TCP connection...

Try:

    
    
    sys.stdout.write(open(filepath,"rb").read())
    sys.stdout.flush()
    

Depending on the file size, it might be better to read the file in chunks,
like so:

    
    
    chunk_size = 4096
    handle = open(filepath, "rb")
    
    while True:
        buffer = handle.read(chunk_size)
        if buffer:
            sys.stdout.write(buffer)
        else:
            break
    

Another thing to be aware of: writing binary data to stdout may cause Python
to choke due to encoding issues. This depends on the Python version you are
using.

