コード例 #1
0
    def serve(self, id, download=False, **kwargs):
        """Serve a :class:`~mediadrop.model.media.MediaFile` binary.

        :param id: File ID
        :type id: ``int``
        :param bool download: If true, serve with an Content-Disposition that
            makes the file download to the users computer instead of playing
            in the browser.
        :raises webob.exc.HTTPNotFound: If no file exists with this ID.
        :raises webob.exc.HTTPNotAcceptable: If an Accept header field
            is present, and if the mimetype of the requested file doesn't
            match, then a 406 (not acceptable) response is returned.

        """
        file = fetch_row(MediaFile, id=id)
        request.perm.assert_permission(u'view', file.media.resource)

        file_type = file.mimetype.encode('utf-8')
        file_name = file.display_name.encode('utf-8')

        file_path = helpers.file_path(file)
        if file_path is None:
            log.warn('No path exists for requested media file: %r', file)
            raise HTTPNotFound()
        file_path = file_path.encode('utf-8')

        if not os.path.exists(file_path):
            log.warn('No such file or directory: %r', file_path)
            raise HTTPNotFound()

        # Ensure the request accepts files with this container
        accept = request.environ.get('HTTP_ACCEPT', '*/*')
        if not mimeparse.best_match([file_type], accept):
            raise HTTPNotAcceptable() # 406

        method = config.get('file_serve_method', None)
        headers = []

        # Serving files with this header breaks playback on iPhone
        if download:
            headers.append(('Content-Disposition',
                            'attachment; filename="%s"' % file_name))

        if method == 'apache_xsendfile':
            # Requires mod_xsendfile for Apache 2.x
            # XXX: Don't send Content-Length or Etag headers,
            #      Apache handles them for you.
            response.headers['X-Sendfile'] = file_path
            response.body = ''

        elif method == 'nginx_redirect':
            # Requires NGINX server configuration:
            # NGINX must have a location block configured that matches
            # the /__mediadrop_serve__ path below (the value configured by
            # setting  "nginx_serve_path" option in the configuration). It
            # should also be configured as an "internal" location to prevent
            # people from surfing directly to it.
            # For more information see: http://wiki.nginx.org/XSendfile
            serve_path = config.get('nginx_serve_path', '__mediadrop_serve__')
            if not serve_path.startswith('/'):
                serve_path = '/' + serve_path
            redirect_filename = '%s/%s' % (serve_path, os.path.basename(file_path))
            response.headers['X-Accel-Redirect'] = redirect_filename


        else:
            app = FileApp(file_path, headers, content_type=file_type)
            return forward(app)

        response.headers['Content-Type'] = file_type
        for header, value in headers:
            response.headers[header] = value

        return None
コード例 #2
0
ファイル: media.py プロジェクト: josuermcosta/mediadrop
    def serve(self, id, download=False, **kwargs):
        """Serve a :class:`~mediadrop.model.media.MediaFile` binary.

        :param id: File ID
        :type id: ``int``
        :param bool download: If true, serve with an Content-Disposition that
            makes the file download to the users computer instead of playing
            in the browser.
        :raises webob.exc.HTTPNotFound: If no file exists with this ID.
        :raises webob.exc.HTTPNotAcceptable: If an Accept header field
            is present, and if the mimetype of the requested file doesn't
            match, then a 406 (not acceptable) response is returned.

        """
        file = fetch_row(MediaFile, id=id)
        request.perm.assert_permission(u'view', file.media.resource)

        file_type = file.mimetype.encode('utf-8')
        file_name = file.display_name.encode('utf-8')

        file_path = helpers.file_path(file)
        if file_path is None:
            log.warn('No path exists for requested media file: %r', file)
            raise HTTPNotFound()
        file_path = file_path.encode('utf-8')

        if not os.path.exists(file_path):
            log.warn('No such file or directory: %r', file_path)
            raise HTTPNotFound()

        # Ensure the request accepts files with this container
        accept = request.environ.get('HTTP_ACCEPT', '*/*')
        if not mimeparse.best_match([file_type], accept):
            raise HTTPNotAcceptable()  # 406

        method = config.get('file_serve_method', None)
        headers = []

        # Serving files with this header breaks playback on iPhone
        if download:
            headers.append(('Content-Disposition',
                            'attachment; filename="%s"' % file_name))

        if method == 'apache_xsendfile':
            # Requires mod_xsendfile for Apache 2.x
            # XXX: Don't send Content-Length or Etag headers,
            #      Apache handles them for you.
            response.headers['X-Sendfile'] = file_path
            response.body = ''

        elif method == 'nginx_redirect':
            # Requires NGINX server configuration:
            # NGINX must have a location block configured that matches
            # the /__mediadrop_serve__ path below (the value configured by
            # setting  "nginx_serve_path" option in the configuration). It
            # should also be configured as an "internal" location to prevent
            # people from surfing directly to it.
            # For more information see: http://wiki.nginx.org/XSendfile
            serve_path = config.get('nginx_serve_path', '__mediadrop_serve__')
            if not serve_path.startswith('/'):
                serve_path = '/' + serve_path
            redirect_filename = '%s/%s' % (serve_path,
                                           os.path.basename(file_path))
            response.headers['X-Accel-Redirect'] = redirect_filename

        else:
            app = FileApp(file_path, headers, content_type=file_type)
            return forward(app)

        response.headers['Content-Type'] = file_type
        for header, value in headers:
            response.headers[header] = value

        return None