Skip to content
Snippets Groups Projects
Verified Commit d715fa0e authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Fixed error handling

parent a82bca0b
No related branches found
No related tags found
No related merge requests found
import asyncio import asyncio
import aiohttp.client import aiohttp.client
import json import json
import ssl
from channels.generic.http import AsyncHttpConsumer from channels.generic.http import AsyncHttpConsumer
...@@ -33,11 +34,58 @@ def wrapper_500(callback): ...@@ -33,11 +34,58 @@ def wrapper_500(callback):
return callback return callback
def ignore_aiohttp_ssl_eror(loop, aiohttpversion="3.5.4"):
"""Ignore aiohttp #3535 issue with SSL data after close
There appears to be an issue on Python 3.7 and aiohttp SSL that throws a
ssl.SSLError fatal error (ssl.SSLError: [SSL: KRB5_S_INIT] application data
after close notify (_ssl.c:2609)) after we are already done with the
connection. See GitHub issue aio-libs/aiohttp#3535
Given a loop, this sets up a exception handler that ignores this specific
exception, but passes everything else on to the previous exception handler
this one replaces.
If the current aiohttp version is not exactly equal to aiohttpversion
nothing is done, assuming that the next version will have this bug fixed.
This can be disabled by setting this parameter to None
"""
if aiohttpversion is not None and aiohttp.__version__ != aiohttpversion:
return
orig_handler = loop.get_exception_handler()
def ignore_ssl_error(loop, context):
if context.get("message") == "SSL error in data received":
# validate we have the right exception, transport and protocol
exception = context.get("exception")
protocol = context.get("protocol")
if (
isinstance(exception, ssl.SSLError)
and exception.reason == "KRB5_S_INIT"
and isinstance(protocol, asyncio.sslproto.SSLProtocol)
and isinstance(
protocol._app_protocol, aiohttp.client_proto.ResponseHandler
)
):
if loop.get_debug():
asyncio.log.logger.debug("Ignoring aiohttp SSL KRB5_S_INIT error")
return
if orig_handler is not None:
orig_handler(loop, context)
else:
loop.default_exception_handler(context)
loop.set_exception_handler(ignore_ssl_error)
class SearchSingleConsumer(AsyncHttpConsumer): class SearchSingleConsumer(AsyncHttpConsumer):
@wrapper_500 @wrapper_500
async def handle(self, body): async def handle(self, body):
lookup_type = self.scope["url_route"]["kwargs"]["lookup_type"] lookup_type = self.scope["url_route"]["kwargs"]["lookup_type"]
lookup = self.scope["url_route"]["kwargs"]["lookup"] lookup = self.scope["url_route"]["kwargs"]["lookup"]
ignore_aiohttp_ssl_eror(asyncio.get_running_loop())
try: try:
source = sources.registry._data[lookup_type] source = sources.registry._data[lookup_type]
except KeyError: except KeyError:
...@@ -59,16 +107,35 @@ async def do_lookup(lookup, lookup_type, session, source, results): ...@@ -59,16 +107,35 @@ async def do_lookup(lookup, lookup_type, session, source, results):
try: try:
data = await source.get(lookup, session) data = await source.get(lookup, session)
profile = sources.result_to_retribute_profile(lookup_type, lookup, data) profile = sources.result_to_retribute_profile(lookup_type, lookup, data)
except (exceptions.SearchError, aiohttp.ClientError) as e: except (
exceptions.SearchError,
aiohttp.ClientError,
serializers.serializers.ValidationError,
asyncio.TimeoutError,
) as e:
results[":".join([lookup_type, lookup])] = None
return
except Exception as e:
print("ERROR: unhandled - {}, {}".format(e.__class__, e))
results[":".join([lookup_type, lookup])] = None results[":".join([lookup_type, lookup])] = None
return return
results[":".join([lookup_type, lookup])] = profile results[":".join([lookup_type, lookup])] = profile
class SearchMultipleConsumer(AsyncHttpConsumer): class SearchMultipleConsumer(AsyncHttpConsumer):
@wrapper_500 @wrapper_500
async def handle(self, body): async def handle(self, body):
if self.scope["method"] == "OPTIONS":
return await self.send_response(
200,
b"",
headers=[
(b"Content-Type", b"application/json"),
(b"Access-Control-Allow-Origin", b"*"),
(b"Access-Control-Allow-Headers", b"content-type"),
],
)
ignore_aiohttp_ssl_eror(asyncio.get_running_loop())
if self.scope["method"] not in ["POST"]: if self.scope["method"] not in ["POST"]:
return await self.send_response(405, b"") return await self.send_response(405, b"")
...@@ -103,6 +170,7 @@ class SearchMultipleConsumer(AsyncHttpConsumer): ...@@ -103,6 +170,7 @@ class SearchMultipleConsumer(AsyncHttpConsumer):
try: try:
await asyncio.gather(*tasks) await asyncio.gather(*tasks)
except Exception as e: except Exception as e:
print("ERROR: unhandled - {}, {}".format(e.__class__, e))
await json_response(self, 500, {}) await json_response(self, 500, {})
raise raise
await json_response(self, 200, results) await json_response(self, 200, results)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment