diff --git a/src/Docker.DotNet.BasicAuth/BasicAuthCredentials.cs b/src/Docker.DotNet.BasicAuth/BasicAuthCredentials.cs
index 16e0a3b1..e20c766a 100644
--- a/src/Docker.DotNet.BasicAuth/BasicAuthCredentials.cs
+++ b/src/Docker.DotNet.BasicAuth/BasicAuthCredentials.cs
@@ -32,15 +32,20 @@ private BasicAuthCredentials(MaybeSecureString username, MaybeSecureString passw
_password = password;
}
- public override bool IsTlsCredentials()
- {
- return _isTls;
- }
-
public override void Dispose()
{
_username.Dispose();
_password.Dispose();
}
+
+ public override bool SupportsScheme(string scheme)
+ {
+ return !(_isTls && scheme == "npipe");
+ }
+
+ public override bool IsTlsCredentials()
+ {
+ return _isTls;
+ }
}
-}
\ No newline at end of file
+}
diff --git a/src/Docker.DotNet.X509/CertificateCredentials.cs b/src/Docker.DotNet.X509/CertificateCredentials.cs
index 852bb34f..72ceb730 100644
--- a/src/Docker.DotNet.X509/CertificateCredentials.cs
+++ b/src/Docker.DotNet.X509/CertificateCredentials.cs
@@ -35,6 +35,11 @@ public override HttpMessageHandler GetHandler(HttpMessageHandler innerHandler)
return handler;
}
+ public override bool SupportsScheme(string scheme)
+ {
+ return scheme != "npipe";
+ }
+
public override bool IsTlsCredentials()
{
return true;
@@ -44,4 +49,4 @@ public override void Dispose()
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Docker.DotNet.X509/Docker.DotNet.X509.csproj b/src/Docker.DotNet.X509/Docker.DotNet.X509.csproj
index b399186a..363839e3 100644
--- a/src/Docker.DotNet.X509/Docker.DotNet.X509.csproj
+++ b/src/Docker.DotNet.X509/Docker.DotNet.X509.csproj
@@ -8,4 +8,4 @@
-
\ No newline at end of file
+
diff --git a/src/Docker.DotNet/AnonymousCredentials.cs b/src/Docker.DotNet/AnonymousCredentials.cs
index 08495359..f1e54004 100644
--- a/src/Docker.DotNet/AnonymousCredentials.cs
+++ b/src/Docker.DotNet/AnonymousCredentials.cs
@@ -9,6 +9,11 @@ public override bool IsTlsCredentials()
return false;
}
+ public override bool SupportsScheme(string scheme)
+ {
+ return true;
+ }
+
public override void Dispose()
{
}
@@ -18,4 +23,4 @@ public override HttpMessageHandler GetHandler(HttpMessageHandler innerHandler)
return innerHandler;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Docker.DotNet/Credentials.cs b/src/Docker.DotNet/Credentials.cs
index 3619f0c9..6c136e9d 100644
--- a/src/Docker.DotNet/Credentials.cs
+++ b/src/Docker.DotNet/Credentials.cs
@@ -5,6 +5,8 @@ namespace Docker.DotNet
{
public abstract class Credentials : IDisposable
{
+ public abstract bool SupportsScheme(string scheme);
+
public abstract bool IsTlsCredentials();
public abstract HttpMessageHandler GetHandler(HttpMessageHandler innerHandler);
@@ -13,4 +15,4 @@ public virtual void Dispose()
{
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Docker.DotNet/DockerClient.cs b/src/Docker.DotNet/DockerClient.cs
index f04e24ee..c967555c 100644
--- a/src/Docker.DotNet/DockerClient.cs
+++ b/src/Docker.DotNet/DockerClient.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.IO;
-using System.IO.Pipes;
using System.Linq;
using System.Net;
using System.Net.Http;
@@ -47,78 +46,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;
-
- 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;
diff --git a/src/Docker.DotNet/DockerClientConfiguration.cs b/src/Docker.DotNet/DockerClientConfiguration.cs
index 39937a7c..188b0bcc 100644
--- a/src/Docker.DotNet/DockerClientConfiguration.cs
+++ b/src/Docker.DotNet/DockerClientConfiguration.cs
@@ -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
{
@@ -63,10 +67,87 @@ public void Dispose()
Credentials.Dispose();
}
+ public virtual (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");
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Docker.DotNet/Microsoft.Net.Http.Client/HttpConnection.cs b/src/Docker.DotNet/Microsoft.Net.Http.Client/HttpConnection.cs
index 86f68264..29df8f37 100644
--- a/src/Docker.DotNet/Microsoft.Net.Http.Client/HttpConnection.cs
+++ b/src/Docker.DotNet/Microsoft.Net.Http.Client/HttpConnection.cs
@@ -106,6 +106,7 @@ private async Task> ReadResponseLinesAsync(CancellationToken cancel
private HttpResponseMessage CreateResponseMessage(List responseLines)
{
string responseLine = responseLines.First();
+
// HTTP/1.1 200 OK
string[] responseLineParts = responseLine.Split(new[] { ' ' }, 3);
// TODO: Verify HTTP/1.0 or 1.1.