Skip to content

Commit b114a5b

Browse files
committed
Add support for external transport implementations
1 parent c0f44a7 commit b114a5b

File tree

8 files changed

+112
-84
lines changed

8 files changed

+112
-84
lines changed

src/Docker.DotNet.BasicAuth/BasicAuthCredentials.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,20 @@ private BasicAuthCredentials(MaybeSecureString username, MaybeSecureString passw
3232
_password = password;
3333
}
3434

35-
public override bool IsTlsCredentials()
36-
{
37-
return _isTls;
38-
}
39-
4035
public override void Dispose()
4136
{
4237
_username.Dispose();
4338
_password.Dispose();
4439
}
40+
41+
public override bool SupportsScheme(string scheme)
42+
{
43+
return !(_isTls && scheme == "npipe");
44+
}
45+
46+
public override bool IsTlsCredentials()
47+
{
48+
return _isTls;
49+
}
4550
}
46-
}
51+
}

src/Docker.DotNet.X509/CertificateCredentials.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ public override HttpMessageHandler GetHandler(HttpMessageHandler innerHandler)
3535
return handler;
3636
}
3737

38+
public override bool SupportsScheme(string scheme)
39+
{
40+
return scheme != "npipe";
41+
}
42+
3843
public override bool IsTlsCredentials()
3944
{
4045
return true;
@@ -44,4 +49,4 @@ public override void Dispose()
4449
{
4550
}
4651
}
47-
}
52+
}

src/Docker.DotNet.X509/Docker.DotNet.X509.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
<ItemGroup>
99
<ProjectReference Include="..\Docker.DotNet\Docker.DotNet.csproj" />
1010
</ItemGroup>
11-
</Project>
11+
</Project>

src/Docker.DotNet/AnonymousCredentials.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ public override bool IsTlsCredentials()
99
return false;
1010
}
1111

12+
public override bool SupportsScheme(string scheme)
13+
{
14+
return true;
15+
}
16+
1217
public override void Dispose()
1318
{
1419
}
@@ -18,4 +23,4 @@ public override HttpMessageHandler GetHandler(HttpMessageHandler innerHandler)
1823
return innerHandler;
1924
}
2025
}
21-
}
26+
}

src/Docker.DotNet/Credentials.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ namespace Docker.DotNet
55
{
66
public abstract class Credentials : IDisposable
77
{
8+
public abstract bool SupportsScheme(string scheme);
9+
810
public abstract bool IsTlsCredentials();
911

1012
public abstract HttpMessageHandler GetHandler(HttpMessageHandler innerHandler);
@@ -13,4 +15,4 @@ public virtual void Dispose()
1315
{
1416
}
1517
}
16-
}
18+
}

src/Docker.DotNet/DockerClient.cs

