Twisted-based asynchronous resolver. This is a non-blocking and non-threaded resolver. It is recommended only when threads cannot be used, since it has limitations compared to the standard ``getaddrinfo``-based `~tornado.netutil.Resolver` and `~tornado.netutil.DefaultExecutorRe
| 37 | |
| 38 | |
| 39 | class TwistedResolver(Resolver): |
| 40 | """Twisted-based asynchronous resolver. |
| 41 | |
| 42 | This is a non-blocking and non-threaded resolver. It is |
| 43 | recommended only when threads cannot be used, since it has |
| 44 | limitations compared to the standard ``getaddrinfo``-based |
| 45 | `~tornado.netutil.Resolver` and |
| 46 | `~tornado.netutil.DefaultExecutorResolver`. Specifically, it returns at |
| 47 | most one result, and arguments other than ``host`` and ``family`` |
| 48 | are ignored. It may fail to resolve when ``family`` is not |
| 49 | ``socket.AF_UNSPEC``. |
| 50 | |
| 51 | Requires Twisted 12.1 or newer. |
| 52 | |
| 53 | .. versionchanged:: 5.0 |
| 54 | The ``io_loop`` argument (deprecated since version 4.1) has been removed. |
| 55 | |
| 56 | .. deprecated:: 6.2 |
| 57 | This class is deprecated and will be removed in Tornado 7.0. Use the default |
| 58 | thread-based resolver instead. |
| 59 | """ |
| 60 | |
| 61 | def initialize(self) -> None: |
| 62 | # partial copy of twisted.names.client.createResolver, which doesn't |
| 63 | # allow for a reactor to be passed in. |
| 64 | self.reactor = twisted.internet.asyncioreactor.AsyncioSelectorReactor() |
| 65 | |
| 66 | host_resolver = twisted.names.hosts.Resolver("/etc/hosts") |
| 67 | cache_resolver = twisted.names.cache.CacheResolver(reactor=self.reactor) |
| 68 | real_resolver = twisted.names.client.Resolver( |
| 69 | "/etc/resolv.conf", reactor=self.reactor |
| 70 | ) |
| 71 | self.resolver = twisted.names.resolve.ResolverChain( |
| 72 | [host_resolver, cache_resolver, real_resolver] |
| 73 | ) |
| 74 | |
| 75 | @gen.coroutine |
| 76 | def resolve( |
| 77 | self, host: str, port: int, family: int = 0 |
| 78 | ) -> "Generator[Any, Any, List[Tuple[int, Any]]]": |
| 79 | # getHostByName doesn't accept IP addresses, so if the input |
| 80 | # looks like an IP address just return it immediately. |
| 81 | if twisted.internet.abstract.isIPAddress(host): |
| 82 | resolved = host |
| 83 | resolved_family = socket.AF_INET |
| 84 | elif twisted.internet.abstract.isIPv6Address(host): |
| 85 | resolved = host |
| 86 | resolved_family = socket.AF_INET6 |
| 87 | else: |
| 88 | deferred = self.resolver.getHostByName(utf8(host)) |
| 89 | fut = Future() # type: Future[Any] |
| 90 | deferred.addBoth(fut.set_result) |
| 91 | resolved = yield fut |
| 92 | if isinstance(resolved, failure.Failure): |
| 93 | try: |
| 94 | resolved.raiseException() |
| 95 | except twisted.names.error.DomainError as e: |
| 96 | raise IOError(e) |