[release/5.0] DelegationRule.Dispose() unsets delegation property on the queue (#28514)

* Unset delegation propery from source queue. This removes the process from the target URL group and allows the delegation rule to be added back later on in the processes lifetime

* Add test

* Add disposing pattern

Co-authored-by: Nolan Glore <nglore@microsoft.com>
This commit is contained in:
Sourabh Shirhatti 2020-12-09 13:33:10 -08:00 committed by GitHub
parent 8a3c8653cd
commit e47cbf6de6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 60 additions and 4 deletions

View File

@ -13,6 +13,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
public class DelegationRule : IDisposable
{
private readonly ILogger _logger;
private readonly UrlGroup _sourceQueueUrlGroup;
private bool _disposed;
/// <summary>
/// The name of the Http.Sys request queue
/// </summary>
@ -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
/// <inheritdoc />
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();
}
}
}

View File

@ -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");

View File

@ -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;
}

View File

@ -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<IHttpSysRequestDelegationFeature>();
delegateFeature.DelegateRequest(destination);
return Task.CompletedTask;
});
var delegationProperty = delegator.Features.Get<IServerDelegationFeature>();
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<string> SendRequestAsync(string uri)
{
using var client = new HttpClient();