Skip to content

Commit

Permalink
Refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
mdarocha committed Jun 22, 2023
1 parent af08be3 commit eca00e0
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 112 deletions.
14 changes: 7 additions & 7 deletions src/Docker.DotNet.BasicAuth/BasicAuthCredentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,20 @@ private BasicAuthCredentials(MaybeSecureString username, MaybeSecureString passw
_password = password;
}

public override bool IsTlsCredentials()
public override void Dispose()
{
return _isTls;
_username.Dispose();
_password.Dispose();
}

public override bool IsSshCredentials()
public override bool SupportsScheme(string scheme)
{
return false;
return !(_isTls && scheme == "npipe");
}

public override void Dispose()
public override bool IsTlsCredentials()
{
_username.Dispose();
_password.Dispose();
return _isTls;
}
}
}
8 changes: 4 additions & 4 deletions src/Docker.DotNet.X509/CertificateCredentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ public override HttpMessageHandler GetHandler(HttpMessageHandler innerHandler)
return handler;
}

public override bool IsTlsCredentials()
public override bool SupportsScheme(string scheme)
{
return true;
return scheme != "npipe";
}

public override bool IsSshCredentials()
public override bool IsTlsCredentials()
{
return false;
return true;
}

public override void Dispose()
Expand Down
4 changes: 2 additions & 2 deletions src/Docker.DotNet/AnonymousCredentials.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ public override bool IsTlsCredentials()
return false;
}

public override bool IsSshCredentials()
public override bool SupportsScheme(string scheme)
{
return false;
return true;
}

public override void Dispose()
Expand Down
10 changes: 2 additions & 8 deletions src/Docker.DotNet/Credentials.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
using System;
using System.Net.Http;
using Microsoft.Net.Http.Client;

