Add tests for HTTPS urls to AddressRegistrationTests (#794)
- Added HttpClientSlim, a lightweight version of HttpClient implemented using Socket and SslStream.
This commit is contained in:
parent
7e1aa4e1d0
commit
0c52529b97
|
|
@ -5,7 +5,6 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
@ -29,12 +28,19 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv4Port80))]
|
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv4Port80))]
|
||||||
[Port80SupportedCondition]
|
[PortSupportedCondition(80)]
|
||||||
public async Task RegisterAddresses_IPv4Port80_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
public async Task RegisterAddresses_IPv4Port80_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||||
{
|
{
|
||||||
await RegisterAddresses_Success(addressInput, testUrls);
|
await RegisterAddresses_Success(addressInput, testUrls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv4Port443))]
|
||||||
|
[PortSupportedCondition(443)]
|
||||||
|
public async Task RegisterAddresses_IPv4Port443_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||||
|
{
|
||||||
|
await RegisterAddresses_Success(addressInput, testUrls);
|
||||||
|
}
|
||||||
|
|
||||||
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6))]
|
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6))]
|
||||||
[IPv6SupportedCondition]
|
[IPv6SupportedCondition]
|
||||||
public async Task RegisterAddresses_IPv6_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
public async Task RegisterAddresses_IPv6_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||||
|
|
@ -44,12 +50,20 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
|
|
||||||
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6Port80))]
|
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6Port80))]
|
||||||
[IPv6SupportedCondition]
|
[IPv6SupportedCondition]
|
||||||
[Port80SupportedCondition]
|
[PortSupportedCondition(80)]
|
||||||
public async Task RegisterAddresses_IPv6Port80_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
public async Task RegisterAddresses_IPv6Port80_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||||
{
|
{
|
||||||
await RegisterAddresses_Success(addressInput, testUrls);
|
await RegisterAddresses_Success(addressInput, testUrls);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6Port443))]
|
||||||
|
[IPv6SupportedCondition]
|
||||||
|
[PortSupportedCondition(443)]
|
||||||
|
public async Task RegisterAddresses_IPv6Port443_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||||
|
{
|
||||||
|
await RegisterAddresses_Success(addressInput, testUrls);
|
||||||
|
}
|
||||||
|
|
||||||
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6ScopeId))]
|
[ConditionalTheory, MemberData(nameof(AddressRegistrationDataIPv6ScopeId))]
|
||||||
[IPv6SupportedCondition]
|
[IPv6SupportedCondition]
|
||||||
public async Task RegisterAddresses_IPv6ScopeId_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
public async Task RegisterAddresses_IPv6ScopeId_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||||
|
|
@ -60,7 +74,10 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
private async Task RegisterAddresses_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
private async Task RegisterAddresses_Success(string addressInput, Func<IServerAddressesFeature, string[]> testUrls)
|
||||||
{
|
{
|
||||||
var hostBuilder = new WebHostBuilder()
|
var hostBuilder = new WebHostBuilder()
|
||||||
.UseKestrel()
|
.UseKestrel(options =>
|
||||||
|
{
|
||||||
|
options.UseHttps(@"TestResources/testCert.pfx", "testPassword");
|
||||||
|
})
|
||||||
.UseUrls(addressInput)
|
.UseUrls(addressInput)
|
||||||
.Configure(ConfigureEchoAddress);
|
.Configure(ConfigureEchoAddress);
|
||||||
|
|
||||||
|
|
@ -68,18 +85,14 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
{
|
{
|
||||||
host.Start();
|
host.Start();
|
||||||
|
|
||||||
using (var client = new HttpClient())
|
var client = new HttpClientSlim() { ValidateCertificate = false };
|
||||||
|
foreach (var testUrl in testUrls(host.ServerFeatures.Get<IServerAddressesFeature>()))
|
||||||
{
|
{
|
||||||
foreach (var testUrl in testUrls(host.ServerFeatures.Get<IServerAddressesFeature>()))
|
var response = await client.GetStringAsync(testUrl);
|
||||||
{
|
|
||||||
var response = await client.GetAsync(testUrl);
|
// Compare the response with Uri.ToString(), rather than testUrl directly.
|
||||||
|
// Required to handle IPv6 addresses with zone index, like "fe80::3%1"
|
||||||
// Compare the response with the RequestMessage.RequestUri, rather than testUrl directly.
|
Assert.Equal(new Uri(testUrl).ToString(), response);
|
||||||
// Required to handle IPv6 addresses with zone index, like "fe80::3%1"
|
|
||||||
Assert.Equal(
|
|
||||||
response.RequestMessage.RequestUri.ToString(),
|
|
||||||
await response.Content.ReadAsStringAsync());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -146,30 +159,33 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
var port2 = GetNextPort();
|
var port2 = GetNextPort();
|
||||||
|
|
||||||
// Loopback
|
// Loopback
|
||||||
dataset.Add($"http://127.0.0.1:{port1}", _ => new[] { $"http://127.0.0.1:{port1}/" });
|
dataset.Add($"http://127.0.0.1:{port1};https://127.0.0.1:{port2}",
|
||||||
|
_ => new[] { $"http://127.0.0.1:{port1}/", $"https://127.0.0.1:{port2}/" });
|
||||||
|
|
||||||
// Localhost
|
// Localhost
|
||||||
dataset.Add($"http://localhost:{port1}", _ => new[] { $"http://localhost:{port1}/", $"http://127.0.0.1:{port1}/" });
|
dataset.Add($"http://localhost:{port1};https://localhost:{port2}",
|
||||||
|
_ => new[] { $"http://localhost:{port1}/", $"http://127.0.0.1:{port1}/",
|
||||||
|
$"https://localhost:{port2}/", $"https://127.0.0.1:{port2}/" });
|
||||||
|
|
||||||
// Any
|
// Any
|
||||||
dataset.Add($"http://*:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/" });
|
dataset.Add($"http://*:{port1}/;https://*:{port2}/",
|
||||||
dataset.Add($"http://+:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/" });
|
_ => new[] { $"http://127.0.0.1:{port1}/", $"https://127.0.0.1:{port2}/" });
|
||||||
|
dataset.Add($"http://+:{port1}/;https://+:{port2}/",
|
||||||
// Multiple addresses
|
_ => new[] { $"http://127.0.0.1:{port1}/", $"https://127.0.0.1:{port2}/" });
|
||||||
dataset.Add($"http://127.0.0.1:{port1};http://127.0.0.1:{port2}", _ => new[] { $"http://127.0.0.1:{port1}/", $"http://127.0.0.1:{port2}/" });
|
|
||||||
|
|
||||||
// Path after port
|
// Path after port
|
||||||
dataset.Add($"http://127.0.0.1:{port1}/base/path", _ => new[] { $"http://127.0.0.1:{port1}/base/path" });
|
dataset.Add($"http://127.0.0.1:{port1}/base/path;https://127.0.0.1:{port2}/base/path",
|
||||||
|
_ => new[] { $"http://127.0.0.1:{port1}/base/path", $"https://127.0.0.1:{port2}/base/path" });
|
||||||
|
|
||||||
// Dynamic port and non-loopback addresses
|
// Dynamic port and non-loopback addresses
|
||||||
dataset.Add("http://127.0.0.1:0/", GetTestUrls);
|
dataset.Add("http://127.0.0.1:0/;https://127.0.0.1:0/", GetTestUrls);
|
||||||
dataset.Add($"http://{Dns.GetHostName()}:0/", GetTestUrls);
|
dataset.Add($"http://{Dns.GetHostName()}:0/;https://{Dns.GetHostName()}:0/", GetTestUrls);
|
||||||
|
|
||||||
var ipv4Addresses = GetIPAddresses()
|
var ipv4Addresses = GetIPAddresses()
|
||||||
.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork);
|
.Where(ip => ip.AddressFamily == AddressFamily.InterNetwork);
|
||||||
foreach (var ip in ipv4Addresses)
|
foreach (var ip in ipv4Addresses)
|
||||||
{
|
{
|
||||||
dataset.Add($"http://{ip}:0/", GetTestUrls);
|
dataset.Add($"http://{ip}:0/;https://{ip}:0/", GetTestUrls);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataset;
|
return dataset;
|
||||||
|
|
@ -191,6 +207,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv4Port443
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var dataset = new TheoryData<string, Func<IServerAddressesFeature, string[]>>();
|
||||||
|
|
||||||
|
// Default port for HTTPS (443)
|
||||||
|
dataset.Add("https://127.0.0.1", _ => new[] { "https://127.0.0.1/" });
|
||||||
|
dataset.Add("https://localhost", _ => new[] { "https://127.0.0.1/" });
|
||||||
|
dataset.Add("https://*", _ => new[] { "https://127.0.0.1/" });
|
||||||
|
|
||||||
|
return dataset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv6
|
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv6
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -206,21 +237,30 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
var port2 = GetNextPort();
|
var port2 = GetNextPort();
|
||||||
|
|
||||||
// Loopback
|
// Loopback
|
||||||
dataset.Add($"http://[::1]:{port1}/", _ => new[] { $"http://[::1]:{port1}/" });
|
dataset.Add($"http://[::1]:{port1}/;https://[::1]:{port2}/",
|
||||||
|
_ => new[] { $"http://[::1]:{port1}/", $"https://[::1]:{port2}/" });
|
||||||
|
|
||||||
// Localhost
|
// Localhost
|
||||||
dataset.Add($"http://localhost:{port1}", _ => new[] { $"http://localhost:{port1}/", $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/" });
|
dataset.Add($"http://localhost:{port1};https://localhost:{port2}",
|
||||||
|
_ => new[] { $"http://localhost:{port1}/", $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/",
|
||||||
|
$"https://localhost:{port2}/", $"https://127.0.0.1:{port2}/", $"https://[::1]:{port2}/" });
|
||||||
|
|
||||||
// Any
|
// Any
|
||||||
dataset.Add($"http://*:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/" });
|
dataset.Add($"http://*:{port1}/;https://*:{port2}/",
|
||||||
dataset.Add($"http://+:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/" });
|
_ => new[] { $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/",
|
||||||
|
$"https://127.0.0.1:{port2}/", $"https://[::1]:{port2}/" });
|
||||||
|
dataset.Add($"http://+:{port1}/;https://+:{port2}/",
|
||||||
|
_ => new[] { $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/",
|
||||||
|
$"https://127.0.0.1:{port2}/", $"https://[::1]:{port2}/" });
|
||||||
|
|
||||||
// Multiple addresses
|
// Explicit IPv4 and IPv6 on same port
|
||||||
dataset.Add($"http://127.0.0.1:{port1}/;http://[::1]:{port1}/", _ => new[] { $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/" });
|
dataset.Add($"http://127.0.0.1:{port1}/;http://[::1]:{port1}/;https://127.0.0.1:{port2}/;https://[::1]:{port2}/",
|
||||||
dataset.Add($"http://[::1]:{port1};http://[::1]:{port2}", _ => new[] { $"http://[::1]:{port1}/", $"http://[::1]:{port2}/" });
|
_ => new[] { $"http://127.0.0.1:{port1}/", $"http://[::1]:{port1}/",
|
||||||
|
$"https://127.0.0.1:{port2}/", $"https://[::1]:{port2}/" });
|
||||||
|
|
||||||
// Path after port
|
// Path after port
|
||||||
dataset.Add($"http://[::1]:{port1}/base/path", _ => new[] { $"http://[::1]:{port1}/base/path" });
|
dataset.Add($"http://[::1]:{port1}/base/path;https://[::1]:{port2}/base/path",
|
||||||
|
_ => new[] { $"http://[::1]:{port1}/base/path", $"https://[::1]:{port2}/base/path" });
|
||||||
|
|
||||||
// Dynamic port and non-loopback addresses
|
// Dynamic port and non-loopback addresses
|
||||||
var ipv6Addresses = GetIPAddresses()
|
var ipv6Addresses = GetIPAddresses()
|
||||||
|
|
@ -228,7 +268,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
.Where(ip => ip.ScopeId == 0);
|
.Where(ip => ip.ScopeId == 0);
|
||||||
foreach (var ip in ipv6Addresses)
|
foreach (var ip in ipv6Addresses)
|
||||||
{
|
{
|
||||||
dataset.Add($"http://[{ip}]:0/", GetTestUrls);
|
dataset.Add($"http://[{ip}]:0/;https://[{ip}]:0/", GetTestUrls);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataset;
|
return dataset;
|
||||||
|
|
@ -250,6 +290,21 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv6Port443
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
var dataset = new TheoryData<string, Func<IServerAddressesFeature, string[]>>();
|
||||||
|
|
||||||
|
// Default port for HTTPS (443)
|
||||||
|
dataset.Add("https://[::1]", _ => new[] { "https://[::1]/" });
|
||||||
|
dataset.Add("https://localhost", _ => new[] { "https://127.0.0.1/", "https://[::1]/" });
|
||||||
|
dataset.Add("https://*", _ => new[] { "https://[::1]/" });
|
||||||
|
|
||||||
|
return dataset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv6ScopeId
|
public static TheoryData<string, Func<IServerAddressesFeature, string[]>> AddressRegistrationDataIPv6ScopeId
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -262,7 +317,7 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
.Where(ip => ip.ScopeId != 0);
|
.Where(ip => ip.ScopeId != 0);
|
||||||
foreach (var ip in ipv6Addresses)
|
foreach (var ip in ipv6Addresses)
|
||||||
{
|
{
|
||||||
dataset.Add($"http://[{ip}]:0/", GetTestUrls);
|
dataset.Add($"http://[{ip}]:0/;https://[{ip}]:0/", GetTestUrls);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dataset;
|
return dataset;
|
||||||
|
|
@ -323,15 +378,22 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
|
||||||
private class Port80SupportedConditionAttribute : Attribute, ITestCondition
|
private class PortSupportedConditionAttribute : Attribute, ITestCondition
|
||||||
{
|
{
|
||||||
private static readonly Lazy<bool> _port80Supported = new Lazy<bool>(CanBindToPort80);
|
private readonly int _port;
|
||||||
|
private readonly Lazy<bool> _portSupported;
|
||||||
|
|
||||||
|
public PortSupportedConditionAttribute(int port)
|
||||||
|
{
|
||||||
|
_port = port;
|
||||||
|
_portSupported = new Lazy<bool>(CanBindToPort);
|
||||||
|
}
|
||||||
|
|
||||||
public bool IsMet
|
public bool IsMet
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return _port80Supported.Value;
|
return _portSupported.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -339,17 +401,17 @@ namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return "Cannot bind to port 80 on the host.";
|
return $"Cannot bind to port {_port} on the host.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool CanBindToPort80()
|
private bool CanBindToPort()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
|
||||||
{
|
{
|
||||||
socket.Bind(new IPEndPoint(IPAddress.Loopback, 80));
|
socket.Bind(new IPEndPoint(IPAddress.Loopback, _port));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Security;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Security.Authentication;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.Server.Kestrel.FunctionalTests
|
||||||
|
{
|
||||||
|
// Lightweight version of HttpClient implemented using Socket and SslStream
|
||||||
|
public class HttpClientSlim
|
||||||
|
{
|
||||||
|
public bool ValidateCertificate { get; set; } = true;
|
||||||
|
|
||||||
|
public Task<string> GetStringAsync(string requestUri) => GetStringAsync(new Uri(requestUri));
|
||||||
|
|
||||||
|
public async Task<string> GetStringAsync(Uri requestUri)
|
||||||
|
{
|
||||||
|
using (var stream = await GetStream(requestUri))
|
||||||
|
{
|
||||||
|
using (var writer = new StreamWriter(stream, Encoding.ASCII, bufferSize: 1024, leaveOpen: true))
|
||||||
|
{
|
||||||
|
await writer.WriteAsync($"GET {requestUri.PathAndQuery} HTTP/1.0\r\n");
|
||||||
|
await writer.WriteAsync($"Host: {requestUri.Authority}\r\n");
|
||||||
|
await writer.WriteAsync("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var reader = new StreamReader(stream, Encoding.ASCII))
|
||||||
|
{
|
||||||
|
var response = await reader.ReadToEndAsync();
|
||||||
|
var body = response.Substring(response.IndexOf("\r\n\r\n") + 4);
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<Stream> GetStream(Uri requestUri)
|
||||||
|
{
|
||||||
|
var socket = await GetSocket(requestUri);
|
||||||
|
Stream stream = new NetworkStream(socket, ownsSocket: true);
|
||||||
|
|
||||||
|
if (requestUri.Scheme.Equals("https", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var sslStream = new SslStream(stream, leaveInnerStreamOpen: false, userCertificateValidationCallback:
|
||||||
|
ValidateCertificate ? null : (RemoteCertificateValidationCallback)((a, b, c, d) => true));
|
||||||
|
await sslStream.AuthenticateAsClientAsync(requestUri.Host, clientCertificates: null,
|
||||||
|
enabledSslProtocols: SslProtocols.Tls11 | SslProtocols.Tls12,
|
||||||
|
checkCertificateRevocation: ValidateCertificate);
|
||||||
|
return sslStream;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static async Task<Socket> GetSocket(Uri requestUri)
|
||||||
|
{
|
||||||
|
var tcs = new TaskCompletionSource<Socket>();
|
||||||
|
|
||||||
|
var socketArgs = new SocketAsyncEventArgs();
|
||||||
|
socketArgs.RemoteEndPoint = new DnsEndPoint(requestUri.DnsSafeHost, requestUri.Port);
|
||||||
|
socketArgs.Completed += (s, e) => tcs.TrySetResult(e.ConnectSocket);
|
||||||
|
|
||||||
|
// Must use static ConnectAsync(), since instance Connect() does not support DNS names on OSX/Linux.
|
||||||
|
if (Socket.ConnectAsync(SocketType.Stream, ProtocolType.Tcp, socketArgs))
|
||||||
|
{
|
||||||
|
await tcs.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
var socket = socketArgs.ConnectSocket;
|
||||||
|
|
||||||
|
if (socket == null)
|
||||||
|
{
|
||||||
|
throw new SocketException((int)socketArgs.SocketError);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return socket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue