Skip to content
This repository was archived by the owner on Mar 19, 2019. It is now read-only.

Commit 1b43c5e

Browse files
author
moozzyk
committed
Force 8-byte alignment on HTTP_REQUEST buffer
Addresses #126
1 parent 4904e9f commit 1b43c5e

File tree

6 files changed

+75
-45
lines changed

6 files changed

+75
-45
lines changed

src/Microsoft.Net.Http.Server/NativeInterop/UnsafeNativeMethods.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,12 +1049,13 @@ internal static bool Supported
10491049

10501050
// Server API
10511051

1052-
internal static void GetUnknownHeaders(IDictionary<string, StringValues> unknownHeaders, byte[] memoryBlob, IntPtr originalAddress)
1052+
internal static void GetUnknownHeaders(IDictionary<string, StringValues> unknownHeaders, byte[] memoryBlob,
1053+
int requestOffset, IntPtr originalAddress)
10531054
{
10541055
// Return value.
10551056
fixed (byte* pMemoryBlob = memoryBlob)
10561057
{
1057-
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
1058+
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
10581059
long fixup = pMemoryBlob - (byte*)originalAddress;
10591060
int index;
10601061

@@ -1064,7 +1065,7 @@ internal static void GetUnknownHeaders(IDictionary<string, StringValues> unknown
10641065
HTTP_UNKNOWN_HEADER* pUnknownHeader = (HTTP_UNKNOWN_HEADER*)(fixup + (byte*)request->Headers.pUnknownHeaders);
10651066
for (index = 0; index < request->Headers.UnknownHeaderCount; index++)
10661067
{
1067-
// For unknown headers, when header value is empty, RawValueLength will be 0 and
1068+
// For unknown headers, when header value is empty, RawValueLength will be 0 and
10681069
// pRawValue will be null.
10691070
if (pUnknownHeader->pName != null && pUnknownHeader->NameLength > 0)
10701071
{
@@ -1093,7 +1094,7 @@ private static string GetKnownHeader(HTTP_REQUEST* request, long fixup, int head
10931094
string header = null;
10941095

10951096
HTTP_KNOWN_HEADER* pKnownHeader = (&request->Headers.KnownHeaders) + headerIndex;
1096-
// For known headers, when header value is empty, RawValueLength will be 0 and
1097+
// For known headers, when header value is empty, RawValueLength will be 0 and
10971098
// pRawValue will point to empty string ("\0")
10981099
if (pKnownHeader->pRawValue != null)
10991100
{
@@ -1103,11 +1104,12 @@ private static string GetKnownHeader(HTTP_REQUEST* request, long fixup, int head
11031104
return header;
11041105
}
11051106

1106-
internal static string GetKnownHeader(byte[] memoryBlob, IntPtr originalAddress, int headerIndex)
1107+
internal static string GetKnownHeader(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, int headerIndex)
11071108
{
11081109
fixed (byte* pMemoryBlob = memoryBlob)
11091110
{
1110-
return GetKnownHeader((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress, headerIndex);
1111+
return GetKnownHeader(
1112+
(HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress, headerIndex);
11111113
}
11121114
}
11131115

@@ -1127,21 +1129,21 @@ private static unsafe string GetVerb(HTTP_REQUEST* request, long fixup)
11271129
return verb;
11281130
}
11291131

1130-
internal static unsafe string GetVerb(byte[] memoryBlob, IntPtr originalAddress)
1132+
internal static unsafe string GetVerb(byte[] memoryBlob, int requestOffset, IntPtr originalAddress)
11311133
{
11321134
fixed (byte* pMemoryBlob = memoryBlob)
11331135
{
1134-
return GetVerb((HTTP_REQUEST*)pMemoryBlob, pMemoryBlob - (byte*)originalAddress);
1136+
return GetVerb((HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress);
11351137
}
11361138
}
11371139

1138-
internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, IntPtr originalAddress)
1140+
internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, int requestOffset, IntPtr originalAddress)
11391141
{
11401142
// Return value.
11411143
HTTP_VERB verb = HTTP_VERB.HttpVerbUnknown;
11421144
fixed (byte* pMemoryBlob = memoryBlob)
11431145
{
1144-
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
1146+
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
11451147
if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum)
11461148
{
11471149
verb = request->Verb;
@@ -1151,13 +1153,14 @@ internal static HTTP_VERB GetKnownVerb(byte[] memoryBlob, IntPtr originalAddress
11511153
return verb;
11521154
}
11531155

1154-
internal static uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size)
1156+
internal static uint GetChunks(byte[] memoryBlob, int requestOffset, IntPtr originalAddress,
1157+
ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size)
11551158
{
11561159
// Return value.
11571160
uint dataRead = 0;
11581161
fixed (byte* pMemoryBlob = memoryBlob)
11591162
{
1160-
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
1163+
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
11611164
long fixup = pMemoryBlob - (byte*)originalAddress;
11621165

11631166
if (request->EntityChunkCount > 0 && dataChunkIndex < request->EntityChunkCount && dataChunkIndex != -1)
@@ -1205,30 +1208,30 @@ internal static uint GetChunks(byte[] memoryBlob, IntPtr originalAddress, ref in
12051208
return dataRead;
12061209
}
12071210

1208-
internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, IntPtr originalAddress)
1211+
internal static SocketAddress GetRemoteEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress)
12091212
{
12101213
fixed (byte* pMemoryBlob = memoryBlob)
12111214
{
1212-
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
1213-
return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pRemoteAddress);
1215+
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
1216+
return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pRemoteAddress);
12141217
}
12151218
}
12161219

1217-
internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, IntPtr originalAddress)
1220+
internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress)
12181221
{
12191222
fixed (byte* pMemoryBlob = memoryBlob)
12201223
{
1221-
HTTP_REQUEST* request = (HTTP_REQUEST*)pMemoryBlob;
1222-
return GetEndPoint(memoryBlob, originalAddress, (byte*)request->Address.pLocalAddress);
1224+
HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
1225+
return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pLocalAddress);
12231226
}
12241227
}
12251228

1226-
internal static SocketAddress GetEndPoint(byte[] memoryBlob, IntPtr originalAddress, byte* source)
1229+
internal static SocketAddress GetEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, byte* source)
12271230
{
12281231
fixed (byte* pMemoryBlob = memoryBlob)
12291232
{
12301233
IntPtr address = source != null ?
1231-
(IntPtr)(pMemoryBlob - (byte*)originalAddress + source) : IntPtr.Zero;
1234+
(IntPtr)(pMemoryBlob + requestOffset - (byte*)originalAddress + source) : IntPtr.Zero;
12321235
return CopyOutAddress(address);
12331236
}
12341237
}

src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ namespace Microsoft.Net.Http.Server
3131
internal unsafe class NativeRequestContext : IDisposable
3232
{
3333
private const int DefaultBufferSize = 4096;
34+
private const int AlignmentPadding = 8;
3435
private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* _memoryBlob;
3536
private IntPtr _originalBlobAddress;
3637
private byte[] _backingBuffer;
38+
private int _offset;
3739
private SafeNativeOverlapped _nativeOverlapped;
3840
private AsyncAcceptContext _acceptResult;
3941

@@ -80,7 +82,15 @@ internal uint Size
8082
{
8183
get
8284
{
83-
return (uint)_backingBuffer.Length;
85+
return (uint)_backingBuffer.Length - AlignmentPadding;
86+
}
87+
}
88+
89+
internal int Offset
90+
{
91+
get
92+
{
93+
return _offset;
8494
}
8595
}
8696

@@ -89,7 +99,7 @@ internal IntPtr OriginalBlobAddress
8999
get
90100
{
91101
UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* blob = _memoryBlob;
92-
return (blob == null ? _originalBlobAddress : (IntPtr)blob);
102+
return blob == null ? _originalBlobAddress : (IntPtr)blob;
93103
}
94104
}
95105

@@ -155,28 +165,31 @@ private void UnsetBlob()
155165

156166
private void SetBuffer(int size)
157167
{
158-
_backingBuffer = size == 0 ? null : new byte[size];
168+
Debug.Assert(size != 0, "unexpected size");
169+
170+
_backingBuffer = new byte[size + AlignmentPadding];
159171
}
160172

161173
private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST* Allocate(uint size)
162174
{
163-
uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size;
164175
// We can't reuse overlapped objects
165176
if (_nativeOverlapped != null)
166177
{
167178
SafeNativeOverlapped nativeOverlapped = _nativeOverlapped;
168179
_nativeOverlapped = null;
169180
nativeOverlapped.Dispose();
170181
}
171-
if (_nativeOverlapped == null)
172-
{
173-
SetBuffer(checked((int)newSize));
174-
var boundHandle = _acceptResult.Server.BoundHandle;
175-
_nativeOverlapped = new SafeNativeOverlapped(boundHandle,
176-
boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer));
177-
return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0);
178-
}
179-
return RequestBlob;
182+
183+
uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size;
184+
SetBuffer(checked((int)newSize));
185+
var boundHandle = _acceptResult.Server.BoundHandle;
186+
_nativeOverlapped = new SafeNativeOverlapped(boundHandle,
187+
boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, RequestBuffer));
188+
189+
var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(RequestBuffer, 0);
190+
_offset = (int)(requestAddress.ToInt64() & 0x07);
191+
192+
return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST*)(requestAddress + _offset);
180193
}
181194

