Force 8-byte alignment on HTTP_REQUEST buffer

Addresses #126
This commit is contained in:
moozzyk 2016-06-15 10:46:24 -07:00
parent 10df99de67
commit f63e53b597
6 changed files with 77 additions and 45 deletions

View File

@ -1049,12 +1049,13 @@ namespace Microsoft.Net.Http.Server
// Server API
internal static void GetUnknownHeaders(IDictionary<string, StringValues> unknownHeaders, byte[] memoryBlob, IntPtr originalAddress)
internal static void GetUnknownHeaders(IDictionary<string, StringValues> unknownHeaders, byte[] memoryBlob,
int requestOffset, IntPtr originalAddress)
{
// Return value.
fixed (byte* pMemoryBlob = memoryBlob)
{
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
long fixup = pMemoryBlob - (byte*)originalAddress;
int index;
@ -1064,7 +1065,7 @@ namespace Microsoft.Net.Http.Server
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
// For unknown headers, when header value is empty, RawValueLength will be 0 and
// pRawValue will be null.
if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0)
{
@ -1093,7 +1094,7 @@ namespace Microsoft.Net.Http.Server
string header = null;
HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex;
// For known headers, when header value is empty, RawValueLength will be 0 and
// For known headers, when header value is empty, RawValueLength will be 0 and
// pRawValue will point to empty string ("\0")
if (pKnownHeader->pRawValue != null)
{
@ -1103,11 +1104,12 @@ namespace Microsoft.Net.Http.Server
return header;
}
internal static string GetKnownHeader(byte[] memoryBlob, IntPtr originalAddress, int headerIndex)
internal static string GetKnownHeader(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, int headerIndex)
{
fixed (byte* pMemoryBlob = memoryBlob)
{
return GetKnownHeader((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress, headerIndex);
return GetKnownHeader(
(HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress, headerIndex);
}
}
@ -1127,21 +1129,21 @@ namespace Microsoft.Net.Http.Server
return verb;
}
internal static unsafe string GetVerb(byte[] memoryBlob, IntPtr originalAddress)
internal static unsafe string GetVerb(byte[] memoryBlob, int requestOffset, IntPtr originalAddress)
{
fixed (byte* pMemoryBlob = memoryBlob)
{
return GetVerb((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress);
return GetVerb((HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress);
}
}
internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, IntPtr originalAddress)
internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, int requestOffset, IntPtr originalAddress)
{
// Return value.
HTTP_VERB verb = HTTP_VERB.HttpVerbUnknown;
fixed (byte* pMemoryBlob = memoryBlob)
{
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum)
{
verb = request->Verb;
@ -1151,13 +1153,14 @@ namespace Microsoft.Net.Http.Server
return verb;
}
internal static uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size)
internal static uint GetChunks(byte[] memoryBlob, int requestOffset, 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;
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
long fixup = pMemoryBlob - (byte*)originalAddress;
if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1)
@ -1205,30 +1208,30 @@ namespace Microsoft.Net.Http.Server
return dataRead;
}
internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, IntPtr originalAddress)
internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress)
{
fixed (byte* pMemoryBlob = memoryBlob)
{
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pRemoteAddress);
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pRemoteAddress);
}
}
internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, IntPtr originalAddress)
internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress)
{
fixed (byte* pMemoryBlob = memoryBlob)
{
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pLocalAddress);
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pLocalAddress);
}
}
internal static SocketAddress GetEndPoint(byte[] memoryBlob, IntPtr originalAddress, byte* source)
internal static SocketAddress GetEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, byte* source)
{
fixed (byte* pMemoryBlob = memoryBlob)
{
IntPtr address = source != null ?
(IntPtr)(pMemoryBlob - (byte*)originalAddress + source) : IntPtr.Zero;
(IntPtr)(pMemoryBlob + requestOffset - (byte*)originalAddress + source) : IntPtr.Zero;
return CopyOutAddress(address);
}
}

View File

@ -31,9 +31,11 @@ namespace Microsoft.Net.Http.Server
internal unsafe class NativeRequestContext : IDisposable
{
private const int DefaultBufferSize = 4096;
private const int AlignmentPadding = 8;
private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* _memoryBlob;
private IntPtr _originalBlobAddress;
private byte[] _backingBuffer;
private int _bufferAlignment;
private SafeNativeOverlapped _nativeOverlapped;
private AsyncAcceptContext _acceptResult;
@ -80,7 +82,15 @@ namespace Microsoft.Net.Http.Server
{
get
{
return (uint)_backingBuffer.Length;
return (uint)_backingBuffer.Length - AlignmentPadding;
}
}
internal int BufferAlignment
{
get
{
return _bufferAlignment;
}
}
@ -89,7 +99,7 @@ namespace Microsoft.Net.Http.Server
get
{
UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* blob = _memoryBlob;
return (blob == null ? _originalBlobAddress : (IntPtr)blob);
return blob == null ? _originalBlobAddress : (IntPtr)blob;
}
}
@ -155,12 +165,13 @@ namespace Microsoft.Net.Http.Server
private void SetBuffer(int size)
{
_backingBuffer = size == 0 ? null : new byte[size];
Debug.Assert(size != 0, "unexpected size");
_backingBuffer = new byte[size + AlignmentPadding];
}
private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(uint size)
{
uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size;
// We can't reuse overlapped objects
if (_nativeOverlapped != null)
{
@ -168,15 +179,19 @@ namespace Microsoft.Net.Http.Server
_nativeOverlapped = null;
nativeOverlapped.Dispose();
}
if (_nativeOverlapped == null)
{
SetBuffer(checked((int)newSize));
var boundHandle = _acceptResult.Server.BoundHandle;
_nativeOverlapped = new SafeNativeOverlapped(boundHandle,
boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer));
return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0);
}
return RequestBlob;
uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size;
SetBuffer(checked((int)newSize));
var boundHandle = _acceptResult.Server.BoundHandle;
_nativeOverlapped = new SafeNativeOverlapped(boundHandle,
boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer));
// HttpReceiveHttpRequest expects the request pointer to be 8-byte-aligned or it fails. On ARM
// CLR creates buffers that are 4-byte-aligned so we need force 8-byte alignment.
var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0);
_bufferAlignment = (int)(requestAddress.ToInt64() & 0x07);
return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment);
}
internal void Reset(ulong requestId, uint size)

