コード例 #1
0
ファイル: tile.py プロジェクト: SlideAtlas/SlideAtlas-Server
def tile(image_store_id, image_id, tile_name):
    """
    Return a tile image.

    Note that the 'image_store' and 'image_id' URL parameters are accepted as
    an ObjectIds, to prevent unnecessary database queries if HTTP caching
    causes a 304 (Not Modified) response to be returned.
    """
    response = Response(content_type='image/jpeg')
    # tiles could change, especially if PTIFFs are rebuilt, so mark the ETag as
    #   weak
    # TODO: could we ensure that tiles are immutable?
    response.set_etag('%s-%s-v2' % (image_id, tile_name), weak=True)
    response.cache_control.public = True
    # since Last Modified is not used, and the ETag is weak, setting a max-age
    #   is important, so clients don't cache tiles too long
    response.cache_control.max_age = current_app.get_send_file_max_age(None)
    # Last Modified is not strictly required, per RFC 2616 14.29, and setting
    #   it accurately would require a database query; by leaving it unset,
    #   user agents will use only If-None-Match with ETags for cache validation

    response.make_conditional(request)
    if response.status_code != 304:  # Not Modified
        image_store = models.ImageStore.objects.get_or_404(id=image_store_id)
        try:
            tile_data = image_store.get_tile(image_id, tile_name)
        except models.DoesNotExist as e:
            # TODO: more specific exception
            current_app.logger.warning('Tile not loaded: %s' % e.message)
            return Response('{"error": "Tile loading error: %s"}' % e.message, status=404)
        response.set_data(tile_data)

    return response
コード例 #2
0
ファイル: content.py プロジェクト: jazzband/website
def favicon():
    filename = 'favicon.ico'
    cache_timeout = current_app.get_send_file_max_age(filename)
    favicon_path = safe_join(current_app.static_folder, 'favicons')
    return send_from_directory(favicon_path,
                               filename,
                               mimetype='image/vnd.microsoft.icon',
                               cache_timeout=cache_timeout)
コード例 #3
0
ファイル: documents.py プロジェクト: BelphegorPrime/sipa
 def dispatch_request(self, filename):
     if os.path.isabs(self.directory):
         directory = self.directory
     else:
         directory = os.path.join(current_app.root_path, self.directory)
     cache_timeout = current_app.get_send_file_max_age(filename)
     return send_from_directory(directory, filename,
                                cache_timeout=cache_timeout)
コード例 #4
0
ファイル: cache.py プロジェクト: hguemar/pb
def add_cache_header(response):
    if request.method == 'GET' and not response.cache_control.public:
        prefix = request.blueprint if request.blueprint else current_app.name
        etag = "{}-{}".format(prefix, sha1(response.data).hexdigest())
        response.set_etag(etag)
        response.cache_control.public = True
        response.cache_control.max_age = current_app.get_send_file_max_age(request.path)
        response.make_conditional(request)
    return response
コード例 #5
0
ファイル: helpers.py プロジェクト: drjova/invenio-files-rest
def send_stream(stream, filename, size, mtime, mimetype=None, restricted=True,
                as_attachment=False, etag=None, content_md5=None,
                chunk_size=8192, conditional=True):
    """Send the contents of a file to the client."""
    # Guess mimetype from filename if not provided.
    if mimetype is None and filename:
        mimetype = mimetypes.guess_type(filename)[0]
    if mimetype is None:
        mimetype = 'application/octet-stream'

    # Construct headers
    headers = Headers()
    if as_attachment:
        headers.add('Content-Disposition', 'attachment', filename=filename)
    else:
        headers.add('Content-Disposition', 'inline')
    headers['Content-Length'] = size
    if content_md5:
        headers['Content-MD5'] = content_md5

    # Construct response object.
    rv = current_app.response_class(
        FileWrapper(stream, buffer_size=chunk_size),
        mimetype=mimetype,
        headers=headers,
        direct_passthrough=True,
    )

    # Set etag if defined
    if etag:
        rv.set_etag(etag)

    # Set last modified time
    if mtime is not None:
        rv.last_modified = int(mtime)

    # Set cache-control
    if not restricted:
        rv.cache_control.public = True
        cache_timeout = current_app.get_send_file_max_age(filename)
        if cache_timeout is not None:
            rv.cache_control.max_age = cache_timeout
            rv.expires = int(time() + cache_timeout)

    if conditional:
        rv = rv.make_conditional(request)

    return rv