182195
internal void Reset(ulong requestId, uint size)

src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ internal unsafe Request(RequestContext httpContext, NativeRequestContext memoryB
141141
_httpVersion = new Version(major, minor);
142142
}
143143

144-
_httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, OriginalBlobAddress);
144+
_httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, RequestOffset, OriginalBlobAddress);
145145
_headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext));
146146

147147
var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob;
@@ -190,6 +190,15 @@ internal byte[] RequestBuffer
190190
}
191191
}
192192

193+
internal int RequestOffset
194+
{
195+
get
196+
{
197+
CheckDisposed();
198+
return _nativeRequestContext.Offset;
199+
}
200+
}
201+
193202
internal IntPtr OriginalBlobAddress
194203
{
195204
get
@@ -304,7 +313,7 @@ public string RawUrl
304313
return _rawUrl;
305314
}
306315
}
307-
316+
308317
public Version ProtocolVersion
309318
{
310319
get
@@ -329,7 +338,7 @@ private SocketAddress RemoteEndPoint
329338
{
330339
if (_remoteEndPoint == null)
331340
{
332-
_remoteEndPoint = UnsafeNclNativeMethods.HttpApi.GetRemoteEndPoint(RequestBuffer, OriginalBlobAddress);
341+
_remoteEndPoint = UnsafeNclNativeMethods.HttpApi.GetRemoteEndPoint(RequestBuffer, RequestOffset, OriginalBlobAddress);
333342
}
334343

335344
return _remoteEndPoint;
@@ -342,7 +351,7 @@ private SocketAddress LocalEndPoint
342351
{
343352
if (_localEndPoint == null)
344353
{
345-
_localEndPoint = UnsafeNclNativeMethods.HttpApi.GetLocalEndPoint(RequestBuffer, OriginalBlobAddress);
354+
_localEndPoint = UnsafeNclNativeMethods.HttpApi.GetLocalEndPoint(RequestBuffer, RequestOffset, OriginalBlobAddress);
346355
}
347356

348357
return _localEndPoint;
@@ -406,7 +415,7 @@ internal ClaimsPrincipal User
406415

407416
internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod()
408417
{
409-
return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, OriginalBlobAddress);
418+
return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, RequestOffset, OriginalBlobAddress);
410419
}
411420

412421
// Populates the client certificate. The result may be null if there is no client cert.

src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@ StringValues IDictionary<string, StringValues>.this[string key]
8686
private string GetKnownHeader(HttpSysRequestHeader header)
8787
{
8888
return UnsafeNclNativeMethods.HttpApi.GetKnownHeader(_requestMemoryBlob.RequestBuffer,
89-
_requestMemoryBlob.OriginalBlobAddress, (int)header);
89+
_requestMemoryBlob.Offset, _requestMemoryBlob.OriginalBlobAddress, (int)header);
9090
}
9191

