Support for wsgi.file_wrapper

Waitress supports the WSGI file_wrapper protocol . Here’s a usage example:

import os

here = os.path.dirname(os.path.abspath(__file__))

def myapp(environ, start_response):
    f = open(os.path.join(here, 'myphoto.jpg'), 'rb')
    headers = [('Content-Type', 'image/jpeg')]
    start_response(
        '200 OK',
        headers
        )
    return environ['wsgi.file_wrapper'](f, 32768)

The file wrapper constructor is accessed via environ['wsgi.file_wrapper']. The signature of the file wrapper constructor is (filelike_object, block_size). Both arguments must be passed as positional (not keyword) arguments. The result of creating a file wrapper should be returned as the app_iter from a WSGI application.

The object passed as filelike_object to the wrapper must be a file-like object which supports at least the read() method, and the read() method must support an optional size hint argument and the read() method must return bytes objects (never unicode). It should support the seek() and tell() methods. If it does not, normal iteration over the filelike_object using the provided block_size is used (and copying is done, negating any benefit of the file wrapper). It should support a close() method.

The specified block_size argument to the file wrapper constructor will be used only when the filelike_object doesn’t support seek and/or tell methods. Waitress needs to use normal iteration to serve the file in this degenerate case (as per the WSGI pec), and this block size will be used as the iteration chunk size. The block_size argument is optional; if it is not passed, a default value 32768 is used.

Waitress will set a Content-Length header on behalf of an application when a file wrapper with a sufficiently file-like object is used if the application hasn’t already set one.

The machinery which handles a file wrapper currently doesn’t do anything particularly special using fancy system calls (it doesn’t use sendfile for example); using it currently just prevents the system from needing to copy data to a temporary buffer in order to send it to the client. No copying of data is done when a WSGI app returns a file wrapper that wraps a sufficiently file-like object. It may do something fancier in the future.