136 lines
4.8 KiB
C#
136 lines
4.8 KiB
C#
// Copyright (c) Microsoft Open Technologies, Inc.
|
|
// All Rights Reserved
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
|
|
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
|
|
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
|
|
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
|
|
// NON-INFRINGEMENT.
|
|
// See the Apache 2 License for the specific language governing
|
|
// permissions and limitations under the License.
|
|
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Threading;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Microsoft.Net.Http.Server
|
|
{
|
|
internal class RequestQueue
|
|
{
|
|
private static readonly int BindingInfoSize =
|
|
Marshal.SizeOf<HttpApi.HTTP_BINDING_INFO>();
|
|
|
|
private readonly UrlGroup _urlGroup;
|
|
private readonly ILogger _logger;
|
|
private bool _disposed;
|
|
|
|
internal RequestQueue(UrlGroup urlGroup, ILogger logger)
|
|
{
|
|
_urlGroup = urlGroup;
|
|
_logger = logger;
|
|
|
|
HttpRequestQueueV2Handle requestQueueHandle = null;
|
|
var statusCode = HttpApi.HttpCreateRequestQueue(
|
|
HttpApi.Version, null, null, 0, out requestQueueHandle);
|
|
|
|
if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
|
|
{
|
|
throw new WebListenerException((int)statusCode);
|
|
}
|
|
|
|
// Disabling callbacks when IO operation completes synchronously (returns ErrorCodes.ERROR_SUCCESS)
|
|
if (WebListener.SkipIOCPCallbackOnSuccess &&
|
|
!UnsafeNclNativeMethods.SetFileCompletionNotificationModes(
|
|
requestQueueHandle,
|
|
UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipCompletionPortOnSuccess |
|
|
UnsafeNclNativeMethods.FileCompletionNotificationModes.SkipSetEventOnHandle))
|
|
{
|
|
throw new WebListenerException(Marshal.GetLastWin32Error());
|
|
}
|
|
|
|
Handle = requestQueueHandle;
|
|
BoundHandle = ThreadPoolBoundHandle.BindHandle(Handle);
|
|
}
|
|
|
|
internal SafeHandle Handle { get; }
|
|
internal ThreadPoolBoundHandle BoundHandle { get; }
|
|
|
|
internal unsafe void AttachToUrlGroup()
|
|
{
|
|
CheckDisposed();
|
|
// Set the association between request queue and url group. After this, requests for registered urls will
|
|
// get delivered to this request queue.
|
|
|
|
var info = new HttpApi.HTTP_BINDING_INFO();
|
|
info.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
|
|
info.RequestQueueHandle = Handle.DangerousGetHandle();
|
|
|
|
var infoptr = new IntPtr(&info);
|
|
|
|
_urlGroup.SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty,
|
|
infoptr, (uint)BindingInfoSize);
|
|
}
|
|
|
|
internal unsafe void DetachFromUrlGroup()
|
|
{
|
|
CheckDisposed();
|
|
// Break the association between request queue and url group. After this, requests for registered urls
|
|
// will get 503s.
|
|
// Note that this method may be called multiple times (Stop() and then Abort()). This
|
|
// is fine since http.sys allows to set HttpServerBindingProperty multiple times for valid
|
|
// Url groups.
|
|
|
|
var info = new HttpApi.HTTP_BINDING_INFO();
|
|
info.Flags = HttpApi.HTTP_FLAGS.NONE;
|
|
info.RequestQueueHandle = IntPtr.Zero;
|
|
|
|
var infoptr = new IntPtr(&info);
|
|
|
|
_urlGroup.SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty,
|
|
infoptr, (uint)BindingInfoSize, throwOnError: false);
|
|
}
|
|
|
|
// The listener must be active for this to work.
|
|
internal unsafe void SetLengthLimit(long length)
|
|
{
|
|
CheckDisposed();
|
|
|
|
var result = HttpApi.HttpSetRequestQueueProperty(Handle,
|
|
HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty,
|
|
new IntPtr((void*)&length), (uint)Marshal.SizeOf<long>(), 0, IntPtr.Zero);
|
|
|
|
if (result != 0)
|
|
{
|
|
throw new WebListenerException((int)result);
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (_disposed)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_disposed = true;
|
|
BoundHandle.Dispose();
|
|
Handle.Dispose();
|
|
}
|
|
|
|
private void CheckDisposed()
|
|
{
|
|
if (_disposed)
|
|
{
|
|
throw new ObjectDisposedException(this.GetType().FullName);
|
|
}
|
|
}
|
|
}
|
|
}
|