]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Add IDNA codec support to tokenizer and dns.rdata.from_text()
authorBob Halley <halley@dnspython.org>
Sun, 3 May 2020 14:23:54 +0000 (07:23 -0700)
committerBob Halley <halley@dnspython.org>
Sun, 3 May 2020 14:23:54 +0000 (07:23 -0700)
dns/rdata.py
dns/tokenizer.py
tests/test_rdata.py

index 6396d1bb96e8f717d6fa033c43aad75034feadc8..dafd4c3be5b69d41746b961a89ff3745b5bcb220 100644 (file)
@@ -392,7 +392,7 @@ def get_rdata_class(rdclass, rdtype):
 
 
 def from_text(rdclass, rdtype, tok, origin=None, relativize=True,
-              relativize_to=None):
+              relativize_to=None, idna_codec=None):
     """Build an rdata object from text format.
 
     This function attempts to dynamically load a class which
@@ -420,11 +420,18 @@ def from_text(rdclass, rdtype, tok, origin=None, relativize=True,
     *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use
     when relativizing names.  If not set, the *origin* value will be used.
 
+    *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
+    encoder/decoder to use if a tokenizer needs to be created.  If
+    ``None``, the default IDNA 2003 encoder/decoder is used.  If a
+    tokenizer is not created, then the codec associated with the tokenizer
+    is the one that is used.
+
     Returns an instance of the chosen Rdata subclass.
+
     """
 
     if isinstance(tok, str):
-        tok = dns.tokenizer.Tokenizer(tok)
+        tok = dns.tokenizer.Tokenizer(tok, idna_codec=idna_codec)
     cls = get_rdata_class(rdclass, rdtype)
     if cls != GenericRdata:
         # peek at first token
index 8585ccc8978d850400108b8ffb9a25a66e0f3132..547e030f4f2419fc9387bfcef861a3d93ba31b50 100644 (file)
@@ -218,9 +218,13 @@ class Tokenizer(object):
     line_number: The current line number
 
     filename: A filename that will be returned by the where() method.
+
+    idna_codec: A dns.name.IDNACodec, specifies the IDNA
+    encoder/decoder.  If None, the default IDNA 2003
+    encoder/decoder is used.
     """
 
-    def __init__(self, f=sys.stdin, filename=None):
+    def __init__(self, f=sys.stdin, filename=None, idna_codec=None):
         """Initialize a tokenizer instance.
 
         f: The file to tokenize.  The default is sys.stdin.
@@ -229,6 +233,10 @@ class Tokenizer(object):
 
         filename: the name of the filename that the where() method
         will return.
+
+        idna_codec: A dns.name.IDNACodec, specifies the IDNA
+        encoder/decoder.  If None, the default IDNA 2003
+        encoder/decoder is used.
         """
 
         if isinstance(f, str):
@@ -254,6 +262,9 @@ class Tokenizer(object):
         self.delimiters = _DELIMITERS
         self.line_number = 1
         self.filename = filename
+        if idna_codec is None:
+            idna_codec = dns.name.IDNA_2003
+        self.idna_codec = idna_codec
 
     def _get_char(self):
         """Read a character from input.
@@ -565,7 +576,7 @@ class Tokenizer(object):
         """
         if not token.is_identifier():
             raise dns.exception.SyntaxError('expecting an identifier')
-        name = dns.name.from_text(token.value, origin)
+        name = dns.name.from_text(token.value, origin, self.idna_codec)
         return name.choose_relativity(relativize_to or origin, relativize)
 
     def get_name(self, origin=None, relativize=False, relativize_to=None):
index c41758c78606904524bb9c649170b48cb5d4781d..55c6c2c0d506ef88d55c631b20ecdffb002d9069 100644 (file)
@@ -1,3 +1,4 @@
+# -*- coding: utf-8
 # Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
 
 # Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
@@ -17,6 +18,7 @@
 
 import unittest
 
+import dns.name
 import dns.rdata
 import dns.rdataclass
 import dns.rdatatype
@@ -104,5 +106,16 @@ class RdataTestCase(unittest.TestCase):
                                     '"foo\u200b\\123bar"')
         self.assertEqual(str(rdata), '"foo\\226\\128\\139{bar"')
 
+    def test_unicode_idna2003_in_rdata(self):
+        rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+                                    "Königsgäßchen")
+        self.assertEqual(str(rdata.target), 'xn--knigsgsschen-lcb0w')
+
+    def test_unicode_idna2008_in_rdata(self):
+        rdata = dns.rdata.from_text(dns.rdataclass.IN, dns.rdatatype.NS,
+                                    "Königsgäßchen",
+                                    idna_codec=dns.name.IDNA_2008)
+        self.assertEqual(str(rdata.target), 'xn--knigsgchen-b4a3dun')
+
 if __name__ == '__main__':
     unittest.main()