Create shared package folder for IIS Integration In-process. (#397)
This commit is contained in:
Родитель
58f82c5b32
Коммит
231cbffe1a
|
@ -45,6 +45,41 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{85914BA9
|
|||
build\Key.snk = build\Key.snk
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "shared", "shared", "{AB6964C9-A7AF-4FAC-BEA1-C8A538EC989E}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Microsoft.AspNetCore.HttpSys.Sources", "Microsoft.AspNetCore.HttpSys.Sources", "{4AB1E069-2A8A-4D46-98AE-CC82E3497038}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\Constants.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\Constants.cs
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "NativeInterop", "NativeInterop", "{94AD33C9-1BDD-4385-A850-4B24FD5D5012}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\CookedUrl.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\CookedUrl.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HeapAllocHandle.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HeapAllocHandle.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpApiTypes.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpApiTypes.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpSysRequestHeader.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpSysRequestHeader.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpSysResponseHeader.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\HttpSysResponseHeader.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\NativeRequestInput.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\NativeRequestInput.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\NclUtilities.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\NclUtilities.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeLocalFreeChannelBinding.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeLocalFreeChannelBinding.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeLocalMemHandle.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeLocalMemHandle.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeNativeOverlapped.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SafeNativeOverlapped.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SocketAddress.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\SocketAddress.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\UnsafeNativeMethods.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\NativeInterop\UnsafeNativeMethods.cs
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "RequestProcessing", "RequestProcessing", "{AA8C91BD-D558-468B-9258-1E186884F78D}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderCollection.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderCollection.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderEncoding.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderEncoding.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderParser.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HeaderParser.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HttpKnownHeaderNames.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\HttpKnownHeaderNames.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\NativeRequestContext.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\NativeRequestContext.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\RequestHeaders.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\RequestHeaders.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\RequestHeaders.Generated.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\RequestHeaders.Generated.cs
|
||||
shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\SslStatus.cs = shared\Microsoft.AspNetCore.HttpSys.Sources\RequestProcessing\SslStatus.cs
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -131,6 +166,9 @@ Global
|
|||
{8BFA392A-8B67-4454-916B-67C545EDFAEF} = {3A1E31E3-2794-4CA3-B8E2-253E96BDE514}
|
||||
{E837249E-E666-4DF2-AFC3-7A4D70234F9F} = {E183C826-1360-4DFF-9994-F33CED5C8525}
|
||||
{85914BA9-4168-48C5-9C3F-E2E8B1479A6E} = {5E9B546C-17AC-4BDF-BCB3-5955D4755ED8}
|
||||
{4AB1E069-2A8A-4D46-98AE-CC82E3497038} = {AB6964C9-A7AF-4FAC-BEA1-C8A538EC989E}
|
||||
{94AD33C9-1BDD-4385-A850-4B24FD5D5012} = {4AB1E069-2A8A-4D46-98AE-CC82E3497038}
|
||||
{AA8C91BD-D558-468B-9258-1E186884F78D} = {4AB1E069-2A8A-4D46-98AE-CC82E3497038}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {34B42B42-FA09-41AB-9216-14073990C504}
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
{
|
||||
"adx-nonshipping": {
|
||||
"rules": [],
|
||||
"packages": {
|
||||
"Microsoft.AspNetCore.HttpSys.Sources": {}
|
||||
}
|
||||
},
|
||||
"Default": {
|
||||
"rules": [
|
||||
"DefaultCompositeRule"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal static class Constants
|
||||
{
|
|
@ -4,14 +4,14 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
// Note this type should only be used while the request buffer remains pinned
|
||||
internal class CookedUrl
|
||||
{
|
||||
private readonly HttpApi.HTTP_COOKED_URL _nativeCookedUrl;
|
||||
private readonly HttpApiTypes.HTTP_COOKED_URL _nativeCookedUrl;
|
||||
|
||||
internal CookedUrl(HttpApi.HTTP_COOKED_URL nativeCookedUrl)
|
||||
internal CookedUrl(HttpApiTypes.HTTP_COOKED_URL nativeCookedUrl)
|
||||
{
|
||||
_nativeCookedUrl = nativeCookedUrl;
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal sealed class HeapAllocHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
|
@ -0,0 +1,694 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal static unsafe class HttpApiTypes
|
||||
{
|
||||
internal enum HTTP_API_VERSION
|
||||
{
|
||||
Invalid,
|
||||
Version10,
|
||||
Version20,
|
||||
}
|
||||
|
||||
// see http.w for definitions
|
||||
internal enum HTTP_SERVER_PROPERTY
|
||||
{
|
||||
HttpServerAuthenticationProperty,
|
||||
HttpServerLoggingProperty,
|
||||
HttpServerQosProperty,
|
||||
HttpServerTimeoutsProperty,
|
||||
HttpServerQueueLengthProperty,
|
||||
HttpServerStateProperty,
|
||||
HttpServer503VerbosityProperty,
|
||||
HttpServerBindingProperty,
|
||||
HttpServerExtendedAuthenticationProperty,
|
||||
HttpServerListenEndpointProperty,
|
||||
HttpServerChannelBindProperty,
|
||||
HttpServerProtectionLevelProperty,
|
||||
}
|
||||
|
||||
// Currently only one request info type is supported but the enum is for future extensibility.
|
||||
|
||||
internal enum HTTP_REQUEST_INFO_TYPE
|
||||
{
|
||||
HttpRequestInfoTypeAuth,
|
||||
HttpRequestInfoTypeChannelBind,
|
||||
HttpRequestInfoTypeSslProtocol,
|
||||
HttpRequestInfoTypeSslTokenBinding
|
||||
}
|
||||
|
||||
internal enum HTTP_RESPONSE_INFO_TYPE
|
||||
{
|
||||
HttpResponseInfoTypeMultipleKnownHeaders,
|
||||
HttpResponseInfoTypeAuthenticationProperty,
|
||||
HttpResponseInfoTypeQosProperty,
|
||||
}
|
||||
|
||||
internal enum HTTP_TIMEOUT_TYPE
|
||||
{
|
||||
EntityBody,
|
||||
DrainEntityBody,
|
||||
RequestQueue,
|
||||
IdleConnection,
|
||||
HeaderWait,
|
||||
MinSendRate,
|
||||
}
|
||||
|
||||
internal const int MaxTimeout = 6;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_VERSION
|
||||
{
|
||||
internal ushort MajorVersion;
|
||||
internal ushort MinorVersion;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_KNOWN_HEADER
|
||||
{
|
||||
internal ushort RawValueLength;
|
||||
internal byte* pRawValue;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
internal struct HTTP_DATA_CHUNK
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
internal HTTP_DATA_CHUNK_TYPE DataChunkType;
|
||||
|
||||
[FieldOffset(8)]
|
||||
internal FromMemory fromMemory;
|
||||
|
||||
[FieldOffset(8)]
|
||||
internal FromFileHandle fromFile;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct FromMemory
|
||||
{
|
||||
// 4 bytes for 32bit, 8 bytes for 64bit
|
||||
internal IntPtr pBuffer;
|
||||
internal uint BufferLength;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct FromFileHandle
|
||||
{
|
||||
internal ulong offset;
|
||||
internal ulong count;
|
||||
internal IntPtr fileHandle;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTPAPI_VERSION
|
||||
{
|
||||
internal ushort HttpApiMajorVersion;
|
||||
internal ushort HttpApiMinorVersion;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_COOKED_URL
|
||||
{
|
||||
internal ushort FullUrlLength;
|
||||
internal ushort HostLength;
|
||||
internal ushort AbsPathLength;
|
||||
internal ushort QueryStringLength;
|
||||
internal ushort* pFullUrl;
|
||||
internal ushort* pHost;
|
||||
internal ushort* pAbsPath;
|
||||
internal ushort* pQueryString;
|
||||
}
|
||||
|
||||
// Only cache unauthorized GETs + HEADs.
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_CACHE_POLICY
|
||||
{
|
||||
internal HTTP_CACHE_POLICY_TYPE Policy;
|
||||
internal uint SecondsToLive;
|
||||
}
|
||||
|
||||
internal enum HTTP_CACHE_POLICY_TYPE : int
|
||||
{
|
||||
HttpCachePolicyNocache = 0,
|
||||
HttpCachePolicyUserInvalidates = 1,
|
||||
HttpCachePolicyTimeToLive = 2,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct SOCKADDR
|
||||
{
|
||||
internal ushort sa_family;
|
||||
internal byte sa_data;
|
||||
internal byte sa_data_02;
|
||||
internal byte sa_data_03;
|
||||
internal byte sa_data_04;
|
||||
internal byte sa_data_05;
|
||||
internal byte sa_data_06;
|
||||
internal byte sa_data_07;
|
||||
internal byte sa_data_08;
|
||||
internal byte sa_data_09;
|
||||
internal byte sa_data_10;
|
||||
internal byte sa_data_11;
|
||||
internal byte sa_data_12;
|
||||
internal byte sa_data_13;
|
||||
internal byte sa_data_14;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_TRANSPORT_ADDRESS
|
||||
{
|
||||
internal SOCKADDR* pRemoteAddress;
|
||||
internal SOCKADDR* pLocalAddress;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SSL_CLIENT_CERT_INFO
|
||||
{
|
||||
internal uint CertFlags;
|
||||
internal uint CertEncodedSize;
|
||||
internal byte* pCertEncoded;
|
||||
internal void* Token;
|
||||
internal byte CertDeniedByMapper;
|
||||
}
|
||||
|
||||
internal enum HTTP_SERVICE_BINDING_TYPE : uint
|
||||
{
|
||||
HttpServiceBindingTypeNone = 0,
|
||||
HttpServiceBindingTypeW,
|
||||
HttpServiceBindingTypeA
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SERVICE_BINDING_BASE
|
||||
{
|
||||
internal HTTP_SERVICE_BINDING_TYPE Type;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_CHANNEL_BIND_STATUS
|
||||
{
|
||||
internal IntPtr ServiceName;
|
||||
internal IntPtr ChannelToken;
|
||||
internal uint ChannelTokenSize;
|
||||
internal uint Flags;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_UNKNOWN_HEADER
|
||||
{
|
||||
internal ushort NameLength;
|
||||
internal ushort RawValueLength;
|
||||
internal byte* pName;
|
||||
internal byte* pRawValue;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SSL_INFO
|
||||
{
|
||||
internal ushort ServerCertKeySize;
|
||||
internal ushort ConnectionKeySize;
|
||||
internal uint ServerCertIssuerSize;
|
||||
internal uint ServerCertSubjectSize;
|
||||
internal byte* pServerCertIssuer;
|
||||
internal byte* pServerCertSubject;
|
||||
internal HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo;
|
||||
internal uint SslClientCertNegotiated;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_RESPONSE_HEADERS
|
||||
{
|
||||
internal ushort UnknownHeaderCount;
|
||||
internal HTTP_UNKNOWN_HEADER* pUnknownHeaders;
|
||||
internal ushort TrailerCount;
|
||||
internal HTTP_UNKNOWN_HEADER* pTrailers;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_02;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_03;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_04;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_05;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_06;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_07;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_08;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_09;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_10;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_11;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_12;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_13;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_14;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_15;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_16;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_17;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_18;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_19;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_20;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_21;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_22;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_23;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_24;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_25;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_26;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_27;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_28;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_29;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_30;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_HEADERS
|
||||
{
|
||||
internal ushort UnknownHeaderCount;
|
||||
internal HTTP_UNKNOWN_HEADER* pUnknownHeaders;
|
||||
internal ushort TrailerCount;
|
||||
internal HTTP_UNKNOWN_HEADER* pTrailers;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_02;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_03;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_04;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_05;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_06;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_07;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_08;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_09;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_10;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_11;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_12;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_13;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_14;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_15;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_16;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_17;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_18;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_19;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_20;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_21;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_22;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_23;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_24;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_25;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_26;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_27;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_28;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_29;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_30;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_31;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_32;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_33;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_34;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_35;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_36;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_37;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_38;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_39;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_40;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_41;
|
||||
}
|
||||
|
||||
internal enum HTTP_VERB : int
|
||||
{
|
||||
HttpVerbUnparsed = 0,
|
||||
HttpVerbUnknown = 1,
|
||||
HttpVerbInvalid = 2,
|
||||
HttpVerbOPTIONS = 3,
|
||||
HttpVerbGET = 4,
|
||||
HttpVerbHEAD = 5,
|
||||
HttpVerbPOST = 6,
|
||||
HttpVerbPUT = 7,
|
||||
HttpVerbDELETE = 8,
|
||||
HttpVerbTRACE = 9,
|
||||
HttpVerbCONNECT = 10,
|
||||
HttpVerbTRACK = 11,
|
||||
HttpVerbMOVE = 12,
|
||||
HttpVerbCOPY = 13,
|
||||
HttpVerbPROPFIND = 14,
|
||||
HttpVerbPROPPATCH = 15,
|
||||
HttpVerbMKCOL = 16,
|
||||
HttpVerbLOCK = 17,
|
||||
HttpVerbUNLOCK = 18,
|
||||
HttpVerbSEARCH = 19,
|
||||
HttpVerbMaximum = 20,
|
||||
}
|
||||
|
||||
internal static readonly string[] HttpVerbs = new string[]
|
||||
{
|
||||
null,
|
||||
"Unknown",
|
||||
"Invalid",
|
||||
"OPTIONS",
|
||||
"GET",
|
||||
"HEAD",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
"TRACE",
|
||||
"CONNECT",
|
||||
"TRACK",
|
||||
"MOVE",
|
||||
"COPY",
|
||||
"PROPFIND",
|
||||
"PROPPATCH",
|
||||
"MKCOL",
|
||||
"LOCK",
|
||||
"UNLOCK",
|
||||
"SEARCH",
|
||||
};
|
||||
|
||||
internal enum HTTP_DATA_CHUNK_TYPE : int
|
||||
{
|
||||
HttpDataChunkFromMemory = 0,
|
||||
HttpDataChunkFromFileHandle = 1,
|
||||
HttpDataChunkFromFragmentCache = 2,
|
||||
HttpDataChunkMaximum = 3,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_RESPONSE_INFO
|
||||
{
|
||||
internal HTTP_RESPONSE_INFO_TYPE Type;
|
||||
internal uint Length;
|
||||
internal HTTP_MULTIPLE_KNOWN_HEADERS* pInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_RESPONSE
|
||||
{
|
||||
internal uint Flags;
|
||||
internal HTTP_VERSION Version;
|
||||
internal ushort StatusCode;
|
||||
internal ushort ReasonLength;
|
||||
internal byte* pReason;
|
||||
internal HTTP_RESPONSE_HEADERS Headers;
|
||||
internal ushort EntityChunkCount;
|
||||
internal HTTP_DATA_CHUNK* pEntityChunks;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_RESPONSE_V2
|
||||
{
|
||||
internal HTTP_RESPONSE Response_V1;
|
||||
internal ushort ResponseInfoCount;
|
||||
internal HTTP_RESPONSE_INFO* pResponseInfo;
|
||||
}
|
||||
|
||||
internal enum HTTP_RESPONSE_INFO_FLAGS : uint
|
||||
{
|
||||
None = 0,
|
||||
PreserveOrder = 1,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_MULTIPLE_KNOWN_HEADERS
|
||||
{
|
||||
internal HTTP_RESPONSE_HEADER_ID.Enum HeaderId;
|
||||
internal HTTP_RESPONSE_INFO_FLAGS Flags;
|
||||
internal ushort KnownHeaderCount;
|
||||
internal HTTP_KNOWN_HEADER* KnownHeaders;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_AUTH_INFO
|
||||
{
|
||||
internal HTTP_AUTH_STATUS AuthStatus;
|
||||
internal uint SecStatus;
|
||||
internal uint Flags;
|
||||
internal HTTP_REQUEST_AUTH_TYPE AuthType;
|
||||
internal IntPtr AccessToken;
|
||||
internal uint ContextAttributes;
|
||||
internal uint PackedContextLength;
|
||||
internal uint PackedContextType;
|
||||
internal IntPtr PackedContext;
|
||||
internal uint MutualAuthDataLength;
|
||||
internal char* pMutualAuthData;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_INFO
|
||||
{
|
||||
internal HTTP_REQUEST_INFO_TYPE InfoType;
|
||||
internal uint InfoLength;
|
||||
internal HTTP_REQUEST_AUTH_INFO* pInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST
|
||||
{
|
||||
internal uint Flags;
|
||||
internal ulong ConnectionId;
|
||||
internal ulong RequestId;
|
||||
internal ulong UrlContext;
|
||||
internal HTTP_VERSION Version;
|
||||
internal HTTP_VERB Verb;
|
||||
internal ushort UnknownVerbLength;
|
||||
internal ushort RawUrlLength;
|
||||
internal byte* pUnknownVerb;
|
||||
internal byte* pRawUrl;
|
||||
internal HTTP_COOKED_URL CookedUrl;
|
||||
internal HTTP_TRANSPORT_ADDRESS Address;
|
||||
internal HTTP_REQUEST_HEADERS Headers;
|
||||
internal ulong BytesReceived;
|
||||
internal ushort EntityChunkCount;
|
||||
internal HTTP_DATA_CHUNK* pEntityChunks;
|
||||
internal ulong RawConnectionId;
|
||||
internal HTTP_SSL_INFO* pSslInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_V2
|
||||
{
|
||||
internal HTTP_REQUEST Request;
|
||||
internal ushort RequestInfoCount;
|
||||
internal HTTP_REQUEST_INFO* pRequestInfo;
|
||||
}
|
||||
|
||||
internal enum HTTP_AUTH_STATUS
|
||||
{
|
||||
HttpAuthStatusSuccess,
|
||||
HttpAuthStatusNotAuthenticated,
|
||||
HttpAuthStatusFailure,
|
||||
}
|
||||
|
||||
internal enum HTTP_REQUEST_AUTH_TYPE
|
||||
{
|
||||
HttpRequestAuthTypeNone = 0,
|
||||
HttpRequestAuthTypeBasic,
|
||||
HttpRequestAuthTypeDigest,
|
||||
HttpRequestAuthTypeNTLM,
|
||||
HttpRequestAuthTypeNegotiate,
|
||||
HttpRequestAuthTypeKerberos
|
||||
}
|
||||
|
||||
internal enum HTTP_QOS_SETTING_TYPE
|
||||
{
|
||||
HttpQosSettingTypeBandwidth,
|
||||
HttpQosSettingTypeConnectionLimit,
|
||||
HttpQosSettingTypeFlowRate
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SERVER_AUTHENTICATION_INFO
|
||||
{
|
||||
internal HTTP_FLAGS Flags;
|
||||
internal HTTP_AUTH_TYPES AuthSchemes;
|
||||
internal bool ReceiveMutualAuth;
|
||||
internal bool ReceiveContextHandle;
|
||||
internal bool DisableNTLMCredentialCaching;
|
||||
internal ulong ExFlags;
|
||||
HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS DigestParams;
|
||||
HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS BasicParams;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS
|
||||
{
|
||||
internal ushort DomainNameLength;
|
||||
internal char* DomainName;
|
||||
internal ushort RealmLength;
|
||||
internal char* Realm;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS
|
||||
{
|
||||
ushort RealmLength;
|
||||
char* Realm;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_TOKEN_BINDING_INFO
|
||||
{
|
||||
public byte* TokenBinding;
|
||||
public uint TokenBindingSize;
|
||||
|
||||
public byte* TlsUnique;
|
||||
public uint TlsUniqueSize;
|
||||
|
||||
public char* KeyType;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_TIMEOUT_LIMIT_INFO
|
||||
{
|
||||
internal HTTP_FLAGS Flags;
|
||||
internal ushort EntityBody;
|
||||
internal ushort DrainEntityBody;
|
||||
internal ushort RequestQueue;
|
||||
internal ushort IdleConnection;
|
||||
internal ushort HeaderWait;
|
||||
internal uint MinSendRate;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_BINDING_INFO
|
||||
{
|
||||
internal HTTP_FLAGS Flags;
|
||||
internal IntPtr RequestQueueHandle;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_CONNECTION_LIMIT_INFO
|
||||
{
|
||||
internal HTTP_FLAGS Flags;
|
||||
internal uint MaxConnections;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_QOS_SETTING_INFO
|
||||
{
|
||||
internal HTTP_QOS_SETTING_TYPE QosType;
|
||||
internal IntPtr QosSetting;
|
||||
}
|
||||
|
||||
// see http.w for definitions
|
||||
[Flags]
|
||||
internal enum HTTP_FLAGS : uint
|
||||
{
|
||||
NONE = 0x00000000,
|
||||
HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY = 0x00000001,
|
||||
HTTP_RECEIVE_SECURE_CHANNEL_TOKEN = 0x00000001,
|
||||
HTTP_SEND_RESPONSE_FLAG_DISCONNECT = 0x00000001,
|
||||
HTTP_SEND_RESPONSE_FLAG_MORE_DATA = 0x00000002,
|
||||
HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA = 0x00000004,
|
||||
HTTP_SEND_RESPONSE_FLAG_RAW_HEADER = 0x00000004,
|
||||
HTTP_SEND_REQUEST_FLAG_MORE_DATA = 0x00000001,
|
||||
HTTP_PROPERTY_FLAG_PRESENT = 0x00000001,
|
||||
HTTP_INITIALIZE_SERVER = 0x00000001,
|
||||
HTTP_INITIALIZE_CBT = 0x00000004,
|
||||
HTTP_SEND_RESPONSE_FLAG_OPAQUE = 0x00000040,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum HTTP_AUTH_TYPES : uint
|
||||
{
|
||||
NONE = 0x00000000,
|
||||
HTTP_AUTH_ENABLE_BASIC = 0x00000001,
|
||||
HTTP_AUTH_ENABLE_DIGEST = 0x00000002,
|
||||
HTTP_AUTH_ENABLE_NTLM = 0x00000004,
|
||||
HTTP_AUTH_ENABLE_NEGOTIATE = 0x00000008,
|
||||
HTTP_AUTH_ENABLE_KERBEROS = 0x00000010,
|
||||
}
|
||||
|
||||
internal static class HTTP_RESPONSE_HEADER_ID
|
||||
{
|
||||
private static string[] _strings =
|
||||
{
|
||||
"Cache-Control",
|
||||
"Connection",
|
||||
"Date",
|
||||
"Keep-Alive",
|
||||
"Pragma",
|
||||
"Trailer",
|
||||
"Transfer-Encoding",
|
||||
"Upgrade",
|
||||
"Via",
|
||||
"Warning",
|
||||
|
||||
"Allow",
|
||||
"Content-Length",
|
||||
"Content-Type",
|
||||
"Content-Encoding",
|
||||
"Content-Language",
|
||||
"Content-Location",
|
||||
"Content-MD5",
|
||||
"Content-Range",
|
||||
"Expires",
|
||||
"Last-Modified",
|
||||
|
||||
"Accept-Ranges",
|
||||
"Age",
|
||||
"ETag",
|
||||
"Location",
|
||||
"Proxy-Authenticate",
|
||||
"Retry-After",
|
||||
"Server",
|
||||
"Set-Cookie",
|
||||
"Vary",
|
||||
"WWW-Authenticate",
|
||||
};
|
||||
|
||||
private static Dictionary<string, int> _lookupTable = CreateLookupTable();
|
||||
|
||||
private static Dictionary<string, int> CreateLookupTable()
|
||||
{
|
||||
Dictionary<string, int> lookupTable = new Dictionary<string, int>((int)Enum.HttpHeaderResponseMaximum, StringComparer.OrdinalIgnoreCase);
|
||||
for (int i = 0; i < (int)Enum.HttpHeaderResponseMaximum; i++)
|
||||
{
|
||||
lookupTable.Add(_strings[i], i);
|
||||
}
|
||||
return lookupTable;
|
||||
}
|
||||
|
||||
internal static int IndexOfKnownHeader(string HeaderName)
|
||||
{
|
||||
int index;
|
||||
return _lookupTable.TryGetValue(HeaderName, out index) ? index : -1;
|
||||
}
|
||||
|
||||
internal enum Enum
|
||||
{
|
||||
HttpHeaderCacheControl = 0, // general-header [section 4.5]
|
||||
HttpHeaderConnection = 1, // general-header [section 4.5]
|
||||
HttpHeaderDate = 2, // general-header [section 4.5]
|
||||
HttpHeaderKeepAlive = 3, // general-header [not in rfc]
|
||||
HttpHeaderPragma = 4, // general-header [section 4.5]
|
||||
HttpHeaderTrailer = 5, // general-header [section 4.5]
|
||||
HttpHeaderTransferEncoding = 6, // general-header [section 4.5]
|
||||
HttpHeaderUpgrade = 7, // general-header [section 4.5]
|
||||
HttpHeaderVia = 8, // general-header [section 4.5]
|
||||
HttpHeaderWarning = 9, // general-header [section 4.5]
|
||||
|
||||
HttpHeaderAllow = 10, // entity-header [section 7.1]
|
||||
HttpHeaderContentLength = 11, // entity-header [section 7.1]
|
||||
HttpHeaderContentType = 12, // entity-header [section 7.1]
|
||||
HttpHeaderContentEncoding = 13, // entity-header [section 7.1]
|
||||
HttpHeaderContentLanguage = 14, // entity-header [section 7.1]
|
||||
HttpHeaderContentLocation = 15, // entity-header [section 7.1]
|
||||
HttpHeaderContentMd5 = 16, // entity-header [section 7.1]
|
||||
HttpHeaderContentRange = 17, // entity-header [section 7.1]
|
||||
HttpHeaderExpires = 18, // entity-header [section 7.1]
|
||||
HttpHeaderLastModified = 19, // entity-header [section 7.1]
|
||||
|
||||
// Response Headers
|
||||
|
||||
HttpHeaderAcceptRanges = 20, // response-header [section 6.2]
|
||||
HttpHeaderAge = 21, // response-header [section 6.2]
|
||||
HttpHeaderEtag = 22, // response-header [section 6.2]
|
||||
HttpHeaderLocation = 23, // response-header [section 6.2]
|
||||
HttpHeaderProxyAuthenticate = 24, // response-header [section 6.2]
|
||||
HttpHeaderRetryAfter = 25, // response-header [section 6.2]
|
||||
HttpHeaderServer = 26, // response-header [section 6.2]
|
||||
HttpHeaderSetCookie = 27, // response-header [not in rfc]
|
||||
HttpHeaderVary = 28, // response-header [section 6.2]
|
||||
HttpHeaderWwwAuthenticate = 29, // response-header [section 6.2]
|
||||
|
||||
HttpHeaderResponseMaximum = 30,
|
||||
|
||||
HttpHeaderMaximum = 41
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal enum HttpSysRequestHeader
|
||||
{
|
|
@ -1,7 +1,7 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal enum HttpSysResponseHeader
|
||||
{
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal static class NclUtilities
|
||||
{
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using System.Security.Authentication.ExtendedProtection;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal class SafeLocalFreeChannelBinding : ChannelBinding
|
||||
{
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal sealed class SafeLocalMemHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal class SafeNativeOverlapped : SafeHandle
|
||||
{
|
|
@ -6,9 +6,10 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics.Contracts;
|
||||
using System.Globalization;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
// a little perf app measured these times when comparing the internal
|
||||
// buffer implemented as a managed byte[] or unmanaged memory IntPtr
|
|
@ -5,7 +5,7 @@ using System;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal static unsafe class UnsafeNclNativeMethods
|
||||
{
|
|
@ -8,7 +8,7 @@ using Microsoft.AspNetCore.Http;
|
|||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal class HeaderCollection : IHeaderDictionary
|
||||
{
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal static class HeaderEncoding
|
||||
{
|
||||
|
@ -12,15 +12,15 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
// (e.g. IE and HttpWebRequest on intranets).
|
||||
private static Encoding Encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false);
|
||||
|
||||
internal static unsafe string GetString(sbyte* pBytes, int byteCount)
|
||||
internal static unsafe string GetString(byte* pBytes, int byteCount)
|
||||
{
|
||||
// net451: return new string(pBytes, 0, byteCount, Encoding);
|
||||
|
||||
var charCount = Encoding.GetCharCount((byte*)pBytes, byteCount);
|
||||
var charCount = Encoding.GetCharCount(pBytes, byteCount);
|
||||
var chars = new char[charCount];
|
||||
fixed (char* pChars = chars)
|
||||
{
|
||||
var count = Encoding.GetChars((byte*)pBytes, byteCount, pChars, charCount);
|
||||
var count = Encoding.GetChars(pBytes, byteCount, pChars, charCount);
|
||||
System.Diagnostics.Debug.Assert(count == charCount);
|
||||
}
|
||||
return new string(chars);
|
|
@ -1,11 +1,10 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal static class HeaderParser
|
||||
{
|
|
@ -1,7 +1,7 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal static class HttpKnownHeaderNames
|
||||
{
|
|
@ -0,0 +1,455 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Principal;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal unsafe class NativeRequestContext : IDisposable
|
||||
{
|
||||
private const int AlignmentPadding = 8;
|
||||
private IntPtr _originalBufferAddress;
|
||||
private HttpApiTypes.HTTP_REQUEST* _nativeRequest;
|
||||
private byte[] _backingBuffer;
|
||||
private int _bufferAlignment;
|
||||
private SafeNativeOverlapped _nativeOverlapped;
|
||||
private bool _permanentlyPinned;
|
||||
|
||||
// To be used by HttpSys
|
||||
internal NativeRequestContext(SafeNativeOverlapped nativeOverlapped,
|
||||
int bufferAlignment,
|
||||
HttpApiTypes.HTTP_REQUEST* nativeRequest,
|
||||
byte[] backingBuffer,
|
||||
ulong requestId)
|
||||
{
|
||||
_nativeOverlapped = nativeOverlapped;
|
||||
_bufferAlignment = bufferAlignment;
|
||||
_nativeRequest = nativeRequest;
|
||||
_backingBuffer = backingBuffer;
|
||||
RequestId = requestId;
|
||||
}
|
||||
|
||||
// To be used by IIS Integration.
|
||||
internal NativeRequestContext(HttpApiTypes.HTTP_REQUEST* request)
|
||||
{
|
||||
_nativeRequest = request;
|
||||
_bufferAlignment = 0;
|
||||
_permanentlyPinned = true;
|
||||
}
|
||||
|
||||
|
||||
internal SafeNativeOverlapped NativeOverlapped => _nativeOverlapped;
|
||||
|
||||
internal HttpApiTypes.HTTP_REQUEST* NativeRequest
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins().");
|
||||
return _nativeRequest;
|
||||
}
|
||||
}
|
||||
|
||||
internal HttpApiTypes.HTTP_REQUEST_V2* NativeRequestV2
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins().");
|
||||
return (HttpApiTypes.HTTP_REQUEST_V2*)_nativeRequest;
|
||||
}
|
||||
}
|
||||
|
||||
internal ulong RequestId
|
||||
{
|
||||
get { return NativeRequest->RequestId; }
|
||||
set { NativeRequest->RequestId = value; }
|
||||
}
|
||||
|
||||
internal ulong ConnectionId => NativeRequest->ConnectionId;
|
||||
|
||||
internal HttpApiTypes.HTTP_VERB VerbId => NativeRequest->Verb;
|
||||
|
||||
internal ulong UrlContext => NativeRequest->UrlContext;
|
||||
|
||||
internal ushort UnknownHeaderCount => NativeRequest->Headers.UnknownHeaderCount;
|
||||
|
||||
internal SslStatus SslStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return NativeRequest->pSslInfo == null ? SslStatus.Insecure :
|
||||
NativeRequest->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert :
|
||||
SslStatus.ClientCert;
|
||||
}
|
||||
}
|
||||
|
||||
internal uint Size
|
||||
{
|
||||
get { return (uint)_backingBuffer.Length - AlignmentPadding; }
|
||||
}
|
||||
|
||||
// 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.
|
||||
internal void ReleasePins()
|
||||
{
|
||||
Debug.Assert(_nativeRequest != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice.");
|
||||
_originalBufferAddress = (IntPtr)_nativeRequest;
|
||||
_nativeRequest = null;
|
||||
_nativeOverlapped?.Dispose();
|
||||
_nativeOverlapped = null;
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
Debug.Assert(_nativeRequest == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins().");
|
||||
_nativeOverlapped?.Dispose();
|
||||
}
|
||||
|
||||
// These methods require the HTTP_REQUEST to still be pinned in its original location.
|
||||
|
||||
internal string GetVerb()
|
||||
{
|
||||
var verb = NativeRequest->Verb;
|
||||
if (verb > HttpApiTypes.HTTP_VERB.HttpVerbUnknown && verb < HttpApiTypes.HTTP_VERB.HttpVerbMaximum)
|
||||
{
|
||||
return HttpApiTypes.HttpVerbs[(int)verb];
|
||||
}
|
||||
else if (verb == HttpApiTypes.HTTP_VERB.HttpVerbUnknown && NativeRequest->pUnknownVerb != null)
|
||||
{
|
||||
return HeaderEncoding.GetString(NativeRequest->pUnknownVerb, NativeRequest->UnknownVerbLength);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal string GetRawUrl()
|
||||
{
|
||||
if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0)
|
||||
{
|
||||
return Marshal.PtrToStringAnsi((IntPtr)NativeRequest->pRawUrl, NativeRequest->RawUrlLength);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal byte[] GetRawUrlInBytes()
|
||||
{
|
||||
if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0)
|
||||
{
|
||||
var result = new byte[NativeRequest->RawUrlLength];
|
||||
Marshal.Copy((IntPtr)NativeRequest->pRawUrl, result, 0, NativeRequest->RawUrlLength);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal CookedUrl GetCookedUrl()
|
||||
{
|
||||
return new CookedUrl(NativeRequest->CookedUrl);
|
||||
}
|
||||
|
||||
internal Version GetVersion()
|
||||
{
|
||||
var major = NativeRequest->Version.MajorVersion;
|
||||
var minor = NativeRequest->Version.MinorVersion;
|
||||
if (major == 1 && minor == 1)
|
||||
{
|
||||
return Constants.V1_1;
|
||||
}
|
||||
else if (major == 1 && minor == 0)
|
||||
{
|
||||
return Constants.V1_0;
|
||||
}
|
||||
return new Version(major, minor);
|
||||
}
|
||||
|
||||
internal bool CheckAuthenticated()
|
||||
{
|
||||
var requestInfo = NativeRequestV2->pRequestInfo;
|
||||
var infoCount = NativeRequestV2->RequestInfoCount;
|
||||
|
||||
for (int i = 0; i < infoCount; i++)
|
||||
{
|
||||
var info = &requestInfo[i];
|
||||
if (info != null
|
||||
&& info->InfoType == HttpApiTypes.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth
|
||||
&& info->pInfo->AuthStatus == HttpApiTypes.HTTP_AUTH_STATUS.HttpAuthStatusSuccess)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal WindowsPrincipal GetUser()
|
||||
{
|
||||
var requestInfo = NativeRequestV2->pRequestInfo;
|
||||
var infoCount = NativeRequestV2->RequestInfoCount;
|
||||
|
||||
for (int i = 0; i < infoCount; i++)
|
||||
{
|
||||
var info = &requestInfo[i];
|
||||
if (info != null
|
||||
&& info->InfoType == HttpApiTypes.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth
|
||||
&& info->pInfo->AuthStatus == HttpApiTypes.HTTP_AUTH_STATUS.HttpAuthStatusSuccess)
|
||||
{
|
||||
// Duplicates AccessToken
|
||||
var identity = new WindowsIdentity(info->pInfo->AccessToken, GetAuthTypeFromRequest(info->pInfo->AuthType));
|
||||
|
||||
// Close the original
|
||||
UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(info->pInfo->AccessToken);
|
||||
|
||||
return new WindowsPrincipal(identity);
|
||||
}
|
||||
}
|
||||
|
||||
return new WindowsPrincipal(WindowsIdentity.GetAnonymous()); // Anonymous / !IsAuthenticated
|
||||
}
|
||||
|
||||
private static string GetAuthTypeFromRequest(HttpApiTypes.HTTP_REQUEST_AUTH_TYPE input)
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case HttpApiTypes.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic:
|
||||
return "Basic";
|
||||
case HttpApiTypes.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM:
|
||||
return "NTLM";
|
||||
// case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest:
|
||||
// return "Digest";
|
||||
case HttpApiTypes.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate:
|
||||
return "Negotiate";
|
||||
case HttpApiTypes.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos:
|
||||
return "Kerberos";
|
||||
default:
|
||||
throw new NotImplementedException(input.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// These methods are for accessing the request structure after it has been unpinned. They need to adjust addresses
|
||||
// in case GC has moved the original object.
|
||||
|
||||
internal string GetKnownHeader(HttpSysRequestHeader header)
|
||||
{
|
||||
if (_permanentlyPinned)
|
||||
{
|
||||
return GetKnowHeaderHelper(header, 0, _nativeRequest);
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
||||
{
|
||||
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
||||
return GetKnowHeaderHelper(header, fixup, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetKnowHeaderHelper(HttpSysRequestHeader header, long fixup, HttpApiTypes.HTTP_REQUEST* request)
|
||||
{
|
||||
int headerIndex = (int)header;
|
||||
string value = null;
|
||||
|
||||
HttpApiTypes.HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex;
|
||||
// For known headers, when header value is empty, RawValueLength will be 0 and
|
||||
// pRawValue will point to empty string ("\0")
|
||||
if (pKnownHeader->pRawValue != null)
|
||||
{
|
||||
value = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
internal void GetUnknownHeaders(IDictionary<string, StringValues> unknownHeaders)
|
||||
{
|
||||
if (_permanentlyPinned)
|
||||
{
|
||||
GetUnknownHeadersHelper(unknownHeaders, 0, _nativeRequest);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return value.
|
||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
||||
{
|
||||
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
||||
GetUnknownHeadersHelper(unknownHeaders, fixup, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void GetUnknownHeadersHelper(IDictionary<string, StringValues> unknownHeaders, long fixup, HttpApiTypes.HTTP_REQUEST* request)
|
||||
{
|
||||
int index;
|
||||
|
||||
// unknown headers
|
||||
if (request->Headers.UnknownHeaderCount != 0)
|
||||
{
|
||||
var pUnknownHeader = (HttpApiTypes.HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders);
|
||||
for (index = 0; index < request->Headers.UnknownHeaderCount; index++)
|
||||
{
|
||||
// For unknown headers, when header value is empty, RawValueLength will be 0 and
|
||||
// pRawValue will be null.
|
||||
if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0)
|
||||
{
|
||||
var headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength);
|
||||
string headerValue;
|
||||
if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0)
|
||||
{
|
||||
headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
headerValue = string.Empty;
|
||||
}
|
||||
// Note that Http.Sys currently collapses all headers of the same name to a single coma separated string,
|
||||
// so we can just call Set.
|
||||
unknownHeaders[headerName] = headerValue;
|
||||
}
|
||||
pUnknownHeader++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal SocketAddress GetRemoteEndPoint()
|
||||
{
|
||||
return GetEndPoint(localEndpoint: false);
|
||||
}
|
||||
|
||||
internal SocketAddress GetLocalEndPoint()
|
||||
{
|
||||
return GetEndPoint(localEndpoint: true);
|
||||
}
|
||||
|
||||
private SocketAddress GetEndPoint(bool localEndpoint)
|
||||
{
|
||||
if (_permanentlyPinned)
|
||||
{
|
||||
return GetEndPointHelper(localEndpoint, _nativeRequest, (byte *)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
||||
{
|
||||
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||
return GetEndPointHelper(localEndpoint, request, pMemoryBlob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SocketAddress GetEndPointHelper(bool localEndpoint, HttpApiTypes.HTTP_REQUEST* request, byte* pMemoryBlob)
|
||||
{
|
||||
var source = localEndpoint ? (byte*)request->Address.pLocalAddress : (byte*)request->Address.pRemoteAddress;
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var address = (IntPtr)(pMemoryBlob + _bufferAlignment - (byte*)_originalBufferAddress + source);
|
||||
return CopyOutAddress(address);
|
||||
}
|
||||
|
||||
private static SocketAddress CopyOutAddress(IntPtr address)
|
||||
{
|
||||
ushort addressFamily = *((ushort*)address);
|
||||
if (addressFamily == (ushort)AddressFamily.InterNetwork)
|
||||
{
|
||||
var v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize);
|
||||
fixed (byte* pBuffer = v4address.Buffer)
|
||||
{
|
||||
for (int index = 2; index < SocketAddress.IPv4AddressSize; index++)
|
||||
{
|
||||
pBuffer[index] = ((byte*)address)[index];
|
||||
}
|
||||
}
|
||||
return v4address;
|
||||
}
|
||||
if (addressFamily == (ushort)AddressFamily.InterNetworkV6)
|
||||
{
|
||||
var v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize);
|
||||
fixed (byte* pBuffer = v6address.Buffer)
|
||||
{
|
||||
for (int index = 2; index < SocketAddress.IPv6AddressSize; index++)
|
||||
{
|
||||
pBuffer[index] = ((byte*)address)[index];
|
||||
}
|
||||
}
|
||||
return v6address;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal uint GetChunks(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size)
|
||||
{
|
||||
// Return value.
|
||||
if (_permanentlyPinned)
|
||||
{
|
||||
return GetChunksHelper(ref dataChunkIndex, ref dataChunkOffset, buffer, offset, size, 0, _nativeRequest);
|
||||
}
|
||||
else
|
||||
{
|
||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
||||
{
|
||||
var request = (HttpApiTypes.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
||||
return GetChunksHelper(ref dataChunkIndex, ref dataChunkOffset, buffer, offset, size, fixup, request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private uint GetChunksHelper(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size, long fixup, HttpApiTypes.HTTP_REQUEST* request)
|
||||
{
|
||||
uint dataRead = 0;
|
||||
|
||||
if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1)
|
||||
{
|
||||
var pDataChunk = (HttpApiTypes.HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]);
|
||||
|
||||
fixed (byte* pReadBuffer = buffer)
|
||||
{
|
||||
byte* pTo = &pReadBuffer[offset];
|
||||
|
||||
while (dataChunkIndex < request->EntityChunkCount && dataRead < size)
|
||||
{
|
||||
if (dataChunkOffset >= pDataChunk->fromMemory.BufferLength)
|
||||
{
|
||||
dataChunkOffset = 0;
|
||||
dataChunkIndex++;
|
||||
pDataChunk++;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte* pFrom = (byte*)pDataChunk->fromMemory.pBuffer + dataChunkOffset + fixup;
|
||||
|
||||
uint bytesToRead = pDataChunk->fromMemory.BufferLength - (uint)dataChunkOffset;
|
||||
if (bytesToRead > (uint)size)
|
||||
{
|
||||
bytesToRead = (uint)size;
|
||||
}
|
||||
for (uint i = 0; i < bytesToRead; i++)
|
||||
{
|
||||
*(pTo++) = *(pFrom++);
|
||||
}
|
||||
dataRead += bytesToRead;
|
||||
dataChunkOffset += bytesToRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// we're finished.
|
||||
if (dataChunkIndex == request->EntityChunkCount)
|
||||
{
|
||||
dataChunkIndex = -1;
|
||||
}
|
||||
return dataRead;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal static class RawUrlHelper
|
||||
{
|
|
@ -11,7 +11,7 @@ using System.Threading;
|
|||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
[GeneratedCode("TextTemplatingFileGenerator", "")]
|
||||
internal partial class RequestHeaders
|
|
@ -6,20 +6,26 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal partial class RequestHeaders : IDictionary<string, StringValues>
|
||||
internal partial class RequestHeaders : IHeaderDictionary
|
||||
{
|
||||
private IDictionary<string, StringValues> _extra;
|
||||
private NativeRequestContext _requestMemoryBlob;
|
||||
private long? _contentLength;
|
||||
private StringValues _contentLengthText;
|
||||
|
||||
internal RequestHeaders(NativeRequestContext requestMemoryBlob)
|
||||
{
|
||||
_requestMemoryBlob = requestMemoryBlob;
|
||||
}
|
||||
|
||||
public bool IsReadOnly { get; internal set; }
|
||||
|
||||
private IDictionary<string, StringValues> Extra
|
||||
{
|
||||
get
|
||||
|
@ -43,6 +49,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
if (!PropertiesTrySetValue(key, value))
|
||||
{
|
||||
Extra[key] = value;
|
||||
|
@ -131,6 +138,96 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
get { return false; }
|
||||
}
|
||||
|
||||
long? IHeaderDictionary.ContentLength
|
||||
{
|
||||
get
|
||||
{
|
||||
long value;
|
||||
var rawValue = this[HttpKnownHeaderNames.ContentLength];
|
||||
|
||||
if (_contentLengthText.Equals(rawValue))
|
||||
{
|
||||
return _contentLength;
|
||||
}
|
||||
|
||||
if (rawValue.Count == 1 &&
|
||||
!string.IsNullOrWhiteSpace(rawValue[0]) &&
|
||||
HeaderUtilities.TryParseNonNegativeInt64(new StringSegment(rawValue[0]).Trim(), out value))
|
||||
{
|
||||
_contentLengthText = rawValue;
|
||||
_contentLength = value;
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
ThrowIfReadOnly();
|
||||
|
||||
if (value.HasValue)
|
||||
{
|
||||
if (value.Value < 0)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value", value.Value, "Cannot be negative.");
|
||||
}
|
||||
_contentLengthText = HeaderUtilities.FormatNonNegativeInt64(value.Value);
|
||||
this[HttpKnownHeaderNames.ContentLength] = _contentLengthText;
|
||||
_contentLength = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Remove(HttpKnownHeaderNames.ContentLength);
|
||||
_contentLengthText = StringValues.Empty;
|
||||
_contentLength = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public StringValues this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
StringValues values;
|
||||
return TryGetValue(key, out values) ? values : StringValues.Empty;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (StringValues.IsNullOrEmpty(value))
|
||||
{
|
||||
Remove(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
Extra[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StringValues IHeaderDictionary.this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (PropertiesTryGetValue(key, out var value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
if (Extra.TryGetValue(key, out value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
return StringValues.Empty;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!PropertiesTrySetValue(key, value))
|
||||
{
|
||||
Extra[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ICollection<KeyValuePair<string, StringValues>>.Remove(KeyValuePair<string, StringValues> item)
|
||||
{
|
||||
return ((IDictionary<string, StringValues>)this).Contains(item) &&
|
||||
|
@ -146,5 +243,23 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
return ((IDictionary<string, StringValues>)this).GetEnumerator();
|
||||
}
|
||||
|
||||
private void ThrowIfReadOnly()
|
||||
{
|
||||
if (IsReadOnly)
|
||||
{
|
||||
throw new InvalidOperationException("The response headers cannot be modified because the response has already started.");
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetValues(string key)
|
||||
{
|
||||
StringValues values;
|
||||
if (TryGetValue(key, out values))
|
||||
{
|
||||
return HeaderParser.SplitValues(values);
|
||||
}
|
||||
return HeaderParser.Empty;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
// We don't use the cooked URL because http.sys unescapes all percent-encoded values. However,
|
||||
// we also can't just use the raw Uri, since http.sys supports not only UTF-8, but also ANSI/DBCS and
|
|
@ -1,7 +1,7 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
namespace Microsoft.AspNetCore.HttpSys.Internal
|
||||
{
|
||||
internal enum SslStatus : byte
|
||||
{
|
|
@ -3,9 +3,10 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
@ -16,12 +17,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private TaskCompletionSource<RequestContext> _tcs;
|
||||
private HttpSysListener _server;
|
||||
private NativeRequestContext _nativeRequestContext;
|
||||
private const int DefaultBufferSize = 4096;
|
||||
private const int AlignmentPadding = 8;
|
||||
|
||||
internal AsyncAcceptContext(HttpSysListener server)
|
||||
{
|
||||
_server = server;
|
||||
_tcs = new TaskCompletionSource<RequestContext>();
|
||||
_nativeRequestContext = new NativeRequestContext(this);
|
||||
AllocateNativeRequest();
|
||||
}
|
||||
|
||||
internal Task<RequestContext> Task
|
||||
|
@ -68,12 +71,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
// at this point we have received an unmanaged HTTP_REQUEST and memoryBlob
|
||||
// points to it we need to hook up our authentication handling code here.
|
||||
bool stoleBlob = false;
|
||||
try
|
||||
{
|
||||
if (server.ValidateRequest(asyncResult._nativeRequestContext) && server.ValidateAuth(asyncResult._nativeRequestContext))
|
||||
{
|
||||
stoleBlob = true;
|
||||
RequestContext requestContext = new RequestContext(server, asyncResult._nativeRequestContext);
|
||||
asyncResult.Tcs.TrySetResult(requestContext);
|
||||
complete = true;
|
||||
|
@ -81,20 +82,21 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
finally
|
||||
{
|
||||
if (stoleBlob)
|
||||
// The request has been handed to the user, which means this code can't reuse the blob. Reset it here.
|
||||
if (complete)
|
||||
{
|
||||
// The request has been handed to the user, which means this code can't reuse the blob. Reset it here.
|
||||
asyncResult._nativeRequestContext = complete ? null : new NativeRequestContext(asyncResult);
|
||||
asyncResult._nativeRequestContext = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
asyncResult._nativeRequestContext.Reset();
|
||||
asyncResult.AllocateNativeRequest(size: asyncResult._nativeRequestContext.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
asyncResult._nativeRequestContext.Reset(asyncResult._nativeRequestContext.RequestId, numBytes);
|
||||
// (uint)backingBuffer.Length - AlignmentPadding
|
||||
asyncResult.AllocateNativeRequest(numBytes, asyncResult._nativeRequestContext.RequestId);
|
||||
}
|
||||
|
||||
// We need to issue a new request, either because auth failed, or because our buffer was too small the first time.
|
||||
|
@ -147,7 +149,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
statusCode = HttpApi.HttpReceiveHttpRequest(
|
||||
Server.RequestQueue.Handle,
|
||||
_nativeRequestContext.RequestId,
|
||||
(uint)HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
|
||||
(uint)HttpApiTypes.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
|
||||
_nativeRequestContext.NativeRequest,
|
||||
_nativeRequestContext.Size,
|
||||
&bytesTransferred,
|
||||
|
@ -165,7 +167,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
// the buffer was not big enough to fit the headers, we need
|
||||
// to read the RequestId returned, allocate a new buffer of the required size
|
||||
_nativeRequestContext.Reset(_nativeRequestContext.RequestId, bytesTransferred);
|
||||
// (uint)backingBuffer.Length - AlignmentPadding
|
||||
AllocateNativeRequest(bytesTransferred);
|
||||
retry = true;
|
||||
}
|
||||
else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS
|
||||
|
@ -179,6 +182,36 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
return statusCode;
|
||||
}
|
||||
|
||||
internal void AllocateNativeRequest(uint? size = null, ulong requestId = 0)
|
||||
{
|
||||
//Debug.Assert(size != 0, "unexpected size");
|
||||
|
||||
// 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 nativeOverlapped = new SafeNativeOverlapped(boundHandle,
|
||||
boundHandle.AllocateNativeOverlapped(IOCallback, this, backingBuffer));
|
||||
|
||||
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
|
||||
_nativeRequestContext = new NativeRequestContext(nativeOverlapped, bufferAlignment, nativeRequest, backingBuffer, requestId);
|
||||
}
|
||||
|
||||
public object AsyncState
|
||||
{
|
||||
get { return _tcs.Task.AsyncState; }
|
||||
|
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
@ -21,7 +22,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public sealed class AuthenticationManager
|
||||
{
|
||||
private static readonly int AuthInfoSize =
|
||||
Marshal.SizeOf<HttpApi.HTTP_SERVER_AUTHENTICATION_INFO>();
|
||||
Marshal.SizeOf<HttpApiTypes.HTTP_SERVER_AUTHENTICATION_INFO>();
|
||||
|
||||
private UrlGroup _urlGroup;
|
||||
private AuthenticationSchemes _authSchemes;
|
||||
|
@ -62,12 +63,12 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
return;
|
||||
}
|
||||
|
||||
HttpApi.HTTP_SERVER_AUTHENTICATION_INFO authInfo =
|
||||
new HttpApi.HTTP_SERVER_AUTHENTICATION_INFO();
|
||||
HttpApiTypes.HTTP_SERVER_AUTHENTICATION_INFO authInfo =
|
||||
new HttpApiTypes.HTTP_SERVER_AUTHENTICATION_INFO();
|
||||
|
||||
authInfo.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
|
||||
var authSchemes = (HttpApi.HTTP_AUTH_TYPES)_authSchemes;
|
||||
if (authSchemes != HttpApi.HTTP_AUTH_TYPES.NONE)
|
||||
authInfo.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
|
||||
var authSchemes = (HttpApiTypes.HTTP_AUTH_TYPES)_authSchemes;
|
||||
if (authSchemes != HttpApiTypes.HTTP_AUTH_TYPES.NONE)
|
||||
{
|
||||
authInfo.AuthSchemes = authSchemes;
|
||||
|
||||
|
@ -81,7 +82,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
IntPtr infoptr = new IntPtr(&authInfo);
|
||||
|
||||
_urlGroup.SetProperty(
|
||||
HttpApi.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty,
|
||||
HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerAuthenticationProperty,
|
||||
infoptr, (uint)AuthInfoSize);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
@ -56,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
throw new PlatformNotSupportedException();
|
||||
}
|
||||
|
||||
Debug.Assert(HttpApi.ApiVersion == HttpApi.HTTP_API_VERSION.Version20, "Invalid Http api version");
|
||||
Debug.Assert(HttpApi.ApiVersion == HttpApiTypes.HTTP_API_VERSION.Version20, "Invalid Http api version");
|
||||
|
||||
Options = options;
|
||||
|
||||
|
@ -317,8 +318,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
private unsafe void SendError(ulong requestId, int httpStatusCode, IList<string> authChallenges)
|
||||
{
|
||||
HttpApi.HTTP_RESPONSE_V2 httpResponse = new HttpApi.HTTP_RESPONSE_V2();
|
||||
httpResponse.Response_V1.Version = new HttpApi.HTTP_VERSION();
|
||||
HttpApiTypes.HTTP_RESPONSE_V2 httpResponse = new HttpApiTypes.HTTP_RESPONSE_V2();
|
||||
httpResponse.Response_V1.Version = new HttpApiTypes.HTTP_VERSION();
|
||||
httpResponse.Response_V1.Version.MajorVersion = (ushort)1;
|
||||
httpResponse.Response_V1.Version.MinorVersion = (ushort)1;
|
||||
|
||||
|
@ -331,25 +332,25 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
pinnedHeaders = new List<GCHandle>();
|
||||
|
||||
HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null;
|
||||
knownHeaderInfo = new HttpApi.HTTP_RESPONSE_INFO[1];
|
||||
HttpApiTypes.HTTP_RESPONSE_INFO[] knownHeaderInfo = null;
|
||||
knownHeaderInfo = new HttpApiTypes.HTTP_RESPONSE_INFO[1];
|
||||
gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
httpResponse.pResponseInfo = (HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject();
|
||||
httpResponse.pResponseInfo = (HttpApiTypes.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject();
|
||||
|
||||
knownHeaderInfo[httpResponse.ResponseInfoCount].Type = HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders;
|
||||
knownHeaderInfo[httpResponse.ResponseInfoCount].Type = HttpApiTypes.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders;
|
||||
knownHeaderInfo[httpResponse.ResponseInfoCount].Length =
|
||||
(uint)Marshal.SizeOf<HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS>();
|
||||
(uint)Marshal.SizeOf<HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS>();
|
||||
|
||||
HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS();
|
||||
HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS();
|
||||
|
||||
header.HeaderId = HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderWwwAuthenticate;
|
||||
header.Flags = HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // The docs say this is for www-auth only.
|
||||
header.HeaderId = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderWwwAuthenticate;
|
||||
header.Flags = HttpApiTypes.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // The docs say this is for www-auth only.
|
||||
|
||||
HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApi.HTTP_KNOWN_HEADER[authChallenges.Count];
|
||||
HttpApiTypes.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApiTypes.HTTP_KNOWN_HEADER[authChallenges.Count];
|
||||
gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
header.KnownHeaders = (HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject();
|
||||
header.KnownHeaders = (HttpApiTypes.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject();
|
||||
|
||||
for (int headerValueIndex = 0; headerValueIndex < authChallenges.Count; headerValueIndex++)
|
||||
{
|
||||
|
@ -359,14 +360,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length;
|
||||
gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
nativeHeaderValues[header.KnownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject();
|
||||
nativeHeaderValues[header.KnownHeaderCount].pRawValue = (byte*)gcHandle.AddrOfPinnedObject();
|
||||
header.KnownHeaderCount++;
|
||||
}
|
||||
|
||||
// This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set.
|
||||
gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
knownHeaderInfo[0].pInfo = (HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject();
|
||||
knownHeaderInfo[0].pInfo = (HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject();
|
||||
|
||||
httpResponse.ResponseInfoCount = 1;
|
||||
}
|
||||
|
@ -378,13 +379,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
byte[] byteReason = HeaderEncoding.GetBytes(statusDescription);
|
||||
fixed (byte* pReason = byteReason)
|
||||
{
|
||||
httpResponse.Response_V1.pReason = (sbyte*)pReason;
|
||||
httpResponse.Response_V1.pReason = (byte*)pReason;
|
||||
httpResponse.Response_V1.ReasonLength = (ushort)byteReason.Length;
|
||||
|
||||
byte[] byteContentLength = new byte[] { (byte)'0' };
|
||||
fixed (byte* pContentLength = byteContentLength)
|
||||
{
|
||||
(&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (sbyte*)pContentLength;
|
||||
(&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].pRawValue = (byte*)pContentLength;
|
||||
(&httpResponse.Response_V1.Headers.KnownHeaders)[(int)HttpSysResponseHeader.ContentLength].RawValueLength = (ushort)byteContentLength.Length;
|
||||
httpResponse.Response_V1.Headers.UnknownHeaderCount = 0;
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Hosting.Server.Features;
|
|||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
<PackageTags>aspnetcore;weblistener;httpsys</PackageTags>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Include="..\..\shared\Microsoft.AspNetCore.HttpSys.Sources\**\*.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Core" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Hosting" />
|
||||
|
|
|
@ -1,168 +0,0 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
/// <devdoc>
|
||||
/// <para>
|
||||
/// Specifies the address families.
|
||||
/// </para>
|
||||
/// </devdoc>
|
||||
internal enum AddressFamily
|
||||
{
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Unknown = -1, // Unknown
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Unspecified = 0, // unspecified
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Unix = 1, // local to host (pipes, portals)
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
InterNetwork = 2, // internetwork: UDP, TCP, etc.
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
ImpLink = 3, // arpanet imp addresses
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Pup = 4, // pup protocols: e.g. BSP
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Chaos = 5, // mit CHAOS protocols
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
NS = 6, // XEROX NS protocols
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Ipx = NS, // IPX and SPX
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Iso = 7, // ISO protocols
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Osi = Iso, // OSI is ISO
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Ecma = 8, // european computer manufacturers
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
DataKit = 9, // datakit protocols
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Ccitt = 10, // CCITT protocols, X.25 etc
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Sna = 11, // IBM SNA
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
DecNet = 12, // DECnet
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
DataLink = 13, // Direct data link interface
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Lat = 14, // LAT
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
HyperChannel = 15, // NSC Hyperchannel
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
AppleTalk = 16, // AppleTalk
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
NetBios = 17, // NetBios-style addresses
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
VoiceView = 18, // VoiceView
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
FireFox = 19, // FireFox
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Banyan = 21, // Banyan
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Atm = 22, // Native ATM Services
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
InterNetworkV6 = 23, // Internetwork Version 6
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Cluster = 24, // Microsoft Wolfpack
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Ieee12844 = 25, // IEEE 1284.4 WG AF
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Irda = 26, // IrDA
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
NetworkDesigners = 28, // Network Designers OSI & gateway enabled protocols
|
||||
|
||||
/// <devdoc>
|
||||
/// <para>[To be supplied.]</para>
|
||||
/// </devdoc>
|
||||
Max = 29, // Max
|
||||
}; // enum AddressFamily
|
||||
}
|
|
@ -6,6 +6,7 @@ using System.Collections.Concurrent;
|
|||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using static Microsoft.AspNetCore.HttpSys.Internal.HttpApiTypes;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
@ -70,688 +70,6 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
||||
internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle);
|
||||
|
||||
internal enum HTTP_API_VERSION
|
||||
{
|
||||
Invalid,
|
||||
Version10,
|
||||
Version20,
|
||||
}
|
||||
|
||||
// see http.w for definitions
|
||||
internal enum HTTP_SERVER_PROPERTY
|
||||
{
|
||||
HttpServerAuthenticationProperty,
|
||||
HttpServerLoggingProperty,
|
||||
HttpServerQosProperty,
|
||||
HttpServerTimeoutsProperty,
|
||||
HttpServerQueueLengthProperty,
|
||||
HttpServerStateProperty,
|
||||
HttpServer503VerbosityProperty,
|
||||
HttpServerBindingProperty,
|
||||
HttpServerExtendedAuthenticationProperty,
|
||||
HttpServerListenEndpointProperty,
|
||||
HttpServerChannelBindProperty,
|
||||
HttpServerProtectionLevelProperty,
|
||||
}
|
||||
|
||||
// Currently only one request info type is supported but the enum is for future extensibility.
|
||||
|
||||
internal enum HTTP_REQUEST_INFO_TYPE
|
||||
{
|
||||
HttpRequestInfoTypeAuth,
|
||||
HttpRequestInfoTypeChannelBind,
|
||||
HttpRequestInfoTypeSslProtocol,
|
||||
HttpRequestInfoTypeSslTokenBinding
|
||||
}
|
||||
|
||||
internal enum HTTP_RESPONSE_INFO_TYPE
|
||||
{
|
||||
HttpResponseInfoTypeMultipleKnownHeaders,
|
||||
HttpResponseInfoTypeAuthenticationProperty,
|
||||
HttpResponseInfoTypeQosProperty,
|
||||
}
|
||||
|
||||
internal enum HTTP_TIMEOUT_TYPE
|
||||
{
|
||||
EntityBody,
|
||||
DrainEntityBody,
|
||||
RequestQueue,
|
||||
IdleConnection,
|
||||
HeaderWait,
|
||||
MinSendRate,
|
||||
}
|
||||
|
||||
internal const int MaxTimeout = 6;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_VERSION
|
||||
{
|
||||
internal ushort MajorVersion;
|
||||
internal ushort MinorVersion;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_KNOWN_HEADER
|
||||
{
|
||||
internal ushort RawValueLength;
|
||||
internal sbyte* pRawValue;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
internal struct HTTP_DATA_CHUNK
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
internal HTTP_DATA_CHUNK_TYPE DataChunkType;
|
||||
|
||||
[FieldOffset(8)]
|
||||
internal FromMemory fromMemory;
|
||||
|
||||
[FieldOffset(8)]
|
||||
internal FromFileHandle fromFile;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct FromMemory
|
||||
{
|
||||
// 4 bytes for 32bit, 8 bytes for 64bit
|
||||
internal IntPtr pBuffer;
|
||||
internal uint BufferLength;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct FromFileHandle
|
||||
{
|
||||
internal ulong offset;
|
||||
internal ulong count;
|
||||
internal IntPtr fileHandle;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTPAPI_VERSION
|
||||
{
|
||||
internal ushort HttpApiMajorVersion;
|
||||
internal ushort HttpApiMinorVersion;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_COOKED_URL
|
||||
{
|
||||
internal ushort FullUrlLength;
|
||||
internal ushort HostLength;
|
||||
internal ushort AbsPathLength;
|
||||
internal ushort QueryStringLength;
|
||||
internal ushort* pFullUrl;
|
||||
internal ushort* pHost;
|
||||
internal ushort* pAbsPath;
|
||||
internal ushort* pQueryString;
|
||||
}
|
||||
|
||||
// Only cache unauthorized GETs + HEADs.
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_CACHE_POLICY
|
||||
{
|
||||
internal HTTP_CACHE_POLICY_TYPE Policy;
|
||||
internal uint SecondsToLive;
|
||||
}
|
||||
|
||||
internal enum HTTP_CACHE_POLICY_TYPE : int
|
||||
{
|
||||
HttpCachePolicyNocache = 0,
|
||||
HttpCachePolicyUserInvalidates = 1,
|
||||
HttpCachePolicyTimeToLive = 2,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct SOCKADDR
|
||||
{
|
||||
internal ushort sa_family;
|
||||
internal byte sa_data;
|
||||
internal byte sa_data_02;
|
||||
internal byte sa_data_03;
|
||||
internal byte sa_data_04;
|
||||
internal byte sa_data_05;
|
||||
internal byte sa_data_06;
|
||||
internal byte sa_data_07;
|
||||
internal byte sa_data_08;
|
||||
internal byte sa_data_09;
|
||||
internal byte sa_data_10;
|
||||
internal byte sa_data_11;
|
||||
internal byte sa_data_12;
|
||||
internal byte sa_data_13;
|
||||
internal byte sa_data_14;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_TRANSPORT_ADDRESS
|
||||
{
|
||||
internal SOCKADDR* pRemoteAddress;
|
||||
internal SOCKADDR* pLocalAddress;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SSL_CLIENT_CERT_INFO
|
||||
{
|
||||
internal uint CertFlags;
|
||||
internal uint CertEncodedSize;
|
||||
internal byte* pCertEncoded;
|
||||
internal void* Token;
|
||||
internal byte CertDeniedByMapper;
|
||||
}
|
||||
|
||||
internal enum HTTP_SERVICE_BINDING_TYPE : uint
|
||||
{
|
||||
HttpServiceBindingTypeNone = 0,
|
||||
HttpServiceBindingTypeW,
|
||||
HttpServiceBindingTypeA
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SERVICE_BINDING_BASE
|
||||
{
|
||||
internal HTTP_SERVICE_BINDING_TYPE Type;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_CHANNEL_BIND_STATUS
|
||||
{
|
||||
internal IntPtr ServiceName;
|
||||
internal IntPtr ChannelToken;
|
||||
internal uint ChannelTokenSize;
|
||||
internal uint Flags;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_UNKNOWN_HEADER
|
||||
{
|
||||
internal ushort NameLength;
|
||||
internal ushort RawValueLength;
|
||||
internal sbyte* pName;
|
||||
internal sbyte* pRawValue;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SSL_INFO
|
||||
{
|
||||
internal ushort ServerCertKeySize;
|
||||
internal ushort ConnectionKeySize;
|
||||
internal uint ServerCertIssuerSize;
|
||||
internal uint ServerCertSubjectSize;
|
||||
internal sbyte* pServerCertIssuer;
|
||||
internal sbyte* pServerCertSubject;
|
||||
internal HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo;
|
||||
internal uint SslClientCertNegotiated;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_RESPONSE_HEADERS
|
||||
{
|
||||
internal ushort UnknownHeaderCount;
|
||||
internal HTTP_UNKNOWN_HEADER* pUnknownHeaders;
|
||||
internal ushort TrailerCount;
|
||||
internal HTTP_UNKNOWN_HEADER* pTrailers;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_02;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_03;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_04;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_05;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_06;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_07;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_08;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_09;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_10;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_11;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_12;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_13;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_14;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_15;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_16;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_17;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_18;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_19;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_20;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_21;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_22;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_23;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_24;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_25;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_26;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_27;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_28;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_29;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_30;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_HEADERS
|
||||
{
|
||||
internal ushort UnknownHeaderCount;
|
||||
internal HTTP_UNKNOWN_HEADER* pUnknownHeaders;
|
||||
internal ushort TrailerCount;
|
||||
internal HTTP_UNKNOWN_HEADER* pTrailers;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_02;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_03;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_04;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_05;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_06;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_07;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_08;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_09;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_10;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_11;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_12;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_13;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_14;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_15;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_16;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_17;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_18;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_19;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_20;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_21;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_22;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_23;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_24;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_25;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_26;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_27;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_28;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_29;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_30;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_31;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_32;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_33;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_34;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_35;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_36;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_37;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_38;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_39;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_40;
|
||||
internal HTTP_KNOWN_HEADER KnownHeaders_41;
|
||||
}
|
||||
|
||||
internal enum HTTP_VERB : int
|
||||
{
|
||||
HttpVerbUnparsed = 0,
|
||||
HttpVerbUnknown = 1,
|
||||
HttpVerbInvalid = 2,
|
||||
HttpVerbOPTIONS = 3,
|
||||
HttpVerbGET = 4,
|
||||
HttpVerbHEAD = 5,
|
||||
HttpVerbPOST = 6,
|
||||
HttpVerbPUT = 7,
|
||||
HttpVerbDELETE = 8,
|
||||
HttpVerbTRACE = 9,
|
||||
HttpVerbCONNECT = 10,
|
||||
HttpVerbTRACK = 11,
|
||||
HttpVerbMOVE = 12,
|
||||
HttpVerbCOPY = 13,
|
||||
HttpVerbPROPFIND = 14,
|
||||
HttpVerbPROPPATCH = 15,
|
||||
HttpVerbMKCOL = 16,
|
||||
HttpVerbLOCK = 17,
|
||||
HttpVerbUNLOCK = 18,
|
||||
HttpVerbSEARCH = 19,
|
||||
HttpVerbMaximum = 20,
|
||||
}
|
||||
|
||||
internal static readonly string[] HttpVerbs = new string[]
|
||||
{
|
||||
null,
|
||||
"Unknown",
|
||||
"Invalid",
|
||||
"OPTIONS",
|
||||
"GET",
|
||||
"HEAD",
|
||||
"POST",
|
||||
"PUT",
|
||||
"DELETE",
|
||||
"TRACE",
|
||||
"CONNECT",
|
||||
"TRACK",
|
||||
"MOVE",
|
||||
"COPY",
|
||||
"PROPFIND",
|
||||
"PROPPATCH",
|
||||
"MKCOL",
|
||||
"LOCK",
|
||||
"UNLOCK",
|
||||
"SEARCH",
|
||||
};
|
||||
|
||||
internal enum HTTP_DATA_CHUNK_TYPE : int
|
||||
{
|
||||
HttpDataChunkFromMemory = 0,
|
||||
HttpDataChunkFromFileHandle = 1,
|
||||
HttpDataChunkFromFragmentCache = 2,
|
||||
HttpDataChunkMaximum = 3,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_RESPONSE_INFO
|
||||
{
|
||||
internal HTTP_RESPONSE_INFO_TYPE Type;
|
||||
internal uint Length;
|
||||
internal HTTP_MULTIPLE_KNOWN_HEADERS* pInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_RESPONSE
|
||||
{
|
||||
internal uint Flags;
|
||||
internal HTTP_VERSION Version;
|
||||
internal ushort StatusCode;
|
||||
internal ushort ReasonLength;
|
||||
internal sbyte* pReason;
|
||||
internal HTTP_RESPONSE_HEADERS Headers;
|
||||
internal ushort EntityChunkCount;
|
||||
internal HTTP_DATA_CHUNK* pEntityChunks;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_RESPONSE_V2
|
||||
{
|
||||
internal HTTP_RESPONSE Response_V1;
|
||||
internal ushort ResponseInfoCount;
|
||||
internal HTTP_RESPONSE_INFO* pResponseInfo;
|
||||
}
|
||||
|
||||
internal enum HTTP_RESPONSE_INFO_FLAGS : uint
|
||||
{
|
||||
None = 0,
|
||||
PreserveOrder = 1,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_MULTIPLE_KNOWN_HEADERS
|
||||
{
|
||||
internal HTTP_RESPONSE_HEADER_ID.Enum HeaderId;
|
||||
internal HTTP_RESPONSE_INFO_FLAGS Flags;
|
||||
internal ushort KnownHeaderCount;
|
||||
internal HTTP_KNOWN_HEADER* KnownHeaders;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_AUTH_INFO
|
||||
{
|
||||
internal HTTP_AUTH_STATUS AuthStatus;
|
||||
internal uint SecStatus;
|
||||
internal uint Flags;
|
||||
internal HTTP_REQUEST_AUTH_TYPE AuthType;
|
||||
internal IntPtr AccessToken;
|
||||
internal uint ContextAttributes;
|
||||
internal uint PackedContextLength;
|
||||
internal uint PackedContextType;
|
||||
internal IntPtr PackedContext;
|
||||
internal uint MutualAuthDataLength;
|
||||
internal char* pMutualAuthData;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_INFO
|
||||
{
|
||||
internal HTTP_REQUEST_INFO_TYPE InfoType;
|
||||
internal uint InfoLength;
|
||||
internal HTTP_REQUEST_AUTH_INFO* pInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST
|
||||
{
|
||||
internal uint Flags;
|
||||
internal ulong ConnectionId;
|
||||
internal ulong RequestId;
|
||||
internal ulong UrlContext;
|
||||
internal HTTP_VERSION Version;
|
||||
internal HTTP_VERB Verb;
|
||||
internal ushort UnknownVerbLength;
|
||||
internal ushort RawUrlLength;
|
||||
internal sbyte* pUnknownVerb;
|
||||
internal sbyte* pRawUrl;
|
||||
internal HTTP_COOKED_URL CookedUrl;
|
||||
internal HTTP_TRANSPORT_ADDRESS Address;
|
||||
internal HTTP_REQUEST_HEADERS Headers;
|
||||
internal ulong BytesReceived;
|
||||
internal ushort EntityChunkCount;
|
||||
internal HTTP_DATA_CHUNK* pEntityChunks;
|
||||
internal ulong RawConnectionId;
|
||||
internal HTTP_SSL_INFO* pSslInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_V2
|
||||
{
|
||||
internal HTTP_REQUEST Request;
|
||||
internal ushort RequestInfoCount;
|
||||
internal HTTP_REQUEST_INFO* pRequestInfo;
|
||||
}
|
||||
|
||||
internal enum HTTP_AUTH_STATUS
|
||||
{
|
||||
HttpAuthStatusSuccess,
|
||||
HttpAuthStatusNotAuthenticated,
|
||||
HttpAuthStatusFailure,
|
||||
}
|
||||
|
||||
internal enum HTTP_REQUEST_AUTH_TYPE
|
||||
{
|
||||
HttpRequestAuthTypeNone = 0,
|
||||
HttpRequestAuthTypeBasic,
|
||||
HttpRequestAuthTypeDigest,
|
||||
HttpRequestAuthTypeNTLM,
|
||||
HttpRequestAuthTypeNegotiate,
|
||||
HttpRequestAuthTypeKerberos
|
||||
}
|
||||
|
||||
internal enum HTTP_QOS_SETTING_TYPE
|
||||
{
|
||||
HttpQosSettingTypeBandwidth,
|
||||
HttpQosSettingTypeConnectionLimit,
|
||||
HttpQosSettingTypeFlowRate
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SERVER_AUTHENTICATION_INFO
|
||||
{
|
||||
internal HTTP_FLAGS Flags;
|
||||
internal HTTP_AUTH_TYPES AuthSchemes;
|
||||
internal bool ReceiveMutualAuth;
|
||||
internal bool ReceiveContextHandle;
|
||||
internal bool DisableNTLMCredentialCaching;
|
||||
internal ulong ExFlags;
|
||||
HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS DigestParams;
|
||||
HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS BasicParams;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SERVER_AUTHENTICATION_DIGEST_PARAMS
|
||||
{
|
||||
internal ushort DomainNameLength;
|
||||
internal char* DomainName;
|
||||
internal ushort RealmLength;
|
||||
internal char* Realm;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_SERVER_AUTHENTICATION_BASIC_PARAMS
|
||||
{
|
||||
ushort RealmLength;
|
||||
char* Realm;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_REQUEST_TOKEN_BINDING_INFO
|
||||
{
|
||||
public byte* TokenBinding;
|
||||
public uint TokenBindingSize;
|
||||
|
||||
public byte* TlsUnique;
|
||||
public uint TlsUniqueSize;
|
||||
|
||||
public char* KeyType;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_TIMEOUT_LIMIT_INFO
|
||||
{
|
||||
internal HTTP_FLAGS Flags;
|
||||
internal ushort EntityBody;
|
||||
internal ushort DrainEntityBody;
|
||||
internal ushort RequestQueue;
|
||||
internal ushort IdleConnection;
|
||||
internal ushort HeaderWait;
|
||||
internal uint MinSendRate;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_BINDING_INFO
|
||||
{
|
||||
internal HTTP_FLAGS Flags;
|
||||
internal IntPtr RequestQueueHandle;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_CONNECTION_LIMIT_INFO
|
||||
{
|
||||
internal HTTP_FLAGS Flags;
|
||||
internal uint MaxConnections;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct HTTP_QOS_SETTING_INFO
|
||||
{
|
||||
internal HTTP_QOS_SETTING_TYPE QosType;
|
||||
internal IntPtr QosSetting;
|
||||
}
|
||||
|
||||
// see http.w for definitions
|
||||
[Flags]
|
||||
internal enum HTTP_FLAGS : uint
|
||||
{
|
||||
NONE = 0x00000000,
|
||||
HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY = 0x00000001,
|
||||
HTTP_RECEIVE_SECURE_CHANNEL_TOKEN = 0x00000001,
|
||||
HTTP_SEND_RESPONSE_FLAG_DISCONNECT = 0x00000001,
|
||||
HTTP_SEND_RESPONSE_FLAG_MORE_DATA = 0x00000002,
|
||||
HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA = 0x00000004,
|
||||
HTTP_SEND_RESPONSE_FLAG_RAW_HEADER = 0x00000004,
|
||||
HTTP_SEND_REQUEST_FLAG_MORE_DATA = 0x00000001,
|
||||
HTTP_PROPERTY_FLAG_PRESENT = 0x00000001,
|
||||
HTTP_INITIALIZE_SERVER = 0x00000001,
|
||||
HTTP_INITIALIZE_CBT = 0x00000004,
|
||||
HTTP_SEND_RESPONSE_FLAG_OPAQUE = 0x00000040,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
internal enum HTTP_AUTH_TYPES : uint
|
||||
{
|
||||
NONE = 0x00000000,
|
||||
HTTP_AUTH_ENABLE_BASIC = 0x00000001,
|
||||
HTTP_AUTH_ENABLE_DIGEST = 0x00000002,
|
||||
HTTP_AUTH_ENABLE_NTLM = 0x00000004,
|
||||
HTTP_AUTH_ENABLE_NEGOTIATE = 0x00000008,
|
||||
HTTP_AUTH_ENABLE_KERBEROS = 0x00000010,
|
||||
}
|
||||
|
||||
internal static class HTTP_RESPONSE_HEADER_ID
|
||||
{
|
||||
private static string[] _strings =
|
||||
{
|
||||
"Cache-Control",
|
||||
"Connection",
|
||||
"Date",
|
||||
"Keep-Alive",
|
||||
"Pragma",
|
||||
"Trailer",
|
||||
"Transfer-Encoding",
|
||||
"Upgrade",
|
||||
"Via",
|
||||
"Warning",
|
||||
|
||||
"Allow",
|
||||
"Content-Length",
|
||||
"Content-Type",
|
||||
"Content-Encoding",
|
||||
"Content-Language",
|
||||
"Content-Location",
|
||||
"Content-MD5",
|
||||
"Content-Range",
|
||||
"Expires",
|
||||
"Last-Modified",
|
||||
|
||||
"Accept-Ranges",
|
||||
"Age",
|
||||
"ETag",
|
||||
"Location",
|
||||
"Proxy-Authenticate",
|
||||
"Retry-After",
|
||||
"Server",
|
||||
"Set-Cookie",
|
||||
"Vary",
|
||||
"WWW-Authenticate",
|
||||
};
|
||||
|
||||
private static Dictionary<string, int> _lookupTable = CreateLookupTable();
|
||||
|
||||
private static Dictionary<string, int> CreateLookupTable()
|
||||
{
|
||||
Dictionary<string, int> lookupTable = new Dictionary<string, int>((int)Enum.HttpHeaderResponseMaximum, StringComparer.OrdinalIgnoreCase);
|
||||
for (int i = 0; i < (int)Enum.HttpHeaderResponseMaximum; i++)
|
||||
{
|
||||
lookupTable.Add(_strings[i], i);
|
||||
}
|
||||
return lookupTable;
|
||||
}
|
||||
|
||||
internal static int IndexOfKnownHeader(string HeaderName)
|
||||
{
|
||||
int index;
|
||||
return _lookupTable.TryGetValue(HeaderName, out index) ? index : -1;
|
||||
}
|
||||
|
||||
internal enum Enum
|
||||
{
|
||||
HttpHeaderCacheControl = 0, // general-header [section 4.5]
|
||||
HttpHeaderConnection = 1, // general-header [section 4.5]
|
||||
HttpHeaderDate = 2, // general-header [section 4.5]
|
||||
HttpHeaderKeepAlive = 3, // general-header [not in rfc]
|
||||
HttpHeaderPragma = 4, // general-header [section 4.5]
|
||||
HttpHeaderTrailer = 5, // general-header [section 4.5]
|
||||
HttpHeaderTransferEncoding = 6, // general-header [section 4.5]
|
||||
HttpHeaderUpgrade = 7, // general-header [section 4.5]
|
||||
HttpHeaderVia = 8, // general-header [section 4.5]
|
||||
HttpHeaderWarning = 9, // general-header [section 4.5]
|
||||
|
||||
HttpHeaderAllow = 10, // entity-header [section 7.1]
|
||||
HttpHeaderContentLength = 11, // entity-header [section 7.1]
|
||||
HttpHeaderContentType = 12, // entity-header [section 7.1]
|
||||
HttpHeaderContentEncoding = 13, // entity-header [section 7.1]
|
||||
HttpHeaderContentLanguage = 14, // entity-header [section 7.1]
|
||||
HttpHeaderContentLocation = 15, // entity-header [section 7.1]
|
||||
HttpHeaderContentMd5 = 16, // entity-header [section 7.1]
|
||||
HttpHeaderContentRange = 17, // entity-header [section 7.1]
|
||||
HttpHeaderExpires = 18, // entity-header [section 7.1]
|
||||
HttpHeaderLastModified = 19, // entity-header [section 7.1]
|
||||
|
||||
// Response Headers
|
||||
|
||||
HttpHeaderAcceptRanges = 20, // response-header [section 6.2]
|
||||
HttpHeaderAge = 21, // response-header [section 6.2]
|
||||
HttpHeaderEtag = 22, // response-header [section 6.2]
|
||||
HttpHeaderLocation = 23, // response-header [section 6.2]
|
||||
HttpHeaderProxyAuthenticate = 24, // response-header [section 6.2]
|
||||
HttpHeaderRetryAfter = 25, // response-header [section 6.2]
|
||||
HttpHeaderServer = 26, // response-header [section 6.2]
|
||||
HttpHeaderSetCookie = 27, // response-header [not in rfc]
|
||||
HttpHeaderVary = 28, // response-header [section 6.2]
|
||||
HttpHeaderWwwAuthenticate = 29, // response-header [section 6.2]
|
||||
|
||||
HttpHeaderResponseMaximum = 30,
|
||||
|
||||
HttpHeaderMaximum = 41
|
||||
}
|
||||
}
|
||||
|
||||
private static HTTPAPI_VERSION version;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// 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.
|
||||
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
@ -17,7 +18,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
serverSessionId = id;
|
||||
|
||||
// This class uses no real handle so we need to set a dummy handle. Otherwise, IsInvalid always remains
|
||||
// This class uses no real handle so we need to set a dummy handle. Otherwise, IsInvalid always remains
|
||||
// true.
|
||||
|
||||
SetHandle(new IntPtr(1));
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
@ -11,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
internal class RequestQueue
|
||||
{
|
||||
private static readonly int BindingInfoSize =
|
||||
Marshal.SizeOf<HttpApi.HTTP_BINDING_INFO>();
|
||||
Marshal.SizeOf<HttpApiTypes.HTTP_BINDING_INFO>();
|
||||
|
||||
private readonly UrlGroup _urlGroup;
|
||||
private readonly ILogger _logger;
|
||||
|
@ -54,13 +55,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
// 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;
|
||||
var info = new HttpApiTypes.HTTP_BINDING_INFO();
|
||||
info.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
|
||||
info.RequestQueueHandle = Handle.DangerousGetHandle();
|
||||
|
||||
var infoptr = new IntPtr(&info);
|
||||
|
||||
_urlGroup.SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty,
|
||||
_urlGroup.SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerBindingProperty,
|
||||
infoptr, (uint)BindingInfoSize);
|
||||
}
|
||||
|
||||
|
@ -73,13 +74,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
// 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;
|
||||
var info = new HttpApiTypes.HTTP_BINDING_INFO();
|
||||
info.Flags = HttpApiTypes.HTTP_FLAGS.NONE;
|
||||
info.RequestQueueHandle = IntPtr.Zero;
|
||||
|
||||
var infoptr = new IntPtr(&info);
|
||||
|
||||
_urlGroup.SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerBindingProperty,
|
||||
_urlGroup.SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerBindingProperty,
|
||||
infoptr, (uint)BindingInfoSize, throwOnError: false);
|
||||
}
|
||||
|
||||
|
@ -89,7 +90,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
CheckDisposed();
|
||||
|
||||
var result = HttpApi.HttpSetRequestQueueProperty(Handle,
|
||||
HttpApi.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty,
|
||||
HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerQueueLengthProperty,
|
||||
new IntPtr((void*)&length), (uint)Marshal.SizeOf<long>(), 0, IntPtr.Zero);
|
||||
|
||||
if (result != 0)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
|
|
@ -3,8 +3,9 @@
|
|||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Microsoft.AspNetCore.Server.HttpSys.HttpApi;
|
||||
using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods.TokenBinding;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using static Microsoft.AspNetCore.HttpSys.Internal.HttpApiTypes;
|
||||
using static Microsoft.AspNetCore.HttpSys.Internal.UnsafeNclNativeMethods.TokenBinding;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
@ -11,7 +12,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
internal class UrlGroup : IDisposable
|
||||
{
|
||||
private static readonly int QosInfoSize =
|
||||
Marshal.SizeOf<HttpApi.HTTP_QOS_SETTING_INFO>();
|
||||
Marshal.SizeOf<HttpApiTypes.HTTP_QOS_SETTING_INFO>();
|
||||
|
||||
private ServerSession _serverSession;
|
||||
private ILogger _logger;
|
||||
|
@ -39,18 +40,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
internal unsafe void SetMaxConnections(long maxConnections)
|
||||
{
|
||||
var connectionLimit = new HttpApi.HTTP_CONNECTION_LIMIT_INFO();
|
||||
connectionLimit.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
|
||||
var connectionLimit = new HttpApiTypes.HTTP_CONNECTION_LIMIT_INFO();
|
||||
connectionLimit.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
|
||||
connectionLimit.MaxConnections = (uint)maxConnections;
|
||||
|
||||
var qosSettings = new HttpApi.HTTP_QOS_SETTING_INFO();
|
||||
qosSettings.QosType = HttpApi.HTTP_QOS_SETTING_TYPE.HttpQosSettingTypeConnectionLimit;
|
||||
var qosSettings = new HttpApiTypes.HTTP_QOS_SETTING_INFO();
|
||||
qosSettings.QosType = HttpApiTypes.HTTP_QOS_SETTING_TYPE.HttpQosSettingTypeConnectionLimit;
|
||||
qosSettings.QosSetting = new IntPtr(&connectionLimit);
|
||||
|
||||
SetProperty(HttpApi.HTTP_SERVER_PROPERTY.HttpServerQosProperty, new IntPtr(&qosSettings), (uint)QosInfoSize);
|
||||
SetProperty(HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerQosProperty, new IntPtr(&qosSettings), (uint)QosInfoSize);
|
||||
}
|
||||
|
||||
internal void SetProperty(HttpApi.HTTP_SERVER_PROPERTY property, IntPtr info, uint infosize, bool throwOnError = true)
|
||||
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");
|
||||
CheckDisposed();
|
||||
|
|
|
@ -12,6 +12,7 @@ using System.Security.Cryptography;
|
|||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
@ -23,11 +24,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private const uint CertBoblSize = 1500;
|
||||
private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(WaitCallback);
|
||||
private static readonly int RequestChannelBindStatusSize =
|
||||
Marshal.SizeOf<HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS>();
|
||||
Marshal.SizeOf<HttpApiTypes.HTTP_REQUEST_CHANNEL_BIND_STATUS>();
|
||||
|
||||
private SafeNativeOverlapped _overlapped;
|
||||
private byte[] _backingBuffer;
|
||||
private HttpApi.HTTP_SSL_CLIENT_CERT_INFO* _memoryBlob;
|
||||
private HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* _memoryBlob;
|
||||
private uint _size;
|
||||
private TaskCompletionSource<object> _tcs;
|
||||
private RequestContext _requestContext;
|
||||
|
@ -104,7 +105,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
}
|
||||
|
||||
private HttpApi.HTTP_SSL_CLIENT_CERT_INFO* RequestBlob
|
||||
private HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* RequestBlob
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -134,7 +135,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
var boundHandle = RequestContext.Server.RequestQueue.BoundHandle;
|
||||
_overlapped = new SafeNativeOverlapped(boundHandle,
|
||||
boundHandle.AllocateNativeOverlapped(IOCallback, this, _backingBuffer));
|
||||
_memoryBlob = (HttpApi.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0);
|
||||
_memoryBlob = (HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO*)Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0);
|
||||
}
|
||||
|
||||
// When you use netsh to configure HTTP.SYS with clientcertnegotiation = enable
|
||||
|
@ -168,7 +169,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
HttpApi.HttpReceiveClientCertificate(
|
||||
RequestQueueHandle,
|
||||
RequestContext.Request.UConnectionId,
|
||||
(uint)HttpApi.HTTP_FLAGS.NONE,
|
||||
(uint)HttpApiTypes.HTTP_FLAGS.NONE,
|
||||
RequestBlob,
|
||||
size,
|
||||
&bytesReceived,
|
||||
|
@ -176,7 +177,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA)
|
||||
{
|
||||
HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = RequestBlob;
|
||||
HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = RequestBlob;
|
||||
size = bytesReceived + pClientCertInfo->CertEncodedSize;
|
||||
Reset(size);
|
||||
retry = true;
|
||||
|
@ -239,7 +240,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
// return the size of the initial cert structure. To get the full size,
|
||||
// we need to add the certificate encoding size as well.
|
||||
|
||||
HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob;
|
||||
HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult.RequestBlob;
|
||||
asyncResult.Reset(numBytes + pClientCertInfo->CertEncodedSize);
|
||||
|
||||
uint bytesReceived = 0;
|
||||
|
@ -247,7 +248,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
HttpApi.HttpReceiveClientCertificate(
|
||||
requestContext.Server.RequestQueue.Handle,
|
||||
requestContext.Request.UConnectionId,
|
||||
(uint)HttpApi.HTTP_FLAGS.NONE,
|
||||
(uint)HttpApiTypes.HTTP_FLAGS.NONE,
|
||||
asyncResult._memoryBlob,
|
||||
asyncResult._size,
|
||||
&bytesReceived,
|
||||
|
@ -271,7 +272,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
else
|
||||
{
|
||||
HttpApi.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult._memoryBlob;
|
||||
HttpApiTypes.HTTP_SSL_CLIENT_CERT_INFO* pClientCertInfo = asyncResult._memoryBlob;
|
||||
if (pClientCertInfo == null)
|
||||
{
|
||||
asyncResult.Complete(0, null);
|
||||
|
@ -374,7 +375,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
statusCode = HttpApi.HttpReceiveClientCertificate(
|
||||
requestQueue.Handle,
|
||||
connectionId,
|
||||
(uint)HttpApi.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN,
|
||||
(uint)HttpApiTypes.HTTP_FLAGS.HTTP_RECEIVE_SECURE_CHANNEL_TOKEN,
|
||||
blobPtr,
|
||||
(uint)size,
|
||||
&bytesReceived,
|
||||
|
@ -418,7 +419,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private static int GetTokenOffsetFromBlob(IntPtr blob)
|
||||
{
|
||||
Debug.Assert(blob != IntPtr.Zero);
|
||||
IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf<HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS>("ChannelToken"));
|
||||
IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf<HttpApiTypes.HTTP_REQUEST_CHANNEL_BIND_STATUS>("ChannelToken"));
|
||||
Debug.Assert(tokenPointer != IntPtr.Zero);
|
||||
return (int)IntPtrHelper.Subtract(tokenPointer, blob);
|
||||
}
|
||||
|
@ -426,7 +427,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private static int GetTokenSizeFromBlob(IntPtr blob)
|
||||
{
|
||||
Debug.Assert(blob != IntPtr.Zero);
|
||||
return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf<HttpApi.HTTP_REQUEST_CHANNEL_BIND_STATUS>("ChannelTokenSize"));
|
||||
return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf<HttpApiTypes.HTTP_REQUEST_CHANNEL_BIND_STATUS>("ChannelTokenSize"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,434 +0,0 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Principal;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
internal unsafe class NativeRequestContext : IDisposable
|
||||
{
|
||||
private const int DefaultBufferSize = 4096;
|
||||
private const int AlignmentPadding = 8;
|
||||
private HttpApi.HTTP_REQUEST* _nativeRequest;
|
||||
private IntPtr _originalBufferAddress;
|
||||
private byte[] _backingBuffer;
|
||||
private int _bufferAlignment;
|
||||
private SafeNativeOverlapped _nativeOverlapped;
|
||||
private AsyncAcceptContext _acceptResult;
|
||||
|
||||
internal NativeRequestContext(AsyncAcceptContext result)
|
||||
{
|
||||
_acceptResult = result;
|
||||
AllocateNativeRequest();
|
||||
}
|
||||
|
||||
internal SafeNativeOverlapped NativeOverlapped => _nativeOverlapped;
|
||||
|
||||
internal HttpApi.HTTP_REQUEST* NativeRequest
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins().");
|
||||
return _nativeRequest;
|
||||
}
|
||||
}
|
||||
|
||||
private HttpApi.HTTP_REQUEST_V2* NativeRequestV2
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins().");
|
||||
return (HttpApi.HTTP_REQUEST_V2*)_nativeRequest;
|
||||
}
|
||||
}
|
||||
|
||||
internal ulong RequestId
|
||||
{
|
||||
get { return NativeRequest->RequestId; }
|
||||
set { NativeRequest->RequestId = value; }
|
||||
}
|
||||
|
||||
internal ulong ConnectionId => NativeRequest->ConnectionId;
|
||||
|
||||
internal HttpApi.HTTP_VERB VerbId => NativeRequest->Verb;
|
||||
|
||||
internal ulong UrlContext => NativeRequest->UrlContext;
|
||||
|
||||
internal ushort UnknownHeaderCount => NativeRequest->Headers.UnknownHeaderCount;
|
||||
|
||||
internal SslStatus SslStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return NativeRequest->pSslInfo == null ? SslStatus.Insecure :
|
||||
NativeRequest->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert :
|
||||
SslStatus.ClientCert;
|
||||
}
|
||||
}
|
||||
|
||||
internal uint Size
|
||||
{
|
||||
get { return (uint)_backingBuffer.Length - AlignmentPadding; }
|
||||
}
|
||||
|
||||
// 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.
|
||||
internal void ReleasePins()
|
||||
{
|
||||
Debug.Assert(_nativeRequest != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice.");
|
||||
_originalBufferAddress = (IntPtr)_nativeRequest;
|
||||
_nativeRequest = null;
|
||||
_nativeOverlapped?.Dispose();
|
||||
_nativeOverlapped = null;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Debug.Assert(_nativeRequest == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins().");
|
||||
_nativeOverlapped?.Dispose();
|
||||
}
|
||||
|
||||
private void SetBuffer(int size)
|
||||
{
|
||||
Debug.Assert(size != 0, "unexpected size");
|
||||
|
||||
_backingBuffer = new byte[size + AlignmentPadding];
|
||||
}
|
||||
|
||||
private void AllocateNativeRequest(uint? size = null)
|
||||
{
|
||||
// We can't reuse overlapped objects
|
||||
_nativeOverlapped?.Dispose();
|
||||
|
||||
uint newSize = size.HasValue ? size.Value : _backingBuffer == null ? DefaultBufferSize : Size;
|
||||
SetBuffer(checked((int)newSize));
|
||||
var boundHandle = _acceptResult.Server.RequestQueue.BoundHandle;
|
||||
_nativeOverlapped = new SafeNativeOverlapped(boundHandle,
|
||||
boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, _backingBuffer));
|
||||
|
||||
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);
|
||||
|
||||
_bufferAlignment = 0;
|
||||
|
||||
_nativeRequest = (HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment);
|
||||
}
|
||||
|
||||
internal void Reset(ulong requestId = 0, uint? size = null)
|
||||
{
|
||||
Debug.Assert(_nativeRequest != null || _backingBuffer == null, "RequestContextBase::Dispose()|SetNativeRequest() called after ReleasePins().");
|
||||
AllocateNativeRequest(size);
|
||||
RequestId = requestId;
|
||||
}
|
||||
|
||||
// These methods require the HTTP_REQUEST to still be pinned in its original location.
|
||||
|
||||
internal string GetVerb()
|
||||
{
|
||||
var verb = NativeRequest->Verb;
|
||||
if (verb > HttpApi.HTTP_VERB.HttpVerbUnknown && verb < HttpApi.HTTP_VERB.HttpVerbMaximum)
|
||||
{
|
||||
return HttpApi.HttpVerbs[(int)verb];
|
||||
}
|
||||
else if (verb == HttpApi.HTTP_VERB.HttpVerbUnknown && NativeRequest->pUnknownVerb != null)
|
||||
{
|
||||
return HeaderEncoding.GetString(NativeRequest->pUnknownVerb, NativeRequest->UnknownVerbLength);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal string GetRawUrl()
|
||||
{
|
||||
if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0)
|
||||
{
|
||||
return Marshal.PtrToStringAnsi((IntPtr)NativeRequest->pRawUrl, NativeRequest->RawUrlLength);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal byte[] GetRawUrlInBytes()
|
||||
{
|
||||
if (NativeRequest->pRawUrl != null && NativeRequest->RawUrlLength > 0)
|
||||
{
|
||||
var result = new byte[NativeRequest->RawUrlLength];
|
||||
Marshal.Copy((IntPtr)NativeRequest->pRawUrl, result, 0, NativeRequest->RawUrlLength);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal CookedUrl GetCookedUrl()
|
||||
{
|
||||
return new CookedUrl(NativeRequest->CookedUrl);
|
||||
}
|
||||
|
||||
internal Version GetVersion()
|
||||
{
|
||||
var major = NativeRequest->Version.MajorVersion;
|
||||
var minor = NativeRequest->Version.MinorVersion;
|
||||
if (major == 1 && minor == 1)
|
||||
{
|
||||
return Constants.V1_1;
|
||||
}
|
||||
else if (major == 1 && minor == 0)
|
||||
{
|
||||
return Constants.V1_0;
|
||||
}
|
||||
return new Version(major, minor);
|
||||
}
|
||||
|
||||
internal bool CheckAuthenticated()
|
||||
{
|
||||
var requestInfo = NativeRequestV2->pRequestInfo;
|
||||
var infoCount = NativeRequestV2->RequestInfoCount;
|
||||
|
||||
for (int i = 0; i < infoCount; i++)
|
||||
{
|
||||
var info = &requestInfo[i];
|
||||
if (info != null
|
||||
&& info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth
|
||||
&& info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
internal WindowsPrincipal GetUser()
|
||||
{
|
||||
var requestInfo = NativeRequestV2->pRequestInfo;
|
||||
var infoCount = NativeRequestV2->RequestInfoCount;
|
||||
|
||||
for (int i = 0; i < infoCount; i++)
|
||||
{
|
||||
var info = &requestInfo[i];
|
||||
if (info != null
|
||||
&& info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth
|
||||
&& info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess)
|
||||
{
|
||||
// Duplicates AccessToken
|
||||
var identity = new WindowsIdentity(info->pInfo->AccessToken,
|
||||
GetAuthTypeFromRequest(info->pInfo->AuthType).ToString());
|
||||
|
||||
// Close the original
|
||||
UnsafeNclNativeMethods.SafeNetHandles.CloseHandle(info->pInfo->AccessToken);
|
||||
|
||||
return new WindowsPrincipal(identity);
|
||||
}
|
||||
}
|
||||
|
||||
return new WindowsPrincipal(WindowsIdentity.GetAnonymous()); // Anonymous / !IsAuthenticated
|
||||
}
|
||||
|
||||
private static AuthenticationSchemes GetAuthTypeFromRequest(HttpApi.HTTP_REQUEST_AUTH_TYPE input)
|
||||
{
|
||||
switch (input)
|
||||
{
|
||||
case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeBasic:
|
||||
return AuthenticationSchemes.Basic;
|
||||
// case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeDigest:
|
||||
// return AuthenticationSchemes.Digest;
|
||||
case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNTLM:
|
||||
return AuthenticationSchemes.NTLM;
|
||||
case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeNegotiate:
|
||||
return AuthenticationSchemes.Negotiate;
|
||||
case HttpApi.HTTP_REQUEST_AUTH_TYPE.HttpRequestAuthTypeKerberos:
|
||||
return AuthenticationSchemes.Kerberos;
|
||||
default:
|
||||
throw new NotImplementedException(input.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// These methods are for accessing the request structure after it has been unpinned. They need to adjust addresses
|
||||
// in case GC has moved the original object.
|
||||
|
||||
internal string GetKnownHeader(HttpSysRequestHeader header)
|
||||
{
|
||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
||||
{
|
||||
var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
||||
int headerIndex = (int)header;
|
||||
string value = null;
|
||||
|
||||
HttpApi.HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex;
|
||||
// For known headers, when header value is empty, RawValueLength will be 0 and
|
||||
// pRawValue will point to empty string ("\0")
|
||||
if (pKnownHeader->pRawValue != null)
|
||||
{
|
||||
value = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
internal void GetUnknownHeaders(IDictionary<string, StringValues> unknownHeaders)
|
||||
{
|
||||
// Return value.
|
||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
||||
{
|
||||
var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
||||
int index;
|
||||
|
||||
// unknown headers
|
||||
if (request->Headers.UnknownHeaderCount != 0)
|
||||
{
|
||||
var pUnknownHeader = (HttpApi.HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders);
|
||||
for (index = 0; index < request->Headers.UnknownHeaderCount; index++)
|
||||
{
|
||||
// For unknown headers, when header value is empty, RawValueLength will be 0 and
|
||||
// pRawValue will be null.
|
||||
if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0)
|
||||
{
|
||||
var headerName = HeaderEncoding.GetString(pUnknownHeader->pName + fixup, pUnknownHeader->NameLength);
|
||||
string headerValue;
|
||||
if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0)
|
||||
{
|
||||
headerValue = HeaderEncoding.GetString(pUnknownHeader->pRawValue + fixup, pUnknownHeader->RawValueLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
headerValue = string.Empty;
|
||||
}
|
||||
// Note that Http.Sys currently collapses all headers of the same name to a single coma separated string,
|
||||
// so we can just call Set.
|
||||
unknownHeaders[headerName] = headerValue;
|
||||
}
|
||||
pUnknownHeader++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal SocketAddress GetRemoteEndPoint()
|
||||
{
|
||||
return GetEndPoint(localEndpoint: false);
|
||||
}
|
||||
|
||||
internal SocketAddress GetLocalEndPoint()
|
||||
{
|
||||
return GetEndPoint(localEndpoint: true);
|
||||
}
|
||||
|
||||
private SocketAddress GetEndPoint(bool localEndpoint)
|
||||
{
|
||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
||||
{
|
||||
var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||
var source = localEndpoint ? (byte*)request->Address.pLocalAddress : (byte*)request->Address.pRemoteAddress;
|
||||
|
||||
if (source == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var address = (IntPtr)(pMemoryBlob + _bufferAlignment - (byte*)_originalBufferAddress + source);
|
||||
return CopyOutAddress(address);
|
||||
}
|
||||
}
|
||||
|
||||
private static SocketAddress CopyOutAddress(IntPtr address)
|
||||
{
|
||||
ushort addressFamily = *((ushort*)address);
|
||||
if (addressFamily == (ushort)AddressFamily.InterNetwork)
|
||||
{
|
||||
var v4address = new SocketAddress(AddressFamily.InterNetwork, SocketAddress.IPv4AddressSize);
|
||||
fixed (byte* pBuffer = v4address.Buffer)
|
||||
{
|
||||
for (int index = 2; index < SocketAddress.IPv4AddressSize; index++)
|
||||
{
|
||||
pBuffer[index] = ((byte*)address)[index];
|
||||
}
|
||||
}
|
||||
return v4address;
|
||||
}
|
||||
if (addressFamily == (ushort)AddressFamily.InterNetworkV6)
|
||||
{
|
||||
var v6address = new SocketAddress(AddressFamily.InterNetworkV6, SocketAddress.IPv6AddressSize);
|
||||
fixed (byte* pBuffer = v6address.Buffer)
|
||||
{
|
||||
for (int index = 2; index < SocketAddress.IPv6AddressSize; index++)
|
||||
{
|
||||
pBuffer[index] = ((byte*)address)[index];
|
||||
}
|
||||
}
|
||||
return v6address;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal uint GetChunks(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size)
|
||||
{
|
||||
// Return value.
|
||||
uint dataRead = 0;
|
||||
fixed (byte* pMemoryBlob = _backingBuffer)
|
||||
{
|
||||
var request = (HttpApi.HTTP_REQUEST*)(pMemoryBlob + _bufferAlignment);
|
||||
long fixup = pMemoryBlob - (byte*)_originalBufferAddress;
|
||||
|
||||
if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1)
|
||||
{
|
||||
var pDataChunk = (HttpApi.HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]);
|
||||
|
||||
fixed (byte* pReadBuffer = buffer)
|
||||
{
|
||||
byte* pTo = &pReadBuffer[offset];
|
||||
|
||||
while (dataChunkIndex < request->EntityChunkCount && dataRead < size)
|
||||
{
|
||||
if (dataChunkOffset >= pDataChunk->fromMemory.BufferLength)
|
||||
{
|
||||
dataChunkOffset = 0;
|
||||
dataChunkIndex++;
|
||||
pDataChunk++;
|
||||
}
|
||||
else
|
||||
{
|
||||
byte* pFrom = (byte*)pDataChunk->fromMemory.pBuffer + dataChunkOffset + fixup;
|
||||
|
||||
uint bytesToRead = pDataChunk->fromMemory.BufferLength - (uint)dataChunkOffset;
|
||||
if (bytesToRead > (uint)size)
|
||||
{
|
||||
bytesToRead = (uint)size;
|
||||
}
|
||||
for (uint i = 0; i < bytesToRead; i++)
|
||||
{
|
||||
*(pTo++) = *(pFrom++);
|
||||
}
|
||||
dataRead += bytesToRead;
|
||||
dataChunkOffset += bytesToRead;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// we're finished.
|
||||
if (dataChunkIndex == request->EntityChunkCount)
|
||||
{
|
||||
dataChunkIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return dataRead;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,11 +5,11 @@ using System;
|
|||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
@ -27,8 +27,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private long? _contentLength;
|
||||
private RequestStream _nativeStream;
|
||||
|
||||
private SocketAddress _localEndPoint;
|
||||
private SocketAddress _remoteEndPoint;
|
||||
private AspNetCore.HttpSys.Internal.SocketAddress _localEndPoint;
|
||||
private AspNetCore.HttpSys.Internal.SocketAddress _remoteEndPoint;
|
||||
|
||||
private bool _isDisposed = false;
|
||||
|
||||
|
@ -57,7 +57,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
var originalPath = RequestUriBuilder.DecodeAndUnescapePath(rawUrlInBytes);
|
||||
|
||||
// 'OPTIONS * HTTP/1.1'
|
||||
if (KnownMethod == HttpApi.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal))
|
||||
if (KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbOPTIONS && string.Equals(RawUrl, "*", StringComparison.Ordinal))
|
||||
{
|
||||
PathBase = string.Empty;
|
||||
Path = string.Empty;
|
||||
|
@ -79,9 +79,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
ProtocolVersion = _nativeRequestContext.GetVersion();
|
||||
|
||||
Headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext));
|
||||
Headers = new RequestHeaders(_nativeRequestContext);
|
||||
|
||||
User = nativeRequestContext.GetUser();
|
||||
User = _nativeRequestContext.GetUser();
|
||||
|
||||
// GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/HttpSysServer/issues/231
|
||||
|
||||
|
@ -136,11 +136,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
}
|
||||
|
||||
public HeaderCollection Headers { get; }
|
||||
public RequestHeaders Headers { get; }
|
||||
|
||||
internal HttpApi.HTTP_VERB KnownMethod { get; }
|
||||
internal HttpApiTypes.HTTP_VERB KnownMethod { get; }
|
||||
|
||||
internal bool IsHeadMethod => KnownMethod == HttpApi.HTTP_VERB.HttpVerbHEAD;
|
||||
internal bool IsHeadMethod => KnownMethod == HttpApiTypes.HTTP_VERB.HttpVerbHEAD;
|
||||
|
||||
public string Method { get; }
|
||||
|
||||
|
@ -190,7 +190,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
}
|
||||
|
||||
private SocketAddress RemoteEndPoint
|
||||
private AspNetCore.HttpSys.Internal.SocketAddress RemoteEndPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -203,7 +203,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
}
|
||||
|
||||
private SocketAddress LocalEndPoint
|
||||
private AspNetCore.HttpSys.Internal.SocketAddress LocalEndPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -10,6 +10,7 @@ using System.Security.Principal;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.IO;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.IO;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
|
|
@ -10,8 +10,9 @@ using System.Runtime.InteropServices;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods;
|
||||
using static Microsoft.AspNetCore.HttpSys.Internal.UnsafeNclNativeMethods;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
@ -24,7 +25,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private TimeSpan? _cacheTtl;
|
||||
private long _expectedBodyLength;
|
||||
private BoundaryType _boundaryType;
|
||||
private HttpApi.HTTP_RESPONSE_V2 _nativeResponse;
|
||||
private HttpApiTypes.HTTP_RESPONSE_V2 _nativeResponse;
|
||||
|
||||
internal Response(RequestContext requestContext)
|
||||
{
|
||||
|
@ -33,7 +34,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
Headers = new HeaderCollection();
|
||||
// We haven't started yet, or we're just buffered, we can clear any data, headers, and state so
|
||||
// that we can start over (e.g. to write an error message).
|
||||
_nativeResponse = new HttpApi.HTTP_RESPONSE_V2();
|
||||
_nativeResponse = new HttpApiTypes.HTTP_RESPONSE_V2();
|
||||
Headers.IsReadOnly = false;
|
||||
Headers.Clear();
|
||||
_reasonPhrase = null;
|
||||
|
@ -249,9 +250,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
// What would we loose by bypassing HttpSendHttpResponse?
|
||||
//
|
||||
// TODO: Consider using the HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA flag for most/all responses rather than just Opaque.
|
||||
internal unsafe uint SendHeaders(HttpApi.HTTP_DATA_CHUNK[] dataChunks,
|
||||
internal unsafe uint SendHeaders(HttpApiTypes.HTTP_DATA_CHUNK[] dataChunks,
|
||||
ResponseStreamAsyncResult asyncResult,
|
||||
HttpApi.HTTP_FLAGS flags,
|
||||
HttpApiTypes.HTTP_FLAGS flags,
|
||||
bool isOpaqueUpgrade)
|
||||
{
|
||||
Debug.Assert(!HasStarted, "HttpListenerResponse::SendHeaders()|SentHeaders is true.");
|
||||
|
@ -273,7 +274,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
var handle = GCHandle.Alloc(dataChunks, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(handle);
|
||||
_nativeResponse.Response_V1.EntityChunkCount = (ushort)dataChunks.Length;
|
||||
_nativeResponse.Response_V1.pEntityChunks = (HttpApi.HTTP_DATA_CHUNK*)handle.AddrOfPinnedObject();
|
||||
_nativeResponse.Response_V1.pEntityChunks = (HttpApiTypes.HTTP_DATA_CHUNK*)handle.AddrOfPinnedObject();
|
||||
}
|
||||
else if (asyncResult != null && asyncResult.DataChunks != null)
|
||||
{
|
||||
|
@ -286,10 +287,10 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
_nativeResponse.Response_V1.pEntityChunks = null;
|
||||
}
|
||||
|
||||
var cachePolicy = new HttpApi.HTTP_CACHE_POLICY();
|
||||
var cachePolicy = new HttpApiTypes.HTTP_CACHE_POLICY();
|
||||
if (_cacheTtl.HasValue && _cacheTtl.Value > TimeSpan.Zero)
|
||||
{
|
||||
cachePolicy.Policy = HttpApi.HTTP_CACHE_POLICY_TYPE.HttpCachePolicyTimeToLive;
|
||||
cachePolicy.Policy = HttpApiTypes.HTTP_CACHE_POLICY_TYPE.HttpCachePolicyTimeToLive;
|
||||
cachePolicy.SecondsToLive = (uint)Math.Min(_cacheTtl.Value.Ticks / TimeSpan.TicksPerSecond, Int32.MaxValue);
|
||||
}
|
||||
|
||||
|
@ -297,8 +298,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
fixed (byte* pReasonPhrase = reasonPhraseBytes)
|
||||
{
|
||||
_nativeResponse.Response_V1.ReasonLength = (ushort)reasonPhraseBytes.Length;
|
||||
_nativeResponse.Response_V1.pReason = (sbyte*)pReasonPhrase;
|
||||
fixed (HttpApi.HTTP_RESPONSE_V2* pResponse = &_nativeResponse)
|
||||
_nativeResponse.Response_V1.pReason = (byte*)pReasonPhrase;
|
||||
fixed (HttpApiTypes.HTTP_RESPONSE_V2* pResponse = &_nativeResponse)
|
||||
{
|
||||
statusCode =
|
||||
HttpApi.HttpSendHttpResponse(
|
||||
|
@ -330,14 +331,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
return statusCode;
|
||||
}
|
||||
|
||||
internal HttpApi.HTTP_FLAGS ComputeHeaders(long writeCount, bool endOfRequest = false)
|
||||
internal HttpApiTypes.HTTP_FLAGS ComputeHeaders(long writeCount, bool endOfRequest = false)
|
||||
{
|
||||
if (StatusCode == (ushort)StatusCodes.Status401Unauthorized)
|
||||
{
|
||||
RequestContext.Server.Options.Authentication.SetAuthenticationChallenge(RequestContext);
|
||||
}
|
||||
|
||||
var flags = HttpApi.HTTP_FLAGS.NONE;
|
||||
var flags = HttpApiTypes.HTTP_FLAGS.NONE;
|
||||
Debug.Assert(!HasComputedHeaders, nameof(HasComputedHeaders) + " is true.");
|
||||
_responseState = ResponseState.ComputedHeaders;
|
||||
|
||||
|
@ -414,7 +415,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
Headers.Append(HttpKnownHeaderNames.Connection, Constants.Close);
|
||||
}
|
||||
flags = HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
|
||||
flags = HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
|
||||
}
|
||||
|
||||
return flags;
|
||||
|
@ -428,8 +429,8 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private unsafe List<GCHandle> SerializeHeaders(bool isOpaqueUpgrade)
|
||||
{
|
||||
Headers.IsReadOnly = true; // Prohibit further modifications.
|
||||
HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null;
|
||||
HttpApi.HTTP_RESPONSE_INFO[] knownHeaderInfo = null;
|
||||
HttpApiTypes.HTTP_UNKNOWN_HEADER[] unknownHeaders = null;
|
||||
HttpApiTypes.HTTP_RESPONSE_INFO[] knownHeaderInfo = null;
|
||||
List<GCHandle> pinnedHeaders;
|
||||
GCHandle gcHandle;
|
||||
|
||||
|
@ -452,11 +453,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
continue;
|
||||
}
|
||||
// See if this is an unknown header
|
||||
lookup = HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key);
|
||||
lookup = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerPair.Key);
|
||||
|
||||
// Http.Sys doesn't let us send the Connection: Upgrade header as a Known header.
|
||||
if (lookup == -1 ||
|
||||
(isOpaqueUpgrade && lookup == (int)HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection))
|
||||
(isOpaqueUpgrade && lookup == (int)HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection))
|
||||
{
|
||||
numUnknownHeaders += headerPair.Value.Count;
|
||||
}
|
||||
|
@ -469,7 +470,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
try
|
||||
{
|
||||
fixed (HttpApi.HTTP_KNOWN_HEADER* pKnownHeaders = &_nativeResponse.Response_V1.Headers.KnownHeaders)
|
||||
fixed (HttpApiTypes.HTTP_KNOWN_HEADER* pKnownHeaders = &_nativeResponse.Response_V1.Headers.KnownHeaders)
|
||||
{
|
||||
foreach (var headerPair in Headers)
|
||||
{
|
||||
|
@ -479,18 +480,18 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
headerName = headerPair.Key;
|
||||
StringValues headerValues = headerPair.Value;
|
||||
lookup = HttpApi.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName);
|
||||
lookup = HttpApiTypes.HTTP_RESPONSE_HEADER_ID.IndexOfKnownHeader(headerName);
|
||||
|
||||
// Http.Sys doesn't let us send the Connection: Upgrade header as a Known header.
|
||||
if (lookup == -1 ||
|
||||
(isOpaqueUpgrade && lookup == (int)HttpApi.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection))
|
||||
(isOpaqueUpgrade && lookup == (int)HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum.HttpHeaderConnection))
|
||||
{
|
||||
if (unknownHeaders == null)
|
||||
{
|
||||
unknownHeaders = new HttpApi.HTTP_UNKNOWN_HEADER[numUnknownHeaders];
|
||||
unknownHeaders = new HttpApiTypes.HTTP_UNKNOWN_HEADER[numUnknownHeaders];
|
||||
gcHandle = GCHandle.Alloc(unknownHeaders, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
_nativeResponse.Response_V1.Headers.pUnknownHeaders = (HttpApi.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject();
|
||||
_nativeResponse.Response_V1.Headers.pUnknownHeaders = (HttpApiTypes.HTTP_UNKNOWN_HEADER*)gcHandle.AddrOfPinnedObject();
|
||||
}
|
||||
|
||||
for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++)
|
||||
|
@ -500,7 +501,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].NameLength = (ushort)bytes.Length;
|
||||
gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pName = (sbyte*)gcHandle.AddrOfPinnedObject();
|
||||
unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pName = (byte*)gcHandle.AddrOfPinnedObject();
|
||||
|
||||
// Add Value
|
||||
headerValue = headerValues[headerValueIndex] ?? string.Empty;
|
||||
|
@ -508,7 +509,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].RawValueLength = (ushort)bytes.Length;
|
||||
gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject();
|
||||
unknownHeaders[_nativeResponse.Response_V1.Headers.UnknownHeaderCount].pRawValue = (byte*)gcHandle.AddrOfPinnedObject();
|
||||
_nativeResponse.Response_V1.Headers.UnknownHeaderCount++;
|
||||
}
|
||||
}
|
||||
|
@ -519,30 +520,30 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
pKnownHeaders[lookup].RawValueLength = (ushort)bytes.Length;
|
||||
gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
pKnownHeaders[lookup].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject();
|
||||
pKnownHeaders[lookup].pRawValue = (byte*)gcHandle.AddrOfPinnedObject();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (knownHeaderInfo == null)
|
||||
{
|
||||
knownHeaderInfo = new HttpApi.HTTP_RESPONSE_INFO[numKnownMultiHeaders];
|
||||
knownHeaderInfo = new HttpApiTypes.HTTP_RESPONSE_INFO[numKnownMultiHeaders];
|
||||
gcHandle = GCHandle.Alloc(knownHeaderInfo, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
_nativeResponse.pResponseInfo = (HttpApi.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject();
|
||||
_nativeResponse.pResponseInfo = (HttpApiTypes.HTTP_RESPONSE_INFO*)gcHandle.AddrOfPinnedObject();
|
||||
}
|
||||
|
||||
knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = HttpApi.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders;
|
||||
knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf<HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS>();
|
||||
knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = HttpApiTypes.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders;
|
||||
knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf<HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS>();
|
||||
|
||||
HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS();
|
||||
HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS header = new HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS();
|
||||
|
||||
header.HeaderId = (HttpApi.HTTP_RESPONSE_HEADER_ID.Enum)lookup;
|
||||
header.Flags = HttpApi.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only.
|
||||
header.HeaderId = (HttpApiTypes.HTTP_RESPONSE_HEADER_ID.Enum)lookup;
|
||||
header.Flags = HttpApiTypes.HTTP_RESPONSE_INFO_FLAGS.PreserveOrder; // TODO: The docs say this is for www-auth only.
|
||||
|
||||
HttpApi.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApi.HTTP_KNOWN_HEADER[headerValues.Count];
|
||||
HttpApiTypes.HTTP_KNOWN_HEADER[] nativeHeaderValues = new HttpApiTypes.HTTP_KNOWN_HEADER[headerValues.Count];
|
||||
gcHandle = GCHandle.Alloc(nativeHeaderValues, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
header.KnownHeaders = (HttpApi.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject();
|
||||
header.KnownHeaders = (HttpApiTypes.HTTP_KNOWN_HEADER*)gcHandle.AddrOfPinnedObject();
|
||||
|
||||
for (int headerValueIndex = 0; headerValueIndex < headerValues.Count; headerValueIndex++)
|
||||
{
|
||||
|
@ -552,14 +553,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
nativeHeaderValues[header.KnownHeaderCount].RawValueLength = (ushort)bytes.Length;
|
||||
gcHandle = GCHandle.Alloc(bytes, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
nativeHeaderValues[header.KnownHeaderCount].pRawValue = (sbyte*)gcHandle.AddrOfPinnedObject();
|
||||
nativeHeaderValues[header.KnownHeaderCount].pRawValue = (byte*)gcHandle.AddrOfPinnedObject();
|
||||
header.KnownHeaderCount++;
|
||||
}
|
||||
|
||||
// This type is a struct, not an object, so pinning it causes a boxed copy to be created. We can't do that until after all the fields are set.
|
||||
gcHandle = GCHandle.Alloc(header, GCHandleType.Pinned);
|
||||
pinnedHeaders.Add(gcHandle);
|
||||
knownHeaderInfo[_nativeResponse.ResponseInfoCount].pInfo = (HttpApi.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject();
|
||||
knownHeaderInfo[_nativeResponse.ResponseInfoCount].pInfo = (HttpApiTypes.HTTP_MULTIPLE_KNOWN_HEADERS*)gcHandle.AddrOfPinnedObject();
|
||||
|
||||
_nativeResponse.ResponseInfoCount++;
|
||||
}
|
||||
|
@ -595,9 +596,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
// TODO: Send headers async?
|
||||
ulong errorCode = SendHeaders(null, null,
|
||||
HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_OPAQUE |
|
||||
HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA |
|
||||
HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA,
|
||||
HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_OPAQUE |
|
||||
HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA |
|
||||
HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_BUFFER_DATA,
|
||||
true);
|
||||
|
||||
if (errorCode != ErrorCodes.ERROR_SUCCESS)
|
||||
|
|
|
@ -9,8 +9,9 @@ using System.IO;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods;
|
||||
using static Microsoft.AspNetCore.HttpSys.Internal.UnsafeNclNativeMethods;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
@ -132,7 +133,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
|
||||
uint statusCode = 0;
|
||||
HttpApi.HTTP_DATA_CHUNK[] dataChunks;
|
||||
HttpApiTypes.HTTP_DATA_CHUNK[] dataChunks;
|
||||
var pinnedBuffers = PinDataBuffers(endOfRequest, data, out dataChunks);
|
||||
try
|
||||
{
|
||||
|
@ -142,7 +143,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
else
|
||||
{
|
||||
fixed (HttpApi.HTTP_DATA_CHUNK* pDataChunks = dataChunks)
|
||||
fixed (HttpApiTypes.HTTP_DATA_CHUNK* pDataChunks = dataChunks)
|
||||
{
|
||||
statusCode = HttpApi.HttpSendResponseEntityBody(
|
||||
RequestQueueHandle,
|
||||
|
@ -183,7 +184,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
}
|
||||
|
||||
private List<GCHandle> PinDataBuffers(bool endOfRequest, ArraySegment<byte> data, out HttpApi.HTTP_DATA_CHUNK[] dataChunks)
|
||||
private List<GCHandle> PinDataBuffers(bool endOfRequest, ArraySegment<byte> data, out HttpApiTypes.HTTP_DATA_CHUNK[] dataChunks)
|
||||
{
|
||||
var pins = new List<GCHandle>();
|
||||
var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked;
|
||||
|
@ -192,14 +193,14 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
// Figure out how many data chunks
|
||||
if (chunked && data.Count == 0 && endOfRequest)
|
||||
{
|
||||
dataChunks = new HttpApi.HTTP_DATA_CHUNK[1];
|
||||
dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[1];
|
||||
SetDataChunk(dataChunks, ref currentChunk, pins, new ArraySegment<byte>(Helpers.ChunkTerminator));
|
||||
return pins;
|
||||
}
|
||||
else if (data.Count == 0)
|
||||
{
|
||||
// No data
|
||||
dataChunks = new HttpApi.HTTP_DATA_CHUNK[0];
|
||||
dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[0];
|
||||
return pins;
|
||||
}
|
||||
|
||||
|
@ -215,7 +216,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
chunkCount += 1;
|
||||
}
|
||||
}
|
||||
dataChunks = new HttpApi.HTTP_DATA_CHUNK[chunkCount];
|
||||
dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[chunkCount];
|
||||
|
||||
if (chunked)
|
||||
{
|
||||
|
@ -238,11 +239,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
return pins;
|
||||
}
|
||||
|
||||
private static void SetDataChunk(HttpApi.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, List<GCHandle> pins, ArraySegment<byte> buffer)
|
||||
private static void SetDataChunk(HttpApiTypes.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, List<GCHandle> pins, ArraySegment<byte> buffer)
|
||||
{
|
||||
var handle = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
|
||||
pins.Add(handle);
|
||||
chunks[chunkIndex].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
|
||||
chunks[chunkIndex].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
|
||||
chunks[chunkIndex].fromMemory.pBuffer = handle.AddrOfPinnedObject() + buffer.Offset;
|
||||
chunks[chunkIndex].fromMemory.BufferLength = (uint)buffer.Count;
|
||||
chunkIndex++;
|
||||
|
@ -355,7 +356,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
|
||||
// Last write, cache it for special cancellation handling.
|
||||
if ((flags & HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0)
|
||||
if ((flags & HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0)
|
||||
{
|
||||
_lastWrite = asyncResult;
|
||||
}
|
||||
|
@ -405,9 +406,9 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
_requestContext.Abort();
|
||||
}
|
||||
|
||||
private HttpApi.HTTP_FLAGS ComputeLeftToWrite(long writeCount, bool endOfRequest = false)
|
||||
private HttpApiTypes.HTTP_FLAGS ComputeLeftToWrite(long writeCount, bool endOfRequest = false)
|
||||
{
|
||||
var flags = HttpApi.HTTP_FLAGS.NONE;
|
||||
var flags = HttpApiTypes.HTTP_FLAGS.NONE;
|
||||
if (!_requestContext.Response.HasComputedHeaders)
|
||||
{
|
||||
flags = _requestContext.Response.ComputeHeaders(writeCount, endOfRequest);
|
||||
|
@ -430,11 +431,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
if (endOfRequest && _requestContext.Response.BoundaryType == BoundaryType.Close)
|
||||
{
|
||||
flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
|
||||
flags |= HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_DISCONNECT;
|
||||
}
|
||||
else if (!endOfRequest && _leftToWrite != writeCount)
|
||||
{
|
||||
flags |= HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
|
||||
flags |= HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
|
||||
}
|
||||
|
||||
// Update _leftToWrite now so we can queue up additional async writes.
|
||||
|
@ -647,7 +648,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
|
||||
// Last write, cache it for special cancellation handling.
|
||||
if ((flags & HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0)
|
||||
if ((flags & HttpApiTypes.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0)
|
||||
{
|
||||
_lastWrite = asyncResult;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ using System.IO;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using static Microsoft.AspNetCore.Server.HttpSys.UnsafeNclNativeMethods;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
private static readonly IOCompletionCallback IOCallback = new IOCompletionCallback(Callback);
|
||||
|
||||
private SafeNativeOverlapped _overlapped;
|
||||
private HttpApi.HTTP_DATA_CHUNK[] _dataChunks;
|
||||
private HttpApiTypes.HTTP_DATA_CHUNK[] _dataChunks;
|
||||
private FileStream _fileStream;
|
||||
private ResponseBody _responseStream;
|
||||
private TaskCompletionSource<object> _tcs;
|
||||
|
@ -53,7 +53,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
return;
|
||||
}
|
||||
|
||||
_dataChunks = new HttpApi.HTTP_DATA_CHUNK[1 + (chunked ? 2 : 0)];
|
||||
_dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[1 + (chunked ? 2 : 0)];
|
||||
objectsToPin = new object[_dataChunks.Length + 1];
|
||||
objectsToPin[0] = _dataChunks;
|
||||
var currentChunk = 0;
|
||||
|
@ -110,7 +110,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
else
|
||||
{
|
||||
_dataChunks = new HttpApi.HTTP_DATA_CHUNK[chunked ? 3 : 1];
|
||||
_dataChunks = new HttpApiTypes.HTTP_DATA_CHUNK[chunked ? 3 : 1];
|
||||
|
||||
object[] objectsToPin = new object[_dataChunks.Length];
|
||||
objectsToPin[_dataChunks.Length - 1] = _dataChunks;
|
||||
|
@ -119,23 +119,23 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
if (chunked)
|
||||
{
|
||||
chunkHeaderBuffer = Helpers.GetChunkHeader(count);
|
||||
_dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
|
||||
_dataChunks[0].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
|
||||
_dataChunks[0].fromMemory.BufferLength = (uint)chunkHeaderBuffer.Count;
|
||||
objectsToPin[0] = chunkHeaderBuffer.Array;
|
||||
|
||||
_dataChunks[1].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle;
|
||||
_dataChunks[1].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle;
|
||||
_dataChunks[1].fromFile.offset = (ulong)offset;
|
||||
_dataChunks[1].fromFile.count = (ulong)count;
|
||||
_dataChunks[1].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle();
|
||||
// Nothing to pin for the file handle.
|
||||
|
||||
_dataChunks[2].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
|
||||
_dataChunks[2].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
|
||||
_dataChunks[2].fromMemory.BufferLength = (uint)Helpers.CRLF.Length;
|
||||
objectsToPin[1] = Helpers.CRLF;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle;
|
||||
_dataChunks[0].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle;
|
||||
_dataChunks[0].fromFile.offset = (ulong)offset;
|
||||
_dataChunks[0].fromFile.count = (ulong)count;
|
||||
_dataChunks[0].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle();
|
||||
|
@ -154,11 +154,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
}
|
||||
|
||||
private static void SetDataChunk(HttpApi.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, object[] objectsToPin, ref int pinIndex, ArraySegment<byte> segment)
|
||||
private static void SetDataChunk(HttpApiTypes.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, object[] objectsToPin, ref int pinIndex, ArraySegment<byte> segment)
|
||||
{
|
||||
objectsToPin[pinIndex] = segment.Array;
|
||||
pinIndex++;
|
||||
chunks[chunkIndex].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
|
||||
chunks[chunkIndex].DataChunkType = HttpApiTypes.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
|
||||
// The address is not set until after we pin it with Overlapped
|
||||
chunks[chunkIndex].fromMemory.BufferLength = (uint)segment.Count;
|
||||
chunkIndex++;
|
||||
|
@ -195,7 +195,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
}
|
||||
|
||||
internal HttpApi.HTTP_DATA_CHUNK* DataChunks
|
||||
internal HttpApiTypes.HTTP_DATA_CHUNK* DataChunks
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -205,7 +205,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
}
|
||||
else
|
||||
{
|
||||
return (HttpApi.HTTP_DATA_CHUNK*)(Marshal.UnsafeAddrOfPinnedArrayElement(_dataChunks, 0));
|
||||
return (HttpApiTypes.HTTP_DATA_CHUNK*)(Marshal.UnsafeAddrOfPinnedArrayElement(_dataChunks, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
@ -15,7 +16,7 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
public sealed class TimeoutManager
|
||||
{
|
||||
private static readonly int TimeoutLimitSize =
|
||||
Marshal.SizeOf<HttpApi.HTTP_TIMEOUT_LIMIT_INFO>();
|
||||
Marshal.SizeOf<HttpApiTypes.HTTP_TIMEOUT_LIMIT_INFO>();
|
||||
|
||||
private UrlGroup _urlGroup;
|
||||
private int[] _timeouts;
|
||||
|
@ -47,11 +48,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.EntityBody);
|
||||
return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.EntityBody);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.EntityBody, value);
|
||||
SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.EntityBody, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,11 +71,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody);
|
||||
return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.DrainEntityBody);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody, value);
|
||||
SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.DrainEntityBody, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,11 +89,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue);
|
||||
return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.RequestQueue);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue, value);
|
||||
SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.RequestQueue, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,11 +108,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection);
|
||||
return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.IdleConnection);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection, value);
|
||||
SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.IdleConnection, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,11 +128,11 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait);
|
||||
return GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.HeaderWait);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait, value);
|
||||
SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE.HeaderWait, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,13 +168,13 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
|
||||
#region Helpers
|
||||
|
||||
private TimeSpan GetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE type)
|
||||
private TimeSpan GetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE type)
|
||||
{
|
||||
// Since we maintain local state, GET is local.
|
||||
return new TimeSpan(0, 0, (int)_timeouts[(int)type]);
|
||||
}
|
||||
|
||||
private void SetTimeSpanTimeout(HttpApi.HTTP_TIMEOUT_TYPE type, TimeSpan value)
|
||||
private void SetTimeSpanTimeout(HttpApiTypes.HTTP_TIMEOUT_TYPE type, TimeSpan value)
|
||||
{
|
||||
// All timeouts are defined as USHORT in native layer (except MinSendRate, which is ULONG). Make sure that
|
||||
// timeout value is within range.
|
||||
|
@ -207,25 +208,25 @@ namespace Microsoft.AspNetCore.Server.HttpSys
|
|||
return;
|
||||
}
|
||||
|
||||
var timeoutinfo = new HttpApi.HTTP_TIMEOUT_LIMIT_INFO();
|
||||
var timeoutinfo = new HttpApiTypes.HTTP_TIMEOUT_LIMIT_INFO();
|
||||
|
||||
timeoutinfo.Flags = HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
|
||||
timeoutinfo.Flags = HttpApiTypes.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
|
||||
timeoutinfo.DrainEntityBody =
|
||||
(ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody];
|
||||
(ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.DrainEntityBody];
|
||||
timeoutinfo.EntityBody =
|
||||
(ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.EntityBody];
|
||||
(ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.EntityBody];
|
||||
timeoutinfo.RequestQueue =
|
||||
(ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue];
|
||||
(ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.RequestQueue];
|
||||
timeoutinfo.IdleConnection =
|
||||
(ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection];
|
||||
(ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.IdleConnection];
|
||||
timeoutinfo.HeaderWait =
|
||||
(ushort)timeouts[(int)HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait];
|
||||
(ushort)timeouts[(int)HttpApiTypes.HTTP_TIMEOUT_TYPE.HeaderWait];
|
||||
timeoutinfo.MinSendRate = minSendBytesPerSecond;
|
||||
|
||||
var infoptr = new IntPtr(&timeoutinfo);
|
||||
|
||||
_urlGroup.SetProperty(
|
||||
HttpApi.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty,
|
||||
HttpApiTypes.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty,
|
||||
infoptr, (uint)TimeoutLimitSize);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.HttpSys
|
||||
{
|
||||
|
|
|
@ -5,6 +5,7 @@ using System.Linq;
|
|||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
|
@ -13,6 +13,7 @@ using Microsoft.AspNetCore.Authentication;
|
|||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.HttpSys.Internal;
|
||||
using Microsoft.AspNetCore.Testing.xunit;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
|
Загрузка…
Ссылка в новой задаче