1168 lines
51 KiB
C#
1168 lines
51 KiB
C#
// Copyright (c) Microsoft Open Technologies, Inc.
|
|
// All Rights Reserved
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
|
|
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
|
|
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
|
|
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
|
|
// NON-INFRINGEMENT.
|
|
// See the Apache 2 License for the specific language governing
|
|
// permissions and limitations under the License.
|
|
|
|
//------------------------------------------------------------------------------
|
|
// <copyright file="UnsafeNativeMethods.cs" company="Microsoft">
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// </copyright>
|
|
//------------------------------------------------------------------------------
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace Microsoft.Net.Server
|
|
{
|
|
internal static class UnsafeNclNativeMethods
|
|
{
|
|
private const string KERNEL32 = "kernel32.dll";
|
|
private const string SECUR32 = "secur32.dll";
|
|
private const string HTTPAPI = "httpapi.dll";
|
|
|
|
// CONSIDER: Make this an enum, requires changing a lot of types from uint to ErrorCodes.
|
|
internal static class ErrorCodes
|
|
{
|
|
internal const uint ERROR_SUCCESS = 0;
|
|
internal const uint ERROR_HANDLE_EOF = 38;
|
|
internal const uint ERROR_NOT_SUPPORTED = 50;
|
|
internal const uint ERROR_INVALID_PARAMETER = 87;
|
|
internal const uint ERROR_ALREADY_EXISTS = 183;
|
|
internal const uint ERROR_MORE_DATA = 234;
|
|
internal const uint ERROR_OPERATION_ABORTED = 995;
|
|
internal const uint ERROR_IO_PENDING = 997;
|
|
internal const uint ERROR_NOT_FOUND = 1168;
|
|
internal const uint ERROR_CONNECTION_INVALID = 1229;
|
|
}
|
|
|
|
[DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint GetCurrentThreadId();
|
|
|
|
[DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static unsafe extern uint CancelIoEx(SafeHandle handle, SafeNativeOverlapped overlapped);
|
|
|
|
[DllImport(KERNEL32, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static unsafe extern bool SetFileCompletionNotificationModes(SafeHandle handle, FileCompletionNotificationModes modes);
|
|
|
|
[Flags]
|
|
internal enum FileCompletionNotificationModes : byte
|
|
{
|
|
None = 0,
|
|
SkipCompletionPortOnSuccess = 1,
|
|
SkipSetEventOnHandle = 2
|
|
}
|
|
|
|
internal static class SafeNetHandles
|
|
{
|
|
[DllImport(SECUR32, ExactSpelling = true, SetLastError = true)]
|
|
internal static extern int FreeContextBuffer(
|
|
[In] IntPtr contextBuffer);
|
|
|
|
[DllImport(SECUR32, ExactSpelling = true, SetLastError = true)]
|
|
internal static unsafe extern int QueryContextAttributesW(
|
|
ref SSPIHandle contextHandle,
|
|
[In] ContextAttribute attribute,
|
|
[In] void* buffer);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
|
|
internal static extern unsafe uint HttpCreateRequestQueue(HttpApi.HTTPAPI_VERSION version, string pName,
|
|
Microsoft.Net.Server.UnsafeNclNativeMethods.SECURITY_ATTRIBUTES pSecurityAttributes, uint flags, out HttpRequestQueueV2Handle pReqQueueHandle);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern unsafe uint HttpCloseRequestQueue(IntPtr pReqQueueHandle);
|
|
|
|
[DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)]
|
|
internal static extern bool CloseHandle(IntPtr handle);
|
|
|
|
[DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)]
|
|
internal static extern SafeLocalFree LocalAlloc(int uFlags, UIntPtr sizetdwBytes);
|
|
|
|
[DllImport(KERNEL32, EntryPoint = "LocalAlloc", SetLastError = true)]
|
|
internal static extern SafeLocalFreeChannelBinding LocalAllocChannelBinding(int uFlags, UIntPtr sizetdwBytes);
|
|
|
|
[DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)]
|
|
internal static extern IntPtr LocalFree(IntPtr handle);
|
|
|
|
[DllImport(KERNEL32, ExactSpelling = true, CharSet = CharSet.Unicode, SetLastError = true)]
|
|
internal static extern unsafe SafeLoadLibrary LoadLibraryExW([In] string lpwLibFileName, [In] void* hFile, [In] uint dwFlags);
|
|
|
|
[DllImport(KERNEL32, ExactSpelling = true, SetLastError = true)]
|
|
internal static extern unsafe bool FreeLibrary([In] IntPtr hModule);
|
|
}
|
|
|
|
internal static unsafe class HttpApi
|
|
{
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpInitialize(HTTPAPI_VERSION version, uint flags, void* pReserved);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpReceiveRequestEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, IntPtr pEntityBuffer, uint entityBufferLength, out uint bytesReturned, SafeNativeOverlapped pOverlapped);
|
|
|
|
[DllImport(HTTPAPI, EntryPoint = "HttpReceiveRequestEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpReceiveRequestEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, void* pEntityBuffer, uint entityBufferLength, out uint bytesReturned, [In] SafeHandle pOverlapped);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, HTTP_SSL_CLIENT_CERT_INFO* pSslClientCertInfo, uint sslClientCertInfoSize, uint* pBytesReceived, SafeNativeOverlapped pOverlapped);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpReceiveClientCertificate(SafeHandle requestQueueHandle, ulong connectionId, uint flags, byte* pSslClientCertInfo, uint sslClientCertInfoSize, uint* pBytesReceived, SafeNativeOverlapped pOverlapped);
|
|
|
|
[SuppressMessage("Microsoft.Interoperability", "CA1415:DeclarePInvokesCorrectly", Justification = "NativeOverlapped is now wrapped by SafeNativeOverlapped")]
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpReceiveHttpRequest(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_REQUEST* pRequestBuffer, uint requestBufferLength, uint* pBytesReturned, SafeNativeOverlapped pOverlapped);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpSendHttpResponse(SafeHandle requestQueueHandle, ulong requestId, uint flags, HTTP_RESPONSE_V2* pHttpResponse, void* pCachePolicy, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpSendResponseEntityBody(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, HTTP_DATA_CHUNK* pEntityChunks, uint* pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeNativeOverlapped pOverlapped, IntPtr pLogData);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpCancelHttpRequest(SafeHandle requestQueueHandle, ulong requestId, IntPtr pOverlapped);
|
|
|
|
[DllImport(HTTPAPI, EntryPoint = "HttpSendResponseEntityBody", ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpSendResponseEntityBody2(SafeHandle requestQueueHandle, ulong requestId, uint flags, ushort entityChunkCount, IntPtr pEntityChunks, out uint pBytesSent, SafeLocalFree pRequestBuffer, uint requestBufferLength, SafeHandle pOverlapped, IntPtr pLogData);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpWaitForDisconnect(SafeHandle requestQueueHandle, ulong connectionId, SafeNativeOverlapped pOverlapped);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpCreateServerSession(HTTPAPI_VERSION version, ulong* serverSessionId, uint reserved);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpCreateUrlGroup(ulong serverSessionId, ulong* urlGroupId, uint reserved);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
|
|
internal static extern uint HttpAddUrlToUrlGroup(ulong urlGroupId, string pFullyQualifiedUrl, ulong context, uint pReserved);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpSetUrlGroupProperty(ulong urlGroupId, HTTP_SERVER_PROPERTY serverProperty, IntPtr pPropertyInfo, uint propertyInfoLength);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
|
|
internal static extern uint HttpRemoveUrlFromUrlGroup(ulong urlGroupId, string pFullyQualifiedUrl, uint flags);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpCloseServerSession(ulong serverSessionId);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpCloseUrlGroup(ulong urlGroupId);
|
|
|
|
[DllImport(HTTPAPI, ExactSpelling = true, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
|
|
internal static extern uint HttpSetRequestQueueProperty(SafeHandle requestQueueHandle, HTTP_SERVER_PROPERTY serverProperty, IntPtr pPropertyInfo, uint propertyInfoLength, uint reserved, IntPtr pReserved);
|
|
|
|
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,
|
|
}
|
|
|
|
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
|
|
{
|
|
[SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used natively")]
|
|
[FieldOffset(0)]
|
|
internal HTTP_DATA_CHUNK_TYPE DataChunkType;
|
|
|
|
[FieldOffset(8)]
|
|
internal FromMemory fromMemory;
|
|
|
|
[FieldOffset(8)]
|
|
internal FromFileHandle fromFile;
|
|
}
|
|
|
|
[SuppressMessage("Microsoft.Design", "CA1049:TypesThatOwnNativeResourcesShouldBeDisposable",
|
|
Justification = "This type does not own the native buffer")]
|
|
[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;
|
|
}
|
|
|
|
[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
|
|
}
|
|
|
|
[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_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;
|
|
}
|
|
|
|
// 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,
|
|
}
|
|
|
|
private const int HttpHeaderRequestMaximum = (int)HttpSysRequestHeader.UserAgent + 1;
|
|
private const int HttpHeaderResponseMaximum = (int)HttpSysResponseHeader.WwwAuthenticate + 1;
|
|
|
|
internal static class HTTP_REQUEST_HEADER_ID
|
|
{
|
|
internal static string ToString(int position)
|
|
{
|
|
return _strings[position];
|
|
}
|
|
|
|
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",
|
|
"Accept-Charset",
|
|
"Accept-Encoding",
|
|
"Accept-Language",
|
|
"Authorization",
|
|
"Cookie",
|
|
"Expect",
|
|
"From",
|
|
"Host",
|
|
"If-Match",
|
|
|
|
"If-Modified-Since",
|
|
"If-None-Match",
|
|
"If-Range",
|
|
"If-Unmodified-Since",
|
|
"Max-Forwards",
|
|
"Proxy-Authorization",
|
|
"Referer",
|
|
"Range",
|
|
"Te",
|
|
"Translate",
|
|
"User-Agent",
|
|
};
|
|
}
|
|
|
|
internal static class HTTP_RESPONSE_HEADER_ID
|
|
{
|
|
private static string[] _strings =
|
|
{
|
|
"Cache-Control",
|
|
"Connection",
|
|
"Date",
|
|
"Keep-Alive",
|
|
"Pragma",
|
|
"Trailer",
|
|
"Transfer-Encoding",
|
|
"Upgrade",
|
|
"Via",
|
|
"Warning",
|
|
|
|
"Allow",
|
|
"Content-Length",
|
|
"Content-Type",
|
|
"Content-Encoding",
|
|
"Content-Language",
|
|
"Content-Location",
|
|
"Content-MD5",
|
|
"Content-Range",
|
|
"Expires",
|
|
"Last-Modified",
|
|
|
|
"Accept-Ranges",
|
|
"Age",
|
|
"ETag",
|
|
"Location",
|
|
"Proxy-Authenticate",
|
|
"Retry-After",
|
|
"Server",
|
|
"Set-Cookie",
|
|
"Vary",
|
|
"WWW-Authenticate",
|
|
};
|
|
|
|
private static Dictionary<string, int> _lookupTable = CreateLookupTable();
|
|
|
|
private static Dictionary<string, int> CreateLookupTable()
|
|
{
|
|
Dictionary<string, int> lookupTable = new Dictionary<string, int>((int)Enum.HttpHeaderResponseMaximum, StringComparer.OrdinalIgnoreCase);
|
|
for (int i = 0; i < (int)Enum.HttpHeaderResponseMaximum; i++)
|
|
{
|
|
lookupTable.Add(_strings[i], i);
|
|
}
|
|
return lookupTable;
|
|
}
|
|
|
|
internal static int IndexOfKnownHeader(string HeaderName)
|
|
{
|
|
int index;
|
|
return _lookupTable.TryGetValue(HeaderName, out index) ? index : -1;
|
|
}
|
|
|
|
internal static string ToString(int position)
|
|
{
|
|
return _strings[position];
|
|
}
|
|
|
|
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;
|
|
|
|
// This property is used by HttpListener to pass the version structure to the native layer in API
|
|
// calls.
|
|
|
|
internal static HTTPAPI_VERSION Version
|
|
{
|
|
get
|
|
{
|
|
return version;
|
|
}
|
|
}
|
|
|
|
// This property is used by HttpListener to get the Api version in use so that it uses appropriate
|
|
// Http APIs.
|
|
|
|
internal static HTTP_API_VERSION ApiVersion
|
|
{
|
|
get
|
|
{
|
|
if (version.HttpApiMajorVersion == 2 && version.HttpApiMinorVersion == 0)
|
|
{
|
|
return HTTP_API_VERSION.Version20;
|
|
}
|
|
else if (version.HttpApiMajorVersion == 1 && version.HttpApiMinorVersion == 0)
|
|
{
|
|
return HTTP_API_VERSION.Version10;
|
|
}
|
|
else
|
|
{
|
|
return HTTP_API_VERSION.Invalid;
|
|
}
|
|
}
|
|
}
|
|
|
|
static HttpApi()
|
|
{
|
|
InitHttpApi(2, 0);
|
|
}
|
|
|
|
private static void InitHttpApi(ushort majorVersion, ushort minorVersion)
|
|
{
|
|
version.HttpApiMajorVersion = majorVersion;
|
|
version.HttpApiMinorVersion = minorVersion;
|
|
|
|
// For pre-Win7 OS versions, we need to check whether http.sys contains the CBT patch.
|
|
// We do so by passing HTTP_INITIALIZE_CBT flag to HttpInitialize. If the flag is not
|
|
// supported, http.sys is not patched. Note that http.sys will return invalid parameter
|
|
// also on Win7, even though it shipped with CBT support. Therefore we must not pass
|
|
// the flag on Win7 and later.
|
|
uint statusCode = ErrorCodes.ERROR_SUCCESS;
|
|
|
|
// on Win7 and later, we don't pass the CBT flag. CBT is always supported.
|
|
statusCode = HttpApi.HttpInitialize(version, (uint)HTTP_FLAGS.HTTP_INITIALIZE_SERVER, null);
|
|
|
|
supported = statusCode == ErrorCodes.ERROR_SUCCESS;
|
|
}
|
|
|
|
private static volatile bool supported;
|
|
internal static bool Supported
|
|
{
|
|
get
|
|
{
|
|
return supported;
|
|
}
|
|
}
|
|
|
|
// Server API
|
|
|
|
internal static void GetUnknownHeaders(IDictionary<string, string[]> unknownHeaders, byte[] memoryBlob, IntPtr originalAddress)
|
|
{
|
|
// Return value.
|
|
fixed (byte* pMemoryBlob = memoryBlob)
|
|
{
|
|
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
|
|
long fixup = pMemoryBlob - (byte*)originalAddress;
|
|
int index;
|
|
|
|
// unknown headers
|
|
if (request->Headers.UnknownHeaderCount != 0)
|
|
{
|
|
HTTP_UNKNOWN_HEADER* pUnknownHeader = (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)
|
|
{
|
|
string 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 seperated string,
|
|
// so we can just call Set.
|
|
unknownHeaders[headerName] = new[] { headerValue };
|
|
}
|
|
pUnknownHeader++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private static string GetKnownHeader(HTTP_REQUEST* request, long fixup, int headerIndex)
|
|
{
|
|
string header = null;
|
|
|
|
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)
|
|
{
|
|
header = HeaderEncoding.GetString(pKnownHeader->pRawValue + fixup, pKnownHeader->RawValueLength);
|
|
}
|
|
|
|
return header;
|
|
}
|
|
|
|
internal static string GetKnownHeader(byte[] memoryBlob, IntPtr originalAddress, int headerIndex)
|
|
{
|
|
fixed (byte* pMemoryBlob = memoryBlob)
|
|
{
|
|
return GetKnownHeader((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress, headerIndex);
|
|
}
|
|
}
|
|
|
|
private static unsafe string GetVerb(HTTP_REQUEST* request, long fixup)
|
|
{
|
|
string verb = null;
|
|
|
|
if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnknown && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum)
|
|
{
|
|
verb = HttpVerbs[(int)request->Verb];
|
|
}
|
|
else if (request->Verb == HTTP_VERB.HttpVerbUnknown && request->pUnknownVerb != null)
|
|
{
|
|
verb = HeaderEncoding.GetString(request->pUnknownVerb + fixup, request->UnknownVerbLength);
|
|
}
|
|
|
|
return verb;
|
|
}
|
|
|
|
internal static unsafe string GetVerb(byte[] memoryBlob, IntPtr originalAddress)
|
|
{
|
|
fixed (byte* pMemoryBlob = memoryBlob)
|
|
{
|
|
return GetVerb((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress);
|
|
}
|
|
}
|
|
|
|
internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, IntPtr originalAddress)
|
|
{
|
|
// Return value.
|
|
HTTP_VERB verb = HTTP_VERB.HttpVerbUnknown;
|
|
fixed (byte* pMemoryBlob = memoryBlob)
|
|
{
|
|
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
|
|
if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum)
|
|
{
|
|
verb = request->Verb;
|
|
}
|
|
}
|
|
|
|
return verb;
|
|
}
|
|
|
|
internal static uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size)
|
|
{
|
|
// Return value.
|
|
uint dataRead = 0;
|
|
fixed (byte* pMemoryBlob = memoryBlob)
|
|
{
|
|
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
|
|
long fixup = pMemoryBlob - (byte*)originalAddress;
|
|
|
|
if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1)
|
|
{
|
|
HTTP_DATA_CHUNK* pDataChunk = (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;
|
|
}
|
|
|
|
internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, IntPtr originalAddress)
|
|
{
|
|
fixed (byte* pMemoryBlob = memoryBlob)
|
|
{
|
|
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
|
|
return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pRemoteAddress);
|
|
}
|
|
}
|
|
|
|
internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, IntPtr originalAddress)
|
|
{
|
|
fixed (byte* pMemoryBlob = memoryBlob)
|
|
{
|
|
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
|
|
return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pLocalAddress);
|
|
}
|
|
}
|
|
|
|
internal static SocketAddress GetEndPoint(byte[] memoryBlob, IntPtr originalAddress, byte* source)
|
|
{
|
|
fixed (byte* pMemoryBlob = memoryBlob)
|
|
{
|
|
IntPtr address = source != null ?
|
|
(IntPtr)(pMemoryBlob - (byte*)originalAddress + source) : IntPtr.Zero;
|
|
return CopyOutAddress(address);
|
|
}
|
|
}
|
|
|
|
private static SocketAddress CopyOutAddress(IntPtr address)
|
|
{
|
|
if (address != IntPtr.Zero)
|
|
{
|
|
ushort addressFamily = *((ushort*)address);
|
|
if (addressFamily == (ushort)AddressFamily.InterNetwork)
|
|
{
|
|
SocketAddress 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)
|
|
{
|
|
SocketAddress 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;
|
|
}
|
|
}
|
|
|
|
// DACL related stuff
|
|
|
|
[SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses", Justification = "Instantiated natively")]
|
|
[SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
|
|
Justification = "Does not own the resource.")]
|
|
[StructLayout(LayoutKind.Sequential)]
|
|
internal class SECURITY_ATTRIBUTES
|
|
{
|
|
public int nLength = 12;
|
|
public SafeLocalMemHandle lpSecurityDescriptor = new SafeLocalMemHandle(IntPtr.Zero, false);
|
|
public bool bInheritHandle = false;
|
|
}
|
|
}
|
|
}
|