コード例 #6
0
ファイル: views_file.py プロジェクト: bubanoid/profireader
def send_file(filename_or_fp, mimetype=None, as_attachment=False,
              attachment_filename=None, add_etags=True,
              cache_timeout=None, conditional=False, headers={}):

    """Sends the contents of a file to the client.  This will use the
    most efficient method available and configured.  By default it will
    try to use the WSGI server's file_wrapper support.  Alternatively
    you can set the application's :attr:`~Flask.use_x_sendfile` attribute
    to ``True`` to directly emit an `X-Sendfile` header.  This however
    requires support of the underlying webserver for `X-Sendfile`.

    By default it will try to guess the mimetype for you, but you can
    also explicitly provide one.  For extra security you probably want
    to send certain files as attachment (HTML for instance).  The mimetype
    guessing requires a `filename` or an `attachment_filename` to be
    provided.

    Please never pass filenames to this function from user sources without
    checking them first.  Something like this is usually sufficient to
    avoid security problems::

        if '..' in filename or filename.startswith('/'):
            abort(404)

    .. versionadded:: 0.2

    .. versionadded:: 0.5
       The `add_etags`, `cache_timeout` and `conditional` parameters were
       added.  The default behavior is now to attach etags.

    .. versionchanged:: 0.7
       mimetype guessing and etag support for file objects was
       deprecated because it was unreliable.  Pass a filename if you are
       able to, otherwise attach an etag yourself.  This functionality
       will be removed in Flask 1.0

    .. versionchanged:: 0.9
       cache_timeout pulls its default from application config, when None.

    :param filename_or_fp: the filename of the file to send.  This is
                           relative to the :attr:`~Flask.root_path` if a
                           relative path is specified.
                           Alternatively a file object might be provided
                           in which case `X-Sendfile` might not work and
                           fall back to the traditional method.  Make sure
                           that the file pointer is positioned at the start
                           of data to send before calling :func:`send_file`.
    :param mimetype: the mimetype of the file if provided, otherwise
                     auto detection happens.
    :param as_attachment: set to `True` if you want to send this file with
                          a ``Content-Disposition: attachment`` header.
    :param attachment_filename: the filename for the attachment if it
                                differs from the file's filename.
    :param add_etags: set to `False` to disable attaching of etags.
    :param conditional: set to `True` to enable conditional responses.

    :param cache_timeout: the timeout in seconds for the headers. When `None`
                          (default), this value is set by
                          :meth:`~Flask.get_send_file_max_age` of
                          :data:`~flask.current_app`.
    """
    mtime = None

    if isinstance(filename_or_fp, string_types):
        filename = filename_or_fp
        file = None
    else:
        from warnings import warn
        file = filename_or_fp
        filename = getattr(file, 'name', None)

        # XXX: this behavior is now deprecated because it was unreliable.
        # removed in Flask 1.0
        if not attachment_filename and not mimetype \
           and isinstance(filename, string_types):
            warn(DeprecationWarning('The filename support for file objects '
                'passed to send_file is now deprecated.  Pass an '
                'attach_filename if you want mimetypes to be guessed.'),
                stacklevel=2)
        if add_etags:
            warn(DeprecationWarning('In future flask releases etags will no '
                'longer be generated for file objects passed to the send_file '
                'function because this behavior was unreliable.  Pass '
                'filenames instead if possible, otherwise attach an etag '
                'yourself based on another value'), stacklevel=2)

    if filename is not None:
        if not os.path.isabs(filename):
            filename = os.path.join(current_app.root_path, filename)
    if mimetype is None and (filename or attachment_filename):
        mimetype = mimetypes.guess_type(filename or attachment_filename)[0]
    if mimetype is None:
        mimetype = 'application/octet-stream'

    default_headers = Headers()
    if as_attachment:
        if attachment_filename is None:
            if filename is None:
                raise TypeError('filename unavailable, required for '
                                'sending as attachment')
            attachment_filename = os.path.basename(filename)
        default_headers.add('Content-Disposition', 'attachment',
                    filename=attachment_filename)

    if current_app.use_x_sendfile and filename:
        if file is not None:
            file.close()
        default_headers['X-Sendfile'] = filename
        default_headers['Content-Length'] = os.path.getsize(filename)
        data = None
    else:
        if file is None:
            file = open(filename, 'rb')
            mtime = os.path.getmtime(filename)
            default_headers['Content-Length'] = os.path.getsize(filename)
        data = wrap_file(request.environ, file)

    for headername in headers:
        default_headers[headername] = headers[headername]

    rv = current_app.response_class(data, mimetype=mimetype, headers=default_headers,
                                    direct_passthrough=True)

    # if we know the file modification date, we can store it as the
    # the time of the last modification.
    if mtime is not None:
        rv.last_modified = int(mtime)

    rv.cache_control.public = True
    if cache_timeout is None:
        cache_timeout = current_app.get_send_file_max_age(filename)
    if cache_timeout is not None:
        rv.cache_control.max_age = cache_timeout
        rv.expires = int(time() + cache_timeout)

    if add_etags and filename is not None:
        rv.set_etag('flask-%s-%s-%s' % (
            os.path.getmtime(filename),
            os.path.getsize(filename),
            adler32(
                filename.encode('utf-8') if isinstance(filename, text_type)
                else filename
            ) & 0xffffffff
        ))
        if conditional:
            rv = rv.make_conditional(request)
            # make sure we don't send x-sendfile for servers that
            # ignore the 304 status code for x-sendfile.
            if rv.status_code == 304:
                rv.headers.pop('x-sendfile', None)
    return rv
