Source code for pyams_file.views.file

#
# Copyright (c) 2008-2015 Thierry Florac <tflorac AT ulthar.net>
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#

__docformat__ = 'restructuredtext'

from http.client import NOT_MODIFIED, PARTIAL_CONTENT

from pyramid.response import Response
from pyramid.view import view_config
from zope.dublincore.interfaces import IZopeDublinCore

from pyams_file.interfaces import IFile
from pyams_utils.unicode import translate_string


MAX_RANGE_LENGTH = 1 << 21  # 2 Mb


[docs]@view_config(context=IFile) def FileView(request): """Default file view""" context = request.context # set content type content_type = context.content_type if isinstance(content_type, bytes): content_type = content_type.decode('utf-8') # check for last modification date modified = IZopeDublinCore(context).modified if_modified_since = request.if_modified_since if if_modified_since and (int(modified.timestamp()) <= int(if_modified_since.timestamp())): return Response(content_type=content_type, status=NOT_MODIFIED) response = Response(content_type=content_type, last_modified=modified) body_file = context.get_blob(mode='c') if request.params.get('download') is not None: response.content_disposition = 'attachment; filename="{0}"'.format(translate_string(context.filename, force_lower=False)) # check for range request if request.range is not None: body = body_file.read() body_length = len(body) range_start = request.range.start or 0 if 'Firefox' in request.user_agent: # avoid partial range for Firefox videos range_end = body_length else: range_end = request.range.end or min(body_length, range_start + MAX_RANGE_LENGTH) ranged_body = body[range_start:range_end] response.status = PARTIAL_CONTENT response.headers['Content-Range'] = 'bytes {first}-{last}/{len}'.format(first=range_start, last=range_start + len(ranged_body) - 1, len=body_length) response.body = ranged_body else: response.body_file = body_file return response