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):
def __init__(self, message, status_code=None):
super().__init__(message)
@ -136,7 +137,7 @@ class RequestTimeout(SanicException):
class PayloadTooLarge(SanicException):
status_code = 413
class HeaderNotFound(SanicException):
status_code = 400
@ -154,87 +155,3 @@ class ContentRangeError(SanicException):
class InvalidRangeType(ContentRangeError):
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 .constants import HTTP_METHODS
from .exceptions import Handler, ServerError, URLBuildError
from .handlers import ErrorHandler
from .exceptions import ServerError, URLBuildError
from .log import log
from .response import HTTPResponse
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')
def handler_5(request):
class CustomServerError(ServerError):
pass
status_code=200
raise CustomServerError('Custom server error')

View File

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

View File

@ -49,12 +49,12 @@ def test_static_directory(file_name, base_uri, static_file_directory):
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'])
def test_static_head_request(
file_name, static_file_content, static_file_directory):
def test_static_head_request(file_name, static_file_directory):
app = Sanic('test_static')
app.static(
'/testing.file', get_file_path(static_file_directory, file_name),
'/testing.file', get_file_path(static_file_directory, file_name),
use_content_range=True)
request, response = sanic_endpoint_test(
@ -62,14 +62,16 @@ def test_static_head_request(
assert response.status == 200
assert 'Accept-Ranges' 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'])
def test_static_content_range_correct(
file_name, static_file_content, static_file_directory):
def test_static_content_range_correct(file_name, static_file_directory):
app = Sanic('test_static')
app.static(
'/testing.file', get_file_path(static_file_directory, file_name),
'/testing.file', get_file_path(static_file_directory, file_name),
use_content_range=True)
headers = {
@ -80,16 +82,18 @@ def test_static_content_range_correct(
assert response.status == 200
assert 'Content-Length' in response.headers
assert 'Content-Range' in response.headers
static_content = bytes(get_file_content(static_file_directory, file_name))[12:19]
assert int(response.headers['Content-Length']) == len(get_file_content(static_file_directory, file_name))
assert response.body == get_file_content(static_file_directory, file_name)
static_content = bytes(get_file_content(
static_file_directory, file_name))[12:19]
assert int(response.headers[
'Content-Length']) == len(static_content)
assert response.body == static_content
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
def test_static_content_range_front(
file_name, static_file_content, static_file_directory):
def test_static_content_range_front(file_name, static_file_directory):
app = Sanic('test_static')
app.static(
'/testing.file', get_file_path(static_file_directory, file_name),
'/testing.file', get_file_path(static_file_directory, file_name),
use_content_range=True)
headers = {
@ -100,19 +104,20 @@ def test_static_content_range_front(
assert response.status == 200
assert 'Content-Length' in response.headers
assert 'Content-Range' in response.headers
static_content = bytes(get_file_content(static_file_directory, file_name))[12:]
assert int(response.headers['Content-Length']) == len(get_file_content(static_file_directory, file_name))
assert response.body == get_file_content(static_file_directory, file_name)
static_content = bytes(get_file_content(
static_file_directory, file_name))[12:]
assert int(response.headers[
'Content-Length']) == len(static_content)
assert response.body == static_content
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
def test_static_content_range_back(
file_name, static_file_content, static_file_directory):
def test_static_content_range_back(file_name, static_file_directory):
app = Sanic('test_static')
app.static(
'/testing.file', get_file_path(static_file_directory, file_name),
'/testing.file', get_file_path(static_file_directory, file_name),
use_content_range=True)
headers = {
'Range': 'bytes=-12'
}
@ -121,30 +126,35 @@ def test_static_content_range_back(
assert response.status == 200
assert 'Content-Length' in response.headers
assert 'Content-Range' in response.headers
static_content = bytes(get_file_content(static_file_directory, file_name))[-12:]
assert int(response.headers['Content-Length']) == len(get_file_content(static_file_directory, file_name))
assert response.body == get_file_content(static_file_directory, file_name)
static_content = bytes(get_file_content(
static_file_directory, file_name))[-12:]
assert int(response.headers[
'Content-Length']) == len(static_content)
assert response.body == static_content
@pytest.mark.parametrize('file_name', ['test.file', 'decode me.txt'])
def test_static_content_range_empty(
file_name, static_file_content, static_file_directory):
def test_static_content_range_empty(file_name, static_file_directory):
app = Sanic('test_static')
app.static(
'/testing.file', get_file_path(static_file_directory, file_name),
'/testing.file', get_file_path(static_file_directory, file_name),
use_content_range=True)
request, response = sanic_endpoint_test(app, uri='/testing.file')
assert response.status == 200
assert 'Content-Length' 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 response.body == bytes(get_file_content(static_file_directory, file_name))
assert int(response.headers[
'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'])
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.static(
'/testing.file', get_file_path(static_file_directory, file_name),
'/testing.file', get_file_path(static_file_directory, file_name),
use_content_range=True)
headers = {
@ -156,4 +166,4 @@ def test_static_content_range_error(static_file_path, static_file_content):
assert 'Content-Length' in response.headers
assert 'Content-Range' in response.headers
assert response.headers['Content-Range'] == "bytes */%s" % (
len(static_file_content),)
len(get_file_content(static_file_directory, file_name)),)