コード例 #7
0
def send_stream(stream, filename, size, mtime, mimetype=None, restricted=True,
                as_attachment=False, etag=None, content_md5=None,
                chunk_size=8192, conditional=True, trusted=False):
    """Send the contents of a file to the client.

    .. warning::

        It is very easy to be exposed to Cross-Site Scripting (XSS) attacks if
        you serve user uploaded files. Here are some recommendations:

            1. Serve user uploaded files from a separate domain
               (not a subdomain). This way a malicious file can only attack
               other user uploaded files.
            2. Prevent the browser from rendering and executing HTML files (by
               setting ``trusted=False``).
            3. Force the browser to download the file as an attachment
               (``as_attachment=True``).

    :param stream: The file stream to send.
    :param filename: The file name.
    :param size: The file size.
    :param mtime: A Unix timestamp that represents last modified time (UTC).
    :param mimetype: The file mimetype. If ``None``, the module will try to
        guess. (Default: ``None``)
    :param restricted: If the file is not restricted, the module will set the
        cache-control. (Default: ``True``)
    :param as_attachment: If the file is an attachment. (Default: ``False``)
    :param etag: If defined, it will be set as HTTP E-Tag.
    :param content_md5: If defined, a HTTP Content-MD5 header will be set.
    :param chunk_size: The chunk size. (Default: ``8192``)
    :param conditional: Make the response conditional to the request.
        (Default: ``True``)
    :param trusted: Do not enable this option unless you know what you are
        doing. By default this function will send HTTP headers and MIME types
        that prevents your browser from rendering e.g. a HTML file which could
        contain a malicious script tag.
        (Default: ``False``)
    :returns: A Flask response instance.
    """
    # Guess mimetype from filename if not provided.
    if mimetype is None and filename:
        mimetype = mimetypes.guess_type(filename)[0]
    if mimetype is None:
        mimetype = 'application/octet-stream'

    # Construct headers
    headers = Headers()
    headers['Content-Length'] = size
    if content_md5:
        headers['Content-MD5'] = content_md5

    if not trusted:
        # Sanitize MIME type
        mimetype = sanitize_mimetype(mimetype, filename=filename)
        # See https://www.owasp.org/index.php/OWASP_Secure_Headers_Project
        # Prevent JavaScript execution
        headers['Content-Security-Policy'] = "default-src 'none';"
        # Prevent MIME type sniffing for browser.
        headers['X-Content-Type-Options'] = 'nosniff'
        # Prevent opening of downloaded file by IE
        headers['X-Download-Options'] = 'noopen'
        # Prevent cross domain requests from Flash/Acrobat.
        headers['X-Permitted-Cross-Domain-Policies'] = 'none'
        # Prevent files from being embedded in frame, iframe and object tags.
        headers['X-Frame-Options'] = 'deny'
        # Enable XSS protection (IE, Chrome, Safari)
        headers['X-XSS-Protection'] = '1; mode=block'

    # Force Content-Disposition for application/octet-stream to prevent
    # Content-Type sniffing.
    if as_attachment or mimetype == 'application/octet-stream':
        # See https://github.com/pallets/flask/commit/0049922f2e690a6d
        try:
            filenames = {'filename': filename.encode('latin-1')}
        except UnicodeEncodeError:
            filenames = {'filename*': "UTF-8''%s" % url_quote(filename)}
            encoded_filename = (unicodedata.normalize('NFKD', filename)
                                .encode('latin-1', 'ignore'))
            if encoded_filename:
                filenames['filename'] = encoded_filename
        headers.add('Content-Disposition', 'attachment', **filenames)
    else:
        headers.add('Content-Disposition', 'inline')

    # Construct response object.
    rv = current_app.response_class(
        FileWrapper(stream, buffer_size=chunk_size),
        mimetype=mimetype,
        headers=headers,
        direct_passthrough=True,
    )

    # Set etag if defined
    if etag:
        rv.set_etag(etag)

    # Set last modified time
    if mtime is not None:
        rv.last_modified = int(mtime)

    # Set cache-control
    if not restricted:
        rv.cache_control.public = True
        cache_timeout = current_app.get_send_file_max_age(filename)
        if cache_timeout is not None:
            rv.cache_control.max_age = cache_timeout
            rv.expires = int(time() + cache_timeout)

    if conditional:
        rv = rv.make_conditional(request)

    return rv
