Download Install Tutorial Docs FAQ Tools WikiLicense Team IRC Planet Involvement Shop Book

Downloading files

CherryPy allows you to serve a file from your page handler. Here is a simple recipe to handle downloads:

import glob
import os.path

import cherrypy
from cherrypy.lib.static import serve_file


class Root:
    def index(self, directory="."):
        html = """<html><body><h2>Here are the files in the selected directory:</h2>
        <a href="index?directory=%s">Up</a><br />
        """ % os.path.dirname(os.path.abspath(directory))

        for filename in glob.glob(directory + '/*'):
            absPath = os.path.abspath(filename)
            if os.path.isdir(absPath):
                html += '<a href="/index?directory=' + absPath + '">' + os.path.basename(filename) + "</a> <br />"
            else:
                html += '<a href="/download/?filepath=' + absPath + '">' + os.path.basename(filename) + "</a> <br />"
                
        html += """</body></html>"""
        return html
    index.exposed = True

class Download:
    
    def index(self, filepath):
        return serve_file(filepath, "application/x-download", "attachment")
    index.exposed = True

if __name__ == '__main__':
    root = Root()
    root.download = Download()
    cherrypy.quickstart(root)

Note that CherryPy is not the fastest for doing such things. If you think you'll have many and big downloads, put CP BehindApache? and let Apache serve those files.

Older versions

replace this with this
2.2cherrypy.quickstart(root)cherrypy.root = root
cherrypy.server.start()
from cherrypy.lib.static import serve_filefrom cherrypy.lib.cptools import serveFile

2.0

import os
from cherrypy import cpg

def file2Generator(f):
    while True:
        data = f.read(1024 * 8) # Read blocks of 8KB at a time
        if not data: break
        yield data

class Root:
    def download(self, path):
        fStat = os.stat(path)
        cpg.response.headerMap["Content-Type"] = "application/x-download"
        cpg.response.headerMap['Content-Length'] = int(fStat.st_size)
        f = open(path, 'rb')
        return file2Generator(f)
    download.exposed = True

cpg.root = Root()
cpg.server.start() 
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Simple downloader script

import sys
import glob
import os.path

from cherrypy import cpg
from cherrypy.lib.filter.basefilter import BaseOutputFilter

class DownloadFilter(BaseOutputFilter):
    def __init__(self):
        self.filepath = None
        
    def beforeResponse(self):
        self.filepath = cpg.response.body[0]
        # Let's learn more about the file...
        fStat = os.stat(self.filepath)
        # CP doc states that we must call this if we write directly to the socket
        cpg.response.sendResponse = False
        # Let's define some headers. For simplicity we send only one type of content type
        cpg.response.headerMap["Content-Type"] = "application/x-download"
        # Make sure we know during the process the size of the file
        cpg.response.headerMap["Content-Length"] = int(fStat.st_size)
        # Let's tell the client we have an attachment for it
        cpg.response.headerMap["Content-Disposition"] = "attachment; filename=%s" % (os.path.basename(self.filepath), )
        # Send now the information
        cpg.response.wfile.flush()
        
    def afterResponse(self):
        # Now send the file to the client
        cpg.response.wfile.writelines(file(self.filepath, 'rb').readlines())
        #cp.response.flush()
            
class Root:
    def index(self, directory="."):
        html = """<html>
        <head />
        <body>
        <h2>Here are the files in the selected directory :</h2>
        <a href="index?directory=%s">Up</a>
        <br />
        """ % (os.path.dirname(os.path.abspath(directory)), )

        for filename in glob.glob(directory + '/*'):
            absPath = os.path.abspath(filename)
            if os.path.isdir(absPath):
                html += '<a href="/index?directory=' + absPath + '">' + os.path.basename(filename) + "</a> <br />"
            else:
                html += '<a href="/download/?filepath=' + absPath + '">' + os.path.basename(filename) + "</a> <br />"
                
        html += """</body></html>"""
        return html
    index.exposed = True

class Download:
    _cpFilterList = [ DownloadFilter() ]
    
    def index(self, filepath):
        return filepath
    index.exposed = True
    
cpg.root = Root()
cpg.root.download = Download()
cpg.server.start()

Hosted by WebFaction

Log in as guest/cpguest to create tickets