Verified Commit d715fa0e authored by Eliot Berriot's avatar Eliot Berriot
Browse files

Fixed error handling

parent a82bca0b
import asyncio
import aiohttp.client
import json
import ssl
from channels.generic.http import AsyncHttpConsumer
......@@ -33,11 +34,58 @@ def wrapper_500(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):
@wrapper_500
async def handle(self, body):
lookup_type = self.scope["url_route"]["kwargs"]["lookup_type"]
lookup = self.scope["url_route"]["kwargs"]["lookup"]
ignore_aiohttp_ssl_eror(asyncio.get_running_loop())
try:
source = sources.registry._data[lookup_type]
except KeyError:
......@@ -59,16 +107,35 @@ async def do_lookup(lookup, lookup_type, session, source, results):
try:
data = await source.get(lookup, session)
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
return
results[":".join([lookup_type, lookup])] = profile
class SearchMultipleConsumer(AsyncHttpConsumer):
@wrapper_500
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"]:
return await self.send_response(405, b"")
......@@ -103,6 +170,7 @@ class SearchMultipleConsumer(AsyncHttpConsumer):
try:
await asyncio.gather(*tasks)
except Exception as e:
print("ERROR: unhandled - {}, {}".format(e.__class__, e))
await json_response(self, 500, {})
raise
await json_response(self, 200, results)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment