Esempio n. 1
0
def swf_file(request):
    sbid = request.matchdict['sbid']
    req_part = request.matchdict['part']

    monograph = Monograph.get(request.db, sbid)
    parts = get_book_parts(monograph._id, request)
    try:
        selected_part = parts[int(req_part)]
    except (IndexError, ValueError):
        raise exceptions.NotFound()

    part = Part.get(request.db, selected_part['part_sbid'])
    try:
        pdf_file = request.db.fetch_attachment(part._id,
                                               part.pdf_file['filename'])
    except (couchdbkit.ResourceNotFound, AttributeError):
        raise exceptions.NotFound()

    swf_file = functions.convert_pdf2swf(pdf_file)

    response = Response(content_type='application/x-shockwave-flash',
                        expires=datetime_rfc822(365))
    response.app_iter = swf_file
    try:
        response.etag = str(hash(swf_file))
    except TypeError:
        #cannot generate a hash for the object, return it without the ETag
        pass

    return response
Esempio n. 2
0
def pdf_file(request):
    sbid = request.matchdict['sbid']
    req_part = request.matchdict['part'].split('-')

    monograph = Monograph.get(request.db, sbid)
    if len(req_part) == 2 and req_part[1] == monograph.isbn:
        try:
            pdf_file = request.db.fetch_attachment(monograph._id, monograph.pdf_file['filename'], stream=True)
        except (couchdbkit.ResourceNotFound, AttributeError):
            raise exceptions.NotFound()
    else:
        parts = get_book_parts(monograph._id, request)
        try:
            selected_part = parts[int(req_part[2])]
        except (IndexError, ValueError):
            raise exceptions.NotFound()

        part = Part.get(request.db, selected_part['part_sbid'])
        try:
            pdf_file = request.db.fetch_attachment(part._id, part.pdf_file['filename'], stream=True)
        except (couchdbkit.ResourceNotFound, AttributeError):
            raise exceptions.NotFound()

    response = Response(content_type='application/pdf', expires=datetime_rfc822(365))
    response.app_iter = pdf_file
    try:
        response.etag = str(hash(pdf_file))
    except TypeError:
        #cannot generate a hash for the object, return it without the ETag
        pass

    return response
Esempio n. 3
0
def get_file_response(filename, document_root=None, accel_header=None):
    """helper the get a file response"""
    if not os.path.isfile(filename):
        return HTTPNotFound()
    resp = Response(content_type=get_mimetype(filename),
                    conditional_response=True)
    resp.content_length = os.path.getsize(filename)
    resp.last_modified = os.path.getmtime(filename)
    resp.etag = '%s-%s-%s' % (os.path.getmtime(filename),
                              os.path.getsize(filename), hash(filename))
    if accel_header:
        if accel_header.lower() == "x-accel-redirect":
            # return full path
            filename = filename[len(os.path.dirname(document_root)):]
            filename = '/%s' % filename.strip('/')
            resp.headers[accel_header.title()] = filename
        elif accel_header.lower() == "x-sendfile":
            # return full path
            resp.headers[accel_header.title()] = filename
        else:
            raise RuntimeError(
                "Can't find a way to use your %s header" % accel_header)
        resp.app_iter = [b'']
    else:
        resp.app_iter = FileIterable(filename)
    return resp
Esempio n. 4
0
def swf_file(request):
    sbid = request.matchdict['sbid']
    req_part = request.matchdict['part']

    monograph = Monograph.get(request.db, sbid)
    if req_part == monograph.isbn:
        try:
            pdf_file = request.db.fetch_attachment(monograph._id, monograph.pdf_file['filename'])
        except (couchdbkit.ResourceNotFound, AttributeError):
            raise exceptions.NotFound()
    else:
        parts = get_book_parts(monograph._id, request)
        try:
            selected_part = parts[int(req_part)]
        except (IndexError, ValueError):
            raise exceptions.NotFound()

        part = Part.get(request.db, selected_part['part_sbid'])
        try:
            pdf_file = request.db.fetch_attachment(part._id, part.pdf_file['filename'])
        except (couchdbkit.ResourceNotFound, AttributeError):
            raise exceptions.NotFound()

    swf_file = functions.convert_pdf2swf(pdf_file)

    response = Response(content_type='application/x-shockwave-flash', expires=datetime_rfc822(365))
    response.app_iter = swf_file
    try:
        response.etag = str(hash(swf_file))
    except TypeError:
        #cannot generate a hash for the object, return it without the ETag
        pass

    return response
