component AP gateway: HTML redirection:
when a request is done on AP endpoint and `Accept` header is not set to `application/json`, the request can now be redirected to a configurable URL.
This commit is contained in:
parent
1ebe54a024
commit
020da52ddd
2 changed files with 61 additions and 5 deletions
|
|
@ -20,7 +20,6 @@ import base64
|
|||
import calendar
|
||||
import hashlib
|
||||
import json
|
||||
from os import access
|
||||
from pathlib import Path
|
||||
from pprint import pformat
|
||||
import re
|
||||
|
|
@ -33,7 +32,6 @@ from typing import (
|
|||
Optional,
|
||||
Set,
|
||||
Tuple,
|
||||
Type,
|
||||
Union,
|
||||
overload,
|
||||
)
|
||||
|
|
@ -266,6 +264,27 @@ class APGateway:
|
|||
self.host.memory.getConfig(CONF_SECTION, "auto_mentions", C.BOOL_TRUE)
|
||||
)
|
||||
|
||||
html_redirect: Dict[str, Union[str, dict]] = self.host.memory.getConfig(
|
||||
CONF_SECTION, 'html_redirect_dict', {}
|
||||
)
|
||||
self.html_redirect: Dict[str, List[dict]] = {}
|
||||
for url_type, target in html_redirect.items():
|
||||
if isinstance(target, str):
|
||||
target = {"url": target}
|
||||
elif not isinstance(target, dict):
|
||||
raise exceptions.ConfigError(
|
||||
f"html_redirect target must be a URL or a dict, not {target!r}"
|
||||
)
|
||||
filters = target.setdefault("filters", {})
|
||||
if "url" not in target:
|
||||
log.warning(f"invalid HTML redirection, missing target URL: {target}")
|
||||
continue
|
||||
# a slash in the url_type is a syntactic shortcut to have a node filter
|
||||
if "/" in url_type:
|
||||
url_type, node_filter = url_type.split("/", 1)
|
||||
filters["node"] = node_filter
|
||||
self.html_redirect.setdefault(url_type, []).append(target)
|
||||
|
||||
# HTTP server launch
|
||||
self.server = HTTPServer(self)
|
||||
if connection_type == 'http':
|
||||
|
|
@ -361,7 +380,7 @@ class APGateway:
|
|||
if resp.code == 404:
|
||||
raise exceptions.NotFound(f"Can't find resource at {url}")
|
||||
else:
|
||||
msg = f"HTTP error {resp.code}: {text}"
|
||||
msg = f"HTTP error {resp.code} (url: {url}): {text}"
|
||||
raise exceptions.ExternalRequestError(msg)
|
||||
try:
|
||||
return await treq.json_content(resp)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import unicodedata
|
|||
|
||||
from twisted.web import http, resource as web_resource, server
|
||||
from twisted.web import static
|
||||
from twisted.web import util as web_util
|
||||
from twisted.python import failure
|
||||
from twisted.internet import defer
|
||||
from twisted.words.protocols.jabber import jid, error
|
||||
|
|
@ -40,8 +41,8 @@ from sat.tools.common import date_utils, uri
|
|||
from sat.memory.sqla_mapping import SubscriptionState
|
||||
|
||||
from .constants import (
|
||||
NS_AP, CONTENT_TYPE_AP, TYPE_ACTOR, TYPE_INBOX, TYPE_SHARED_INBOX, TYPE_OUTBOX,
|
||||
TYPE_EVENT, AP_REQUEST_TYPES, PAGE_SIZE, ACTIVITY_TYPES_LOWER,
|
||||
NS_AP, MEDIA_TYPE_AP, CONTENT_TYPE_AP, TYPE_ACTOR, TYPE_INBOX, TYPE_SHARED_INBOX,
|
||||
TYPE_OUTBOX, TYPE_EVENT, AP_REQUEST_TYPES, PAGE_SIZE, ACTIVITY_TYPES_LOWER,
|
||||
ACTIVIY_NO_ACCOUNT_ALLOWED, SIGN_HEADERS, HS2019, SIGN_EXP, TYPE_FOLLOWERS,
|
||||
TYPE_FOLLOWING, TYPE_ITEM, TYPE_LIKE, TYPE_REACTION, ST_AP_CACHE
|
||||
)
|
||||
|
|
@ -949,6 +950,42 @@ class HTTPAPGServer(web_resource.Resource):
|
|||
path
|
||||
)
|
||||
request_type, extra_args = self.apg.parseAPURL(ap_url)
|
||||
if ((request.getHeader("accept") != MEDIA_TYPE_AP
|
||||
and request_type in self.apg.html_redirect)):
|
||||
# this is not a AP request, and we have a redirections for it
|
||||
kw = {}
|
||||
if extra_args:
|
||||
kw["jid"], kw["node"] = await self.apg.getJIDAndNode(extra_args[0])
|
||||
kw["jid_user"] = kw["jid"].user
|
||||
if kw["node"] is None:
|
||||
kw["node"] = self.apg._m.namespace
|
||||
if len(extra_args) > 1:
|
||||
kw["item"] = extra_args[1]
|
||||
else:
|
||||
kw["item"] = ""
|
||||
else:
|
||||
kw["jid"], kw["jid_user"], kw["node"], kw["item"] = "", "", "", ""
|
||||
|
||||
redirections = self.apg.html_redirect[request_type]
|
||||
for redirection in redirections:
|
||||
filters = redirection["filters"]
|
||||
if not filters:
|
||||
break
|
||||
# if we have filter, they must all match
|
||||
elif all(v in kw[k] for k,v in filters.items()):
|
||||
break
|
||||
else:
|
||||
# no redirection is matching
|
||||
redirection = None
|
||||
|
||||
if redirection is not None:
|
||||
kw = {k: parse.quote(str(v), safe="") for k,v in kw.items()}
|
||||
target_url = redirection["url"].format(**kw)
|
||||
content = web_util.redirectTo(target_url.encode(), request)
|
||||
request.write(content)
|
||||
request.finish()
|
||||
return
|
||||
|
||||
if len(extra_args) == 0:
|
||||
if request_type != "shared_inbox":
|
||||
raise exceptions.DataError(f"Invalid request type: {request_type!r}")
|
||||
|
|
|
|||
Loading…
Reference in a new issue