Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DONT MERGE, DEMONSTRATION ONLY] Http exceptions refactoring #2521

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 31 additions & 25 deletions aiohttp/web_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,22 @@
# HTTP Exceptions
############################################################

class HTTPException(Response, Exception):
class HTTPException(Exception):

# You should set in subclasses:
# status = 200

status_code = None
empty_body = False

def __init__(self, *, headers=None, reason=None,
body=None, text=None, content_type=None):
Response.__init__(self, status=self.status_code,
headers=headers, reason=reason,
body=body, text=text, content_type=content_type)
Exception.__init__(self, self.reason)
if self.body is None and not self.empty_body:
self.text = "{}: {}".format(self.status, self.reason)
def build_response(self):
if self.status_code is None:
raise RuntimeError("Cannot build abstract HTTP exception: "
"status is not set.")
resp = Response(status=self.status_code)
if not self.empty_body:
resp.text = "{}: {}".format(resp.status, resp.reason)
return resp


class HTTPError(HTTPException):
Expand Down Expand Up @@ -133,15 +133,17 @@ class HTTPPartialContent(HTTPSuccessful):

class _HTTPMove(HTTPRedirection):

def __init__(self, location, *, headers=None, reason=None,
body=None, text=None, content_type=None):
def __init__(self, location):
if not location:
raise ValueError("HTTP redirects need a location to redirect to.")
super().__init__(headers=headers, reason=reason,
body=body, text=text, content_type=content_type)
self.headers['Location'] = str(location)
super().__init__()
self.location = location

def build_response(self):
resp = super().build_response()
resp.headers['Location'] = str(self.location)
return resp


class HTTPMultipleChoices(_HTTPMove):
status_code = 300
Expand Down Expand Up @@ -212,15 +214,17 @@ class HTTPNotFound(HTTPClientError):
class HTTPMethodNotAllowed(HTTPClientError):
status_code = 405

def __init__(self, method, allowed_methods, *, headers=None, reason=None,
body=None, text=None, content_type=None):
allow = ','.join(sorted(allowed_methods))
super().__init__(headers=headers, reason=reason,
body=body, text=text, content_type=content_type)
self.headers['Allow'] = allow
def __init__(self, method, allowed_methods):
super().__init__()
self.allow = ','.join(sorted(allowed_methods))
self.allowed_methods = allowed_methods
self.method = method.upper()

def build_response(self):
resp = super().build_response()
resp.headers['Allow'] = self.allow
return resp


class HTTPNotAcceptable(HTTPClientError):
status_code = 406
Expand Down Expand Up @@ -301,13 +305,15 @@ class HTTPRequestHeaderFieldsTooLarge(HTTPClientError):
class HTTPUnavailableForLegalReasons(HTTPClientError):
status_code = 451

def __init__(self, link, *, headers=None, reason=None,
body=None, text=None, content_type=None):
super().__init__(headers=headers, reason=reason,
body=body, text=text, content_type=content_type)
self.headers['Link'] = '<%s>; rel="blocked-by"' % link
def __init__(self, link):
super().__init__()
self.link = link

def build_response(self):
resp = super().build_response()
resp.headers['Link'] = '<%s>; rel="blocked-by"' % self.link
return resp


############################################################
# 5xx Server Error
Expand Down
2 changes: 1 addition & 1 deletion aiohttp/web_middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ async def normalize_path_middleware(request, handler):
resolves, request = await _check_request_resolves(
request, path)
if resolves:
return redirect_class(request.path + query)
raise redirect_class(request.path + query)

return (await handler(request))

Expand Down
2 changes: 1 addition & 1 deletion aiohttp/web_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ async def start(self, message, payload, handler):
try:
resp = await self._request_handler(request)
except HTTPException as exc:
resp = exc
resp = exc.build_response()
except asyncio.CancelledError:
self.log_debug('Ignored premature client disconnection')
break
Expand Down
8 changes: 5 additions & 3 deletions aiohttp/web_urldispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,9 @@ def http_exception(self):
return self._exception

def __repr__(self):
return "<MatchInfoError {}: {}>".format(self._exception.status,
self._exception.reason)
resp = self._exception.build_response()
return "<MatchInfoError {}: {}>".format(resp.status,
resp.reason)


async def _defaultExpectHandler(request):
Expand All @@ -233,7 +234,8 @@ async def _defaultExpectHandler(request):
if expect.lower() == "100-continue":
request.writer.write(b"HTTP/1.1 100 Continue\r\n\r\n", drain=False)
else:
raise HTTPExpectationFailed(text="Unknown Expect: %s" % expect)
return HTTPExpectationFailed(
text="Unknown Expect: %s" % expect).build_response()


class Resource(AbstractResource):
Expand Down
2 changes: 1 addition & 1 deletion aiohttp/web_ws.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def _pre_start(self, request):
except HttpProcessingError as err:
if err.code == 405:
raise HTTPMethodNotAllowed(
request.method, [hdrs.METH_GET], body=b'')
request.method, [hdrs.METH_GET])
elif err.code == 400:
raise HTTPBadRequest(text=err.message, headers=err.headers)
else: # pragma: no cover
Expand Down
10 changes: 6 additions & 4 deletions tests/test_classbasedview.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ async def get(self):
request.method = 'UNKNOWN'
with pytest.raises(web.HTTPMethodNotAllowed) as ctx:
await MyView(request)
assert ctx.value.headers['allow'] == 'GET,OPTIONS'
assert ctx.value.status == 405
resp = ctx.value.build_response()
assert resp.headers['allow'] == 'GET,OPTIONS'
assert resp.status == 405


async def test_render_unsupported_method():
Expand All @@ -51,5 +52,6 @@ async def get(self):
request.method = 'POST'
with pytest.raises(web.HTTPMethodNotAllowed) as ctx:
await MyView(request)
assert ctx.value.headers['allow'] == 'DELETE,GET,OPTIONS'
assert ctx.value.status == 405
resp = ctx.value.build_response()
assert resp.headers['allow'] == 'DELETE,GET,OPTIONS'
assert resp.status == 405
Loading