2018-07-20 17:15:47 -05:00
|
|
|
import json
|
|
|
|
|
2018-07-20 18:05:51 -05:00
|
|
|
import little_boxes.activitypub as ap
|
2018-07-20 17:15:47 -05:00
|
|
|
import mf2py
|
2018-07-20 18:05:51 -05:00
|
|
|
import requests
|
2018-07-22 04:44:42 -05:00
|
|
|
from little_boxes.errors import NotAnActivityError
|
2019-08-07 14:38:50 -05:00
|
|
|
from little_boxes.errors import RemoteServerUnavailableError
|
2018-07-22 05:04:18 -05:00
|
|
|
from little_boxes.webfinger import get_actor_url
|
2018-07-20 17:15:47 -05:00
|
|
|
|
|
|
|
|
|
|
|
def lookup(url: str) -> ap.BaseActivity:
|
|
|
|
"""Try to find an AP object related to the given URL."""
|
2018-07-21 04:41:49 -05:00
|
|
|
try:
|
2019-04-13 03:00:56 -05:00
|
|
|
if url.startswith("@"):
|
2018-07-30 02:41:04 -05:00
|
|
|
actor_url = get_actor_url(url)
|
|
|
|
if actor_url:
|
|
|
|
return ap.fetch_remote_activity(actor_url)
|
2018-07-22 04:44:42 -05:00
|
|
|
except NotAnActivityError:
|
2018-07-21 04:41:49 -05:00
|
|
|
pass
|
2018-07-26 15:39:12 -05:00
|
|
|
except requests.HTTPError:
|
|
|
|
# Some websites may returns 404, 503 or others when they don't support webfinger, and we're just taking a guess
|
|
|
|
# when performing the lookup.
|
|
|
|
pass
|
2019-08-07 14:38:50 -05:00
|
|
|
except requests.RequestException as err:
|
|
|
|
raise RemoteServerUnavailableError(f"failed to fetch {url}: {err!r}")
|
2018-07-21 04:41:49 -05:00
|
|
|
|
2018-07-20 17:15:47 -05:00
|
|
|
backend = ap.get_backend()
|
2019-08-07 14:38:50 -05:00
|
|
|
try:
|
|
|
|
resp = requests.head(
|
|
|
|
url,
|
|
|
|
timeout=10,
|
|
|
|
allow_redirects=True,
|
|
|
|
headers={"User-Agent": backend.user_agent()},
|
|
|
|
)
|
|
|
|
except requests.RequestException as err:
|
|
|
|
raise RemoteServerUnavailableError(f"failed to GET {url}: {err!r}")
|
|
|
|
|
2019-08-17 11:38:15 -05:00
|
|
|
try:
|
|
|
|
resp.raise_for_status()
|
|
|
|
except Exception:
|
|
|
|
return ap.fetch_remote_activity(url)
|
2018-07-20 17:15:47 -05:00
|
|
|
|
|
|
|
# If the page is HTML, maybe it contains an alternate link pointing to an AP object
|
|
|
|
for alternate in mf2py.parse(resp.text).get("alternates", []):
|
|
|
|
if alternate.get("type") == "application/activity+json":
|
|
|
|
return ap.fetch_remote_activity(alternate["url"])
|
|
|
|
|
|
|
|
try:
|
|
|
|
# Maybe the page was JSON-LD?
|
|
|
|
data = resp.json()
|
|
|
|
return ap.parse_activity(data)
|
|
|
|
except json.JSONDecodeError:
|
|
|
|
pass
|
|
|
|
|
|
|
|
# Try content negotiation (retry with the AP Accept header)
|
|
|
|
return ap.fetch_remote_activity(url)
|