Lines changed: 2 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using System;
22
using System.Collections.Generic;
33
using System.IO;
4-
using System.IO.Pipes;
54
using System.Linq;
65
using System.Net;
76
using System.Net.Http;
@@ -47,78 +46,8 @@ internal DockerClient(DockerClientConfiguration configuration, Version requested
4746
Plugin = new PluginOperations(this);
4847
Exec = new ExecOperations(this);
4948

50-
ManagedHandler handler;
51-
var uri = Configuration.EndpointBaseUri;
52-
switch (uri.Scheme.ToLowerInvariant())
53-
{
54-
case "npipe":
55-
if (Configuration.Credentials.IsTlsCredentials())
56-
{
57-
throw new Exception("TLS not supported over npipe");
58-
}
59-
60-
var segments = uri.Segments;
61-
if (segments.Length != 3 || !segments[1].Equals("pipe/", StringComparison.OrdinalIgnoreCase))
62-
{
63-
throw new ArgumentException($"{Configuration.EndpointBaseUri} is not a valid npipe URI");
64-
}
65-
66-
var serverName = uri.Host;
67-
if (string.Equals(serverName, "localhost", StringComparison.OrdinalIgnoreCase))
68-
{
69-
// npipe schemes dont work with npipe://localhost/... and need npipe://./... so fix that for a client here.
70-
serverName = ".";
71-
}
72-
73-
var pipeName = uri.Segments[2];
74-
75-
uri = new UriBuilder("http", pipeName).Uri;
76-
handler = new ManagedHandler(async (host, port, cancellationToken) =>
77-
{
78-
var timeout = (int)Configuration.NamedPipeConnectTimeout.TotalMilliseconds;
79-
var stream = new NamedPipeClientStream(serverName, pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
80-
var dockerStream = new DockerPipeStream(stream);
81-
82-
await stream.ConnectAsync(timeout, cancellationToken)
83-
.ConfigureAwait(false);
84-
85-
return dockerStream;
86-
});
87-
break;
88-
89-
case "tcp":
90-
case "http":
91-
var builder = new UriBuilder(uri)
92-
{
93-
Scheme = configuration.Credentials.IsTlsCredentials() ? "https" : "http"
94-
};
95-
uri = builder.Uri;
96-
handler = new ManagedHandler();
97-
break;
98-
99-
case "https":
100-
handler = new ManagedHandler();
101-
break;
102-
103-
case "unix":
104-
var pipeString = uri.LocalPath;
105-
handler = new ManagedHandler(async (host, port, cancellationToken) =>
106-
{
107-
var sock = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
108-
109-
await sock.ConnectAsync(new Microsoft.Net.Http.Client.UnixDomainSocketEndPoint(pipeString))
110-
.ConfigureAwait(false);
111-
112-
return sock;
113-
});
114-
uri = new UriBuilder("http", uri.Segments.Last()).Uri;
115-
break;
116-
117-
default:
118-
throw new Exception($"Unknown URL scheme {configuration.EndpointBaseUri.Scheme}");
119-
}
120-
121-
_endpointBaseUri = uri;
49+
var (url, handler) = Configuration.GetHandler();
50+
_endpointBaseUri = url;
12251

12352
_client = new HttpClient(Configuration.Credentials.GetHandler(handler), true);
12453
_client.Timeout = SInfiniteTimeout;

src/Docker.DotNet/DockerClientConfiguration.cs

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.IO.Pipes;
4+
using System.Linq;
5+
using System.Net.Sockets;
36
using System.Runtime.InteropServices;
47
using System.Threading;
8+
using Microsoft.Net.Http.Client;
59

610
namespace Docker.DotNet
711
{
@@ -63,10 +67,87 @@ public void Dispose()
6367
Credentials.Dispose();
6468
}
6569

70+
public (Uri url, ManagedHandler handler) GetHandler()
71+
{
72+
if (!Credentials.SupportsScheme(EndpointBaseUri.Scheme))
73+
{
74+
throw new Exception($"The provided credentials don't support the {EndpointBaseUri.Scheme} scheme.");
75+
}
76+
77+
var uri = EndpointBaseUri;
78+
ManagedHandler handler;
79+
80+
switch (EndpointBaseUri.Scheme.ToLowerInvariant())
81+
{
82+
case "npipe":
83+
var segments = uri.Segments;
84+
if (segments.Length != 3 || !segments[1].Equals("pipe/", StringComparison.OrdinalIgnoreCase))
85+
{
86+
throw new ArgumentException($"{uri} is not a valid npipe URI");
87+
}
88+
89+
var serverName = uri.Host;
90+
if (string.Equals(serverName, "localhost", StringComparison.OrdinalIgnoreCase))
91+
{
92+
// npipe schemes dont work with npipe://localhost/... and need npipe://./... so fix that for a client here.
93+
serverName = ".";
94+
}
95+
96+
var pipeName = uri.Segments[2];
97+
98+
uri = new UriBuilder("http", pipeName).Uri;
99+
handler = new ManagedHandler(async (host, port, cancellationToken) =>
100+
{
101+
var timeout = (int)NamedPipeConnectTimeout.TotalMilliseconds;
102+
var stream = new NamedPipeClientStream(serverName, pipeName, PipeDirection.InOut, PipeOptions.Asynchronous);
103+
var dockerStream = new DockerPipeStream(stream);
104+
105+
await stream.ConnectAsync(timeout, cancellationToken)
106+
.ConfigureAwait(false);
107+
108+
return dockerStream;
109+
});
110+
break;
111+
112+
case "tcp":
113+
case "http":
114+
var builder = new UriBuilder(uri)
115+
{
116+
Scheme = Credentials.IsTlsCredentials() ? "https" : "http"
117+
};
118+
uri = builder.Uri;
119+
handler = new ManagedHandler();
120+
break;
121+
122+
case "https":
123+
handler = new ManagedHandler();
124+
break;
125+
126+
case "unix":
127+
var pipeString = uri.LocalPath;
128+
handler = new ManagedHandler(async (host, port, cancellationToken) =>
129+
{
130+
var sock = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
131+
132+
await sock.ConnectAsync(new Microsoft.Net.Http.Client.UnixDomainSocketEndPoint(pipeString))
133+
.ConfigureAwait(false);
134+
135+
return sock;
136+
});
137+
uri = new UriBuilder("http", uri.Segments.Last()).Uri;
138+
break;
139+
140+
default:
141+
throw new Exception($"URL scheme {EndpointBaseUri.Scheme} is unsupported by this implementation.");
142+
}
143+
144+
return (uri, handler);
145+
}
146+
66147
private static Uri GetLocalDockerEndpoint()
67148
{
68149
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
69150
return isWindows ? new Uri("npipe://./pipe/docker_engine") : new Uri("unix:/var/run/docker.sock");
70151
}
71152
}
72-
}
153+
}

src/Docker.DotNet/Microsoft.Net.Http.Client/HttpConnection.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ private async Task<List<string>> ReadResponseLinesAsync(CancellationToken cancel
106106
private HttpResponseMessage CreateResponseMessage(List<string> responseLines)
107107
{
108108
string responseLine = responseLines.First();
109+
109110
// HTTP/1.1 200 OK
110111
string[] responseLineParts = responseLine.Split(new[] { ' ' }, 3);
111112
// TODO: Verify HTTP/1.0 or 1.1.

0 commit comments

Comments
 (0)