Esempio n. 5
0
 def SendFile(self, file):
     """
     Creates the response and sends the file back. Uses the FileIterator.
     
     #!date format
     """
     if not file:
         return HTTPNotFound()
     last_mod = file.mtime()
     if not last_mod:
         last_mod = self.context.meta.pool_change
     r = Response(content_type=str(GetMimeTypeExtension(file.extension)), conditional_response=True)
     iterator = file.iterator()
     if iterator:
         r.app_iter = iterator
     else:
         try:
             r.body = file.read()
         except FileNotFound:
             raise NotFound
     r.content_length = file.size
     r.last_modified = last_mod
     r.etag = '%s-%s' % (last_mod, hash(file.path))
     r.cache_expires(self.fileExpires)
     return r    
Esempio n. 6
0
def cover(request):
    sbid = request.matchdict['sbid']

    response_headers = {'content_type': 'image/jpeg',}

    try:
        monograph = request.db.get(sbid)
        if 'thumbnail' in request.path:
            img = request.db.fetch_attachment(monograph,monograph['cover_thumbnail']['filename'], stream=True)
        else:
            img = request.db.fetch_attachment(monograph,monograph['cover']['filename'], stream=True)
        response_headers['expires'] = datetime_rfc822(365)

    except (couchdbkit.ResourceNotFound, KeyError):
        img = urllib2.urlopen(static_url('scielobooks:static/images/fakecover.jpg', request))

    response = Response(**response_headers)
    response.app_iter = img
    try:
        response.etag = str(hash(img))
    except TypeError:
        #cannot generate a hash for the object, return it without the ETag
        pass

    return response
Esempio n. 7
0
def get_file_response(filename, document_root=None, accel_header=None):
    """helper the get a file response"""
    if not os.path.isfile(filename):
        return HTTPNotFound()
    resp = Response(content_type=get_mimetype(filename),
                    conditional_response=True)
    resp.content_length = os.path.getsize(filename)
    resp.last_modified = os.path.getmtime(filename)
    resp.etag = '%s-%s-%s' % (os.path.getmtime(filename),
                              os.path.getsize(filename), hash(filename))
    if accel_header:
        if accel_header.lower() == "x-accel-redirect":
            # return full path
            filename = filename[len(os.path.dirname(document_root)):]
            filename = '/%s' % filename.strip('/')
            resp.headers[accel_header.title()] = filename
        elif accel_header.lower() == "x-sendfile":
            # return full path
            resp.headers[accel_header.title()] = filename
        else:
            raise RuntimeError("Can't find a way to use your %s header" %
                               accel_header)
        resp.app_iter = [b'']
    else:
        resp.app_iter = FileIterable(filename)
    return resp
Esempio n. 8
0
 def SendFile(self, file):
     """
     Creates the response and sends the file back. Uses the FileIterator.
     
     #!date format
     """
     if not file:
         return HTTPNotFound()
     last_mod = file.mtime()
     if not last_mod:
         last_mod = self.context.meta.pool_change
     r = Response(content_type=str(GetMimeTypeExtension(file.extension)),
                  conditional_response=True)
     iterator = file.iterator()
     if iterator:
         r.app_iter = iterator
     else:
         try:
             r.body = file.read()
         except FileNotFound:
             raise NotFound
     r.content_length = file.size
     r.last_modified = last_mod
     r.etag = '%s-%s' % (last_mod, hash(file.path))
     r.cache_expires(self.fileExpires)
     return r
Esempio n. 9
0
def serve_gridfs_file(file):
    response = Response()
    response.content_type = file.content_type
    response.last_modified = file.upload_date
    response.etag = file.md5
    for chunk in file:
        response.body_file.write(chunk)
    file.close()
    response.content_length = file.length
    return response
Esempio n. 10
0
    def _return_file_response(self, value):

        blob = value['data']
        filename = value['name']
        mimeType = "application/octet-stream"

        try:
            guessed = mimetypes.guess_type(filename, strict=False)[0]
            if guessed:
                mimeType = guessed
        except:
            pass

        if isinstance(blob, str):
            # hmm. no blob image.. (should probably never happen)
            response = Response(blob, content_type=mimeType)
            etag = len(blob)

        elif isinstance(blob, TheBlob):

            # Can't use FileResponse like this because file might be zipped

            # get file path.. don't know the proper way to do this..
            # but open() sort of works..
            #opened_file = blob.open_blob('r')
            etag = blob._blob._p_mtime
            #response = FileResponse(opened_file.name, self.request,
            #                        content_type=mimeType)

            response = Response(blob.get(), content_type=mimeType)

        elif isinstance(blob, Blob):

            # get file path.. don't know the proper way to do this..
            # but open() sort of works..
            opened_file = blob.open('r')

            etag = blob._p_mtime

            response = FileResponse(opened_file.name, self.request,
                                    content_type=mimeType)

        else:
            raise "Not a valid file type"

        # set response caching headers..

        response.etag = str(etag)
        response.cache_expires = (3600 * 24 * 7)

        cd = u'attachment; filename="{0}"'.format(value['name'])
        response.content_disposition = cd.encode('utf-8')

        return response
Esempio n. 11
0
def _make_response(file_path):
    res = Response(content_type=_get_mimetype(file_path),
                   conditional_response=True)
    res.app_iter = FileIterable(file_path)
    res.content_length = os.path.getsize(file_path)
    res.last_modified = os.path.getmtime(file_path)
    res.etag = '{0}-{1}-{2}'.format(os.path.getmtime(file_path),
                                    os.path.getsize(file_path),
                                    hash(file_path))
    filename = os.path.basename(file_path)
    res.content_disposition = 'attachment; filename={0}'.format(filename)
    return res
Esempio n. 12
0
    def test_compresses_streaming_with_etag(self):
        decompressed_body = b"foofoofoofoofoofoofoofoofoofoofoofoofoofoo"
        compressed_body = b"".join(list(gzip_app_iter([decompressed_body])))

        request = pretend.stub(accept_encoding=AcceptEncodingValidHeader("gzip"))
        response = Response(app_iter=iter([decompressed_body]))
        response.etag = "foo"

        compressor(request, response)

        assert response.content_encoding == "gzip"
        assert response.content_length is None
        assert response.body == compressed_body
        assert response.etag == "rfbezwKUdGjz6VPWDLDTvA"
Esempio n. 13
0
    def _return_file_response(self, value):

        blob = value['data']
        filename = value['name']
        mimeType = "image/png"

        try:
            guessed = mimetypes.guess_type(filename, strict=False)[0]
            if guessed:
                mimeType = guessed
        except:
            pass

        if isinstance(blob, str):
            # hmm. no blob image.. (should probably never happen)
            response = Response(blob, content_type=mimeType)
            etag = len(blob)

        elif isinstance(blob, TheBlob):

            # get file path.. don't know the proper way to do this..
            # but open() sort of works..
            opened_file = blob.open_blob('r')

            etag = blob._blob._p_mtime

            response = FileResponse(opened_file.name, self.request,
                    content_type=mimeType)

        elif isinstance(blob, Blob):

            # get file path.. don't know the proper way to do this..
            # but open() sort of works..
            opened_file = blob.open('r')

            etag = blob._p_mtime

            response = FileResponse(opened_file.name, self.request,
                    content_type=mimeType)

        else:
            raise "Not a valid image type"

        # set response caching headers..

        response.etag = str(etag)
        response.cache_expires = (3600 * 24 * 7)

        return response
Esempio n. 14
0
    def download(self, value, filename, request):
        from mimetypes import guess_type
        content_type, encoding = guess_type(filename)

        file_path = value.file_path(filename)

        res = Response(content_type=content_type, conditional_response=True)
        res.app_iter = open(file_path,'rb')
        res.content_length = os.path.getsize(file_path)
        res.last_modified = os.path.getmtime(file_path)
        res.etag = '%s-%s-%s' % (os.path.getmtime(file_path),
                                 os.path.getsize(file_path),
                                 hash(file_path))

        return res
Esempio n. 15
0
 def serve(self, request):
     """ Serve the GridFS file referred to by this object.
     Returns a :class:`pyramid.response.Response` if a matching file was found in the GridFS.
     Otherwise returns :class:`pyramid.httpexceptions.HTTPNotFound`.
     """
     file = self.get_gridfs_file(request)
     if file is None:
         return HTTPNotFound("No file found for %s." % repr(self._id))
     response = Response()
     response.content_type = str(file.content_type)
     response.last_modified = file.upload_date
     response.etag = file.md5
     for chunk in file:
         response.body_file.write(chunk)
     file.close()
     response.content_length = file.length
     return response
Esempio n. 16
0
def epub_file(request):
    sbid = request.matchdict['sbid']

    monograph = Monograph.get(request.db, sbid)
    try:
        epub_file = request.db.fetch_attachment(monograph._id, monograph.epub_file['filename'], stream=True)
    except (couchdbkit.ResourceNotFound, AttributeError, KeyError):
        raise exceptions.NotFound()

    response = Response(content_type='application/epub', expires=datetime_rfc822(365))
    response.app_iter = epub_file
    try:
        response.etag = str(hash(epub_file))
    except TypeError:
        #cannot generate a hash for the object, return it without the ETag
        pass

    return response
Esempio n. 17
0
def epub_file(request):
    sbid = request.matchdict['sbid']

    monograph = Monograph.get(request.db, sbid)
    try:
        epub_file = request.db.fetch_attachment(
            monograph._id, monograph.epub_file['filename'], stream=True)
    except (couchdbkit.ResourceNotFound, AttributeError, KeyError):
        raise exceptions.NotFound()

    response = Response(content_type='application/epub',
                        expires=datetime_rfc822(365))
    response.app_iter = epub_file
    try:
        response.etag = str(hash(epub_file))
    except TypeError:
        #cannot generate a hash for the object, return it without the ETag
        pass

    return response
Esempio n. 18
0
def pdf_file(request):
    sbid = request.matchdict['sbid']
    req_part = request.matchdict['part'].split('-')

    monograph = Monograph.get(request.db, sbid)
    if len(req_part) == 2:

        if req_part[1] != getattr(monograph, 'isbn',
                                  None) and req_part[1] != getattr(
                                      monograph, 'eisbn', None):
            raise exceptions.NotFound()

        try:
            url = static_url(
                'scielobooks:fileserver/{0}/pdf/{1}.pdf'.format(
                    sbid, request.matchdict['part']), request)
            u = urllib2.urlopen(url)
            return HTTPFound(location=url)
        except (urllib2.HTTPError, urllib2.URLError):
            #cannot find in static file server, fetch from db
            try:
                pdf_file = request.db.fetch_attachment(
                    monograph._id, monograph.pdf_file['filename'], stream=True)
            except (couchdbkit.ResourceNotFound, AttributeError):
                raise exceptions.NotFound()
            else:
                if asbool(
                        request.registry.settings.get('fileserver_sync_enable',
                                                      False)):
                    if req_part[1] == getattr(monograph, 'eisbn',
                                              None) and getattr(
                                                  monograph, 'isbn', None):
                        #when the eisbn is registered at an already published book. The eisbn takes
                        #precedence when generating the shortname.
                        source_filename = '-'.join([
                            monograph.shortname.split('-')[0], monograph.isbn
                        ])

                        try:
                            url = static_url(
                                'scielobooks:fileserver/{0}/pdf/{1}.pdf'.
                                format(sbid, source_filename), request)
                            u = urllib2.urlopen(url)
                        except (urllib2.HTTPError, urllib2.URLError):
                            # there are no static files available for this book.
                            fresh_pdf_file = request.db.fetch_attachment(
                                monograph._id,
                                monograph.pdf_file['filename'],
                                stream=True)
                            functions.transfer_static_file(
                                request, fresh_pdf_file, monograph._id,
                                monograph.shortname, 'pdf', request.registry.
                                settings['fileserver_remotebase'])
                        else:
                            dest_filename = monograph.shortname
                            functions.symlink_static_file(
                                request, monograph._id, source_filename,
                                dest_filename, 'pdf', request.registry.
                                settings['fileserver_remotebase'])
                    else:
                        fresh_pdf_file = request.db.fetch_attachment(
                            monograph._id,
                            monograph.pdf_file['filename'],
                            stream=True)
                        functions.transfer_static_file(
                            request, fresh_pdf_file, monograph._id,
                            monograph.shortname, 'pdf',
                            request.registry.settings['fileserver_remotebase'])
    else:
        parts = get_book_parts(monograph._id, request)
        try:
            selected_part = parts[int(req_part[2])]
        except (IndexError, ValueError):
            raise exceptions.NotFound()

        part = Part.get(request.db, selected_part['part_sbid'])
        try:
            pdf_file = request.db.fetch_attachment(part._id,
                                                   part.pdf_file['filename'],
                                                   stream=True)
        except (couchdbkit.ResourceNotFound, AttributeError):
            raise exceptions.NotFound()

    response = Response(content_type='application/pdf',
                        expires=datetime_rfc822(365))
    response.app_iter = pdf_file
    try:
        response.etag = str(hash(pdf_file))
    except TypeError:
        #cannot generate a hash for the object, return it without the ETag
        pass

    return response