コード例 #8
0
def send_stream(stream,
                filename,
                size,
                mtime,
                mimetype=None,
                restricted=True,
                as_attachment=False,
                etag=None,
                content_md5=None,
                chunk_size=None,
                conditional=True,
                trusted=False):
    """Send the contents of a file to the client.

    .. warning::

        It is very easy to be exposed to Cross-Site Scripting (XSS) attacks if
        you serve user uploaded files. Here are some recommendations:

            1. Serve user uploaded files from a separate domain
               (not a subdomain). This way a malicious file can only attack
               other user uploaded files.
            2. Prevent the browser from rendering and executing HTML files (by
               setting ``trusted=False``).
            3. Force the browser to download the file as an attachment
               (``as_attachment=True``).

    :param stream: The file stream to send.
    :param filename: The file name.
    :param size: The file size.
    :param mtime: A Unix timestamp that represents last modified time (UTC).
    :param mimetype: The file mimetype. If ``None``, the module will try to
        guess. (Default: ``None``)
    :param restricted: If the file is not restricted, the module will set the
        cache-control. (Default: ``True``)
    :param as_attachment: If the file is an attachment. (Default: ``False``)
    :param etag: If defined, it will be set as HTTP E-Tag.
    :param content_md5: If defined, a HTTP Content-MD5 header will be set.
    :param chunk_size: The chunk size.
    :param conditional: Make the response conditional to the request.
        (Default: ``True``)
    :param trusted: Do not enable this option unless you know what you are
        doing. By default this function will send HTTP headers and MIME types
        that prevents your browser from rendering e.g. a HTML file which could
        contain a malicious script tag.
        (Default: ``False``)
    :returns: A Flask response instance.
    """
    chunk_size = chunk_size_or_default(chunk_size)

    # Guess mimetype from filename if not provided.
    if mimetype is None and filename:
        mimetype = mimetypes.guess_type(filename)[0]
    if mimetype is None:
        mimetype = 'application/octet-stream'

    # Construct headers
    headers = Headers()
    headers['Content-Length'] = size
    if content_md5:
        headers['Content-MD5'] = content_md5

    if not trusted:
        # Sanitize MIME type
        mimetype = sanitize_mimetype(mimetype, filename=filename)
        # See https://www.owasp.org/index.php/OWASP_Secure_Headers_Project
        # Prevent JavaScript execution
        headers['Content-Security-Policy'] = "default-src 'none';"
        # Prevent MIME type sniffing for browser.
        headers['X-Content-Type-Options'] = 'nosniff'
        # Prevent opening of downloaded file by IE
        headers['X-Download-Options'] = 'noopen'
        # Prevent cross domain requests from Flash/Acrobat.
        headers['X-Permitted-Cross-Domain-Policies'] = 'none'
        # Prevent files from being embedded in frame, iframe and object tags.
        headers['X-Frame-Options'] = 'deny'
        # Enable XSS protection (IE, Chrome, Safari)
        headers['X-XSS-Protection'] = '1; mode=block'

    # Force Content-Disposition for application/octet-stream to prevent
    # Content-Type sniffing.
    if as_attachment or mimetype == 'application/octet-stream':
        # See https://github.com/pallets/flask/commit/0049922f2e690a6d
        try:
            filenames = {'filename': filename.encode('latin-1')}
        except UnicodeEncodeError:
            filenames = {'filename*': "UTF-8''%s" % url_quote(filename)}
            encoded_filename = (unicodedata.normalize('NFKD', filename).encode(
                'latin-1', 'ignore'))
            if encoded_filename:
                filenames['filename'] = encoded_filename
        headers.add('Content-Disposition', 'attachment', **filenames)
    else:
        headers.add('Content-Disposition', 'inline')

    # Construct response object.
    rv = current_app.response_class(
        FileWrapper(stream, buffer_size=chunk_size),
        mimetype=mimetype,
        headers=headers,
        direct_passthrough=True,
    )

    # Set etag if defined
    if etag:
        rv.set_etag(etag)

    # Set last modified time
    if mtime is not None:
        rv.last_modified = int(mtime)

    # Set cache-control
    if not restricted:
        rv.cache_control.public = True
        cache_timeout = current_app.get_send_file_max_age(filename)
        if cache_timeout is not None:
            rv.cache_control.max_age = cache_timeout
            rv.expires = int(time() + cache_timeout)

    if conditional:
        rv = rv.make_conditional(request)

    return rv
