From 5a6e0c297e54c6e9516f9ce3a96258f7dc6cfb88 Mon Sep 17 00:00:00 2001 From: chadawagner Date: Fri, 15 Oct 2021 23:35:52 -0700 Subject: [PATCH 1/4] handle JSON decode error when parsing error response --- twirp/client.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/twirp/client.py b/twirp/client.py index 7f81238..df8b439 100644 --- a/twirp/client.py +++ b/twirp/client.py @@ -22,8 +22,14 @@ def _make_request(self, *args, url, ctx, request, response_obj, **kwargs): response = response_obj() response.ParseFromString(resp.content) return response - else: + try: raise exceptions.TwirpServerException.from_json(resp.json()) + except: + if resp.status_code == 503: + code = errors.Errors.Unavailable + else: + code = errors.Errors.Unknown + raise exceptions.TwirpServerException(code=code, message=resp.text) # Todo: handle error except requests.exceptions.Timeout as e: raise exceptions.TwirpServerException( From a4d5669bb52c64ec2b84fb9cfd04db29afa43934 Mon Sep 17 00:00:00 2001 From: Chad Wagner Date: Sun, 14 Nov 2021 22:40:12 -0800 Subject: [PATCH 2/4] catch only JSONDecodeError --- twirp/client.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/twirp/client.py b/twirp/client.py index df8b439..1e7755d 100644 --- a/twirp/client.py +++ b/twirp/client.py @@ -1,3 +1,4 @@ +import json import requests from . import exceptions @@ -24,7 +25,7 @@ def _make_request(self, *args, url, ctx, request, response_obj, **kwargs): return response try: raise exceptions.TwirpServerException.from_json(resp.json()) - except: + except json.JSONDecodeError: if resp.status_code == 503: code = errors.Errors.Unavailable else: From e3adfc7c92642d963af6c0db97b63e3761f64c0c Mon Sep 17 00:00:00 2001 From: Chad Wagner Date: Mon, 15 Nov 2021 00:10:25 -0800 Subject: [PATCH 3/4] raise exception from None --- twirp/client.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/twirp/client.py b/twirp/client.py index 1e7755d..6e62f16 100644 --- a/twirp/client.py +++ b/twirp/client.py @@ -30,7 +30,9 @@ def _make_request(self, *args, url, ctx, request, response_obj, **kwargs): code = errors.Errors.Unavailable else: code = errors.Errors.Unknown - raise exceptions.TwirpServerException(code=code, message=resp.text) + raise exceptions.TwirpServerException( + code=code, message=resp.text + ) from None # Todo: handle error except requests.exceptions.Timeout as e: raise exceptions.TwirpServerException( From f2f4b1c339e6d1c6942eeb65a3144d548c71f095 Mon Sep 17 00:00:00 2001 From: Chad Wagner Date: Sat, 27 Nov 2021 23:56:30 -0800 Subject: [PATCH 4/4] handle errors from intermediate proxies in client --- twirp/client.py | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/twirp/client.py b/twirp/client.py index 6e62f16..fe34fc1 100644 --- a/twirp/client.py +++ b/twirp/client.py @@ -26,13 +26,7 @@ def _make_request(self, *args, url, ctx, request, response_obj, **kwargs): try: raise exceptions.TwirpServerException.from_json(resp.json()) except json.JSONDecodeError: - if resp.status_code == 503: - code = errors.Errors.Unavailable - else: - code = errors.Errors.Unknown - raise exceptions.TwirpServerException( - code=code, message=resp.text - ) from None + raise self._twirp_error_from_intermediary(resp) from None # Todo: handle error except requests.exceptions.Timeout as e: raise exceptions.TwirpServerException( @@ -46,3 +40,42 @@ def _make_request(self, *args, url, ctx, request, response_obj, **kwargs): message=str(e), meta={"original_exception": e}, ) + + @staticmethod + def _twirp_error_from_intermediary(resp): + # see https://twitchtv.github.io/twirp/docs/errors.html#http-errors-from-intermediary-proxies + meta = { + 'http_error_from_intermediary': 'true', + 'status_code': str(resp.status_code), + } + + if resp.is_redirect: + # twirp uses POST which should not redirect + code = errors.Errors.Internal + location = resp.headers.get('location') + message = 'unexpected HTTP status code %d "%s" received, Location="%s"' % ( + resp.status_code, + resp.reason, + location, + ) + meta['location'] = location + + else: + code = { + 400: errors.Errors.Internal, # JSON response should have been returned + 401: errors.Errors.Unauthenticated, + 403: errors.Errors.PermissionDenied, + 404: errors.Errors.BadRoute, + 429: errors.Errors.ResourceExhausted, + 502: errors.Errors.Unavailable, + 503: errors.Errors.Unavailable, + 504: errors.Errors.Unavailable, + }.get(resp.status_code, errors.Errors.Unknown) + + message = 'Error from intermediary with HTTP status code %d "%s"' % ( + resp.status_code, + resp.reason, + ) + meta['body'] = resp.text + + return exceptions.TwirpServerException(code=code, message=message, meta=meta)