8

In .NET Core I can send raw HTTP over a unix-domain socket, but I would like to use the HTTP handling classes in the library instead of hacking together my own HTTP handling.

Here is my current working-but-ugly code:

const string HTTP_REQUEST = "POST /containers/foo/kill?signal=SIGHUP HTTP/1.0\r\n" +
    "Host: localhost\r\n" +
    "Accept: */*\r\n\r\n";
socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP);
socket.ReceiveTimeout = 2000; // 2 seconds
var endpoint = new UnixDomainSocketEndPoint("/var/run/docker.sock");
socket.Connect(endpoint);
byte[] requestBytes = Encoding.ASCII.GetBytes(HTTP_REQUEST);
socket.Send(requestBytes);
byte[] recvBytes = new byte[1024];
int numBytes = socket.Receive(recvBytes, 1024, SocketFlags.None);
socket.Disconnect(false);
Console.WriteLine( Encoding.ASCII.GetString(recvBytes));

Is there a way to use the classes in the .NET Core library to handle the HTTP request and response over a unix-domain socket?

[edit] I'm aware in this particular use case that there is the Docker.DotNet library to achieve what I want, but the question in general is still worth asking.

cdjc
  • 1,039
  • 12
  • 24
  • 2
    I think you can use `HttpClient` and write your own `HttpMessageHandler` – Daniel A. White Nov 29 '18 at 21:14
  • 1
    You could just implement a `System.Net.HttpMessageHandler` and pass it to a `HttpClient` for use. – George Helyar Nov 29 '18 at 21:15
  • https://github.com/dotnet/corefx/tree/master/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler – Daniel A. White Nov 29 '18 at 21:15
  • @DanielA.White I'm aware of HttpClient and HttpMessageHandler and SocketsHttpHandler, but there does not appear to be any way to tell SocketsHttpHandler what socket to use. It's not obvious to me anyway... – cdjc Dec 02 '18 at 20:16
  • @DanielA.White but that seems like an overkill - in that case the deserialization of the response must also be handled in the handler? When all that is needed is just to tell what kind of endpoint to use. – Rudolfs Bundulis Feb 03 '20 at 11:39
  • @RudolfsBundulis it’s the right thing way to do it to get what the op wants – Daniel A. White Feb 03 '20 at 12:00
  • 1
    @DanielA.White writing code to parse HTTP status line, headers, etc. when all he wants is to switch the address family of the underlying socket? There seem to be feature requests (e.g. https://github.com/dotnet/runtime/issues/30995) for such a thing, but none seem finished. – Rudolfs Bundulis Feb 03 '20 at 12:05

1 Answers1

4

In .NET 5, a ConnectCallback was added to SocketsHttpHandler which makes this a little easier, not saying this is the only way, but worked for me:

    private static readonly HttpClient _httpClient = new HttpClient(new SocketsHttpHandler
    {
        ConnectCallback = async (context, token) =>
        {
            var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.IP);
            var endpoint = new UnixDomainSocketEndPoint("/var/run/test.sock");
            await socket.ConnectAsync(endpoint);
            return new NetworkStream(socket, ownsSocket: true);
        }
    });

    public async Task TestSocket(string url)
    {
        var result = await _httpClient.GetStringAsync(url);
    }
Brad Albright
  • 686
  • 7
  • 12