diff --git a/src/Servers/HttpSys/src/DelegationRule.cs b/src/Servers/HttpSys/src/DelegationRule.cs index e33997338c..70b85c7c22 100644 --- a/src/Servers/HttpSys/src/DelegationRule.cs +++ b/src/Servers/HttpSys/src/DelegationRule.cs @@ -13,6 +13,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys public class DelegationRule : IDisposable { private readonly ILogger _logger; + private readonly UrlGroup _sourceQueueUrlGroup; + private bool _disposed; /// /// The name of the Http.Sys request queue /// @@ -23,8 +25,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys public string UrlPrefix { get; } internal RequestQueue Queue { get; } - internal DelegationRule(string queueName, string urlPrefix, ILogger logger) + internal DelegationRule(UrlGroup sourceQueueUrlGroup, string queueName, string urlPrefix, ILogger logger) { + _sourceQueueUrlGroup = sourceQueueUrlGroup; _logger = logger; QueueName = queueName; UrlPrefix = urlPrefix; @@ -34,8 +37,20 @@ namespace Microsoft.AspNetCore.Server.HttpSys /// public void Dispose() { - Queue.UrlGroup?.Dispose(); - Queue?.Dispose(); + if (_disposed) + { + return; + } + + _disposed = true; + + try + { + _sourceQueueUrlGroup.UnSetDelegationProperty(Queue, throwOnError: false); + } + catch (ObjectDisposedException) { /* Server may have been shutdown */ } + Queue.UrlGroup.Dispose(); + Queue.Dispose(); } } } diff --git a/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs b/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs index ea6c657813..d93d236477 100644 --- a/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs +++ b/src/Servers/HttpSys/src/NativeInterop/UrlGroup.cs @@ -83,6 +83,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerDelegationProperty, new IntPtr(&propertyInfo), (uint)RequestPropertyInfoSize); } + internal unsafe void UnSetDelegationProperty(RequestQueue destination, bool throwOnError = true) + { + var propertyInfo = new HttpApiTypes.HTTP_BINDING_INFO(); + propertyInfo.Flags = HttpApiTypes.HTTP_FLAGS.NONE; + propertyInfo.RequestQueueHandle = destination.Handle.DangerousGetHandle(); + + SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerDelegationProperty, new IntPtr(&propertyInfo), (uint)RequestPropertyInfoSize, throwOnError); + } + internal void SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true) { Debug.Assert(info != IntPtr.Zero, "SetUrlGroupProperty called with invalid pointer"); diff --git a/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs b/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs index d9066a3dd5..07041f08d2 100644 --- a/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs +++ b/src/Servers/HttpSys/src/ServerDelegationPropertyFeature.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys public DelegationRule CreateDelegationRule(string queueName, string uri) { - var rule = new DelegationRule(queueName, uri, _logger); + var rule = new DelegationRule(_queue.UrlGroup, queueName, uri, _logger); _queue.UrlGroup.SetDelegationProperty(rule.Queue); return rule; } diff --git a/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs b/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs index f94f0bf0be..de896ed679 100644 --- a/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs +++ b/src/Servers/HttpSys/test/FunctionalTests/DelegateTests.cs @@ -161,6 +161,38 @@ namespace Microsoft.AspNetCore.Server.HttpSys.FunctionalTests _ = await SendRequestAsync(delegatorAddress); } + [ConditionalFact] + [DelegateSupportedCondition(true)] + public async Task UpdateDelegationRuleTest() + { + var queueName = Guid.NewGuid().ToString(); + using var receiver = Utilities.CreateHttpServer(out var receiverAddress, async httpContext => + { + await httpContext.Response.WriteAsync(_expectedResponseString); + }, + options => + { + options.RequestQueueName = queueName; + }); + + DelegationRule destination = default; + + using var delegator = Utilities.CreateHttpServer(out var delegatorAddress, httpContext => + { + var delegateFeature = httpContext.Features.Get(); + delegateFeature.DelegateRequest(destination); + return Task.CompletedTask; + }); + + var delegationProperty = delegator.Features.Get(); + destination = delegationProperty.CreateDelegationRule(queueName, receiverAddress); + destination?.Dispose(); + destination = delegationProperty.CreateDelegationRule(queueName, receiverAddress); + var responseString = await SendRequestAsync(delegatorAddress); + Assert.Equal(_expectedResponseString, responseString); + destination?.Dispose(); + } + private async Task SendRequestAsync(string uri) { using var client = new HttpClient();