Middleware and error handling refactoring.
This commit is contained in:
parent
d2d6008eec
commit
17d100400f
32
sanic/app.py
32
sanic/app.py
|
@ -955,22 +955,22 @@ class Sanic:
|
||||||
response = HTTPResponse(
|
response = HTTPResponse(
|
||||||
"An error occurred while handling an error", status=500
|
"An error occurred while handling an error", status=500
|
||||||
)
|
)
|
||||||
# Run response middleware
|
|
||||||
if response is not None:
|
if response is not None:
|
||||||
try:
|
try:
|
||||||
response = await self._run_response_middleware(
|
response = await request.respond(response)
|
||||||
request, response, request_name=request.name
|
except:
|
||||||
|
# Skip response middleware
|
||||||
|
request.stream.respond(response)
|
||||||
|
await response.send(end_stream=True)
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
response = request.stream.response
|
||||||
|
if isinstance(response, BaseHTTPResponse):
|
||||||
|
await response.send(end_stream=True)
|
||||||
|
else:
|
||||||
|
raise ServerError(
|
||||||
|
f"Invalid response type {response!r} (need HTTPResponse)"
|
||||||
)
|
)
|
||||||
except CancelledError:
|
|
||||||
# FIXME: Ensure exiting in a clean manner instead of this
|
|
||||||
# and verify py37 and py38 test_middleware.py separately
|
|
||||||
request.stream.keep_alive = False
|
|
||||||
except Exception:
|
|
||||||
error_logger.exception(
|
|
||||||
"Exception occurred in one of response "
|
|
||||||
"middleware handlers"
|
|
||||||
)
|
|
||||||
return response
|
|
||||||
|
|
||||||
async def handle_request(self, request):
|
async def handle_request(self, request):
|
||||||
"""Take a request from the HTTP Server and return a response object
|
"""Take a request from the HTTP Server and return a response object
|
||||||
|
@ -1039,6 +1039,8 @@ class Sanic:
|
||||||
response = await response
|
response = await response
|
||||||
if response:
|
if response:
|
||||||
response = await request.respond(response)
|
response = await request.respond(response)
|
||||||
|
else:
|
||||||
|
response = request.stream.response
|
||||||
# Make sure that response is finished / run StreamingHTTP callback
|
# Make sure that response is finished / run StreamingHTTP callback
|
||||||
if isinstance(response, BaseHTTPResponse):
|
if isinstance(response, BaseHTTPResponse):
|
||||||
await response.send(end_stream=True)
|
await response.send(end_stream=True)
|
||||||
|
@ -1053,9 +1055,7 @@ class Sanic:
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
# Response Generation Failed
|
# Response Generation Failed
|
||||||
# -------------------------------------------- #
|
# -------------------------------------------- #
|
||||||
response = await self.handle_exception(request, e)
|
await self.handle_exception(request, e)
|
||||||
response = await request.respond(response)
|
|
||||||
await response.send(end_stream=True)
|
|
||||||
|
|
||||||
# -------------------------------------------------------------------- #
|
# -------------------------------------------------------------------- #
|
||||||
# Testing
|
# Testing
|
||||||
|
|
|
@ -274,9 +274,26 @@ class Http:
|
||||||
# From request and handler states we can respond, otherwise be silent
|
# From request and handler states we can respond, otherwise be silent
|
||||||
if self.stage is Stage.HANDLER:
|
if self.stage is Stage.HANDLER:
|
||||||
app = self.protocol.app
|
app = self.protocol.app
|
||||||
|
if self.request is None:
|
||||||
|
self.create_empty_request()
|
||||||
response = await app.handle_exception(self.request, exception)
|
response = await app.handle_exception(self.request, exception)
|
||||||
await self.respond(response).send(end_stream=True)
|
await self.respond(response).send(end_stream=True)
|
||||||
|
|
||||||
|
def create_empty_request(self):
|
||||||
|
"""Current error handling code needs a request object that won't exist
|
||||||
|
if an error occurred during before a request was received. Create a
|
||||||
|
bogus response for error handling use."""
|
||||||
|
# FIXME: Avoid this by refactoring error handling and response code
|
||||||
|
self.request = self.protocol.request_class(
|
||||||
|
url_bytes=self.url.encode() if self.url else b"*",
|
||||||
|
headers=Header({}),
|
||||||
|
version="1.1",
|
||||||
|
method="NONE",
|
||||||
|
transport=self.protocol.transport,
|
||||||
|
app=self.protocol.app,
|
||||||
|
)
|
||||||
|
self.request.stream = self
|
||||||
|
|
||||||
def log_response(self):
|
def log_response(self):
|
||||||
"""
|
"""
|
||||||
Helper method provided to enable the logging of responses in case if
|
Helper method provided to enable the logging of responses in case if
|
||||||
|
|
|
@ -137,6 +137,12 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("protocol.connection_task uncaught")
|
logger.exception("protocol.connection_task uncaught")
|
||||||
finally:
|
finally:
|
||||||
|
if self._debug and self._http and self._http.request:
|
||||||
|
ip = self.transport.get_extra_info("peername")
|
||||||
|
logger.error(
|
||||||
|
"Connection lost before response written"
|
||||||
|
f" @ {ip} {self._http.request}"
|
||||||
|
)
|
||||||
self._http = None
|
self._http = None
|
||||||
self._task = None
|
self._task = None
|
||||||
try:
|
try:
|
||||||
|
@ -229,9 +235,6 @@ class HttpProtocol(asyncio.Protocol):
|
||||||
self.resume_writing()
|
self.resume_writing()
|
||||||
if self._task:
|
if self._task:
|
||||||
self._task.cancel()
|
self._task.cancel()
|
||||||
if self._debug and self._http and self._http.response:
|
|
||||||
ip = self.transport.get_extra_info("peername")
|
|
||||||
logger.error(f"Connection lost before response written @ {ip}")
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception("protocol.connection_lost")
|
logger.exception("protocol.connection_lost")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user