diff --git a/core/vibe/core/drivers/libevent2.d b/core/vibe/core/drivers/libevent2.d index db0f40a6f9..ded1345383 100644 --- a/core/vibe/core/drivers/libevent2.d +++ b/core/vibe/core/drivers/libevent2.d @@ -389,8 +389,29 @@ final class Libevent2Driver : EventDriver { Libevent2TCPListener listenTCP(ushort port, void delegate(TCPConnection conn) @safe connection_callback, string address, TCPListenOptions options) { - auto bind_addr = resolveHost(address, AF_UNSPEC, false); - bind_addr.port = port; + NetworkAddress bind_addr; + version(Posix) + { + import core.sys.posix.sys.un; + import core.stdc.string : strcpy; + + if (address[0] == '/') + { + bind_addr.family = AF_UNIX; + sockaddr_un* s = bind_addr.sockAddrUnix(); + enforce(s.sun_path.length > address.length, "Unix sockets cannot have that long a name."); + s.sun_family = AF_UNIX; + () @trusted { strcpy(cast(char*)s.sun_path.ptr,address.toStringz()); } (); + } else + { + bind_addr = resolveHost(address, AF_UNSPEC, false); + bind_addr.port = port; + } + } else + { + bind_addr = resolveHost(address, AF_UNSPEC, false); + bind_addr.port = port; + } auto listenfd_raw = () @trusted { return socket(bind_addr.family, SOCK_STREAM, 0); } (); // on Win64 socket() returns a 64-bit value but libevent expects an int diff --git a/core/vibe/core/drivers/libevent2_tcp.d b/core/vibe/core/drivers/libevent2_tcp.d index 3589ae1afb..c92a0bf68a 100644 --- a/core/vibe/core/drivers/libevent2_tcp.d +++ b/core/vibe/core/drivers/libevent2_tcp.d @@ -477,6 +477,13 @@ final class Libevent2TCPListener : TCPListener { TCPContextAlloc.free(ctx); } (); m_ctx = null; + + version(Posix) + { + if (m_bindAddress.family == AF_UNIX) { + removeFile(m_bindAddress.toAddressString()); + } + } } } } diff --git a/examples/unix_socket/dub.json b/examples/unix_socket_client/dub.json similarity index 68% rename from examples/unix_socket/dub.json rename to examples/unix_socket_client/dub.json index cf9542314c..b7f1e3d3ab 100644 --- a/examples/unix_socket/dub.json +++ b/examples/unix_socket_client/dub.json @@ -1,6 +1,6 @@ { - "name": "unit-socket-example", - "description": "Example for sending http requests to unix sockets", + "name": "unit-socket-client-example", + "description": "Example for sending HTTP requests to Unix sockets", "dependencies": { "vibe-d:http": {"path": "../../"}, "vibe-d:web": {"path": "../../"}, diff --git a/examples/unix_socket/source/app.d b/examples/unix_socket_client/source/app.d similarity index 74% rename from examples/unix_socket/source/app.d rename to examples/unix_socket_client/source/app.d index d7e7fd7132..ea54ce2725 100644 --- a/examples/unix_socket/source/app.d +++ b/examples/unix_socket_client/source/app.d @@ -5,7 +5,7 @@ import std.stdio; void main() { - URL url = URL("http+unix://%2Fvar%2Frun%2Fdocker.sock/containers/json"); + URL url = URL("http+unix://%2Ftmp%2Fvibe.sock/hello"); writeln(url); requestHTTP(url,(scope req){},(scope res){ writeln(res.bodyReader.readAllUTF8); diff --git a/examples/unix_socket_server/dub.json b/examples/unix_socket_server/dub.json new file mode 100644 index 0000000000..04066a5ef9 --- /dev/null +++ b/examples/unix_socket_server/dub.json @@ -0,0 +1,11 @@ +{ + "name": "unit-socket-server-example", + "description": "A minimal HTTP server using Unix domain sockets", + "dependencies": { + "vibe-d:http": {"path": "../../"}, + "vibe-d:web": {"path": "../../"}, + "vibe-d:core": {"path": "../../"} + }, + "versions": ["VibeNoSSL", "VibeDefaultMain"], + "subConfigurations": { "vibe-d:core": "libevent"} +} diff --git a/examples/unix_socket_server/source/app.d b/examples/unix_socket_server/source/app.d new file mode 100644 index 0000000000..969465a63e --- /dev/null +++ b/examples/unix_socket_server/source/app.d @@ -0,0 +1,20 @@ +import vibe.inet.url; +import vibe.http.server; +import vibe.http.router; +import std.stdio; + +void handleHelloRequest(scope HTTPServerRequest req, scope HTTPServerResponse res) +{ + res.writeBody("Hello, World!", "text/plain"); +} + +shared static this() +{ + auto router = new URLRouter; + router.get("/hello", &handleHelloRequest); + + auto settings = new HTTPServerSettings; + settings.bindAddresses = ["/tmp/vibe.sock"]; + + listenHTTP(settings, router); +} diff --git a/http/vibe/http/server.d b/http/vibe/http/server.d index d773ad16ba..7d21855e5e 100644 --- a/http/vibe/http/server.d +++ b/http/vibe/http/server.d @@ -52,6 +52,14 @@ else version (Have_botan) {} else version (Have_openssl) {} else version = HaveNoTLS; +version(Posix) +{ + version(VibeLibeventDriver) + { + version = UnixSocket; + } +} + /**************************************************************************************************/ /* Public functions */ /**************************************************************************************************/ @@ -1750,7 +1758,18 @@ struct HTTPListener { if (l.removeVirtualHost(vhid)) { if (!l.hasVirtualHosts) { l.m_listener.stopListening(); - logInfo("Stopped to listen for HTTP%s requests on %s:%s", l.tlsContext ? "S": "", l.bindAddress, l.bindPort); + version(UnixSocket) + { + if (l.bindAddress[0] == '/') { + logInfo("Stopped to listen for HTTP%s requests on %s", l.tlsContext ? "S": "", l.bindAddress); + } + else { + logInfo("Stopped to listen for HTTP%s requests on %s:%s", l.tlsContext ? "S": "", l.bindAddress, l.bindPort); + } + } + else { + logInfo("Stopped to listen for HTTP%s requests on %s:%s", l.tlsContext ? "S": "", l.bindAddress, l.bindPort); + } s_listeners = s_listeners[0 .. lidx] ~ s_listeners[lidx+1 .. $]; } } @@ -2005,10 +2024,27 @@ private HTTPListener listenHTTPPlain(HTTPServerSettings settings, HTTPServerRequ auto proto = listen_info.tlsContext ? "https" : "http"; auto urladdr = listen_info.bindAddress; if (urladdr.canFind(':')) urladdr = "["~urladdr~"]"; + version(UnixSocket) if (urladdr[0] == '/') { + proto ~= "+unix"; + logInfo("Listening for requests on %s://%s/", proto, urladdr); + return ret; + } logInfo("Listening for requests on %s://%s:%s/", proto, urladdr, listen_info.bindPort); return ret; } catch( Exception e ) { - logWarn("Failed to listen on %s:%s", listen_info.bindAddress, listen_info.bindPort); + version(UnixSocket) + { + if (listen_info.bindAddress[0] == '/') { + logWarn("Failed to listen on %s", listen_info.bindAddress); + } + else { + logWarn("Failed to listen on %s:%s", listen_info.bindAddress, listen_info.bindPort); + } + } + else + { + logWarn("Failed to listen on %s:%s", listen_info.bindAddress, listen_info.bindPort); + } return TCPListener.init; } }