Pool HttpSys request buffers (#17314)
This commit is contained in:
parent
6f2b107b88
commit
ca23b1a325
|
|
@ -1,6 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<configuration>
|
|
||||||
<startup>
|
|
||||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6"/>
|
|
||||||
</startup>
|
|
||||||
</configuration>
|
|
||||||
|
|
@ -11,20 +11,45 @@ namespace TestClient
|
||||||
public class Program
|
public class Program
|
||||||
{
|
{
|
||||||
private const string Address =
|
private const string Address =
|
||||||
// "http://localhost:5000/public/1kb.txt";
|
"http://localhost:5000/public/1kb.txt";
|
||||||
"https://localhost:9090/public/1kb.txt";
|
// "https://localhost:9090/public/1kb.txt";
|
||||||
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
WebRequestHandler handler = new WebRequestHandler();
|
Console.WriteLine("Ready");
|
||||||
handler.ServerCertificateValidationCallback = (_, __, ___, ____) => true;
|
Console.ReadKey();
|
||||||
|
|
||||||
|
var handler = new HttpClientHandler();
|
||||||
|
handler.MaxConnectionsPerServer = 500;
|
||||||
|
handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
|
||||||
// handler.UseDefaultCredentials = true;
|
// handler.UseDefaultCredentials = true;
|
||||||
handler.Credentials = new NetworkCredential(@"redmond\chrross", "passwird");
|
|
||||||
HttpClient client = new HttpClient(handler);
|
HttpClient client = new HttpClient(handler);
|
||||||
|
|
||||||
/*
|
RunParallelRequests(client);
|
||||||
|
|
||||||
|
// RunManualRequests(client);
|
||||||
|
|
||||||
|
// RunWebSocketClient().Wait();
|
||||||
|
|
||||||
|
Console.WriteLine("Done");
|
||||||
|
// Console.ReadKey();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RunManualRequests(HttpClient client)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Press any key to send request");
|
||||||
|
Console.ReadKey();
|
||||||
|
var result = client.GetAsync(Address).Result;
|
||||||
|
Console.WriteLine(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RunParallelRequests(HttpClient client)
|
||||||
|
{
|
||||||
int completionCount = 0;
|
int completionCount = 0;
|
||||||
int iterations = 30000;
|
int iterations = 100000;
|
||||||
for (int i = 0; i < iterations; i++)
|
for (int i = 0; i < iterations; i++)
|
||||||
{
|
{
|
||||||
client.GetAsync(Address)
|
client.GetAsync(Address)
|
||||||
|
|
@ -34,19 +59,7 @@ namespace TestClient
|
||||||
while (completionCount < iterations)
|
while (completionCount < iterations)
|
||||||
{
|
{
|
||||||
Thread.Sleep(10);
|
Thread.Sleep(10);
|
||||||
}*/
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Press any key to send request");
|
|
||||||
Console.ReadKey();
|
|
||||||
var result = client.GetAsync(Address).Result;
|
|
||||||
Console.WriteLine(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RunWebSocketClient().Wait();
|
|
||||||
// Console.WriteLine("Done");
|
|
||||||
// Console.ReadKey();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task RunWebSocketClient()
|
public static async Task RunWebSocketClient()
|
||||||
|
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
// 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.Reflection;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
// General Information about an assembly is controlled through the following
|
|
||||||
// set of attributes. Change these attribute values to modify the information
|
|
||||||
// associated with an assembly.
|
|
||||||
[assembly: AssemblyTitle("TestClient")]
|
|
||||||
[assembly: AssemblyDescription("")]
|
|
||||||
[assembly: AssemblyConfiguration("")]
|
|
||||||
[assembly: AssemblyCompany("")]
|
|
||||||
[assembly: AssemblyProduct("TestClient")]
|
|
||||||
[assembly: AssemblyCopyright("Copyright © 2012")]
|
|
||||||
[assembly: AssemblyTrademark("")]
|
|
||||||
[assembly: AssemblyCulture("")]
|
|
||||||
|
|
||||||
// Setting ComVisible to false makes the types in this assembly not visible
|
|
||||||
// to COM components. If you need to access a type in this assembly from
|
|
||||||
// COM, set the ComVisible attribute to true on that type.
|
|
||||||
[assembly: ComVisible(false)]
|
|
||||||
|
|
||||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
|
||||||
[assembly: Guid("8db62eb3-48c0-4049-b33e-271c738140a0")]
|
|
||||||
|
|
||||||
// Version information for an assembly consists of the following four values:
|
|
||||||
//
|
|
||||||
// Major Version
|
|
||||||
// Minor Version
|
|
||||||
// Build Number
|
|
||||||
// Revision
|
|
||||||
//
|
|
||||||
// You can specify all the values or you can default the Build and Revision Numbers
|
|
||||||
// by using the '*' as shown below:
|
|
||||||
// [assembly: AssemblyVersion("0.5")]
|
|
||||||
[assembly: AssemblyVersion("0.5")]
|
|
||||||
[assembly: AssemblyFileVersion("0.5.40117.0")]
|
|
||||||
|
|
@ -1,64 +1,13 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
<TargetFramework>$(DefaultNetCoreTargetFramework)</TargetFramework>
|
||||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
|
||||||
<ProjectGuid>{8B828433-B333-4C19-96AE-00BFFF9D8841}</ProjectGuid>
|
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
<StartupObject>TestClient.Program</StartupObject>
|
||||||
<RootNamespace>TestClient</RootNamespace>
|
|
||||||
<AssemblyName>TestClient</AssemblyName>
|
|
||||||
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
|
|
||||||
<FileAlignment>512</FileAlignment>
|
|
||||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
|
|
||||||
<RestorePackages>true</RestorePackages>
|
|
||||||
<TargetFrameworkProfile />
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<DebugSymbols>true</DebugSymbols>
|
|
||||||
<DebugType>full</DebugType>
|
|
||||||
<Optimize>false</Optimize>
|
|
||||||
<OutputPath>bin\Debug\</OutputPath>
|
|
||||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
|
||||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
|
||||||
<DebugType>pdbonly</DebugType>
|
|
||||||
<Optimize>true</Optimize>
|
|
||||||
<OutputPath>bin\Release\</OutputPath>
|
|
||||||
<DefineConstants>TRACE</DefineConstants>
|
|
||||||
<ErrorReport>prompt</ErrorReport>
|
|
||||||
<WarningLevel>4</WarningLevel>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="System" />
|
<Reference Include="Microsoft.Extensions.Logging.Console" />
|
||||||
<Reference Include="System.Core" />
|
|
||||||
<Reference Include="System.Net.Http" />
|
|
||||||
<Reference Include="System.Net.Http.WebRequest" />
|
|
||||||
<Reference Include="System.Xml.Linq" />
|
|
||||||
<Reference Include="System.Data.DataSetExtensions" />
|
|
||||||
<Reference Include="Microsoft.CSharp" />
|
|
||||||
<Reference Include="System.Data" />
|
|
||||||
<Reference Include="System.Xml" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<Compile Include="Program.cs" />
|
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="App.config" />
|
|
||||||
</ItemGroup>
|
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
|
||||||
<Target Name="Pack" />
|
|
||||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
|
||||||
Other similar extension points exist, see Microsoft.Common.targets.
|
|
||||||
<Target Name="BeforeBuild">
|
|
||||||
</Target>
|
|
||||||
<Target Name="AfterBuild">
|
|
||||||
</Target>
|
|
||||||
-->
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
|
|
@ -18,8 +17,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
private TaskCompletionSource<RequestContext> _tcs;
|
private TaskCompletionSource<RequestContext> _tcs;
|
||||||
private HttpSysListener _server;
|
private HttpSysListener _server;
|
||||||
private NativeRequestContext _nativeRequestContext;
|
private NativeRequestContext _nativeRequestContext;
|
||||||
private const int DefaultBufferSize = 4096;
|
|
||||||
private const int AlignmentPadding = 8;
|
|
||||||
|
|
||||||
internal AsyncAcceptContext(HttpSysListener server)
|
internal AsyncAcceptContext(HttpSysListener server)
|
||||||
{
|
{
|
||||||
|
|
@ -192,32 +189,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
{
|
{
|
||||||
_nativeRequestContext?.ReleasePins();
|
_nativeRequestContext?.ReleasePins();
|
||||||
_nativeRequestContext?.Dispose();
|
_nativeRequestContext?.Dispose();
|
||||||
//Debug.Assert(size != 0, "unexpected size");
|
|
||||||
|
|
||||||
// We can't reuse overlapped objects
|
// We can't reuse overlapped objects
|
||||||
uint newSize = size.HasValue ? size.Value : DefaultBufferSize;
|
|
||||||
var backingBuffer = new byte[newSize + AlignmentPadding];
|
|
||||||
|
|
||||||
var boundHandle = Server.RequestQueue.BoundHandle;
|
var boundHandle = Server.RequestQueue.BoundHandle;
|
||||||
var nativeOverlapped = new SafeNativeOverlapped(boundHandle,
|
var nativeOverlapped = new SafeNativeOverlapped(boundHandle,
|
||||||
boundHandle.AllocateNativeOverlapped(IOCallback, this, backingBuffer));
|
boundHandle.AllocateNativeOverlapped(IOCallback, this, pinData: null));
|
||||||
|
|
||||||
var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(backingBuffer, 0);
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// Apparently the HttpReceiveHttpRequest memory alignment requirements for non - ARM processors
|
|
||||||
// are different than for ARM processors. We have seen 4 - byte - aligned buffers allocated on
|
|
||||||
// virtual x64/x86 machines which were accepted by HttpReceiveHttpRequest without errors. In
|
|
||||||
// these cases the buffer alignment may cause reading values at invalid offset. Setting buffer
|
|
||||||
// alignment to 0 for now.
|
|
||||||
//
|
|
||||||
// _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07);
|
|
||||||
|
|
||||||
var bufferAlignment = 0;
|
|
||||||
|
|
||||||
var nativeRequest = (HttpApiTypes.HTTP_REQUEST*)(requestAddress + bufferAlignment);
|
|
||||||
// nativeRequest
|
// nativeRequest
|
||||||
_nativeRequestContext = new NativeRequestContext(nativeOverlapped, bufferAlignment, nativeRequest, backingBuffer, requestId);
|
_nativeRequestContext = new NativeRequestContext(nativeOverlapped, Server.MemoryPool, size, requestId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public object AsyncState
|
public object AsyncState
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
@ -32,6 +33,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
||||||
// 0.5 seconds per request. Respond with a 400 Bad Request.
|
// 0.5 seconds per request. Respond with a 400 Bad Request.
|
||||||
private const int UnknownHeaderLimit = 1000;
|
private const int UnknownHeaderLimit = 1000;
|
||||||
|
|
||||||
|
internal MemoryPool<byte> MemoryPool { get; } = SlabMemoryPoolFactory.Create();
|
||||||
|
|
||||||
private volatile State _state; // m_State is set only within lock blocks, but often read outside locks.
|
private volatile State _state; // m_State is set only within lock blocks, but often read outside locks.
|
||||||
|
|
||||||
private ServerSession _serverSession;
|
private ServerSession _serverSession;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<Description>ASP.NET Core HTTP server that uses the Windows HTTP Server API.</Description>
|
<Description>ASP.NET Core HTTP server that uses the Windows HTTP Server API.</Description>
|
||||||
|
|
@ -13,6 +13,10 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="$(SharedSourceRoot)HttpSys\**\*.cs" />
|
<Compile Include="$(SharedSourceRoot)HttpSys\**\*.cs" />
|
||||||
|
<Compile Include="$(SharedSourceRoot)Buffers.MemoryPool\*.cs" LinkBase="MemoryPool" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
|
|
@ -14,16 +15,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
|
|
||||||
internal static unsafe string GetString(byte* pBytes, int byteCount)
|
internal static unsafe string GetString(byte* pBytes, int byteCount)
|
||||||
{
|
{
|
||||||
// net451: return new string(pBytes, 0, byteCount, Encoding);
|
return Encoding.GetString(new ReadOnlySpan<byte>(pBytes, byteCount));
|
||||||
|
|
||||||
var charCount = Encoding.GetCharCount(pBytes, byteCount);
|
|
||||||
var chars = new char[charCount];
|
|
||||||
fixed (char* pChars = chars)
|
|
||||||
{
|
|
||||||
var count = Encoding.GetChars(pBytes, byteCount, pChars, charCount);
|
|
||||||
System.Diagnostics.Debug.Assert(count == charCount);
|
|
||||||
}
|
|
||||||
return new string(chars);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static byte[] GetBytes(string myString)
|
internal static byte[] GetBytes(string myString)
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
@ -17,24 +18,45 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
internal unsafe class NativeRequestContext : IDisposable
|
internal unsafe class NativeRequestContext : IDisposable
|
||||||
{
|
{
|
||||||
private const int AlignmentPadding = 8;
|
private const int AlignmentPadding = 8;
|
||||||
|
private const int DefaultBufferSize = 4096 - AlignmentPadding;
|
||||||
private IntPtr _originalBufferAddress;
|
private IntPtr _originalBufferAddress;
|
||||||
private HttpApiTypes.HTTP_REQUEST* _nativeRequest;
|
private HttpApiTypes.HTTP_REQUEST* _nativeRequest;
|
||||||
private byte[] _backingBuffer;
|
private IMemoryOwner<byte> _backingBuffer;
|
||||||
|
private MemoryHandle _memoryHandle;
|
||||||
private int _bufferAlignment;
|
private int _bufferAlignment;
|
||||||
private SafeNativeOverlapped _nativeOverlapped;
|
private SafeNativeOverlapped _nativeOverlapped;
|
||||||
private bool _permanentlyPinned;
|
private bool _permanentlyPinned;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
// To be used by HttpSys
|
// To be used by HttpSys
|
||||||
internal NativeRequestContext(SafeNativeOverlapped nativeOverlapped,
|
internal NativeRequestContext(SafeNativeOverlapped nativeOverlapped, MemoryPool<Byte> memoryPool, uint? bufferSize, ulong requestId)
|
||||||
int bufferAlignment,
|
|
||||||
HttpApiTypes.HTTP_REQUEST* nativeRequest,
|
|
||||||
byte[] backingBuffer,
|
|
||||||
ulong requestId)
|
|
||||||
{
|
{
|
||||||
_nativeOverlapped = nativeOverlapped;
|
_nativeOverlapped = nativeOverlapped;
|
||||||
_bufferAlignment = bufferAlignment;
|
|
||||||
_nativeRequest = nativeRequest;
|
// TODO:
|
||||||
_backingBuffer = backingBuffer;
|
// Apparently the HttpReceiveHttpRequest memory alignment requirements for non - ARM processors
|
||||||
|
// are different than for ARM processors. We have seen 4 - byte - aligned buffers allocated on
|
||||||
|
// virtual x64/x86 machines which were accepted by HttpReceiveHttpRequest without errors. In
|
||||||
|
// these cases the buffer alignment may cause reading values at invalid offset. Setting buffer
|
||||||
|
// alignment to 0 for now.
|
||||||
|
//
|
||||||
|
// _bufferAlignment = (int)(requestAddress.ToInt64() & 0x07);
|
||||||
|
_bufferAlignment = 0;
|
||||||
|
|
||||||
|
var newSize = (int)(bufferSize ?? DefaultBufferSize) + AlignmentPadding;
|
||||||
|
if (newSize <= memoryPool.MaxBufferSize)
|
||||||
|
{
|
||||||
|
_backingBuffer = memoryPool.Rent(newSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No size limit
|
||||||
|
_backingBuffer = MemoryPool<byte>.Shared.Rent(newSize);
|
||||||
|
}
|
||||||
|
_backingBuffer.Memory.Span.Fill(0);// Zero the buffer
|
||||||
|
_memoryHandle = _backingBuffer.Memory.Pin();
|
||||||
|
_nativeRequest = (HttpApiTypes.HTTP_REQUEST*)((long)_memoryHandle.Pointer + _bufferAlignment);
|
||||||
|
|
||||||
RequestId = requestId;
|
RequestId = requestId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,15 +116,17 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
|
|
||||||
internal uint Size
|
internal uint Size
|
||||||
{
|
{
|
||||||
get { return (uint)_backingBuffer.Length - AlignmentPadding; }
|
get { return (uint)_backingBuffer.Memory.Length - AlignmentPadding; }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReleasePins() should be called exactly once. It must be called before Dispose() is called, which means it must be called
|
// ReleasePins() should be called exactly once. It must be called before Dispose() is called, which means it must be called
|
||||||
// before an object (Request) which closes the RequestContext on demand is returned to the application.
|
// before an object (Request) which closes the RequestContext on demand is returned to the application.
|
||||||
internal void ReleasePins()
|
internal void ReleasePins()
|
||||||
{
|
{
|
||||||
Debug.Assert(_nativeRequest != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice.");
|
Debug.Assert(_nativeRequest != null, "RequestContextBase::ReleasePins()|ReleasePins() called twice.");
|
||||||
_originalBufferAddress = (IntPtr)_nativeRequest;
|
_originalBufferAddress = (IntPtr)_nativeRequest;
|
||||||
|
_memoryHandle.Dispose();
|
||||||
|
_memoryHandle = default;
|
||||||
_nativeRequest = null;
|
_nativeRequest = null;
|
||||||
_nativeOverlapped?.Dispose();
|
_nativeOverlapped?.Dispose();
|
||||||
_nativeOverlapped = null;
|
_nativeOverlapped = null;
|
||||||
|
|
@ -110,8 +134,14 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
Debug.Assert(_nativeRequest == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins().");
|
if (!_disposed)
|
||||||
_nativeOverlapped?.Dispose();
|
{
|
||||||
|
_disposed = true;
|
||||||
|
Debug.Assert(_nativeRequest == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins().");
|
||||||
|
_nativeOverlapped?.Dispose();
|
||||||
|
_memoryHandle.Dispose();
|
||||||
|
_backingBuffer.Dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These methods require the HTTP_REQUEST to still be pinned in its original location.
|
// These methods require the HTTP_REQUEST to still be pinned in its original location.
|
||||||
|
|
@ -272,7 +302,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
fixed (byte* pMemoryBlob = _backingBuffer.Memory.Span)
|
||||||
{
|
{
|
||||||
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||||
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
||||||
|
|
@ -306,7 +336,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Return value.
|
// Return value.
|
||||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
fixed (byte* pMemoryBlob = _backingBuffer.Memory.Span)
|
||||||
{
|
{
|
||||||
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||||
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
||||||
|
|
@ -366,7 +396,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
fixed (byte* pMemoryBlob = _backingBuffer.Memory.Span)
|
||||||
{
|
{
|
||||||
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||||
return GetEndPointHelper(localEndpoint, request, pMemoryBlob);
|
return GetEndPointHelper(localEndpoint, request, pMemoryBlob);
|
||||||
|
|
@ -426,7 +456,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
fixed (byte* pMemoryBlob = _backingBuffer.Memory.Span)
|
||||||
{
|
{
|
||||||
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||||
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
||||||
|
|
@ -490,7 +520,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
fixed (byte* pMemoryBlob = _backingBuffer.Memory.Span)
|
||||||
{
|
{
|
||||||
var request = (HttpApiTypes.HTTP_REQUEST_V2*)(pMemoryBlob + _bufferAlignment);
|
var request = (HttpApiTypes.HTTP_REQUEST_V2*)(pMemoryBlob + _bufferAlignment);
|
||||||
return GetRequestInfo(_originalBufferAddress, request);
|
return GetRequestInfo(_originalBufferAddress, request);
|
||||||
|
|
@ -514,7 +544,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
var offset = (long)requestInfo.pInfo - (long)baseAddress;
|
var offset = (long)requestInfo.pInfo - (long)baseAddress;
|
||||||
info.Add(
|
info.Add(
|
||||||
(int)requestInfo.InfoType,
|
(int)requestInfo.InfoType,
|
||||||
new ReadOnlyMemory<byte>(_backingBuffer, (int)offset, (int)requestInfo.InfoLength));
|
_backingBuffer.Memory.Slice((int)offset, (int)requestInfo.InfoLength));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ReadOnlyDictionary<int, ReadOnlyMemory<byte>>(info);
|
return new ReadOnlyDictionary<int, ReadOnlyMemory<byte>>(info);
|
||||||
|
|
@ -528,7 +558,7 @@ namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
fixed (byte* pMemoryBlob = _backingBuffer.Memory.Span)
|
||||||
{
|
{
|
||||||
var request = (HttpApiTypes.HTTP_REQUEST_V2*)(pMemoryBlob + _bufferAlignment);
|
var request = (HttpApiTypes.HTTP_REQUEST_V2*)(pMemoryBlob + _bufferAlignment);
|
||||||
return GetClientCertificate(_originalBufferAddress, request);
|
return GetClientCertificate(_originalBufferAddress, request);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue