diff --git a/src/Common/src/Interop/Windows/HttpApi/Interop.HttpApi.cs b/src/Common/src/Interop/Windows/HttpApi/Interop.HttpApi.cs index a4654b51ab44..38d8491d5aab 100644 --- a/src/Common/src/Interop/Windows/HttpApi/Interop.HttpApi.cs +++ b/src/Common/src/Interop/Windows/HttpApi/Interop.HttpApi.cs @@ -786,75 +786,69 @@ internal static unsafe string GetVerb(HTTP_REQUEST* request) return GetVerb(request, 0); } - internal static unsafe string GetVerb(byte[] memoryBlob, IntPtr originalAddress) + internal static unsafe string GetVerb(IntPtr memoryBlob, IntPtr originalAddress) { - fixed (byte* pMemoryBlob = memoryBlob) - { - return GetVerb((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress); - } + return GetVerb((HTTP_REQUEST*)memoryBlob.ToPointer(), (byte*)memoryBlob - (byte*)originalAddress); } // Server API - internal static unsafe WebHeaderCollection GetHeaders(byte[] memoryBlob, IntPtr originalAddress) + internal static unsafe WebHeaderCollection GetHeaders(IntPtr memoryBlob, IntPtr originalAddress) { NetEventSource.Enter(null); // Return value. WebHeaderCollection headerCollection = new WebHeaderCollection(); - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; - long fixup = pMemoryBlob - (byte*)originalAddress; - int index; + byte* pMemoryBlob = (byte*)memoryBlob; + HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + long fixup = pMemoryBlob - (byte*)originalAddress; + int index; - // unknown headers - if (request->Headers.UnknownHeaderCount != 0) + // 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++) { - 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) { - // 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 = new string(pUnknownHeader->pName + fixup, 0, pUnknownHeader->NameLength); + string headerValue; + if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) { - string headerName = new string(pUnknownHeader->pName + fixup, 0, pUnknownHeader->NameLength); - string headerValue; - if (pUnknownHeader->pRawValue != null && pUnknownHeader->RawValueLength > 0) - { - headerValue = new string(pUnknownHeader->pRawValue + fixup, 0, pUnknownHeader->RawValueLength); - } - else - { - headerValue = string.Empty; - } - headerCollection.Add(headerName, headerValue); + headerValue = new string(pUnknownHeader->pRawValue + fixup, 0, pUnknownHeader->RawValueLength); } - pUnknownHeader++; + else + { + headerValue = string.Empty; + } + headerCollection.Add(headerName, headerValue); } + pUnknownHeader++; } + } - // known headers - HTTP_KNOWN_HEADER* pKnownHeader = &request->Headers.KnownHeaders; - for (index = 0; index < HttpHeaderRequestMaximum; index++) + // known headers + HTTP_KNOWN_HEADER* pKnownHeader = &request->Headers.KnownHeaders; + for (index = 0; index < HttpHeaderRequestMaximum; index++) + { + // For known headers, when header value is empty, RawValueLength will be 0 and + // pRawValue will point to empty string ("\0") + if (pKnownHeader->pRawValue != null) { - // For known headers, when header value is empty, RawValueLength will be 0 and - // pRawValue will point to empty string ("\0") - if (pKnownHeader->pRawValue != null) - { - string headerValue = new string(pKnownHeader->pRawValue + fixup, 0, pKnownHeader->RawValueLength); - headerCollection.Add(HTTP_REQUEST_HEADER_ID.ToString(index), headerValue); - } - pKnownHeader++; + string headerValue = new string(pKnownHeader->pRawValue + fixup, 0, pKnownHeader->RawValueLength); + headerCollection.Add(HTTP_REQUEST_HEADER_ID.ToString(index), headerValue); } + pKnownHeader++; } NetEventSource.Exit(null); return headerCollection; } - - internal static unsafe uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) + internal static unsafe uint GetChunks(IntPtr memoryBlob, IntPtr originalAddress, ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size) { if (NetEventSource.IsEnabled) { @@ -863,53 +857,51 @@ internal static unsafe uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, // Return value. uint dataRead = 0; - fixed (byte* pMemoryBlob = memoryBlob) + byte* pMemoryBlob = (byte*)memoryBlob; + HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + long fixup = pMemoryBlob - (byte*)originalAddress; + + if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; - long fixup = pMemoryBlob - (byte*)originalAddress; + HTTP_DATA_CHUNK* pDataChunk = (HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]); - if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1) + fixed (byte* pReadBuffer = buffer) { - HTTP_DATA_CHUNK* pDataChunk = (HTTP_DATA_CHUNK*)(fixup + (byte*)&request->pEntityChunks[dataChunkIndex]); + byte* pTo = &pReadBuffer[offset]; - fixed (byte* pReadBuffer = buffer) + while (dataChunkIndex < request->EntityChunkCount && dataRead < size) { - byte* pTo = &pReadBuffer[offset]; - - while (dataChunkIndex < request->EntityChunkCount && dataRead < size) + if (dataChunkOffset >= pDataChunk->BufferLength) + { + dataChunkOffset = 0; + dataChunkIndex++; + pDataChunk++; + } + else { - if (dataChunkOffset >= pDataChunk->BufferLength) + byte* pFrom = pDataChunk->pBuffer + dataChunkOffset + fixup; + + uint bytesToRead = pDataChunk->BufferLength - (uint)dataChunkOffset; + if (bytesToRead > (uint)size) { - dataChunkOffset = 0; - dataChunkIndex++; - pDataChunk++; + bytesToRead = (uint)size; } - else + for (uint i = 0; i < bytesToRead; i++) { - byte* pFrom = pDataChunk->pBuffer + dataChunkOffset + fixup; - - uint bytesToRead = pDataChunk->BufferLength - (uint)dataChunkOffset; - if (bytesToRead > (uint)size) - { - bytesToRead = (uint)size; - } - for (uint i = 0; i < bytesToRead; i++) - { - *(pTo++) = *(pFrom++); - } - dataRead += bytesToRead; - dataChunkOffset += bytesToRead; + *(pTo++) = *(pFrom++); } + dataRead += bytesToRead; + dataChunkOffset += bytesToRead; } } } - //we're finished. - if (dataChunkIndex == request->EntityChunkCount) - { - dataChunkIndex = -1; - } } - + //we're finished. + if (dataChunkIndex == request->EntityChunkCount) + { + dataChunkIndex = -1; + } + if (NetEventSource.IsEnabled) { NetEventSource.Exit(null); @@ -917,38 +909,34 @@ internal static unsafe uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, return dataRead; } - internal static unsafe HTTP_VERB GetKnownVerb(byte[] memoryBlob, IntPtr originalAddress) + internal static unsafe HTTP_VERB GetKnownVerb(IntPtr memoryBlob, IntPtr originalAddress) { NetEventSource.Enter(null); // Return value. HTTP_VERB verb = HTTP_VERB.HttpVerbUnknown; - fixed (byte* pMemoryBlob = memoryBlob) + + HTTP_REQUEST* request = (HTTP_REQUEST*)memoryBlob.ToPointer(); + if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; - if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum) - { - verb = request->Verb; - } + verb = request->Verb; } NetEventSource.Exit(null); return verb; } - internal static unsafe IPEndPoint GetRemoteEndPoint(byte[] memoryBlob, IntPtr originalAddress) + internal static unsafe IPEndPoint GetRemoteEndPoint(IntPtr memoryBlob, IntPtr originalAddress) { if (NetEventSource.IsEnabled) NetEventSource.Enter(null); SocketAddress v4address = new SocketAddress(AddressFamily.InterNetwork, IPv4AddressSize); SocketAddress v6address = new SocketAddress(AddressFamily.InterNetworkV6, IPv6AddressSize); - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; - IntPtr address = request->Address.pRemoteAddress != null ? (IntPtr)(pMemoryBlob - (byte*)originalAddress + (byte*)request->Address.pRemoteAddress) : IntPtr.Zero; - CopyOutAddress(address, ref v4address, ref v6address); - } + byte* pMemoryBlob = (byte*)memoryBlob; + HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + IntPtr address = request->Address.pRemoteAddress != null ? (IntPtr)(pMemoryBlob - (byte*)originalAddress + (byte*)request->Address.pRemoteAddress) : IntPtr.Zero; + CopyOutAddress(address, ref v4address, ref v6address); IPEndPoint endpoint = null; if (v4address != null) @@ -964,19 +952,17 @@ internal static unsafe IPEndPoint GetRemoteEndPoint(byte[] memoryBlob, IntPtr or return endpoint; } - internal static unsafe IPEndPoint GetLocalEndPoint(byte[] memoryBlob, IntPtr originalAddress) + internal static unsafe IPEndPoint GetLocalEndPoint(IntPtr memoryBlob, IntPtr originalAddress) { if (NetEventSource.IsEnabled) NetEventSource.Enter(null); SocketAddress v4address = new SocketAddress(AddressFamily.InterNetwork, IPv4AddressSize); SocketAddress v6address = new SocketAddress(AddressFamily.InterNetworkV6, IPv6AddressSize); - fixed (byte* pMemoryBlob = memoryBlob) - { - HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; - IntPtr address = request->Address.pLocalAddress != null ? (IntPtr)(pMemoryBlob - (byte*)originalAddress + (byte*)request->Address.pLocalAddress) : IntPtr.Zero; - CopyOutAddress(address, ref v4address, ref v6address); - } + byte* pMemoryBlob = (byte*)memoryBlob; + HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob; + IntPtr address = request->Address.pLocalAddress != null ? (IntPtr)(pMemoryBlob - (byte*)originalAddress + (byte*)request->Address.pLocalAddress) : IntPtr.Zero; + CopyOutAddress(address, ref v4address, ref v6address); IPEndPoint endpoint = null; if (v4address != null) diff --git a/src/System.Net.HttpListener/src/System/Net/Windows/AsyncRequestContext.cs b/src/System.Net.HttpListener/src/System/Net/Windows/AsyncRequestContext.cs index b2d2d7258f2c..138db12aff03 100644 --- a/src/System.Net.HttpListener/src/System/Net/Windows/AsyncRequestContext.cs +++ b/src/System.Net.HttpListener/src/System/Net/Windows/AsyncRequestContext.cs @@ -38,7 +38,7 @@ internal AsyncRequestContext(ThreadPoolBoundHandle boundHandle, ListenerAsyncRes private Interop.HttpApi.HTTP_REQUEST* Allocate(ThreadPoolBoundHandle boundHandle, uint size) { - uint newSize = size != 0 ? size : RequestBuffer == null ? 4096 : Size; + uint newSize = size != 0 ? size : RequestBuffer == IntPtr.Zero ? 4096 : Size; if (_nativeOverlapped != null) { #if DEBUG @@ -57,7 +57,7 @@ internal AsyncRequestContext(ThreadPoolBoundHandle boundHandle, ListenerAsyncRes _boundHandle = boundHandle; _nativeOverlapped = boundHandle.AllocateNativeOverlapped(ListenerAsyncResult.IOCallback, state: _result, pinData: RequestBuffer); - return (Interop.HttpApi.HTTP_REQUEST*)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); + return (Interop.HttpApi.HTTP_REQUEST*)RequestBuffer.ToPointer(); } internal void Reset(ThreadPoolBoundHandle boundHandle, ulong requestId, uint size) diff --git a/src/System.Net.HttpListener/src/System/Net/Windows/HttpListenerRequest.Windows.cs b/src/System.Net.HttpListener/src/System/Net/Windows/HttpListenerRequest.Windows.cs index b947bf5b304c..177f8222b828 100644 --- a/src/System.Net.HttpListener/src/System/Net/Windows/HttpListenerRequest.Windows.cs +++ b/src/System.Net.HttpListener/src/System/Net/Windows/HttpListenerRequest.Windows.cs @@ -109,7 +109,7 @@ internal HttpListenerRequest(HttpListenerContext httpContext, RequestContextBase // Note: RequestBuffer may get moved in memory. If you dereference a pointer from inside the RequestBuffer, // you must use 'OriginalBlobAddress' below to adjust the location of the pointer to match the location of // RequestBuffer. - internal byte[] RequestBuffer + internal IntPtr RequestBuffer { get { diff --git a/src/System.Net.HttpListener/src/System/Net/Windows/RequestContextBase.cs b/src/System.Net.HttpListener/src/System/Net/Windows/RequestContextBase.cs index 6c73b70fa5ae..6f7127931846 100644 --- a/src/System.Net.HttpListener/src/System/Net/Windows/RequestContextBase.cs +++ b/src/System.Net.HttpListener/src/System/Net/Windows/RequestContextBase.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Diagnostics; +using System.Runtime.InteropServices; namespace System.Net { @@ -10,7 +11,8 @@ internal abstract unsafe class RequestContextBase : IDisposable { private Interop.HttpApi.HTTP_REQUEST* _memoryBlob; private Interop.HttpApi.HTTP_REQUEST* _originalBlobAddress; - private byte[] _backingBuffer; + private IntPtr _backingBuffer = IntPtr.Zero; + private int _backingBufferLength = 0; // Must call this from derived class' constructors. protected void BaseConstruction(Interop.HttpApi.HTTP_REQUEST* requestBlob) @@ -29,7 +31,7 @@ protected void BaseConstruction(Interop.HttpApi.HTTP_REQUEST* requestBlob) // before an object (HttpListenerRequest) which closes the RequestContext on demand is returned to the application. internal void ReleasePins() { - Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice."); + Debug.Assert(_memoryBlob != null || _backingBuffer == IntPtr.Zero, "RequestContextBase::ReleasePins()|ReleasePins() called twice."); _originalBlobAddress = _memoryBlob; UnsetBlob(); OnReleasePins(); @@ -48,7 +50,14 @@ public void Dispose() Dispose(true); } - protected virtual void Dispose(bool disposing) { } + protected virtual void Dispose(bool disposing) + { + if (_backingBuffer != IntPtr.Zero) + { + Marshal.FreeHGlobal(_backingBuffer); + _backingBuffer = IntPtr.Zero; + } + } ~RequestContextBase() { @@ -59,12 +68,12 @@ internal Interop.HttpApi.HTTP_REQUEST* RequestBlob { get { - Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::Dispose()|RequestBlob requested after ReleasePins()."); + Debug.Assert(_memoryBlob != null || _backingBuffer == IntPtr.Zero, "RequestContextBase::Dispose()|RequestBlob requested after ReleasePins()."); return _memoryBlob; } } - internal byte[] RequestBuffer + internal IntPtr RequestBuffer { get { @@ -76,7 +85,7 @@ internal uint Size { get { - return (uint)_backingBuffer.Length; + return (uint)_backingBufferLength; } } @@ -91,7 +100,7 @@ internal IntPtr OriginalBlobAddress protected void SetBlob(Interop.HttpApi.HTTP_REQUEST* requestBlob) { - Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::Dispose()|SetBlob() called after ReleasePins()."); + Debug.Assert(_memoryBlob != null || _backingBuffer == IntPtr.Zero, "RequestContextBase::Dispose()|SetBlob() called after ReleasePins()."); if (requestBlob == null) { UnsetBlob(); @@ -116,7 +125,16 @@ protected void UnsetBlob() protected void SetBuffer(int size) { - _backingBuffer = size == 0 ? null : new byte[size]; + if (_backingBuffer != IntPtr.Zero) + { + Marshal.FreeHGlobal(_backingBuffer); + } + + _backingBuffer = size == 0 ? IntPtr.Zero : Marshal.AllocHGlobal(size); + _backingBufferLength = size; + + // Zero out the contents of the buffer. + new Span(_backingBuffer.ToPointer(), size).Fill(0); } } } diff --git a/src/System.Net.HttpListener/src/System/Net/Windows/SyncRequestContext.cs b/src/System.Net.HttpListener/src/System/Net/Windows/SyncRequestContext.cs index f7ba1e4f1b54..b140ab1564f0 100644 --- a/src/System.Net.HttpListener/src/System/Net/Windows/SyncRequestContext.cs +++ b/src/System.Net.HttpListener/src/System/Net/Windows/SyncRequestContext.cs @@ -9,30 +9,20 @@ namespace System.Net { internal unsafe class SyncRequestContext : RequestContextBase { - private GCHandle _pinnedHandle; - internal SyncRequestContext(int size) { BaseConstruction(Allocate(size)); } - private Interop.HttpApi.HTTP_REQUEST* Allocate(int size) + private Interop.HttpApi.HTTP_REQUEST* Allocate(int newSize) { - if (_pinnedHandle.IsAllocated) - { - if (RequestBuffer.Length == size) - { - return RequestBlob; - } - _pinnedHandle.Free(); - } - SetBuffer(size); - if (RequestBuffer == null) + if (Size > 0 && Size == newSize) { - return null; + return RequestBlob; } - _pinnedHandle = GCHandle.Alloc(RequestBuffer, GCHandleType.Pinned); - return (Interop.HttpApi.HTTP_REQUEST*)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0); + SetBuffer(newSize); + + return RequestBuffer == IntPtr.Zero ? null : (Interop.HttpApi.HTTP_REQUEST*)RequestBuffer.ToPointer(); } internal void Reset(int size) @@ -40,25 +30,6 @@ internal void Reset(int size) SetBlob(Allocate(size)); } - protected override void OnReleasePins() - { - if (_pinnedHandle.IsAllocated) - { - _pinnedHandle.Free(); - } - } - - protected override void Dispose(bool disposing) - { - if (_pinnedHandle.IsAllocated) - { - Debug.Assert(!disposing, "AsyncRequestContext::Dispose()|Must call ReleasePins() before calling Dispose()."); - if (!Environment.HasShutdownStarted || disposing) - { - _pinnedHandle.Free(); - } - } - base.Dispose(disposing); - } + protected override void OnReleasePins() { } } }