Esempio n. 19
0
	def __call__(self):
		make_zip = False

		request = self.request
		user = request.user
		filename = request.context.filename

		download_dir = os.path.join(const._app_path, 'download')
		fnamelower = filename.lower()

		need_super = False
		user_dom = None
		if fnamelower.endswith('cic.zip'):
			need_super = True
			user_dom = user.cic
		elif fnamelower.endswith('vol.zip'):
			need_super = True
			user_dom = user.vol

		if need_super:
			if not user_dom.SuperUser:
				self._security_failure()

		else:
			username = filename.rsplit('_', 1)
			if len(username) != 2 or username[0] != user.Login.replace(' ', '_'):
				self._security_failure()

		if '/' in filename or '\\' in filename or '..' in filename or \
				':' in filename:
			self._security_failure()

		root, ext = os.path.splitext(filename)
		root2, ext2 = os.path.splitext(root)
		if ext.lower() == '.zip' and ext2:
			make_zip = True
			filename = root

		fullpath = None
		if fnamelower.endswith('cic.zip') or fnamelower.endswith('vol.zip'):
			fullpath = os.path.join(download_dir, str(request.dboptions.MemberID).join(os.path.splitext(filename)))
		else:
			fullpath = os.path.join(download_dir, filename)

		relativepath = os.path.relpath(fullpath, download_dir)

		if '..' in relativepath or '/' in relativepath or '\\' in relativepath or \
				':' in relativepath:
			self._security_failure()

		if not os.path.exists(fullpath):
			raise NotFound(_('File not found', request))

		if make_zip:
			file = tempfile.TemporaryFile()
			zip = zipfile.ZipFile(file, 'w', zipfile.ZIP_DEFLATED)
			zip.write(fullpath, strip_accents(filename))
			zip.close()
			length = file.tell()
			file.seek(0)

			res = Response(content_type='application/zip', charset=None)
			res.app_iter = FileIterator(file)
			res.content_length = length
			res.last_modified = os.path.getmtime(fullpath)

		else:
			res = Response(content_type=get_mimetype(ext), conditional_response=True)
			res.app_iter = FileIterable(fullpath)
			res.content_length = os.path.getsize(fullpath)
			res.last_modified = os.path.getmtime(fullpath)
			res.etag = '%s-%s-%s' % (os.path.getmtime(fullpath),
						os.path.getsize(fullpath), hash(fullpath))

		res.headers['Content-Disposition'] = 'attachment;filename=' + strip_accents(request.context.filename).encode('utf8')
		return res
