commit 6a3882a372149ff18b5be7f82fa4b9e5cac113b1 Author: Damian Johnson atagar@torproject.org Date: Thu Dec 4 17:30:59 2014 -0800
Throwing DescriptorUnavailable when tor can't provide one for a relay
Tor gives a pretty sucky 'GETINFO request contained unrecognized keywords: ns/id/5AC9C5AA75BA1F18D8459B326B4B8111A856D290' error when the descriptor is unavailable for a given relay. Having us give something better...
https://trac.torproject.org/projects/tor/ticket/13879 --- docs/change_log.rst | 1 + stem/__init__.py | 8 ++++++++ stem/control.py | 40 ++++++++++++++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 8 deletions(-)
diff --git a/docs/change_log.rst b/docs/change_log.rst index 4034884..e9fcac7 100644 --- a/docs/change_log.rst +++ b/docs/change_log.rst @@ -52,6 +52,7 @@ The following are only available within Stem's `git repository * :func:`~stem.process.launch_tor_with_config` could cause a "Too many open files" OSError if called too many times (:trac:`13141`) * The :func:`~stem.control.Controller.get_exit_policy` method errored if tor couldn't determine our external address * The Controller's methods for retrieving descriptors could raise unexpected ValueErrors if tor didn't have any descriptors available + * Throwing a new :class:`~stem.DescriptorUnavailable` exception type when the :class:`~stem.control.Controller` can't provide the descriptor for a relay (:trac:`13879`)
* **Descriptors**
diff --git a/stem/__init__.py b/stem/__init__.py index 310f4ab..ffdfe72 100644 --- a/stem/__init__.py +++ b/stem/__init__.py @@ -13,6 +13,7 @@ Library for working with the tor process. |- OperationFailed - Tor was unable to successfully complete the operation. | |- UnsatisfiableRequest - Tor was unable to satisfy a valid request. | | +- CircuitExtensionFailed - Attempt to make or extend a circuit failed. + | |- DescriptorUnavailable - The given relay descriptor is unavailable. | +- InvalidRequest - Invalid request. | +- InvalidArguments - Invalid request parameters. +- SocketError - Communication with the socket failed. @@ -459,6 +460,7 @@ __all__ = [ 'OperationFailed', 'UnsatisfiableRequest', 'CircuitExtensionFailed', + 'DescriptorUnavailable', 'InvalidRequest', 'InvalidArguments', 'SocketError', @@ -539,6 +541,12 @@ class CircuitExtensionFailed(UnsatisfiableRequest): self.circ = circ
+class DescriptorUnavailable(OperationFailed): + """ + Tor was unable to provide a descriptor for the given relay. + """ + + class InvalidRequest(OperationFailed): """ Exception raised when the request was invalid or malformed. diff --git a/stem/control.py b/stem/control.py index f947aca..cace3ad 100644 --- a/stem/control.py +++ b/stem/control.py @@ -1456,6 +1456,8 @@ class Controller(BaseController): :returns: :class:`~stem.descriptor.microdescriptor.Microdescriptor` for the given relay
:raises: + * :class:`stem.DescriptorUnavailable` if unable to provide a descriptor + for the given relay * :class:`stem.ControllerError` if unable to query the descriptor * **ValueError** if **relay** doesn't conform with the pattern for being a fingerprint or nickname @@ -1476,10 +1478,16 @@ class Controller(BaseController): else: raise ValueError("'%s' isn't a valid fingerprint or nickname" % relay)
- desc_content = self.get_info(query, get_bytes = True) + try: + desc_content = self.get_info(query, get_bytes = True) + except stem.InvalidArguments as exc: + if str(exc).startswith('GETINFO request contained unrecognized keywords:'): + raise stem.DescriptorUnavailable("Tor was unable to provide the descriptor for '%s'" % relay) + else: + raise exc
if not desc_content: - raise stem.ControllerError("Descriptor information is unavailable, tor might still be downloading it") + raise stem.DescriptorUnavailable("Descriptor information is unavailable, tor might still be downloading it")
return stem.descriptor.microdescriptor.Microdescriptor(desc_content)
@@ -1555,6 +1563,8 @@ class Controller(BaseController): :returns: :class:`~stem.descriptor.server_descriptor.RelayDescriptor` for the given relay
:raises: + * :class:`stem.DescriptorUnavailable` if unable to provide a descriptor + for the given relay * :class:`stem.ControllerError` if unable to query the descriptor * **ValueError** if **relay** doesn't conform with the pattern for being a fingerprint or nickname @@ -1576,10 +1586,16 @@ class Controller(BaseController): else: raise ValueError("'%s' isn't a valid fingerprint or nickname" % relay)
- desc_content = self.get_info(query, get_bytes = True) + try: + desc_content = self.get_info(query, get_bytes = True) + except stem.InvalidArguments as exc: + if str(exc).startswith('GETINFO request contained unrecognized keywords:'): + raise stem.DescriptorUnavailable("Tor was unable to provide the descriptor for '%s'" % relay) + else: + raise exc
if not desc_content: - raise stem.ControllerError("Descriptor information is unavailable, tor might still be downloading it") + raise stem.DescriptorUnavailable("Descriptor information is unavailable, tor might still be downloading it")
return stem.descriptor.server_descriptor.RelayDescriptor(desc_content) except Exception as exc: @@ -1622,7 +1638,7 @@ class Controller(BaseController): if not self._is_server_descriptors_available(): raise stem.ControllerError(SERVER_DESCRIPTORS_UNSUPPORTED) else: - raise stem.ControllerError("Descriptor information is unavailable, tor might still be downloading it") + raise stem.DescriptorUnavailable("Descriptor information is unavailable, tor might still be downloading it")
for desc in stem.descriptor.server_descriptor._parse_file(io.BytesIO(desc_content)): yield desc @@ -1670,6 +1686,8 @@ class Controller(BaseController): for the given relay
:raises: + * :class:`stem.DescriptorUnavailable` if unable to provide a descriptor + for the given relay * :class:`stem.ControllerError` if unable to query the descriptor * **ValueError** if **relay** doesn't conform with the pattern for being a fingerprint or nickname @@ -1695,10 +1713,16 @@ class Controller(BaseController): else: raise ValueError("'%s' isn't a valid fingerprint or nickname" % relay)
- desc_content = self.get_info(query, get_bytes = True) + try: + desc_content = self.get_info(query, get_bytes = True) + except stem.InvalidArguments as exc: + if str(exc).startswith('GETINFO request contained unrecognized keywords:'): + raise stem.DescriptorUnavailable("Tor was unable to provide the descriptor for '%s'" % relay) + else: + raise exc
if not desc_content: - raise stem.ControllerError("Descriptor information is unavailable, tor might still be downloading it") + raise stem.DescriptorUnavailable("Descriptor information is unavailable, tor might still be downloading it")
if self.get_conf('UseMicrodescriptors', '0') == '1': return stem.descriptor.router_status_entry.RouterStatusEntryMicroV3(desc_content) @@ -1747,7 +1771,7 @@ class Controller(BaseController): desc_content = self.get_info('ns/all', get_bytes = True)
if not desc_content: - raise stem.ControllerError("Descriptor information is unavailable, tor might still be downloading it") + raise stem.DescriptorUnavailable("Descriptor information is unavailable, tor might still be downloading it")
desc_iterator = stem.descriptor.router_status_entry._parse_file( io.BytesIO(desc_content),
tor-commits@lists.torproject.org