Resolved issue #949

This commit is contained in:
= 2017-09-22 00:57:44 +03:00
parent 1b0286916e
commit 3b0634bec8
5 changed files with 53 additions and 9 deletions

View File

@ -352,13 +352,13 @@ class Sanic:
attach_to=middleware_or_request)
# Static Files
def static(self, uri, file_or_directory, pattern=r'/?.+',
def static(self, uri, file_or_directory, host=None, pattern=r'/?.+',
use_modified_since=True, use_content_range=False,
stream_large_files=False, name='static'):
"""Register a root to serve files from. The input can either be a
file or a directory. See
"""
static_register(self, uri, file_or_directory, pattern,
static_register(self, uri, file_or_directory, host, pattern,
use_modified_since, use_content_range,
stream_large_files, name)

View File

@ -14,7 +14,6 @@ FutureStatic = namedtuple('Route',
class Blueprint:
def __init__(self, name,
url_prefix=None,
host=None, version=None,
@ -92,7 +91,7 @@ class Blueprint:
# Prepend the blueprint URI prefix if available
uri = url_prefix + future.uri if url_prefix else future.uri
app.static(uri, future.file_or_directory,
*future.args, **future.kwargs)
self.host, *future.args, **future.kwargs)
# Event listeners
for event, listeners in self.listeners.items():
@ -115,6 +114,7 @@ class Blueprint:
name)
self.routes.append(route)
return handler
return decorator
def add_route(self, handler, uri, methods=frozenset({'GET'}), host=None,
@ -165,6 +165,7 @@ class Blueprint:
False, version, name)
self.websocket_routes.append(route)
return handler
return decorator
def add_websocket_route(self, handler, uri, host=None, version=None,
@ -184,13 +185,16 @@ class Blueprint:
:param event: Event to listen to.
"""
def decorator(listener):
self.listeners[event].append(listener)
return listener
return decorator
def middleware(self, *args, **kwargs):
"""Create a blueprint middleware from a decorated function."""
def register_middleware(_middleware):
future_middleware = FutureMiddleware(_middleware, args, kwargs)
self.middlewares.append(future_middleware)
@ -206,10 +210,12 @@ class Blueprint:
def exception(self, *args, **kwargs):
"""Create a blueprint exception from a decorated function."""
def decorator(handler):
exception = FutureException(handler, args, kwargs)
self.exceptions.append(exception)
return handler
return decorator
def static(self, uri, file_or_directory, *args, **kwargs):

View File

@ -16,7 +16,7 @@ from sanic.handlers import ContentRangeHandler
from sanic.response import file, file_stream, HTTPResponse
def register(app, uri, file_or_directory, pattern,
def register(app, uri, file_or_directory, host, pattern,
use_modified_since, use_content_range,
stream_large_files, name='static'):
# TODO: Though sanic is not a file server, I feel like we should at least
@ -29,6 +29,7 @@ def register(app, uri, file_or_directory, pattern,
:param app: Sanic
:param file_or_directory: File or directory path to serve from
:param uri: URL to serve from
:param host: vhost to serve from. 'None' for all
:param pattern: regular expression used to match files in the URL
:param use_modified_since: If true, send file modified time, and return
not modified if the browser's matches the
@ -103,7 +104,7 @@ def register(app, uri, file_or_directory, pattern,
if isinstance(stream_large_files, int):
threshold = stream_large_files
else:
threshold = 1024*1000
threshold = 1024 * 1000
if not stats:
stats = await stat(file_path)
@ -122,4 +123,4 @@ def register(app, uri, file_or_directory, pattern,
if not name.startswith('_static_'):
name = '_static_{}'.format(name)
app.route(uri, methods=['GET', 'HEAD'], name=name)(_handler)
app.route(uri, methods=['GET', 'HEAD'], name=name, host=host)(_handler)

View File

@ -13,7 +13,7 @@ class SanicTestClient:
async def _local_request(self, method, uri, cookies=None, *args, **kwargs):
import aiohttp
if uri.startswith(('http:', 'https:', 'ftp:', 'ftps://' '//')):
if uri.startswith(('http:', 'https:', 'ftp:', 'ftps://', '//')):
url = uri
else:
url = 'http://{host}:{port}{uri}'.format(
@ -51,6 +51,7 @@ class SanicTestClient:
def _collect_request(request):
if results[0] is None:
results[0] = request
self.app.request_middleware.appendleft(_collect_request)
@self.app.listener('after_server_start')

View File

@ -3,7 +3,8 @@ import os
import pytest
from sanic import Sanic
from sanic import Sanic, exceptions
@pytest.fixture(scope='module')
@ -161,3 +162,38 @@ def test_static_content_range_error(file_name, static_file_directory):
assert 'Content-Range' in response.headers
assert response.headers['Content-Range'] == "bytes */%s" % (
len(get_file_content(static_file_directory, file_name)),)
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt', 'python.png'])
def test_static_file_vhost(static_file_directory, file_name):
app = Sanic('test_static')
app.static(
'/testing.file', get_file_path(static_file_directory, file_name), host='vhost')
# no vhost
request, response = app.test_client.get('/testing.file')
assert response.status == 404
# vhost
request, response = app.test_client.get('/testing.file', headers={"host": "vhost"})
assert response.status == 200
assert response.body == get_file_content(static_file_directory, file_name)
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt', 'python.png'])
def test_bp_static_file_vhost(static_file_directory, file_name):
from sanic import Blueprint
app = Sanic('test_static')
bp = Blueprint(name="bp", url_prefix="", host="vhost")
bp.static('/testing.file', get_file_path(static_file_directory, file_name))
app.blueprint(bp)
# no vhost
request, response = app.test_client.get('/testing.file')
assert response.status == 404
request, response = app.test_client.get('/testing.file', headers={"host": "vhost"})
assert response.status == 200
assert response.body == get_file_content(static_file_directory, file_name)