Tornado: Add example how to connect via UNIX socket with httpclient

Created on 5 Jun 2019  路  7Comments  路  Source: tornadoweb/tornado

It would be very nice if there would be an example in the documentation how one can connect to a UNIX socket with tornado.httpclient.
I currently could not figure out how to do this.

docs

Most helpful comment

An easier way to do it (and no need to use pycurl and the curl client) is to create a custom resolver that returns [(socket.AF_UNIX, "/path/to/socketfile")] when it matches a certain host (or host/port) combination.

class UnixResolver(Resolver):
    def initialize(self, resolver, unix_sockets, *args, **kwargs):
        self.resolver = resolver
        self.unix_sockets = unix_sockets

    def close(self):
        self.resolver.close()

    @gen.coroutine
    def resolve(self, host, port, *args, **kwargs):
        if host in self.unix_sockets:
            return [(socket.AF_UNIX, self.unix_sockets[host])]
        result = yield self.resolver.resolve(host, port, *args, **kwargs)
        return result

resolver = Resolver()
Resolver.configure(UnixResolver, resolver=resolver, unix_sockets={"host_on_socket": "/path/to/socketfile"})

All 7 comments

I don't think this is currently possible with tornado.

@ploxiln I saw that tornado.httpclient has a curl implementation. Maybe it is possible by setting some curl options?

Yippieh! Got it:

import tornado.httpclient
import pycurl
tornado.httpclient.AsyncHTTPClient.configure('tornado.curl_httpclient.CurlAsyncHTTPClient')
client = tornado.httpclient.AsyncHTTPClient()
client.fetch('http://www.google.com', prepare_curl_callback=lambda curl: curl.setopt(pycurl.UNIX_SOCKET_PATH, '/tmp/1'))
tornado.ioloop.IOLoop.instance().run_sync(lambda *a: None)

(to start it run in bash socat unix-listen:/tmp/1 stdout)

ah, looks like that would do it :)

An easier way to do it (and no need to use pycurl and the curl client) is to create a custom resolver that returns [(socket.AF_UNIX, "/path/to/socketfile")] when it matches a certain host (or host/port) combination.

class UnixResolver(Resolver):
    def initialize(self, resolver, unix_sockets, *args, **kwargs):
        self.resolver = resolver
        self.unix_sockets = unix_sockets

    def close(self):
        self.resolver.close()

    @gen.coroutine
    def resolve(self, host, port, *args, **kwargs):
        if host in self.unix_sockets:
            return [(socket.AF_UNIX, self.unix_sockets[host])]
        result = yield self.resolver.resolve(host, port, *args, **kwargs)
        return result

resolver = Resolver()
Resolver.configure(UnixResolver, resolver=resolver, unix_sockets={"host_on_socket": "/path/to/socketfile"})

This is pretty esoteric; I'm not sure it's worth adding to the docs without opening up a lot of questions about how and why you'd run an HTTP server on an address that's not URL-addressable anyway. And now this issue exists so people can find an answer by googling :)

Was this page helpful?
0 / 5 - 0 ratings