View File

@ -141,7 +141,7 @@ namespace Microsoft.Net.Http.Server
_httpVersion = new Version(major, minor);
}
_httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, OriginalBlobAddress);
_httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, BufferAlignment, OriginalBlobAddress);
_headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext));
var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob;
@ -190,6 +190,15 @@ namespace Microsoft.Net.Http.Server
}
}
internal int BufferAlignment
{
get
{
CheckDisposed();
return _nativeRequestContext.BufferAlignment;
}
}
internal IntPtr OriginalBlobAddress
{
get
@ -304,7 +313,7 @@ namespace Microsoft.Net.Http.Server
return _rawUrl;
}
}
public Version ProtocolVersion
{
get
@ -329,7 +338,7 @@ namespace Microsoft.Net.Http.Server
{
if (_remoteEndPoint == null)
{
_remoteEndPoint = UnsafeNclNativeMethods.HttpApi.GetRemoteEndPoint(RequestBuffer, OriginalBlobAddress);
_remoteEndPoint = UnsafeNclNativeMethods.HttpApi.GetRemoteEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress);
}
return _remoteEndPoint;
@ -342,7 +351,7 @@ namespace Microsoft.Net.Http.Server
{
if (_localEndPoint == null)
{
_localEndPoint = UnsafeNclNativeMethods.HttpApi.GetLocalEndPoint(RequestBuffer, OriginalBlobAddress);
_localEndPoint = UnsafeNclNativeMethods.HttpApi.GetLocalEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress);
}
return _localEndPoint;
@ -406,7 +415,7 @@ namespace Microsoft.Net.Http.Server
internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod()
{
return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, OriginalBlobAddress);
return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, BufferAlignment, OriginalBlobAddress);
}
// Populates the client certificate. The result may be null if there is no client cert.

View File

@ -86,13 +86,13 @@ namespace Microsoft.Net.Http.Server
private string GetKnownHeader(HttpSysRequestHeader header)
{
return UnsafeNclNativeMethods.HttpApi.GetKnownHeader(_requestMemoryBlob.RequestBuffer,
_requestMemoryBlob.OriginalBlobAddress, (int)header);
_requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress, (int)header);
}
private void GetUnknownHeaders(IDictionary<string, StringValues> extra)
{
UnsafeNclNativeMethods.HttpApi.GetUnknownHeaders(extra, _requestMemoryBlob.RequestBuffer,
_requestMemoryBlob.OriginalBlobAddress);
_requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress);
}
void IDictionary<string, StringValues>.Add(string key, StringValues value)

View File

@ -147,7 +147,9 @@ namespace Microsoft.Net.Http.Server
if (_dataChunkIndex != -1)
{
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer,
_requestContext.Request.BufferAlignment, _requestContext.Request.OriginalBlobAddress,
ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
}
if (_dataChunkIndex == -1 && dataRead < size)
@ -223,7 +225,9 @@ namespace Microsoft.Net.Http.Server
uint dataRead = 0;
if (_dataChunkIndex != -1)
{
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment,
_requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
if (_dataChunkIndex != -1 && dataRead == size)
{
asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, 0);
@ -339,7 +343,8 @@ namespace Microsoft.Net.Http.Server
uint dataRead = 0;
if (_dataChunkIndex != -1)
{
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment,
_requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
if (_dataChunkIndex != -1 && dataRead == size)
{
UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead);
@ -347,7 +352,7 @@ namespace Microsoft.Net.Http.Server
return Task.FromResult<int>((int)dataRead);
}
}
if (_dataChunkIndex == -1 && dataRead < size)
{
uint statusCode = 0;

View File

@ -890,7 +890,7 @@ namespace Microsoft.Net.Http.Server
blob = new byte[size];
fixed (byte* blobPtr = blob)
{
// Http.sys team: ServiceName will always be null if
// Http.sys team: ServiceName will always be null if
// HTTP_RECEIVE_SECURE_CHANNEL_TOKEN flag is set.
statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate(
RequestQueueHandle,