9292
private void GetUnknownHeaders(IDictionary<string, StringValues> extra)
9393
{
9494
UnsafeNclNativeMethods.HttpApi.GetUnknownHeaders(extra, _requestMemoryBlob.RequestBuffer,
95-
_requestMemoryBlob.OriginalBlobAddress);
95+
_requestMemoryBlob.Offset, _requestMemoryBlob.OriginalBlobAddress);
9696
}
9797

9898
void IDictionary<string, StringValues>.Add(string key, StringValues value)

src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ public override unsafe int Read([In, Out] byte[] buffer, int offset, int size)
147147

148148
if (_dataChunkIndex != -1)
149149
{
150-
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
150+
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer,
151+
_requestContext.Request.RequestOffset, _requestContext.Request.OriginalBlobAddress,
152+
ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
151153
}
152154

153155
if (_dataChunkIndex == -1 && dataRead < size)
@@ -223,7 +225,9 @@ public override unsafe IAsyncResult BeginRead(byte[] buffer, int offset, int siz
223225
uint dataRead = 0;
224226
if (_dataChunkIndex != -1)
225227
{
226-
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
228+
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.RequestOffset,
229+
_requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
230+
227231
if (_dataChunkIndex != -1 && dataRead == size)
228232
{
229233
asyncResult = new RequestStreamAsyncResult(this, state, callback, buffer, offset, 0);
@@ -339,15 +343,16 @@ public override unsafe Task<int> ReadAsync(byte[] buffer, int offset, int size,
339343
uint dataRead = 0;
340344
if (_dataChunkIndex != -1)
341345
{
342-
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
346+
dataRead = UnsafeNclNativeMethods.HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.RequestOffset,
347+
_requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
343348
if (_dataChunkIndex != -1 && dataRead == size)
344349
{
345350
UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead);
346351
// TODO: Verbose log #dataRead
347352
return Task.FromResult<int>((int)dataRead);
348353
}
349354
}
350-
355+
351356
if (_dataChunkIndex == -1 && dataRead < size)
352357
{
353358
uint statusCode = 0;

src/Microsoft.Net.Http.Server/WebListener.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,7 +890,7 @@ private unsafe ChannelBinding GetChannelBindingFromTls(ulong connectionId)
890890
blob = new byte[size];
891891
fixed (byte* blobPtr = blob)
892892
{
893-
// Http.sys team: ServiceName will always be null if
893+
// Http.sys team: ServiceName will always be null if
894894
// HTTP_RECEIVE_SECURE_CHANNEL_TOKEN flag is set.
895895
statusCode = UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate(
896896
RequestQueueHandle,

0 commit comments

Comments
 (0)