namespace Docker.DotNet
{
public abstract class Credentials : IDisposable
{
public abstract bool IsTlsCredentials();
public abstract bool SupportsScheme(string scheme);

public abstract bool IsSshCredentials();
public abstract bool IsTlsCredentials();

public abstract HttpMessageHandler GetHandler(HttpMessageHandler innerHandler);

public virtual ManagedHandler.StreamOpener GetSshStreamOpener(string username)
{
return null;
}

public virtual void Dispose()
{
}
Expand Down
92 changes: 2 additions & 90 deletions src/Docker.DotNet/DockerClient.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Net.Http.Client;
Expand Down Expand Up @@ -46,94 +44,8 @@ internal DockerClient(DockerClientConfiguration configuration, Version requested
Plugin = new PluginOperations(this);
Exec = new ExecOperations(this);

ManagedHandler handler;
var uri = Configuration.EndpointBaseUri;
switch (uri.Scheme.ToLowerInvariant())
{
case "npipe":
if (Configuration.Credentials.IsTlsCredentials())
{
throw new Exception("TLS not supported over npipe");
}

var segments = uri.Segments;
if (segments.Length != 3 || !segments[1].Equals("pipe/", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException($"{Configuration.EndpointBaseUri} is not a valid npipe URI");
}

var serverName = uri.Host;
if (string.Equals(serverName, "localhost", StringComparison.OrdinalIgnoreCase))
{
// npipe schemes dont work with npipe://localhost/... and need npipe://./... so fix that for a client here.
serverName = ".";
}

var pipeName = uri.Segments[2];

uri = new UriBuilder("http", pipeName).Uri;
handler = new ManagedHandler(async (host, port, cancellationToken) =>
{
var timeout = (int)Configuration.NamedPipeConnectTimeout.TotalMilliseconds;
var stream = new NamedPipeClientStream(serverName, pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
var dockerStream = new DockerPipeStream(stream);
await stream.ConnectAsync(timeout, cancellationToken)
.ConfigureAwait(false);
return dockerStream;
});
break;

case "tcp":
case "http":
var builder = new UriBuilder(uri)
{
Scheme = configuration.Credentials.IsTlsCredentials() ? "https" : "http"
};
uri = builder.Uri;
handler = new ManagedHandler();
break;

case "https":
handler = new ManagedHandler();
break;

case "unix":
var pipeString = uri.LocalPath;
handler = new ManagedHandler(async (host, port, cancellationToken) =>
{
var sock = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
await sock.ConnectAsync(new Microsoft.Net.Http.Client.UnixDomainSocketEndPoint(pipeString))
.ConfigureAwait(false);
return sock;
});
uri = new UriBuilder("http", uri.Segments.Last()).Uri;
break;

case "ssh":
if(!Configuration.Credentials.IsSshCredentials())
{
throw new ArgumentException("ssh:// protocol can only be used with SSHCredentials");
};

var username = uri.UserInfo;
if(username.Contains(":"))
{
throw new ArgumentException("ssh:// protocol only supports authentication with private keys");
};

handler = new ManagedHandler(Configuration.Credentials.GetSshStreamOpener(username));
uri = new UriBuilder("http", uri.Host, uri.IsDefaultPort ? 22 : uri.Port).Uri;
break;

default:
throw new Exception($"Unknown URL scheme {configuration.EndpointBaseUri.Scheme}");
}

_endpointBaseUri = uri;
var (url, handler) = Configuration.GetHandler();
_endpointBaseUri = url;

_client = new HttpClient(Configuration.Credentials.GetHandler(handler), true);
_client.Timeout = SInfiniteTimeout;
Expand Down
83 changes: 82 additions & 1 deletion src/Docker.DotNet/DockerClientConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using System;
using System.Collections.Generic;
using System.IO.Pipes;
using System.Linq;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.Net.Http.Client;

namespace Docker.DotNet
{
Expand Down Expand Up @@ -63,10 +67,87 @@ public void Dispose()
Credentials.Dispose();
}

public (Uri url, ManagedHandler handler) GetHandler()
{
if (!Credentials.SupportsScheme(EndpointBaseUri.Scheme))
{
throw new Exception($"The provided credentials don't support the {EndpointBaseUri.Scheme} scheme.");
}

var uri = EndpointBaseUri;
ManagedHandler handler;

switch (EndpointBaseUri.Scheme.ToLowerInvariant())
{
case "npipe":
var segments = uri.Segments;
if (segments.Length != 3 || !segments[1].Equals("pipe/", StringComparison.OrdinalIgnoreCase))
{
throw new ArgumentException($"{uri} is not a valid npipe URI");
}

var serverName = uri.Host;
if (string.Equals(serverName, "localhost", StringComparison.OrdinalIgnoreCase))
{
// npipe schemes dont work with npipe://localhost/... and need npipe://./... so fix that for a client here.
serverName = ".";
}

var pipeName = uri.Segments[2];

uri = new UriBuilder("http", pipeName).Uri;
handler = new ManagedHandler(async (host, port, cancellationToken) =>
{
var timeout = (int)NamedPipeConnectTimeout.TotalMilliseconds;
var stream = new NamedPipeClientStream(serverName, pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
var dockerStream = new DockerPipeStream(stream);
await stream.ConnectAsync(timeout, cancellationToken)
.ConfigureAwait(false);
return dockerStream;
});
break;

case "tcp":
case "http":
var builder = new UriBuilder(uri)
{
Scheme = Credentials.IsTlsCredentials() ? "https" : "http"
};
uri = builder.Uri;
handler = new ManagedHandler();
break;

case "https":
handler = new ManagedHandler();
break;

case "unix":
var pipeString = uri.LocalPath;
handler = new ManagedHandler(async (host, port, cancellationToken) =>
{
var sock = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
await sock.ConnectAsync(new Microsoft.Net.Http.Client.UnixDomainSocketEndPoint(pipeString))
.ConfigureAwait(false);
return sock;
});
uri = new UriBuilder("http", uri.Segments.Last()).Uri;
break;

default:
throw new Exception($"URL scheme {EndpointBaseUri.Scheme} is unsupported by this implementation.");
}

return (uri, handler);
}

private static Uri GetLocalDockerEndpoint()
{
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
return isWindows ? new Uri("npipe://./pipe/docker_engine") : new Uri("unix:/var/run/docker.sock");
}
}
}
}

0 comments on commit eca00e0

Please sign in to comment.