예제 #1
0
파일: media.py 프로젝트: 86me/mediacore
    def serve(self, id, slug, container, **kwargs):
        """Serve a :class:`~mediacore.model.media.MediaFile` binary.

        :param id: File ID
        :type id: ``int``
        :param slug: The media :attr:`~mediacore.model.media.Media.slug`
        :type slug: The file :attr:`~mediacore.model.media.MediaFile.container`
        :raises webob.exc.HTTPNotFound: If no file exists for the given params.
        :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.

        """
        media = fetch_row(Media, slug=slug)

        for file in media.files:
            if file.id == id and file.container == container:
                # Catch external redirects in case they aren't linked to directly
                if file.url:
                    redirect(file.url.encode('utf-8'))

                # Ensure that the clients request allows for files of this container
                mimetype = mimeparse.best_match([file.mimetype],
                    request.environ.get('HTTP_ACCEPT', '*/*'))
                if mimetype == '':
                    raise webob.exc.HTTPNotAcceptable() # 406

                response.headers['Content-Type'] = mimetype
                response.headers['Content-Disposition'] = \
                    'attachment;filename="%s"' % file.display_name.encode('utf-8')
                return open(file.file_path, 'rb').read()
        else:
            raise webob.exc.HTTPNotFound()
예제 #2
0
    def feed(self, limit=30, **kwargs):
        """ Generate a media rss feed of the latest media

        :param limit: the max number of results to return. Defaults to 30

        """
        if request.settings['rss_display'] != 'True':
            abort(404)

        response.content_type = mimeparse.best_match(
            ['application/rss+xml', 'application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*')
        )

        media = Media.query.published()

        if c.category:
            media = media.in_category(c.category)

        media = media.order_by(Media.publish_on.desc()).limit(limit)

        return dict(
            media = media,
            title = u'%s Media' % c.category.name,
        )
예제 #3
0
    def feed(self, limit=30, **kwargs):
        """ Generate a media rss feed of the latest media

        :param limit: the max number of results to return. Defaults to 30

        """
        if app_globals.settings['rss_display'] != 'True':
            abort(404)

        response.content_type = mimeparse.best_match(
            ['application/rss+xml', 'application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*')
        )

        media = Media.query.published()

        if c.category:
            media = media.in_category(c.category)

        media = media.order_by(Media.publish_on.desc()).limit(limit)

        return dict(
            media = media,
            title = u'%s Media' % c.category.name,
        )
예제 #4
0
    def get_request(self, delegation_id):
        request_formats = ('application/x-pkcs10+der', 'application/x-pkcs10', 'application/x-pkcs10+pem')
        format = mimeparse.best_match(request_formats, request.headers.get('Accept', '*/*'))
        if format == '':
            format = request_formats[0]
        enc = 'der'
        if '+' in format:
            enc = format.split('+')[1]
        if enc not in ('pem', 'der'):
            abort(412, 'This object may be served only in these Content-Types: %s.' % ', '.join(request_formats),
                  headers={'Content-Type': 'text/plain'})
            
        delegation = self.find_delegation(delegation_id)
        if delegation.new_key is None:
            delegation.new_key = make_key()
            Session.flush()

        pkey = EVP.PKey()
        pkey.assign_rsa(delegation.new_key)

        req = X509.Request()
        req.set_pubkey(pkey)

        subj = X509.X509_Name()
        digest = EVP.MessageDigest('sha1')
        digest.update(pkey.as_der())
        serial = struct.unpack("<L", digest.final()[:4])[0]
        subj.add_entry_by_txt('CN', ASN1.MBSTRING_ASC, str(serial), -1, -1, 0)
        req.set_subject(subj)
        req.sign(pkey, 'sha1')

        if enc == 'pem':
            return render_data(req.as_pem(), format)
        else:
            return render_data(req.as_der(), format)