コード例 #9
0
def send_file(filename_or_fp,
              mimetype=None,
              as_attachment=False,
              attachment_filename=None,
              add_etags=True,
              cache_timeout=None,
              conditional=False,
              headers={}):
    """Sends the contents of a file to the client.  This will use the
    most efficient method available and configured.  By default it will
    try to use the WSGI server's file_wrapper support.  Alternatively
    you can set the application's :attr:`~Flask.use_x_sendfile` attribute
    to ``True`` to directly emit an `X-Sendfile` header.  This however
    requires support of the underlying webserver for `X-Sendfile`.

    By default it will try to guess the mimetype for you, but you can
    also explicitly provide one.  For extra security you probably want
    to send certain files as attachment (HTML for instance).  The mimetype
    guessing requires a `filename` or an `attachment_filename` to be
    provided.

    Please never pass filenames to this function from user sources without
    checking them first.  Something like this is usually sufficient to
    avoid security problems::

        if '..' in filename or filename.startswith('/'):
            abort(404)

    .. versionadded:: 0.2

    .. versionadded:: 0.5
       The `add_etags`, `cache_timeout` and `conditional` parameters were
       added.  The default behavior is now to attach etags.

    .. versionchanged:: 0.7
       mimetype guessing and etag support for file objects was
       deprecated because it was unreliable.  Pass a filename if you are
       able to, otherwise attach an etag yourself.  This functionality
       will be removed in Flask 1.0

    .. versionchanged:: 0.9
       cache_timeout pulls its default from application config, when None.

    :param filename_or_fp: the filename of the file to send.  This is
                           relative to the :attr:`~Flask.root_path` if a
                           relative path is specified.
                           Alternatively a file object might be provided
                           in which case `X-Sendfile` might not work and
                           fall back to the traditional method.  Make sure
                           that the file pointer is positioned at the start
                           of data to send before calling :func:`send_file`.
    :param mimetype: the mimetype of the file if provided, otherwise
                     auto detection happens.
    :param as_attachment: set to `True` if you want to send this file with
                          a ``Content-Disposition: attachment`` header.
    :param attachment_filename: the filename for the attachment if it
                                differs from the file's filename.
    :param add_etags: set to `False` to disable attaching of etags.
    :param conditional: set to `True` to enable conditional responses.

    :param cache_timeout: the timeout in seconds for the headers. When `None`
                          (default), this value is set by
                          :meth:`~Flask.get_send_file_max_age` of
                          :data:`~flask.current_app`.
    """
    mtime = None

    if isinstance(filename_or_fp, string_types):
        filename = filename_or_fp
        file = None
    else:
        from warnings import warn
        file = filename_or_fp
        filename = getattr(file, 'name', None)

        # XXX: this behavior is now deprecated because it was unreliable.
        # removed in Flask 1.0
        if not attachment_filename and not mimetype \
           and isinstance(filename, string_types):
            warn(DeprecationWarning(
                'The filename support for file objects '
                'passed to send_file is now deprecated.  Pass an '
                'attach_filename if you want mimetypes to be guessed.'),
                 stacklevel=2)
        if add_etags:
            warn(DeprecationWarning(
                'In future flask releases etags will no '
                'longer be generated for file objects passed to the send_file '
                'function because this behavior was unreliable.  Pass '
                'filenames instead if possible, otherwise attach an etag '
                'yourself based on another value'),
                 stacklevel=2)

    if filename is not None:
        if not os.path.isabs(filename):
            filename = os.path.join(current_app.root_path, filename)
    if mimetype is None and (filename or attachment_filename):
        mimetype = mimetypes.guess_type(filename or attachment_filename)[0]
    if mimetype is None:
        mimetype = 'application/octet-stream'

    default_headers = Headers()
    if as_attachment:
        if attachment_filename is None:
            if filename is None:
                raise TypeError('filename unavailable, required for '
                                'sending as attachment')
            attachment_filename = os.path.basename(filename)
        default_headers.add('Content-Disposition',
                            'attachment',
                            filename=attachment_filename)

    if current_app.use_x_sendfile and filename:
        if file is not None:
            file.close()
        default_headers['X-Sendfile'] = filename
        default_headers['Content-Length'] = os.path.getsize(filename)
        data = None
    else:
        if file is None:
            file = open(filename, 'rb')
            mtime = os.path.getmtime(filename)
            default_headers['Content-Length'] = os.path.getsize(filename)
        data = wrap_file(request.environ, file)

    for headername in headers:
        default_headers[headername] = headers[headername]

    rv = current_app.response_class(data,
                                    mimetype=mimetype,
                                    headers=default_headers,
                                    direct_passthrough=True)

    # if we know the file modification date, we can store it as the
    # the time of the last modification.
    if mtime is not None:
        rv.last_modified = int(mtime)

    rv.cache_control.public = True
    if cache_timeout is None:
        cache_timeout = current_app.get_send_file_max_age(filename)
    if cache_timeout is not None:
        rv.cache_control.max_age = cache_timeout
        rv.expires = int(time() + cache_timeout)

    if add_etags and filename is not None:
        rv.set_etag('flask-%s-%s-%s' %
                    (os.path.getmtime(filename), os.path.getsize(filename),
                     adler32(
                         filename.encode('utf-8') if isinstance(
                             filename, text_type) else filename) & 0xffffffff))
        if conditional:
            rv = rv.make_conditional(request)
            # make sure we don't send x-sendfile for servers that
            # ignore the 304 status code for x-sendfile.
            if rv.status_code == 304:
                rv.headers.pop('x-sendfile', None)
    return rv
