diff options
author | Bob Halley <halley@dnspython.org> | 2022-01-23 15:38:05 -0800 |
---|---|---|
committer | Bob Halley <halley@dnspython.org> | 2022-01-23 15:38:05 -0800 |
commit | c07d11ea060bc4bb02ee8deadba8365bd5b8b99d (patch) | |
tree | 07b0a7447376d25f4016a9f14242ff0e058f2bff | |
parent | ecdc63b866856d7a38f73484722226f29b95224f (diff) | |
download | dnspython-absolute_origin_zone_txn_fix.tar.gz |
Use the version's origin if the zone doesn't have one yet. [#766]absolute_origin_zone_txn_fix
-rw-r--r-- | dns/transaction.py | 11 | ||||
-rw-r--r-- | dns/zone.py | 20 | ||||
-rw-r--r-- | tests/test_zone.py | 7 |
3 files changed, 35 insertions, 3 deletions
diff --git a/dns/transaction.py b/dns/transaction.py index ae7417e..846db4e 100644 --- a/dns/transaction.py +++ b/dns/transaction.py @@ -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() diff --git a/dns/zone.py b/dns/zone.py index 2e73144..69c3a73 100644 --- a/dns/zone.py +++ b/dns/zone.py @@ -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, diff --git a/tests/test_zone.py b/tests/test_zone.py index bdc99a3..d0765df 100644 --- a/tests/test_zone.py +++ b/tests/test_zone.py @@ -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) |