Skip to content

Commit

Permalink
Support x-send and nginx headers.
Browse files Browse the repository at this point in the history
closes #2914
  • Loading branch information
jortel committed Nov 27, 2017
1 parent 8c828c2 commit ec92211
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 13 deletions.
13 changes: 13 additions & 0 deletions docs/installation/configuration-files.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,19 @@ logging
handlers: ["myCustomHandler"]
level: DEBUG
content
^^^^^^^

The configuration for the content serving application.

web_server
Defines the type of web server that is running the content application.
When set to `django`, the content is streamed.
When set to `apache`, the `X-SENDFILE` header is injected which delegates
streaming the content to Apache. Requires: `mod_xsendfile` to be installed.
When set to `nginx`, the `X-Accel-Redirect` header is injected which delegates
streaming the content to NGINX.

JWT_AUTH
^^^^^^^^

Expand Down
3 changes: 3 additions & 0 deletions pulpcore/pulpcore/app/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,9 @@
'server': {
'working_directory': '/var/cache/pulp',
},
'content': {
'web_server': 'django',
},
'broker': {
'url': 'amqp://guest@localhost//',
'celery_require_ssl': False,
Expand Down
57 changes: 44 additions & 13 deletions pulpcore/pulpcore/app/views/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
from gettext import gettext as _
from logging import getLogger, DEBUG

from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponseNotFound, StreamingHttpResponse
from django.http import (HttpResponse, HttpResponseForbidden, HttpResponseNotFound,
StreamingHttpResponse)
from django.views.generic import View

from wsgiref.util import FileWrapper
Expand Down Expand Up @@ -117,32 +119,32 @@ def _match(self, path):
else:
raise ObjectDoesNotExist()

@staticmethod
def _stream(storage_path):
def _stream(self, storage_path):
"""
Get streaming response.
Args:
storage_path (str): The storage path of the requested object.
Returns:
HttpResponse: Always.
StreamingHttpResponse: Stream the requested content.
"""
try:
file = FileWrapper(open(storage_path, 'rb'))
except FileNotFoundError:
return HttpResponseNotFound()
except PermissionError:
return HttpResponseForbidden()
response = StreamingHttpResponse(file)
response['Content-Length'] = os.path.getsize(storage_path)
response['Content-Disposition'] = \
'attachment; filename={n}'.format(n=os.path.basename(storage_path))
return response

@staticmethod
def _redirect(storage_path):
def _redirect(self, storage_path):
"""
Redirect to streamer.
Get redirect-to-streamer response.
Args:
storage_path (str): The storage path of the requested object.
Expand All @@ -152,18 +154,40 @@ def _redirect(storage_path):
"""
# :TODO:

@staticmethod
def _xsend(storage_path):
def _apache(self, storage_path):
"""
Stream using X-SEND.
The content web server is Apache.
Args:
storage_path (str): The storage path of the requested object.
Returns:
HttpResponse: A response with X-SENDFILE header.
"""
response = HttpResponse()
response['X-SENDFILE'] = storage_path
return response

def _nginx(self, storage_path):
"""
# :TODO:
The content web server is NGINX.
Args:
storage_path (str): The storage path of the requested object.
Returns:
HttpResponse: A response with X-Accel-Redirect header.
"""
response = HttpResponse()
response['X-Accel-Redirect'] = storage_path
return response

# Mapping of responder method by web server.
RESPONDER = {
'django': _stream,
'apache': _apache,
'nginx': _nginx,
}

def get(self, request):
"""
Expand All @@ -175,14 +199,21 @@ def get(self, request):
Returns:
django.http.StreamingHttpResponse: on found.
django.http.HttpResponseNotFound: on not-found.
django.http.HttpResponseForbidden: on forbidden.
"""
server = settings.CONTENT['web_server']

try:
path = request.path.strip('/')
path = path[len(self.BASE_PATH):]
storage_path = self._match(path)
except ObjectDoesNotExist:
return HttpResponseNotFound()

# TODO: Eventually, choose _redirect() and _xsend() as appropriate.
return self._stream(storage_path)
try:
responder = self.RESPONDER[server]
except KeyError:
raise ValueError(_('Web server "{t}" not supported.'.format(t=server)))
else:
return responder(self, storage_path)
11 changes: 11 additions & 0 deletions pulpcore/pulpcore/etc/pulp/server.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@
# server:
# working_directory: /var/cache/pulp

# Content Application
#
# `content`: The content serving application.
# `web_server`: The type of web server. Must be: (django|apache|nginx).
# When set to 'apache', the X-SENDFILE header is injected which delegates
# streaming the content to Apache. Requires: mod_xsendfile to be installed.
# When set to 'nginx', the X-Accel-Redirect header is injected which delegates
# streaming the content to NGINX.
#
# web_server: django

# JWT Authentication configuration
#
# For more JWT settings, see
Expand Down

0 comments on commit ec92211

Please sign in to comment.