From: Martine Lenders Date: Sun, 15 Mar 2026 22:41:50 +0000 (+0100) Subject: svcbbase: add docpath SvcParamKey (#1262) X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=08c5a9e6914b63eafb3a8b959c463a9213714ca3;p=thirdparty%2Fdnspython.git svcbbase: add docpath SvcParamKey (#1262) * svcbbase: add docpath SvcParamKey * tests: add tests for docpath * svcbbase: remove debug print * Allow for empty docpath to be printed without "" * Remove now unnecessary DoCPathParam construtor --- diff --git a/dns/rdtypes/svcbbase.py b/dns/rdtypes/svcbbase.py index 148c263c..60d9555c 100644 --- a/dns/rdtypes/svcbbase.py +++ b/dns/rdtypes/svcbbase.py @@ -37,6 +37,7 @@ class ParamKey(dns.enum.IntEnum): IPV6HINT = 6 DOHPATH = 7 OHTTP = 8 + DOCPATH = 10 @classmethod def _maximum(cls): @@ -428,6 +429,25 @@ class OHTTPParam(Param): raise NotImplementedError # pragma: no cover +@dns.immutable.immutable +class DoCPathParam(ALPNParam): + @classmethod + def emptiness(cls): + return Emptiness.ALLOWED + + @classmethod + def from_value(cls, value): + if value is None or value == "": + return None + return super().from_value(value) + + @classmethod + def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613 + if parser.remaining() == 0: + return None + return super().from_wire_parser(parser, origin=origin) + + _class_for_key: dict[ParamKey, Any] = { ParamKey.MANDATORY: MandatoryParam, ParamKey.ALPN: ALPNParam, @@ -437,6 +457,7 @@ _class_for_key: dict[ParamKey, Any] = { ParamKey.ECH: ECHParam, ParamKey.IPV6HINT: IPv6HintParam, ParamKey.OHTTP: OHTTPParam, + ParamKey.DOCPATH: DoCPathParam, } diff --git a/tests/test_svcb.py b/tests/test_svcb.py index c62a393e..c1a8a6ab 100644 --- a/tests/test_svcb.py +++ b/tests/test_svcb.py @@ -225,6 +225,50 @@ class SVCBTestCase(unittest.TestCase): ) self.check_invalid_inputs(invalid_inputs) + def test_svcb_docpath(self): + valid_inputs_two_items = ( + '1 . docpath="n,s"', + "1 . docpath=n,s", + "1 . docpath=\\110,s", + '1 . docpath="\\110,s"', + "1 . docpath=\\n,s", + '1 . docpath="n\\,s"', + "1 . docpath=n\\,s", + "1 . docpath=n\\044s", + "1 . key10=\\001n\\001s", + ) + self.check_valid_inputs(valid_inputs_two_items) + + valid_inputs_one_item = ( + '1 . docpath="n\\\\,s"', + "1 . docpath=n\\\\,s", + "1 . docpath=n\\092\\044s", + "1 . key10=\\003n,s", + ) + self.check_valid_inputs(valid_inputs_one_item) + + valid_inputs_no_item = ( + "1 . docpath", + '1 . docpath=""', + '1 . key10=""', + "1 . key10", + ) + self.check_valid_inputs(valid_inputs_no_item) + + invalid_inputs = ( + "1 . docpath=n,,s", + "1 . docpath=01234567890abcdef01234567890abcdef01234567890abcdef" + "01234567890abcdef01234567890abcdef01234567890abcdef" + "01234567890abcdef01234567890abcdef01234567890abcdef" + "01234567890abcdef01234567890abcdef01234567890abcdef" + "01234567890abcdef01234567890abcdef01234567890abcdef" + "01234567890abcdef", + '1 . docpath=",n,s"', + '1 . docpath="n,s,"', + ) + self.check_invalid_inputs(invalid_inputs) + + def test_svcb_unknown(self): valid_inputs_one_key = ( '1 . key23="key45"', @@ -260,6 +304,18 @@ class SVCBTestCase(unittest.TestCase): ) self.check_valid_inputs(valid_inputs) + valid_inputs = ( + '1 . alpn="co" docpath="n,s"', + "\\# 18 0001 00 0001000302636f 000a0004016e0173", + ) + self.check_valid_inputs(valid_inputs) + + valid_inputs = ( + '1 . alpn="co" docpath', + "\\# 14 0001 00 0001000302636f 000a0000", + ) + self.check_valid_inputs(valid_inputs) + everything = ( '100 foo.com. mandatory="alpn,port" alpn="h2,h3" ' ' no-default-alpn port="12345" ech="abcd" '