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()
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, )
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, )
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)
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
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
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
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]
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]
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")
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', )
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")
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', )
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', )
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
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, )
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', )
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', )
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, )
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, )
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)
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()
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
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()
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
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