コード例 #10
0
def send_stream(stream,
                filename,
                size,
                mtime,
                mimetype=None,
                restricted=True,
                as_attachment=False,
                etag=None,
                content_md5=None,
                chunk_size=8192,
                conditional=True):
    """Send the contents of a file to the client.

    :param stream: The file stream to send.
    :param filename: The file name.
    :param size: The file size.
    :param mtime: A Unix timestamp that represents last modified time.
    :param mimetype: The file mimetype. If ``None``, the module will try to
        guess. (Default: ``None``)
    :param restricted: If the file is not restricted, the module will set the
        cache-control. (Default: ``True``)
    :param as_attachment: If the file is an attachment. (Default: ``False``)
    :param etag: If defined, it will be set as HTTP E-Tag.
    :param content_md5: If defined, a HTTP Content-MD5 header will be set.
    :param chunk_size: The chunk size. (Default: ``8192``)
    :param conditional: Make the response conditional to the request.
        (Default: ``True``)
    :returns: A Flask response instance.
    """
    # Guess mimetype from filename if not provided.
    if mimetype is None and filename:
        mimetype = mimetypes.guess_type(filename)[0]
    if mimetype is None:
        mimetype = 'application/octet-stream'

    # Construct headers
    headers = Headers()
    if as_attachment:
        headers.add('Content-Disposition', 'attachment', filename=filename)
    else:
        headers.add('Content-Disposition', 'inline')
    headers['Content-Length'] = size
    if content_md5:
        headers['Content-MD5'] = content_md5

    # Construct response object.
    rv = current_app.response_class(
        FileWrapper(stream, buffer_size=chunk_size),
        mimetype=mimetype,
        headers=headers,
        direct_passthrough=True,
    )

    # Set etag if defined
    if etag:
        rv.set_etag(etag)

    # Set last modified time
    if mtime is not None:
        rv.last_modified = int(mtime)

    # Set cache-control
    if not restricted:
        rv.cache_control.public = True
        cache_timeout = current_app.get_send_file_max_age(filename)
        if cache_timeout is not None:
            rv.cache_control.max_age = cache_timeout
            rv.expires = int(time() + cache_timeout)

    if conditional:
        rv = rv.make_conditional(request)

    return rv