예제 #5
0
    def serve(self, id, download=False, **kwargs):
        """Serve a :class:`~mediacore.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)

        file_path = helpers.file_path(file).encode('utf-8')
        file_type = file.mimetype.encode('utf-8')
        file_name = file.display_name.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 = ''
            response.headers.update(headers)
        elif method == 'nginx_redirect':
            for header in ['pragma', 'cache-control', "content-type"]:
                if header in response.headers:
                    del response.headers[header]
            response.headers['X-Accel-Redirect'] = file_path
            response.headers.update(headers)
        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
예제 #6
0
파일: decorators.py 프로젝트: chiehwen/tg2
    def lookup_template_engine(self, request):
        """Return the template engine data.

        Provides a convenience method to get the proper engine,
        content_type, template, and exclude_names for a particular
        tg_format (which is pulled off of the request headers).

        """

        if hasattr(request, 'response_type'
                ) and request.response_type in self.engines:
            accept_types = request.response_type
        else:
            accept_types = request.headers.get('accept', '*/*')

        try:
            render_custom_format = request._render_custom_format[
                self.controller]
        except:
            render_custom_format = self.render_custom_format

        if render_custom_format:
            (content_type, engine, template, exclude_names, render_params
                ) = self.custom_engines[render_custom_format]
        else:
            if self.engines:
                content_type = best_match(self.engines_keys, accept_types)
            else:
                content_type = 'text/html'

            if content_type == 'CUSTOM/LEAVE':
                warn('@expose(CUSTOM_CONTENT_TYPE) is no longer needed'
                     ' and should be replaced with @expose()')

            # check for overridden content type from the controller call
            controller_content_type = response.headers.get('Content-Type')

            if controller_content_type:
                # make sure we handle types like 'text/html; charset=utf-8'
                content_type = controller_content_type.split(';', 1)[0]

            # check for overridden templates
            try:
                (engine, template, exclude_names, render_params
                    ) = request._override_mapping[
                            self.controller][content_type.split(';', 1)[0]]
            except (AttributeError, KeyError):
                (engine, template, exclude_names, render_params
                    ) = self.engines.get(content_type, (None,) * 4)

        if 'charset' not in content_type and (content_type.startswith('text')
                or  content_type in ('application/xhtml+xml',
                        'application/xml', 'application/json')):
            content_type = '%s; charset=utf-8' % content_type

        return content_type, engine, template, exclude_names, render_params
예제 #7
0
파일: decorators.py 프로젝트: clsdaniel/tg2
    def lookup_template_engine(self, request):
        """Return the template engine data.

        Provides a convenience method to get the proper engine,
        content_type, template, and exclude_names for a particular
        tg_format (which is pulled off of the request headers).

        """

        if hasattr(request,
                   'response_type') and request.response_type in self.engines:
            accept_types = request.response_type
        else:
            accept_types = request.headers.get('accept', '*/*')

        try:
            render_custom_format = request._render_custom_format[
                self.controller]
        except:
            render_custom_format = self.render_custom_format

        if render_custom_format:
            (content_type, engine, template, exclude_names,
             render_params) = self.custom_engines[render_custom_format]
        else:
            if self.engines:
                content_type = best_match(self.engines_keys, accept_types)
            else:
                content_type = 'text/html'

            if content_type == 'CUSTOM/LEAVE':
                warn('@expose(CUSTOM_CONTENT_TYPE) is no longer needed'
                     ' and should be replaced with @expose()')

            # check for overridden content type from the controller call
            controller_content_type = response.headers.get('Content-Type')

            if controller_content_type:
                # make sure we handle types like 'text/html; charset=utf-8'
                content_type = controller_content_type.split(';', 1)[0]

            # check for overridden templates
            try:
                (engine, template, exclude_names,
                 render_params) = request._override_mapping[self.controller][
                     content_type.split(';', 1)[0]]
            except (AttributeError, KeyError):
                (engine, template, exclude_names,
                 render_params) = self.engines.get(content_type, (None, ) * 4)

        if 'charset' not in content_type and (
                content_type.startswith('text') or content_type in
            ('application/xhtml+xml', 'application/xml', 'application/json')):
            content_type = '%s; charset=utf-8' % content_type

        return content_type, engine, template, exclude_names, render_params
예제 #8
0
파일: helpers.py 프로젝트: micheg/mediadrop
def content_type_for_response(available_formats):
    content_type = mimeparse.best_match(available_formats, request.environ.get("HTTP_ACCEPT", "*/*"))
    # force a content-type: if the user agent did not specify any acceptable
    # content types (e.g. just 'text/html' like some bots) we still need to
    # set a content type, otherwise the WebOb will generate an exception
    # AttributeError: You cannot access Response.unicode_body unless charset
    # the only alternative to forcing a "bad" content type would be not to
    # deliver any content at all - however most bots are just faulty and they
    # requested something like 'sitemap.xml'.
    return content_type or available_formats[0]
예제 #9
0
def content_type_for_response(available_formats):
    content_type = mimeparse.best_match(
        available_formats, request.environ.get('HTTP_ACCEPT', '*/*'))
    # force a content-type: if the user agent did not specify any acceptable
    # content types (e.g. just 'text/html' like some bots) we still need to
    # set a content type, otherwise the WebOb will generate an exception
    # AttributeError: You cannot access Response.unicode_body unless charset
    # the only alternative to forcing a "bad" content type would be not to
    # deliver any content at all - however most bots are just faulty and they
    # requested something like 'sitemap.xml'.
    return content_type or available_formats[0]
예제 #10
0
    def mrss(self, **kwargs):
        """Generate a media rss (mRSS) feed of all the sites media."""
        if app_globals.settings["sitemaps_display"] != "True":
            abort(404)

        response.content_type = mimeparse.best_match(
            ["application/rss+xml", "application/xml", "text/xml"], request.environ.get("HTTP_ACCEPT", "*/*")
        )

        media = Media.query.published()

        return dict(media=media, title="MediaRSS Sitemap")
예제 #11
0
    def mrss(self, **kwargs):
        """Generate a media rss (mRSS) feed of all the sites media."""

        response.content_type = mimeparse.best_match(
            ['application/rss+xml', 'application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*')
        )

        media = Media.query.published()

        return dict(
            media = media,
            title = 'MediaRSS Sitemap',
        )
예제 #12
0
    def featured(self, limit=30, skip=0, **kwargs):
        """Generate a media rss (mRSS) feed of the sites featured media."""
        if app_globals.settings["rss_display"] != "True":
            abort(404)

        response.content_type = mimeparse.best_match(
            ["application/rss+xml", "application/xml", "text/xml"], request.environ.get("HTTP_ACCEPT", "*/*")
        )

        media = Media.query.in_category(get_featured_category()).order_by(Media.publish_on.desc()).limit(limit)

        if skip > 0:
            media = media.offset(skip)

        return dict(media=media, title="Featured Media")
예제 #13
0
    def mrss(self, **kwargs):
        """Generate a media rss (mRSS) feed of all the sites media."""
        if request.settings['sitemaps_display'] != 'True':
            abort(404)

        response.content_type = mimeparse.best_match(
            ['application/rss+xml', 'application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*'))

        media = Media.query.published()

        return dict(
            media=media,
            title='MediaRSS Sitemap',
        )
예제 #14
0
    def latest(self, limit=30, **kwargs):
        """Generate a media rss (mRSS) feed of all the sites media."""

        response.content_type = mimeparse.best_match(
            ['application/rss+xml', 'application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*')
        )

        media = Media.query.published()\
            .order_by(Media.publish_on.desc())\
            .limit(limit)\
            .all()

        return dict(
            media = media,
            title = 'Latest Media',
        )
예제 #15
0
    def lookup_template_engine(self, request):
        """Return the template engine data.

        Provides a convenience method to get the proper engine,
        content_type, template, and exclude_names for a particular
        tg_format (which is pulled off of the request headers).
        """
        #remove this after deprecation period for tg_format
        tg_format = request.headers.get('tg_format')

        if hasattr(request,
                   'response_type') and request.response_type in self.engines:
            accept_types = request.response_type

        elif tg_format:
            warnings.warn(
                'tg_format is now deprecated.  Use .mimetype in your URL to create the same behavior'
            )
            if '/' not in tg_format:
                accept_types = mimetypes.guess_type('.' + tg_format)[0]
                if accept_types is None:
                    raise Exception('Unknown mimetype: %s' % tg_format)
            else:
                accept_types = tg_format
        else:
            accept_types = request.headers.get('accept', '*/*')

        if self.render_custom_format:
            content_type, engine, template, exclude_names = self.custom_engines[
                self.render_custom_format]

        else:
            content_type = best_match(self.engines.keys(), accept_types)
            # check for overridden templates
            try:
                engine, template, exclude_names = request._override_mapping[
                    self.controller][content_type]
            except (AttributeError, KeyError):
                engine, template, exclude_names = self.engines[content_type]

        if 'charset' not in content_type and (content_type.startswith('text')
                                              or content_type
                                              == 'application/json'):
            content_type = '%s; charset=utf-8' % content_type

        return content_type, engine, template, exclude_names
예제 #16
0
    def google(self, page=None, limit=10000, **kwargs):
        """Generate a sitemap which contains googles Video Sitemap information.

        This action may return a <sitemapindex> or a <urlset>, depending
        on how many media items are in the database, and the values of the
        page and limit params.

        :param page: Page number, defaults to 1.
        :type page: int
        :param page: max records to display on page, defaults to 10000.
        :type page: int

        """
        if request.settings['sitemaps_display'] != 'True':
            abort(404)

        response.content_type = mimeparse.best_match(
            ['application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*')
        )

        media = Media.query.published()

        if page is None:
            if media.count() > limit:
                return dict(pages=math.ceil(media.count() / float(limit)))
        else:
            page = int(page)
            media = media.offset(page * limit).limit(limit)

        if page:
            links = []
        else:
            links = [
                url_for(controller='/', qualified=True),
                url_for(controller='/media', show='popular', qualified=True),
                url_for(controller='/media', show='latest', qualified=True),
                url_for(controller='/categories', qualified=True),
            ]

        return dict(
            media = media,
            page = page,
            links = links,
        )
예제 #17
0
    def google(self, page=None, limit=10000, **kwargs):
        """Generate a sitemap which contains googles Video Sitemap information.

        This action may return a <sitemapindex> or a <urlset>, depending
        on how many media items are in the database, and the values of the
        page and limit params.

        :param page: Page number, defaults to 1.
        :type page: int
        :param page: max records to display on page, defaults to 10000.
        :type page: int

        """
        if request.settings['sitemaps_display'] != 'True':
            abort(404)

        response.content_type = mimeparse.best_match(
            ['application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*')
        )

        media = Media.query.published()

        if page is None:
            if media.count() > limit:
                return dict(pages=math.ceil(media.count() / float(limit)))
        else:
            page = int(page)
            media = media.offset(page * limit).limit(limit)

        if page:
            links = []
        else:
            links = [
                url_for(controller='/', qualified=True),
                url_for(controller='/media', show='popular', qualified=True),
                url_for(controller='/media', show='latest', qualified=True),
                url_for(controller='/categories', qualified=True),
            ]

        return dict(
            media = media,
            page = page,
            links = links,
        )
예제 #18
0
    def featured(self, limit=30, skip=0, **kwargs):
        """Generate a media rss (mRSS) feed of the sites featured media."""
        if request.settings['rss_display'] != 'True':
            abort(404)

        response.content_type = mimeparse.best_match(
            ['application/rss+xml', 'application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*'))

        media = Media.query.in_category(get_featured_category())\
            .order_by(Media.publish_on.desc())\
            .limit(limit)

        if skip > 0:
            media = media.offset(skip)

        return dict(
            media=media,
            title='Featured Media',
        )
예제 #19
0
    def featured(self, limit=30, skip=0, **kwargs):
        """Generate a media rss (mRSS) feed of the sites featured media."""
        if request.settings['rss_display'] != 'True':
            abort(404)

        response.content_type = mimeparse.best_match(
            ['application/rss+xml', 'application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*')
        )

        media = Media.query.in_category(get_featured_category())\
            .order_by(Media.publish_on.desc())\
            .limit(limit)

        if skip > 0:
            media = media.offset(skip)

        return dict(
            media = media,
            title = 'Featured Media',
        )
예제 #20
0
    def feed(self, slug, **kwargs):
        """Serve the feed as RSS 2.0.

        If :attr:`~mediacore.model.podcasts.Podcast.feedburner_url` is
        specified for this podcast, we redirect there if the useragent
        does not contain 'feedburner', as described here:
        http://www.google.com/support/feedburner/bin/answer.py?hl=en&answer=78464

        :param feedburner_bypass: If true, the redirect to feedburner is disabled.
        :rtype: Dict
        :returns:
            podcast
                A :class:`~mediacore.model.podcasts.Podcast` instance.
            episodes
                A list of :class:`~mediacore.model.media.Media` instances
                that belong to the ``podcast``.

        Renders: :data:`podcasts/feed.xml` XML

        """
        podcast = fetch_row(Podcast, slug=slug)

        if (podcast.feedburner_url
            and not 'feedburner' in request.environ.get('HTTP_USER_AGENT', '').lower()
            and not kwargs.get('feedburner_bypass', False)):
            redirect(podcast.feedburner_url.encode('utf-8'))

        # Choose the most appropriate content_type for the client
        response.content_type = mimeparse.best_match(
            ['application/rss+xml', 'application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*')
        )

        episodes = podcast.media.published()\
            .order_by(Media.publish_on.desc())[:25]

        return dict(
            podcast = podcast,
            episodes = episodes,
        )
예제 #21
0
    def feed(self, slug, **kwargs):
        """Serve the feed as RSS 2.0.

        If :attr:`~mediacore.model.podcasts.Podcast.feedburner_url` is
        specified for this podcast, we redirect there if the useragent
        does not contain 'feedburner', as described here:
        http://www.google.com/support/feedburner/bin/answer.py?hl=en&answer=78464

        :param feedburner_bypass: If true, the redirect to feedburner is disabled.
        :rtype: Dict
        :returns:
            podcast
                A :class:`~mediacore.model.podcasts.Podcast` instance.
            episodes
                A list of :class:`~mediacore.model.media.Media` instances
                that belong to the ``podcast``.

        Renders: :data:`podcasts/feed.xml` XML

        """
        podcast = fetch_row(Podcast, slug=slug)

        if (podcast.feedburner_url and not 'feedburner' in request.environ.get(
                'HTTP_USER_AGENT', '').lower()
                and not kwargs.get('feedburner_bypass', False)):
            redirect(podcast.feedburner_url.encode('utf-8'))

        # Choose the most appropriate content_type for the client
        response.content_type = mimeparse.best_match(
            ['application/rss+xml', 'application/xml', 'text/xml'],
            request.environ.get('HTTP_ACCEPT', '*/*'))

        episodes = podcast.media.published()\
            .order_by(Media.publish_on.desc())[:25]

        return dict(
            podcast=podcast,
            episodes=episodes,
        )
예제 #22
0
    def get_pubkey(self, delegation_id):
        request_formats = ('application/x-pkcs1+pem', 'application/x-pkcs1', 'application/x-pkcs1+der')
        format = mimeparse.best_match(request_formats, request.headers.get('Accept', '*/*'))
        if format == '':
            format = request_formats[0]
        enc = 'der'
        if '+' in format:
            enc = format.split('+')[1]
        if enc not in ('pem', 'der'):
            abort(412, 'This object may be served only in these Content-Types: %s.' % ', '.join(request_formats),
                  headers={'Content-Type': 'text/plain'})

        delegation = self.find_delegation(delegation_id)
        if delegation.new_key is None:
            delegation.new_key = make_key()
            Session.flush()
        buf = BIO.MemoryBuffer()
        delegation.new_key.save_pub_key_bio(buf)
        pubkey_pem = buf.getvalue()
        if enc == 'pem':
            return render_data(pubkey_pem, format)
        else:
            return render_data(pubkey_pem.split("-----")[2].decode('base64'), format)
예제 #23
0
    def serve(self, id, slug, type, **kwargs):
        """Serve a :class:`~mediacore.model.media.MediaFile` binary.

        :param id: File ID
        :type id: ``int``
        :param slug: The media :attr:`~mediacore.model.media.Media.slug`
        :type slug: The file :attr:`~mediacore.model.media.MediaFile.type`
        :raises tg.exceptions.HTTPNotFound: If no file exists for the given params.
        :raises tg.exceptions.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.

        """
        media = fetch_row(Media, slug=slug)

        for file in media.files:
            if file.id == id and file.type == type:
                # Redirect to an external URL
                if urlparse(file.url)[1]:
                    redirect(file.url.encode('utf-8'))

                # Ensure that the clients request allows for files of this type
                mimetype = mimeparse.best_match([file.mimetype],
                    request.environ.get('HTTP_ACCEPT', '*/*'))
                if mimetype == '':
                    raise exceptions.HTTPNotAcceptable() # 406

                file_name = '%s-%s.%s' % (media.slug, file.id, file.type)
                file_path = os.path.join(config.media_dir, file.url)
                file_handle = open(file_path, 'rb')

                response.headers['Content-Type'] = mimetype
                response.headers['Content-Disposition'] = \
                    'attachment;filename=%s' % file_name.encode('utf-8')
                return file_handle.read()
        else:
            raise exceptions.HTTPNotFound()
예제 #24
0
    def serve(self, id, download=False, **kwargs):
        """Serve a :class:`~mediacore.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 __mediacore_serve__ path below. 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
            redirect_filename = '/__mediacore_serve__/%s' % 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
예제 #25
0
    def serve(self, id, slug, container, environ, start_response, **kwargs):
        """Serve a :class:`~mediacore.model.media.MediaFile` binary.

        :param id: File ID
        :type id: ``int``
        :param slug: The media :attr:`~mediacore.model.media.Media.slug`
        :type slug: The file :attr:`~mediacore.model.media.MediaFile.container`
        :raises webob.exc.HTTPNotFound: If no file exists for the given params.
        :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.

        """
        media = fetch_row(Media, slug=slug)

        for file in media.files:
            if file.id == int(id) and file.container == container:
                # Catch external redirects in case they aren't linked to directly
                if file.url:
                    redirect(file.url.encode('utf-8'))
                elif file.embed:
                    redirect(file.link_url())

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

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

                # Headers to add to FileApp
                headers = [
                    ('Content-Disposition',
                     'attachment; filename="%s"' % file_name),
                ]

                serve_method = config.get('file_serve_method', None)

                if serve_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 serve_method == 'nginx_redirect':
                    raise NotImplementedError, 'This is only a placeholder'
                    response.headers['X-Accel-Redirect'] = '../relative/path'

                else:
                    fileapp = FileApp(file_path, headers,
                                      content_type=file_type)
                    return fileapp(environ, start_response)

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

                return None
        else:
            raise webob.exc.HTTPNotFound()
예제 #26
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
예제 #27
0
    def serve(self, id, download=False, **kwargs):
        """Serve a :class:`~mediacore.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)

        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().exception
        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().exception

        # Ensure the request accepts files with this container
        accept = request.environ.get('HTTP_ACCEPT', '*/*')
        if not mimeparse.best_match([file_type], accept):
            raise HTTPNotAcceptable().exception  # 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':
            raise NotImplementedError, 'This is only a placeholder'
            response.headers['X-Accel-Redirect'] = '../relative/path'

        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