fix(client): keep advertised port for a port-less URL; narrow history refusal catch to unwrapped faults (L4 review)
This commit is contained in:
@@ -183,9 +183,10 @@ public class HistoryReadCommand : CommandBase
|
|||||||
await console.Output.WriteLineAsync();
|
await console.Output.WriteLineAsync();
|
||||||
await console.Output.WriteLineAsync($"{values.Count} values returned.");
|
await console.Output.WriteLineAsync($"{values.Count} values returned.");
|
||||||
}
|
}
|
||||||
catch (ServiceResultException ex)
|
catch (ServiceResultException ex) when (ex.InnerException is null)
|
||||||
{
|
{
|
||||||
// e.g. HistoryReadStatus.ThrowIfRefused: a refusal is an operator-facing outcome, not a crash.
|
// e.g. HistoryReadStatus.ThrowIfRefused: a refusal is an operator-facing outcome, not a crash.
|
||||||
|
// A wrapped failure (certificate validation, identity rejection on connect) keeps its full detail.
|
||||||
throw new CommandException(ex.Message);
|
throw new CommandException(ex.Message);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|||||||
@@ -92,13 +92,15 @@ internal static class EndpointSelector
|
|||||||
// Only when the scheme matches: a different scheme (https vs opc.tcp) is a different transport.
|
// Only when the scheme matches: a different scheme (https vs opc.tcp) is a different transport.
|
||||||
var serverUri = new Uri(best.EndpointUrl);
|
var serverUri = new Uri(best.EndpointUrl);
|
||||||
var requestedUri = new Uri(endpointUrl);
|
var requestedUri = new Uri(endpointUrl);
|
||||||
|
// A URL typed without a port (opc.tcp has no registered default, so Port is -1) keeps the advertised port.
|
||||||
|
var port = requestedUri.Port > 0 ? requestedUri.Port : serverUri.Port;
|
||||||
if (string.Equals(serverUri.Scheme, requestedUri.Scheme, StringComparison.OrdinalIgnoreCase)
|
if (string.Equals(serverUri.Scheme, requestedUri.Scheme, StringComparison.OrdinalIgnoreCase)
|
||||||
&& (serverUri.Host != requestedUri.Host || serverUri.Port != requestedUri.Port))
|
&& (serverUri.Host != requestedUri.Host || serverUri.Port != port))
|
||||||
{
|
{
|
||||||
var builder = new UriBuilder(best.EndpointUrl) { Host = requestedUri.Host, Port = requestedUri.Port };
|
var builder = new UriBuilder(best.EndpointUrl) { Host = requestedUri.Host, Port = port };
|
||||||
best.EndpointUrl = builder.ToString();
|
best.EndpointUrl = builder.ToString();
|
||||||
Logger.Debug("Rewrote endpoint from {ServerHost}:{ServerPort} to {RequestedHost}:{RequestedPort}",
|
Logger.Debug("Rewrote endpoint from {ServerHost}:{ServerPort} to {RequestedHost}:{RequestedPort}",
|
||||||
serverUri.Host, serverUri.Port, requestedUri.Host, requestedUri.Port);
|
serverUri.Host, serverUri.Port, requestedUri.Host, port);
|
||||||
}
|
}
|
||||||
|
|
||||||
return best;
|
return best;
|
||||||
|
|||||||
@@ -197,4 +197,30 @@ public class EndpointSelectorTests
|
|||||||
|
|
||||||
best.EndpointUrl.ShouldBe("opc.tcp://server:4840");
|
best.EndpointUrl.ShouldBe("opc.tcp://server:4840");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>A URL typed without a port keeps the advertised port (opc.tcp has no default; Uri.Port is -1).</summary>
|
||||||
|
[Fact]
|
||||||
|
public void SelectBest_KeepsAdvertisedPort_WhenRequestedUrlHasNoPort()
|
||||||
|
{
|
||||||
|
var endpoints = new[] { Ep(MessageSecurityMode.None, SecurityPolicies.None, "opc.tcp://internal-host:4840/OtOpcUa") };
|
||||||
|
|
||||||
|
var best = EndpointSelector.SelectBest(endpoints, "opc.tcp://localhost", MessageSecurityMode.None);
|
||||||
|
|
||||||
|
var uri = new Uri(best.EndpointUrl);
|
||||||
|
uri.Host.ShouldBe("localhost");
|
||||||
|
uri.Port.ShouldBe(4840);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>An IPv6 host is rewritten with its brackets intact.</summary>
|
||||||
|
[Fact]
|
||||||
|
public void SelectBest_RewritesIpv6Host()
|
||||||
|
{
|
||||||
|
var endpoints = new[] { Ep(MessageSecurityMode.None, SecurityPolicies.None, "opc.tcp://internal-host:4840/OtOpcUa") };
|
||||||
|
|
||||||
|
var best = EndpointSelector.SelectBest(endpoints, "opc.tcp://[::1]:4841", MessageSecurityMode.None);
|
||||||
|
|
||||||
|
var uri = new Uri(best.EndpointUrl);
|
||||||
|
uri.Host.ShouldBe("[::1]");
|
||||||
|
uri.Port.ShouldBe(4841);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user