Skip to content

Commit

Permalink
Merge fd93a8d into 93f4e30
Browse files Browse the repository at this point in the history
  • Loading branch information
Glignos committed Mar 9, 2020
2 parents 93f4e30 + fd93a8d commit 68b6335
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 1 deletion.
9 changes: 9 additions & 0 deletions invenio_files_rest/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

from datetime import timedelta

from invenio_files_rest.helpers import create_file_streaming_redirect_response

MAX_CONTENT_LENGTH = 16 * 1024 * 1024
"""Maximum allowed content length for form data.
Expand Down Expand Up @@ -127,3 +129,10 @@

FILES_REST_FILE_TAGS_HEADER = 'X-Invenio-File-Tags'
"""Header for updating file tags."""

FILES_REST_OFFLOAD_STREAMING_EXTERNALLY = False
"""Use the X-Accel-Redirect header to stream the file through NGINX"""

FILES_REST_STREAMING_REDIRECT_RESPONSE_FUNC = \
create_file_streaming_redirect_response
"""Function for the creation of a file streaming redirect response."""
13 changes: 12 additions & 1 deletion invenio_files_rest/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
import unicodedata
from time import time

from flask import current_app, request
from flask import current_app, make_response, request
from six.moves.urllib.parse import urlsplit
from werkzeug.datastructures import Headers
from werkzeug.urls import url_quote
from werkzeug.wsgi import FileWrapper
Expand Down Expand Up @@ -291,3 +292,13 @@ def create_file(key, path):
assert filename.startswith(source)
parts = [p for p in filename[len(source):].split(os.sep) if p]
yield create_file('/'.join(parts), os.path.join(root, name))


def create_file_streaming_redirect_response(obj):
"""Redirect response generating function."""
response = make_response()
redirect_url_base = '/secure_files/'
redirect_url_key = urlsplit(obj.file.uri).path
response.headers['X-Accel-Redirect'] = redirect_url_base + \
redirect_url_key[1:]
return response
4 changes: 4 additions & 0 deletions invenio_files_rest/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -814,6 +814,10 @@ def get(self, bucket=None, key=None, version_id=None, upload_id=None,
return self.multipart_listparts(bucket, key, upload_id)
else:
obj = self.get_object(bucket, key, version_id)
if current_app.config['FILES_REST_OFFLOAD_STREAMING_EXTERNALLY']:
response_constructor = current_app.config[
'FILES_REST_STREAMING_REDIRECT_RESPONSE_FUNC']
return response_constructor(obj)
# If 'download' is missing from query string it will have
# the value None.
return self.send_object(bucket, obj,
Expand Down
8 changes: 8 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,3 +402,11 @@ def inner(resp, code=None):
assert resp.status_code == code
return json.loads(resp.get_data(as_text=True))
return inner


@pytest.fixture()
def offload_file_serving(app):
"""Serve a redirect instead of streaming the file."""
app.config['FILES_REST_OFFLOAD_STREAMING_EXTERNALLY'] = True
yield app
app.config['FILES_REST_OFFLOAD_STREAMING_EXTERNALLY'] = False
23 changes: 23 additions & 0 deletions tests/test_views_objectversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,29 @@ def test_get(client, headers, bucket, objects, permissions):
assert resp.get_etag()[0] == obj.file.checksum


def test_get_with_redirect(
client, headers, bucket, objects, permissions, offload_file_serving):
"""Test getting a redirect to an object."""

login_user(client, permissions['bucket'])

for obj in objects:
object_url = url_for(
'invenio_files_rest.object_api',
bucket_id=bucket.id,
key=obj.key, )

# Get specifying version (of latest obj).
resp = client.get(
object_url,
query_string='versionId={0}'.format(obj.version_id),
headers=headers)
assert resp.status_code == 200

assert resp.headers['X-Accel-Redirect'].startswith(
'/secure_files/')


def test_get_download(client, headers, bucket, objects, permissions):
"""Test getting an object."""
login_user(client, permissions['objects'])
Expand Down

0 comments on commit 68b6335

Please sign in to comment.