]> git.ipfire.org Git - thirdparty/dnspython.git/commitdiff
Use the version's origin if the zone doesn't have one yet. [#766]
authorBob Halley <halley@dnspython.org>
Sun, 23 Jan 2022 23:38:05 +0000 (15:38 -0800)
committerBob Halley <halley@play-bow.org>
Mon, 24 Jan 2022 21:15:38 +0000 (13:15 -0800)
(cherry picked from commit c07d11ea060bc4bb02ee8deadba8365bd5b8b99d)

dns/transaction.py
dns/zone.py
tests/test_zone.py

index ae7417edb10c8e929a92ecab3ccfe3038a2cba61..846db4ec30048cdbad230126d21739a5133d3f53 100644 (file)
@@ -389,7 +389,7 @@ class Transaction:
             if rdataset.rdclass != self.manager.get_class():
                 raise ValueError(f'{method} has objects of wrong RdataClass')
             if rdataset.rdtype == dns.rdatatype.SOA:
-                (_, _, origin) = self.manager.origin_information()
+                (_, _, origin) = self._origin_information()
                 if name != origin:
                     raise ValueError(f'{method} has non-origin SOA')
             self._raise_if_not_empty(method, args)
@@ -585,3 +585,12 @@ class Transaction:
         Returns a node or ``None``.
         """
         raise NotImplementedError  # pragma: no cover
+
+    #
+    # Low-level API with a default implementation, in case a subclass needs
+    # to override.
+    #
+
+    def _origin_information(self):
+        # This is only used by _add()
+        return self.manager.origin_information()
index 2e73144613b20b5134f9cb42876cd820fd1bd4eb..69c3a73843afec52f3ca0bf0731c216201d4c80f 100644 (file)
@@ -870,10 +870,14 @@ class Version:
 
     def _validate_name(self, name):
         if name.is_absolute():
-            if not name.is_subdomain(self.zone.origin):
+            if self.origin is None:
+                # This should probably never happen as other code (e.g.
+                # _rr_line) will notice the lack of an origin before us, but
+                # we check just in case!
+                raise KeyError('no zone origin is defined')
+            if not name.is_subdomain(self.origin):
                 raise KeyError("name is not a subdomain of the zone origin")
             if self.zone.relativize:
-                # XXXRTH should it be an error if self.origin is still None?
                 name = name.relativize(self.origin)
         return name
 
@@ -1030,6 +1034,18 @@ class Transaction(dns.transaction.Transaction):
     def _get_node(self, name):
         return self.version.get_node(name)
 
+    def _origin_information(self):
+        (absolute, relativize, effective) = self.manager.origin_information()
+        if absolute is None and self.version.origin is not None:
+            # No origin has been committed yet, but we've learned one as part of
+            # this txn.  Use it.
+            absolute = self.version.origin
+            if relativize:
+                effective = dns.name.empty
+            else:
+                effective = absolute
+        return (absolute, relativize, effective)
+
 
 def from_text(text, origin=None, rdclass=dns.rdataclass.IN,
               relativize=True, zone_factory=Zone, filename=None,
index bdc99a35a972e24fd3c759bc0624ccf82d30cb6e..d0765df1f7fc5e8900f8224ae69b40f5e2ffb7a5 100644 (file)
@@ -1012,6 +1012,13 @@ class VersionedZoneTestCase(unittest.TestCase):
             rds = txn.get('example.', 'soa')
             self.assertEqual(rds[0].serial, 1)
 
+    def testNoRelativizeReaderOriginInText(self):
+        z = dns.zone.from_text(example_text, relativize=False,
+                               zone_factory=dns.versioned.Zone)
+        with z.reader(serial=1) as txn:
+            rds = txn.get('example.', 'soa')
+            self.assertEqual(rds[0].serial, 1)
+
     def testCnameAndOtherDataAddOther(self):
         z = dns.zone.from_text(example_cname, 'example.', relativize=True,
                                zone_factory=dns.versioned.Zone)