diff --git a/HttpSysServer.sln b/HttpSysServer.sln index 9468f957f1..adc3b6d351 100644 --- a/HttpSysServer.sln +++ b/HttpSysServer.sln @@ -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} diff --git a/NuGetPackageVerifier.json b/NuGetPackageVerifier.json index b153ab1515..c02b36b40a 100644 --- a/NuGetPackageVerifier.json +++ b/NuGetPackageVerifier.json @@ -1,4 +1,10 @@ { + "adx-nonshipping": { + "rules": [], + "packages": { + "Microsoft.AspNetCore.HttpSys.Sources": {} + } + }, "Default": { "rules": [ "DefaultCompositeRule" diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs similarity index 93% rename from src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs index d7b5382d18..0982badab8 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Constants.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/Constants.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class Constants { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/CookedUrl.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs similarity index 89% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/CookedUrl.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs index a444c48854..ee5b2ec53d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/CookedUrl.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/CookedUrl.cs @@ -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; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HeapAllocHandle.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs similarity index 94% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HeapAllocHandle.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs index 289252e7dc..9175fd8572 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HeapAllocHandle.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HeapAllocHandle.cs @@ -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 { diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs new file mode 100644 index 0000000000..6b3a3b6908 --- /dev/null +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpApiTypes.cs @@ -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 _lookupTable = CreateLookupTable(); + + private static Dictionary CreateLookupTable() + { + Dictionary lookupTable = new Dictionary((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 + } + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysRequestHeader.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs similarity index 98% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysRequestHeader.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs index bf8cda9c6f..c52444b1be 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysRequestHeader.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysRequestHeader.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysResponseHeader.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs similarity index 97% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysResponseHeader.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs index 2d6ee2a915..5b00f35d29 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpSysResponseHeader.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/HttpSysResponseHeader.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs similarity index 90% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs index abd74045e5..504e82a300 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/NclUtilities.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/NclUtilities.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class NclUtilities { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFreeChannelBinding.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs similarity index 96% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFreeChannelBinding.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs index eb3ecf7487..4c83257e5d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalFreeChannelBinding.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalFreeChannelBinding.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalMemHandle.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs similarity index 93% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalMemHandle.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs index 5e60f6e2d1..75fb508714 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeLocalMemHandle.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeLocalMemHandle.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeNativeOverlapped.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs similarity index 97% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeNativeOverlapped.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs index 8073499996..01ba3c32f2 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SafeNativeOverlapped.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SafeNativeOverlapped.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SocketAddress.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SocketAddress.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs index a06adf2913..fbe82fa7bc 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/SocketAddress.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/SocketAddress.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs index 81662ac8c1..4483cbc306 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UnsafeNativeMethods.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/NativeInterop/UnsafeNativeMethods.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs index d0d6716486..504c434667 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderCollection.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderCollection.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderEncoding.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs similarity index 79% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderEncoding.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs index 9c22ce1695..991571904b 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderEncoding.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderEncoding.cs @@ -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); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderParser.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs similarity index 96% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderParser.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs index 8b57bb3a4c..770a3ee3a7 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HeaderParser.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HeaderParser.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpKnownHeaderNames.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs similarity index 98% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpKnownHeaderNames.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs index 45ed640625..ac299f9785 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/HttpKnownHeaderNames.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/HttpKnownHeaderNames.cs @@ -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 { diff --git a/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs new file mode 100644 index 0000000000..45d002e5b8 --- /dev/null +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/NativeRequestContext.cs @@ -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 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 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; + } + } +} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RawUrlHelper.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RawUrlHelper.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs index 7538ba9b2c..7402c4ef8f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RawUrlHelper.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RawUrlHelper.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Server.HttpSys +namespace Microsoft.AspNetCore.HttpSys.Internal { internal static class RawUrlHelper { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs index 431f23558b..47759a41c5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.Generated.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.Generated.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs similarity index 57% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs index 3d6f701b61..0f87c3565a 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestHeaders.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestHeaders.cs @@ -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 + internal partial class RequestHeaders : IHeaderDictionary { private IDictionary _extra; private NativeRequestContext _requestMemoryBlob; + private long? _contentLength; + private StringValues _contentLengthText; internal RequestHeaders(NativeRequestContext requestMemoryBlob) { _requestMemoryBlob = requestMemoryBlob; } + public bool IsReadOnly { get; internal set; } + private IDictionary 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>.Remove(KeyValuePair item) { return ((IDictionary)this).Contains(item) && @@ -146,5 +243,23 @@ namespace Microsoft.AspNetCore.Server.HttpSys { return ((IDictionary)this).GetEnumerator(); } + + private void ThrowIfReadOnly() + { + if (IsReadOnly) + { + throw new InvalidOperationException("The response headers cannot be modified because the response has already started."); + } + } + + public IEnumerable GetValues(string key) + { + StringValues values; + if (TryGetValue(key, out values)) + { + return HeaderParser.SplitValues(values); + } + return HeaderParser.Empty; + } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestUriBuilder.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs similarity index 99% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestUriBuilder.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs index 813970025e..6308d6d8ea 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestUriBuilder.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/RequestUriBuilder.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/SslStatus.cs b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs similarity index 85% rename from src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/SslStatus.cs rename to shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs index b7c325bc01..5154a0e9da 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/SslStatus.cs +++ b/shared/Microsoft.AspNetCore.HttpSys.Sources/RequestProcessing/SslStatus.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs index 3057e138e7..efb191760e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AsyncAcceptContext.cs @@ -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 _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(); - _nativeRequestContext = new NativeRequestContext(this); + AllocateNativeRequest(); } internal Task 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; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs index e4b728dcd4..b9594d1143 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/AuthenticationManager.cs @@ -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(); + Marshal.SizeOf(); 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); } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs index 56d1e4356d..2c70016e3f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/HttpSysListener.cs @@ -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 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(); - 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(); + (uint)Marshal.SizeOf(); - 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; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs index 00a28df87c..2b06066936 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/MessagePump.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj index a7373c095c..592368a043 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj +++ b/src/Microsoft.AspNetCore.Server.HttpSys/Microsoft.AspNetCore.Server.HttpSys.csproj @@ -9,6 +9,10 @@ aspnetcore;weblistener;httpsys + + + + diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs deleted file mode 100644 index 9f4a7063be..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/AddressFamily.cs +++ /dev/null @@ -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 -{ - /// - /// - /// Specifies the address families. - /// - /// - internal enum AddressFamily - { - /// - /// [To be supplied.] - /// - Unknown = -1, // Unknown - - /// - /// [To be supplied.] - /// - Unspecified = 0, // unspecified - - /// - /// [To be supplied.] - /// - Unix = 1, // local to host (pipes, portals) - - /// - /// [To be supplied.] - /// - InterNetwork = 2, // internetwork: UDP, TCP, etc. - - /// - /// [To be supplied.] - /// - ImpLink = 3, // arpanet imp addresses - - /// - /// [To be supplied.] - /// - Pup = 4, // pup protocols: e.g. BSP - - /// - /// [To be supplied.] - /// - Chaos = 5, // mit CHAOS protocols - - /// - /// [To be supplied.] - /// - NS = 6, // XEROX NS protocols - - /// - /// [To be supplied.] - /// - Ipx = NS, // IPX and SPX - - /// - /// [To be supplied.] - /// - Iso = 7, // ISO protocols - - /// - /// [To be supplied.] - /// - Osi = Iso, // OSI is ISO - - /// - /// [To be supplied.] - /// - Ecma = 8, // european computer manufacturers - - /// - /// [To be supplied.] - /// - DataKit = 9, // datakit protocols - - /// - /// [To be supplied.] - /// - Ccitt = 10, // CCITT protocols, X.25 etc - - /// - /// [To be supplied.] - /// - Sna = 11, // IBM SNA - - /// - /// [To be supplied.] - /// - DecNet = 12, // DECnet - - /// - /// [To be supplied.] - /// - DataLink = 13, // Direct data link interface - - /// - /// [To be supplied.] - /// - Lat = 14, // LAT - - /// - /// [To be supplied.] - /// - HyperChannel = 15, // NSC Hyperchannel - - /// - /// [To be supplied.] - /// - AppleTalk = 16, // AppleTalk - - /// - /// [To be supplied.] - /// - NetBios = 17, // NetBios-style addresses - - /// - /// [To be supplied.] - /// - VoiceView = 18, // VoiceView - - /// - /// [To be supplied.] - /// - FireFox = 19, // FireFox - - /// - /// [To be supplied.] - /// - Banyan = 21, // Banyan - - /// - /// [To be supplied.] - /// - Atm = 22, // Native ATM Services - - /// - /// [To be supplied.] - /// - InterNetworkV6 = 23, // Internetwork Version 6 - - /// - /// [To be supplied.] - /// - Cluster = 24, // Microsoft Wolfpack - - /// - /// [To be supplied.] - /// - Ieee12844 = 25, // IEEE 1284.4 WG AF - - /// - /// [To be supplied.] - /// - Irda = 26, // IrDA - - /// - /// [To be supplied.] - /// - NetworkDesigners = 28, // Network Designers OSI & gateway enabled protocols - - /// - /// [To be supplied.] - /// - Max = 29, // Max - }; // enum AddressFamily -} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs index f9a3a7c0e5..ecef12b989 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/DisconnectListener.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs index 94bc558af5..1dc97ef20d 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpApi.cs @@ -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 _lookupTable = CreateLookupTable(); - - private static Dictionary CreateLookupTable() - { - Dictionary lookupTable = new Dictionary((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; diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs index 46c725b193..6fac23f67f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpRequestQueueV2Handle.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs index 4ed550c1d6..903e4d9065 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/HttpServerSessionHandle.cs @@ -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)); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs index 4468f7029e..29f43b6fd5 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/RequestQueue.cs @@ -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(); + Marshal.SizeOf(); 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(), 0, IntPtr.Zero); if (result != 0) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs index 9bebb1e9c5..1d2798bd8e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/ServerSession.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs index ddb11c5240..21d17656a8 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/TokenBindingUtil.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs index cdeaae7800..8f33c7b678 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/NativeInterop/UrlGroup.cs @@ -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(); + Marshal.SizeOf(); 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(); diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs index b453bed46f..74d7ed902f 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ClientCertLoader.cs @@ -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(); + Marshal.SizeOf(); 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 _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("ChannelToken")); + IntPtr tokenPointer = Marshal.ReadIntPtr(blob, (int)Marshal.OffsetOf("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("ChannelTokenSize")); + return Marshal.ReadInt32(blob, (int)Marshal.OffsetOf("ChannelTokenSize")); } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs deleted file mode 100644 index 7bcbb258b5..0000000000 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/NativeRequestContext.cs +++ /dev/null @@ -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 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; - } - } -} diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs index 7e4ef322d6..3dedf347a9 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Request.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs index a57064fb55..89405cf538 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestContext.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs index baef4c5a9f..284a3d856e 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStream.cs @@ -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 diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs index 5304f616f1..a2fa887f56 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/RequestStreamAsyncResult.cs @@ -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 { diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs index 427f1a1f2b..feef66ca24 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/Response.cs @@ -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 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 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(); + knownHeaderInfo[_nativeResponse.ResponseInfoCount].Type = HttpApiTypes.HTTP_RESPONSE_INFO_TYPE.HttpResponseInfoTypeMultipleKnownHeaders; + knownHeaderInfo[_nativeResponse.ResponseInfoCount].Length = (uint)Marshal.SizeOf(); - 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) diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs index 35eb89c6e7..87ae976cbd 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseBody.cs @@ -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 PinDataBuffers(bool endOfRequest, ArraySegment data, out HttpApi.HTTP_DATA_CHUNK[] dataChunks) + private List PinDataBuffers(bool endOfRequest, ArraySegment data, out HttpApiTypes.HTTP_DATA_CHUNK[] dataChunks) { var pins = new List(); 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(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 pins, ArraySegment buffer) + private static void SetDataChunk(HttpApiTypes.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, List pins, ArraySegment 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; } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs index 28a890e51a..32a90e4b51 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/RequestProcessing/ResponseStreamAsyncResult.cs @@ -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 _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 segment) + private static void SetDataChunk(HttpApiTypes.HTTP_DATA_CHUNK[] chunks, ref int chunkIndex, object[] objectsToPin, ref int pinIndex, ArraySegment 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)); } } } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs b/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs index aa61ef85a4..e9bb62dfce 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/TimeoutManager.cs @@ -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(); + Marshal.SizeOf(); 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); } diff --git a/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs b/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs index 1a74402a9f..4286870d71 100644 --- a/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs +++ b/src/Microsoft.AspNetCore.Server.HttpSys/UrlPrefix.cs @@ -3,6 +3,7 @@ using System; using System.Globalization; +using Microsoft.AspNetCore.HttpSys.Internal; namespace Microsoft.AspNetCore.Server.HttpSys { diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs index 7232d97fe4..5fc93e69e7 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/MessagePumpTests.cs @@ -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; diff --git a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs index 56f8989859..38ec6d0cb2 100644 --- a/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs +++ b/test/Microsoft.AspNetCore.Server.HttpSys.FunctionalTests/RequestTests.cs @@ -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;