#
# 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