Esempio n. 20
0
def pdf_file(request):
    sbid = request.matchdict['sbid']
    req_part = request.matchdict['part'].split('-')

    monograph = Monograph.get(request.db, sbid)
    if len(req_part) == 2:

        if req_part[1] != getattr(monograph, 'isbn', None) and req_part[1] != getattr(monograph, 'eisbn', None):
            raise exceptions.NotFound()

        try:
            url = static_url('scielobooks:fileserver/{0}/pdf/{1}.pdf'.format(sbid, request.matchdict['part']), request)
            u = urllib2.urlopen(url)
            return HTTPFound(location=url)
        except (urllib2.HTTPError, urllib2.URLError):
            #cannot find in static file server, fetch from db
            try:
                pdf_file = request.db.fetch_attachment(monograph._id, monograph.pdf_file['filename'], stream=True)
            except (couchdbkit.ResourceNotFound, AttributeError):
                raise exceptions.NotFound()
            else:
                if asbool(request.registry.settings.get('fileserver_sync_enable', False)):
                    if req_part[1] == getattr(monograph, 'eisbn', None) and getattr(monograph, 'isbn', None):
                        #when the eisbn is registered at an already published book. The eisbn takes
                        #precedence when generating the shortname.
                        source_filename = '-'.join([monograph.shortname.split('-')[0], monograph.isbn])

                        try:
                            url = static_url('scielobooks:fileserver/{0}/pdf/{1}.pdf'.format(sbid, source_filename), request)
                            u = urllib2.urlopen(url)
                        except (urllib2.HTTPError, urllib2.URLError):
                            # there are no static files available for this book.
                            fresh_pdf_file = request.db.fetch_attachment(monograph._id, monograph.pdf_file['filename'], stream=True)
                            functions.transfer_static_file(request, fresh_pdf_file, monograph._id,
                                monograph.shortname, 'pdf', request.registry.settings['fileserver_remotebase'])
                        else:
                            dest_filename = monograph.shortname
                            functions.symlink_static_file(request, monograph._id, source_filename,
                                dest_filename, 'pdf', request.registry.settings['fileserver_remotebase'])
                    else:
                        fresh_pdf_file = request.db.fetch_attachment(monograph._id, monograph.pdf_file['filename'], stream=True)
                        functions.transfer_static_file(request, fresh_pdf_file, monograph._id,
                            monograph.shortname, 'pdf', request.registry.settings['fileserver_remotebase'])
    else:
        parts = get_book_parts(monograph._id, request)
        try:
            selected_part = parts[int(req_part[2])]
        except (IndexError, ValueError):
            raise exceptions.NotFound()

        part = Part.get(request.db, selected_part['part_sbid'])
        try:
            pdf_file = request.db.fetch_attachment(part._id, part.pdf_file['filename'], stream=True)
        except (couchdbkit.ResourceNotFound, AttributeError):
            raise exceptions.NotFound()

    response = Response(content_type='application/pdf', expires=datetime_rfc822(365))
    response.app_iter = pdf_file
    try:
        response.etag = str(hash(pdf_file))
    except TypeError:
        #cannot generate a hash for the object, return it without the ETag
        pass

    return response
Esempio n. 21
0
    def __call__(self):
        make_zip = False

        request = self.request
        user = request.user
        filename = request.context.filename

        download_dir = os.path.join(const._app_path, "download")
        fnamelower = filename.lower()

        need_super = False
        user_dom = None
        if fnamelower.endswith("cic.zip"):
            need_super = True
            user_dom = user.cic
        elif fnamelower.endswith("vol.zip"):
            need_super = True
            user_dom = user.vol

        if need_super:
            if not user_dom.SuperUser:
                self._security_failure()

        else:
            username = filename.rsplit("_", 1)
            if len(username) != 2 or username[0] != user.Login.replace(
                    " ", "_"):
                self._security_failure()

        if "/" in filename or "\\" in filename or ".." in filename or ":" in filename:
            self._security_failure()

        root, ext = os.path.splitext(filename)
        root2, ext2 = os.path.splitext(root)
        if ext.lower() == ".zip" and ext2:
            make_zip = True
            filename = root

        fullpath = None
        if fnamelower.endswith("cic.zip") or fnamelower.endswith("vol.zip"):
            fullpath = os.path.join(
                download_dir,
                str(request.dboptions.MemberID).join(
                    os.path.splitext(filename)),
            )
        else:
            fullpath = os.path.join(download_dir, filename)

        relativepath = os.path.relpath(fullpath, download_dir)

        if (".." in relativepath or "/" in relativepath or "\\" in relativepath
                or ":" in relativepath):
            self._security_failure()

        if not os.path.exists(fullpath):
            raise NotFound(_("File not found", request))

        if make_zip:
            file = tempfile.TemporaryFile()
            zip = zipfile.ZipFile(file, "w", zipfile.ZIP_DEFLATED)
            zip.write(fullpath, strip_accents(filename))
            zip.close()
            length = file.tell()
            file.seek(0)

            res = Response(content_type="application/zip", charset=None)
            res.app_iter = FileIterator(file)
            res.content_length = length
            res.last_modified = os.path.getmtime(fullpath)

        else:
            res = Response(content_type=get_mimetype(ext),
                           conditional_response=True)
            res.app_iter = FileIterable(fullpath)
            res.content_length = os.path.getsize(fullpath)
            res.last_modified = os.path.getmtime(fullpath)
            res.etag = "{}-{}-{}".format(
                os.path.getmtime(fullpath),
                os.path.getsize(fullpath),
                hash(fullpath),
            )

        res.headers[
            "Content-Disposition"] = "attachment;filename=" + strip_accents(
                request.context.filename)
        return res