diff options
| author | Damian Johnson <atagar@torproject.org> | 2014-12-04 17:30:59 -0800 |
|---|---|---|
| committer | Damian Johnson <atagar@torproject.org> | 2014-12-04 17:33:08 -0800 |
| commit | 6a3882a372149ff18b5be7f82fa4b9e5cac113b1 (patch) | |
| tree | f9a718a37aecc31a6594db40e310cd4bd89bba3a | |
| parent | 73f04de83faa5f6f560cd1305efd0faa409a2314 (diff) | |
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
| -rw-r--r-- | docs/change_log.rst | 1 | ||||
| -rw-r--r-- | stem/__init__.py | 8 | ||||
| -rw-r--r-- | stem/control.py | 40 |
3 files changed, 41 insertions, 8 deletions
diff --git a/docs/change_log.rst b/docs/change_log.rst index 4034884f..e9fcac7f 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 310f4ab4..ffdfe72e 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 f947aca2..cace3ade 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), |
