Mercurial > libervia-backend
comparison libervia/backend/tools/common/uri.py @ 4071:4b842c1fb686
refactoring: renamed `sat` package to `libervia.backend`
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 02 Jun 2023 11:49:51 +0200 |
parents | sat/tools/common/uri.py@524856bd7b19 |
children |
comparison
equal
deleted
inserted
replaced
4070:d10748475025 | 4071:4b842c1fb686 |
---|---|
1 #!/usr/bin/env python3 | |
2 | |
3 | |
4 # SAT: a jabber client | |
5 # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) | |
6 | |
7 # This program is free software: you can redistribute it and/or modify | |
8 # it under the terms of the GNU Affero General Public License as published by | |
9 # the Free Software Foundation, either version 3 of the License, or | |
10 # (at your option) any later version. | |
11 | |
12 # This program is distributed in the hope that it will be useful, | |
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 # GNU Affero General Public License for more details. | |
16 | |
17 # You should have received a copy of the GNU Affero General Public License | |
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 | |
20 """ XMPP uri parsing tools """ | |
21 | |
22 from typing import Optional | |
23 import sys | |
24 import urllib.parse | |
25 import urllib.request, urllib.parse, urllib.error | |
26 | |
27 # FIXME: basic implementation, need to follow RFC 5122 | |
28 | |
29 | |
30 def parse_xmpp_uri(uri): | |
31 """Parse an XMPP uri and return a dict with various information | |
32 | |
33 @param uri(unicode): uri to parse | |
34 @return dict(unicode, unicode): data depending of the URI where key can be: | |
35 type: one of ("pubsub", TODO) | |
36 type is always present | |
37 sub_type: can be: | |
38 - microblog | |
39 only used for pubsub for now | |
40 path: XMPP path (jid of the service or entity) | |
41 node: node used | |
42 id: id of the element (item for pubsub) | |
43 @raise ValueError: the scheme is not xmpp | |
44 """ | |
45 uri_split = urllib.parse.urlsplit(uri) | |
46 if uri_split.scheme != "xmpp": | |
47 raise ValueError("this is not a XMPP URI") | |
48 | |
49 # XXX: we don't use jid.JID for path as it can be used both in backend and frontend | |
50 # which may use different JID classes | |
51 data = {"path": urllib.parse.unquote(uri_split.path)} | |
52 | |
53 query_end = uri_split.query.find(";") | |
54 if query_end == -1: | |
55 # we just have a JID | |
56 query_type = None | |
57 else: | |
58 query_type = uri_split.query[:query_end] | |
59 if "=" in query_type: | |
60 raise ValueError("no query type, invalid XMPP URI") | |
61 | |
62 if sys.version_info >= (3, 9): | |
63 # parse_qs behaviour has been modified in Python 3.9, ";" is not understood as a | |
64 # parameter separator anymore but the "separator" argument has been added to | |
65 # change it. | |
66 pairs = urllib.parse.parse_qs(uri_split.geturl(), separator=";") | |
67 else: | |
68 pairs = urllib.parse.parse_qs(uri_split.geturl()) | |
69 for k, v in list(pairs.items()): | |
70 if len(v) != 1: | |
71 raise NotImplementedError("multiple values not managed") | |
72 if k in ("path", "type", "sub_type"): | |
73 raise NotImplementedError("reserved key used in URI, this is not supported") | |
74 data[k] = urllib.parse.unquote(v[0]) | |
75 | |
76 if query_type: | |
77 data["type"] = query_type | |
78 elif "node" in data: | |
79 data["type"] = "pubsub" | |
80 else: | |
81 data["type"] = "" | |
82 | |
83 if "node" in data: | |
84 if data["node"].startswith("urn:xmpp:microblog:"): | |
85 data["sub_type"] = "microblog" | |
86 | |
87 return data | |
88 | |
89 | |
90 def add_pairs(uri, pairs): | |
91 for k, v in pairs.items(): | |
92 uri.append( | |
93 ";" | |
94 + urllib.parse.quote_plus(k.encode("utf-8")) | |
95 + "=" | |
96 + urllib.parse.quote_plus(v.encode("utf-8")) | |
97 ) | |
98 | |
99 | |
100 def build_xmpp_uri(type_: Optional[str] = None, **kwargs: str) -> str: | |
101 uri = ["xmpp:"] | |
102 subtype = kwargs.pop("subtype", None) | |
103 path = kwargs.pop("path") | |
104 uri.append(urllib.parse.quote_plus(path.encode("utf-8")).replace("%40", "@")) | |
105 | |
106 if type_ is None: | |
107 # we have an URI to a JID | |
108 if kwargs: | |
109 raise NotImplementedError( | |
110 "keyword arguments are not supported for URI without type" | |
111 ) | |
112 elif type_ == "pubsub": | |
113 if subtype == "microblog" and not kwargs.get("node"): | |
114 kwargs["node"] = "urn:xmpp:microblog:0" | |
115 if kwargs: | |
116 uri.append("?") | |
117 add_pairs(uri, kwargs) | |
118 else: | |
119 raise NotImplementedError("{type_} URI are not handled yet".format(type_=type_)) | |
120 | |
121 return "".join(uri) |