From 51ae78a33cfbaa01e7972aee3d3983e446c506b7 Mon Sep 17 00:00:00 2001 From: Michael Manfre Date: Thu, 19 Jan 2023 15:14:55 -0500 Subject: [PATCH] Downgrade most fetch related errors to capture_message (#443) --- activities/models/post.py | 3 ++- core/signatures.py | 20 +++++++++++++------- users/models/domain.py | 13 +++++++++---- users/models/identity.py | 19 +++++++++++-------- 4 files changed, 35 insertions(+), 20 deletions(-) diff --git a/activities/models/post.py b/activities/models/post.py index d2f31bd..e9ec76c 100644 --- a/activities/models/post.py +++ b/activities/models/post.py @@ -3,6 +3,7 @@ import hashlib import json import mimetypes import re +import ssl from collections.abc import Iterable from typing import Optional from urllib.parse import urlparse @@ -890,7 +891,7 @@ class Post(StatorModel): response = async_to_sync(SystemActor().signed_request)( method="get", uri=object_uri ) - except httpx.RequestError: + except (httpx.HTTPError, ssl.SSLCertVerificationError): raise cls.DoesNotExist(f"Could not fetch {object_uri}") if response.status_code in [404, 410]: raise cls.DoesNotExist(f"No post at {object_uri}") diff --git a/core/signatures.py b/core/signatures.py index a0f8279..9434588 100644 --- a/core/signatures.py +++ b/core/signatures.py @@ -12,6 +12,7 @@ from django.http import HttpRequest from django.utils import timezone from django.utils.http import http_date, parse_http_date from httpx._types import TimeoutTypes +from idna.core import InvalidCodepoint from pyld import jsonld from core.ld import format_ld_date @@ -235,13 +236,18 @@ class HttpSignature: # Send the request with all those headers except the pseudo one del headers["(request-target)"] async with httpx.AsyncClient(timeout=timeout) as client: - response = await client.request( - method, - uri, - headers=headers, - content=body_bytes, - follow_redirects=method == "get", - ) + try: + response = await client.request( + method, + uri, + headers=headers, + content=body_bytes, + follow_redirects=method == "get", + ) + except InvalidCodepoint as ex: + # Convert to a more generic error we handle + raise httpx.HTTPError(f"InvalidCodepoint: {str(ex)}") from None + if ( method == "post" and response.status_code >= 400 diff --git a/users/models/domain.py b/users/models/domain.py index 1aeca04..ecf6347 100644 --- a/users/models/domain.py +++ b/users/models/domain.py @@ -195,9 +195,14 @@ class Domain(StatorModel): and response.status_code < 500 and response.status_code not in [401, 403, 404, 406, 410] ): - raise ValueError( - f"Client error fetching nodeinfo: domain={self.domain}, code={response.status_code}", - response.content, + capture_message( + f"Client error fetching nodeinfo: {str(ex)}", + extras={ + "code": response.status_code, + "content": response.content, + "domain": self.domain, + "nodeinfo20_url": nodeinfo20_url, + }, ) return None @@ -206,7 +211,7 @@ class Domain(StatorModel): except (json.JSONDecodeError, pydantic.ValidationError) as ex: capture_message( f"Client error decoding nodeinfo: {str(ex)}", - extra={ + extras={ "domain": self.domain, "nodeinfo20_url": nodeinfo20_url, }, diff --git a/users/models/identity.py b/users/models/identity.py index 864c572..b31575c 100644 --- a/users/models/identity.py +++ b/users/models/identity.py @@ -12,7 +12,7 @@ from django.utils import timezone from django.utils.functional import lazy from lxml import etree -from core.exceptions import ActorMismatchError +from core.exceptions import ActorMismatchError, capture_message from core.html import ContentRenderer, html_to_plaintext, strip_html from core.ld import ( canonicalise, @@ -723,14 +723,17 @@ class Identity(StatorModel): # Their account got deleted, so let's do the same. await Identity.objects.filter(pk=self.pk).adelete() - if status_code >= 500 or status_code in [403, 404, 410]: - # Common errors with other server, not worth reporting - return False + if status_code < 500 and status_code not in [401, 403, 404, 406, 410]: + capture_message( + f"Client error fetching actor at {self.actor_uri}: {status_code}", + extras={ + "identity": self.pk, + "domain": self.domain_id, + "content": response.content, + }, + ) + return False - raise ValueError( - f"Client error fetching actor at {self.actor_uri}: {status_code}", - response.content, - ) document = canonicalise(response.json(), include_security=True) if "type" not in document: return False