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
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': # 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-%s' % (id, file_name) response.headers['X-Accel-Redirect'] = redirect_filename.lower() 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