コード例 #11
0
def send_stream(stream, filename, size, mtime, mimetype=None, restricted=True,
                as_attachment=False, etag=None, content_md5=None,
                chunk_size=8192, conditional=True):
    """Send the contents of a file to the client.

    :param stream: The file stream to send.
    :param filename: The file name.
    :param size: The file size.
    :param mtime: A Unix timestamp that represents last modified time.
    :param mimetype: The file mimetype. If ``None``, the module will try to
        guess. (Default: ``None``)
    :param restricted: If the file is not restricted, the module will set the
        cache-control. (Default: ``True``)
    :param as_attachment: If the file is an attachment. (Default: ``False``)
    :param etag: If defined, it will be set as HTTP E-Tag.
    :param content_md5: If defined, a HTTP Content-MD5 header will be set.
    :param chunk_size: The chunk size. (Default: ``8192``)
    :param conditional: Make the response conditional to the request.
        (Default: ``True``)
    :returns: A Flask response instance.
    """
    # Guess mimetype from filename if not provided.
    if mimetype is None and filename:
        mimetype = mimetypes.guess_type(filename)[0]
    if mimetype is None:
        mimetype = 'application/octet-stream'

    # Construct headers
    headers = Headers()
    if as_attachment:
        headers.add('Content-Disposition', 'attachment', filename=filename)
    else:
        headers.add('Content-Disposition', 'inline')
    headers['Content-Length'] = size
    if content_md5:
        headers['Content-MD5'] = content_md5

    # Construct response object.
    rv = current_app.response_class(
        FileWrapper(stream, buffer_size=chunk_size),
        mimetype=mimetype,
        headers=headers,
        direct_passthrough=True,
    )

    # Set etag if defined
    if etag:
        rv.set_etag(etag)

    # Set last modified time
    if mtime is not None:
        rv.last_modified = int(mtime)

    # Set cache-control
    if not restricted:
        rv.cache_control.public = True
        cache_timeout = current_app.get_send_file_max_age(filename)
        if cache_timeout is not None:
            rv.cache_control.max_age = cache_timeout
            rv.expires = int(time() + cache_timeout)

    if conditional:
        rv = rv.make_conditional(request)

    return rv