Silence a few common errors when fetching (#404)

Downgrade nodeinfo json error to a captured message
This commit is contained in:
Michael Manfre 2023-01-13 12:53:02 -05:00 committed by GitHub
parent fa688a5a73
commit 18b50ce0e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 22 deletions

View file

@ -1,4 +1,5 @@
import hashlib
import json
import mimetypes
import re
from collections.abc import Iterable
@ -872,12 +873,15 @@ class Post(StatorModel):
f"Error fetching post from {object_uri}: {response.status_code}",
{response.content},
)
post = cls.by_ap(
canonicalise(response.json(), include_security=True),
create=True,
update=True,
fetch_author=True,
)
try:
post = cls.by_ap(
canonicalise(response.json(), include_security=True),
create=True,
update=True,
fetch_author=True,
)
except (json.JSONDecodeError, ValueError):
raise cls.DoesNotExist(f"Invalid ld+json response for {object_uri}")
# We may need to fetch the author too
if post.author.state == IdentityStates.outdated:
async_to_sync(post.author.fetch_actor)()

View file

@ -1,4 +1,5 @@
import json
import ssl
from typing import Optional
import httpx
@ -7,6 +8,7 @@ from asgiref.sync import sync_to_async
from django.conf import settings
from django.db import models
from core.exceptions import capture_message
from stator.models import State, StateField, StateGraph, StatorModel
from users.schemas import NodeInfo
@ -164,6 +166,8 @@ class Domain(StatorModel):
)
except httpx.HTTPError:
pass
except ssl.SSLCertVerificationError:
return None
else:
try:
for link in response.json().get("links", []):
@ -183,7 +187,7 @@ class Domain(StatorModel):
headers={"Accept": "application/json"},
)
response.raise_for_status()
except httpx.HTTPError as ex:
except (httpx.HTTPError, ssl.SSLCertVerificationError) as ex:
response = getattr(ex, "response", None)
if (
response
@ -199,9 +203,10 @@ class Domain(StatorModel):
try:
info = NodeInfo(**response.json())
except json.JSONDecodeError as ex:
raise ValueError(
capture_message(
f"Client error decoding nodeinfo: domain={self.domain}, error={str(ex)}"
)
return None
return info
@property

View file

@ -1,3 +1,4 @@
import ssl
from functools import cached_property, partial
from typing import Literal
from urllib.parse import urlparse
@ -642,7 +643,10 @@ class Identity(StatorModel):
(actor uri, canonical handle) or None, None if it does not resolve.
"""
domain = handle.split("@")[1].lower()
webfinger_url = await cls.fetch_webfinger_url(domain)
try:
webfinger_url = await cls.fetch_webfinger_url(domain)
except ssl.SSLCertVerificationError:
return None, None
# Go make a Webfinger request
async with httpx.AsyncClient(
@ -656,7 +660,7 @@ class Identity(StatorModel):
headers={"Accept": "application/json"},
)
response.raise_for_status()
except httpx.RequestError as ex:
except (httpx.HTTPError, ssl.SSLCertVerificationError) as ex:
response = getattr(ex, "response", None)
if (
response
@ -703,25 +707,24 @@ class Identity(StatorModel):
method="get",
uri=self.actor_uri,
)
except httpx.RequestError:
except (httpx.RequestError, ssl.SSLCertVerificationError):
return False
content_type = response.headers.get("content-type")
if content_type and "html" in content_type:
# Some servers don't properly handle "application/activity+json"
return False
if response.status_code == 410:
# Their account got deleted, so let's do the same.
if self.pk:
status_code = response.status_code
if status_code >= 400:
if status_code == 410 and self.pk:
# Their account got deleted, so let's do the same.
await Identity.objects.filter(pk=self.pk).adelete()
return False
if response.status_code == 404:
# We don't trust this as much as 410 Gone, but skip for now
return False
if response.status_code >= 500:
return False
if response.status_code >= 400:
if status_code >= 500 or status_code in [403, 404, 410]:
# Common errors with other server, not worth reporting
return False
raise ValueError(
f"Client error fetching actor at {self.actor_uri}: {response.status_code}",
f"Client error fetching actor at {self.actor_uri}: {status_code}",
response.content,
)
document = canonicalise(response.json(), include_security=True)