Merge pull request #398 from seemethere/fix_errors_from_content_range

Fixes errors related to #378
This commit is contained in:
Eli Uriegas 2017-02-08 20:06:02 -06:00 committed by GitHub
commit 7401facc21
6 changed files with 50 additions and 121 deletions

View File

@ -97,6 +97,7 @@ INTERNAL_SERVER_ERROR_HTML = '''
class SanicException(Exception): class SanicException(Exception):
def __init__(self, message, status_code=None): def __init__(self, message, status_code=None):
super().__init__(message) super().__init__(message)
@ -154,87 +155,3 @@ class ContentRangeError(SanicException):
class InvalidRangeType(ContentRangeError): class InvalidRangeType(ContentRangeError):
pass pass
class Handler:
handlers = None
cached_handlers = None
_missing = object()
def __init__(self):
self.handlers = []
self.cached_handlers = {}
self.debug = False
def _render_traceback_html(self, exception, request):
exc_type, exc_value, tb = sys.exc_info()
frames = extract_tb(tb)
frame_html = []
for frame in frames:
frame_html.append(TRACEBACK_LINE_HTML.format(frame))
return TRACEBACK_WRAPPER_HTML.format(
style=TRACEBACK_STYLE,
exc_name=exc_type.__name__,
exc_value=exc_value,
frame_html=''.join(frame_html),
uri=request.url)
def add(self, exception, handler):
self.handlers.append((exception, handler))
def lookup(self, exception):
handler = self.cached_handlers.get(exception, self._missing)
if handler is self._missing:
for exception_class, handler in self.handlers:
if isinstance(exception, exception_class):
self.cached_handlers[type(exception)] = handler
return handler
self.cached_handlers[type(exception)] = None
handler = None
return handler
def response(self, request, exception):
"""
Fetches and executes an exception handler and returns a response object
:param request: Request
:param exception: Exception to handle
:return: Response object
"""
handler = self.lookup(exception)
try:
response = handler and handler(
request=request, exception=exception)
if response is None:
response = self.default(request=request, exception=exception)
except:
log.error(format_exc())
if self.debug:
response_message = (
'Exception raised in exception handler "{}" '
'for uri: "{}"\n{}').format(
handler.__name__, request.url, format_exc())
log.error(response_message)
return text(response_message, 500)
else:
return text('An error occurred while handling an error', 500)
return response
def default(self, request, exception):
log.error(format_exc())
if isinstance(exception, SanicException):
return text(
'Error: {}'.format(exception),
status=getattr(exception, 'status_code', 500))
elif self.debug:
html_output = self._render_traceback_html(exception, request)
response_message = (
'Exception occurred while handling uri: "{}"\n{}'.format(
request.url, format_exc()))
log.error(response_message)
return html(html_output, status=500)
else:
return html(INTERNAL_SERVER_ERROR_HTML, status=500)

View File

@ -10,7 +10,8 @@ from urllib.parse import urlencode, urlunparse
from .config import Config from .config import Config
from .constants import HTTP_METHODS from .constants import HTTP_METHODS
from .exceptions import Handler, ServerError, URLBuildError from .handlers import ErrorHandler
from .exceptions import ServerError, URLBuildError
from .log import log from .log import log
from .response import HTTPResponse from .response import HTTPResponse
from .router import Router from .router import Router

View File

@ -1 +1 @@
I need to be decoded as a uri I am just a regular static file that needs to have its uri decoded

View File

@ -31,7 +31,7 @@ def handler_4(request):
@exception_handler_app.route('/5') @exception_handler_app.route('/5')
def handler_5(request): def handler_5(request):
class CustomServerError(ServerError): class CustomServerError(ServerError):
pass status_code=200
raise CustomServerError('Custom server error') raise CustomServerError('Custom server error')

View File

@ -6,6 +6,7 @@ import signal
import pytest import pytest
from sanic import Sanic from sanic import Sanic
from sanic.utils import HOST, PORT
AVAILABLE_LISTENERS = [ AVAILABLE_LISTENERS = [
'before_start', 'before_start',
@ -30,7 +31,7 @@ def start_stop_app(random_name_app, **run_kwargs):
signal.signal(signal.SIGALRM, stop_on_alarm) signal.signal(signal.SIGALRM, stop_on_alarm)
signal.alarm(1) signal.alarm(1)
try: try:
random_name_app.run(**run_kwargs) random_name_app.run(HOST, PORT, **run_kwargs)
except KeyboardInterrupt: except KeyboardInterrupt:
pass pass

View File

@ -49,9 +49,9 @@ def test_static_directory(file_name, base_uri, static_file_directory):
assert response.status == 200 assert response.status == 200
assert response.body == get_file_content(static_file_directory, file_name) assert response.body == get_file_content(static_file_directory, file_name)
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) @pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
def test_static_head_request( def test_static_head_request(file_name, static_file_directory):
file_name, static_file_content, static_file_directory):
app = Sanic('test_static') app = Sanic('test_static')
app.static( app.static(
'/testing.file', get_file_path(static_file_directory, file_name), '/testing.file', get_file_path(static_file_directory, file_name),
@ -62,11 +62,13 @@ def test_static_head_request(
assert response.status == 200 assert response.status == 200
assert 'Accept-Ranges' in response.headers assert 'Accept-Ranges' in response.headers
assert 'Content-Length' in response.headers assert 'Content-Length' in response.headers
assert int(response.headers['Content-Length']) == len(get_file_content(static_file_directory, file_name)) assert int(response.headers[
'Content-Length']) == len(
get_file_content(static_file_directory, file_name))
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) @pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
def test_static_content_range_correct( def test_static_content_range_correct(file_name, static_file_directory):
file_name, static_file_content, static_file_directory):
app = Sanic('test_static') app = Sanic('test_static')
app.static( app.static(
'/testing.file', get_file_path(static_file_directory, file_name), '/testing.file', get_file_path(static_file_directory, file_name),
@ -80,13 +82,15 @@ def test_static_content_range_correct(
assert response.status == 200 assert response.status == 200
assert 'Content-Length' in response.headers assert 'Content-Length' in response.headers
assert 'Content-Range' in response.headers assert 'Content-Range' in response.headers
static_content = bytes(get_file_content(static_file_directory, file_name))[12:19] static_content = bytes(get_file_content(
assert int(response.headers['Content-Length']) == len(get_file_content(static_file_directory, file_name)) static_file_directory, file_name))[12:19]
assert response.body == get_file_content(static_file_directory, file_name) assert int(response.headers[
'Content-Length']) == len(static_content)
assert response.body == static_content
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) @pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
def test_static_content_range_front( def test_static_content_range_front(file_name, static_file_directory):
file_name, static_file_content, static_file_directory):
app = Sanic('test_static') app = Sanic('test_static')
app.static( app.static(
'/testing.file', get_file_path(static_file_directory, file_name), '/testing.file', get_file_path(static_file_directory, file_name),
@ -100,14 +104,15 @@ def test_static_content_range_front(
assert response.status == 200 assert response.status == 200
assert 'Content-Length' in response.headers assert 'Content-Length' in response.headers
assert 'Content-Range' in response.headers assert 'Content-Range' in response.headers
static_content = bytes(get_file_content(static_file_directory, file_name))[12:] static_content = bytes(get_file_content(
assert int(response.headers['Content-Length']) == len(get_file_content(static_file_directory, file_name)) static_file_directory, file_name))[12:]
assert response.body == get_file_content(static_file_directory, file_name) assert int(response.headers[
'Content-Length']) == len(static_content)
assert response.body == static_content
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) @pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
def test_static_content_range_back( def test_static_content_range_back(file_name, static_file_directory):
file_name, static_file_content, static_file_directory):
app = Sanic('test_static') app = Sanic('test_static')
app.static( app.static(
'/testing.file', get_file_path(static_file_directory, file_name), '/testing.file', get_file_path(static_file_directory, file_name),
@ -121,13 +126,15 @@ def test_static_content_range_back(
assert response.status == 200 assert response.status == 200
assert 'Content-Length' in response.headers assert 'Content-Length' in response.headers
assert 'Content-Range' in response.headers assert 'Content-Range' in response.headers
static_content = bytes(get_file_content(static_file_directory, file_name))[-12:] static_content = bytes(get_file_content(
assert int(response.headers['Content-Length']) == len(get_file_content(static_file_directory, file_name)) static_file_directory, file_name))[-12:]
assert response.body == get_file_content(static_file_directory, file_name) assert int(response.headers[
'Content-Length']) == len(static_content)
assert response.body == static_content
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) @pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
def test_static_content_range_empty( def test_static_content_range_empty(file_name, static_file_directory):
file_name, static_file_content, static_file_directory):
app = Sanic('test_static') app = Sanic('test_static')
app.static( app.static(
'/testing.file', get_file_path(static_file_directory, file_name), '/testing.file', get_file_path(static_file_directory, file_name),
@ -137,11 +144,14 @@ def test_static_content_range_empty(
assert response.status == 200 assert response.status == 200
assert 'Content-Length' in response.headers assert 'Content-Length' in response.headers
assert 'Content-Range' not in response.headers assert 'Content-Range' not in response.headers
assert int(response.headers['Content-Length']) == len(get_file_content(static_file_directory, file_name)) assert int(response.headers[
assert response.body == bytes(get_file_content(static_file_directory, file_name)) 'Content-Length']) == len(get_file_content(static_file_directory, file_name))
assert response.body == bytes(
get_file_content(static_file_directory, file_name))
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt']) @pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
def test_static_content_range_error(static_file_path, static_file_content): def test_static_content_range_error(file_name, static_file_directory):
app = Sanic('test_static') app = Sanic('test_static')
app.static( app.static(
'/testing.file', get_file_path(static_file_directory, file_name), '/testing.file', get_file_path(static_file_directory, file_name),
@ -156,4 +166,4 @@ def test_static_content_range_error(static_file_path, static_file_content):
assert 'Content-Length' in response.headers assert 'Content-Length' in response.headers
assert 'Content-Range' in response.headers assert 'Content-Range' in response.headers
assert response.headers['Content-Range'] == "bytes */%s" % ( assert response.headers['Content-Range'] == "bytes */%s" % (
len(static_file_content),) len(get_file_content(static_file_directory, file_name)),)