diff --git a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs
index d42a66e605..58a5f7f186 100644
--- a/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs
+++ b/src/Microsoft.Net.Http.Server/AsyncAcceptContext.cs
@@ -108,13 +108,13 @@ namespace Microsoft.Net.Http.Server
}
else
{
- asyncResult._nativeRequestContext.Reset(0, 0);
+ asyncResult._nativeRequestContext.Reset();
}
}
}
else
{
- asyncResult._nativeRequestContext.Reset(asyncResult._nativeRequestContext.RequestBlob->RequestId, numBytes);
+ asyncResult._nativeRequestContext.Reset(asyncResult._nativeRequestContext.RequestId, numBytes);
}
// We need to issue a new request, either because auth failed, or because our buffer was too small the first time.
@@ -166,26 +166,26 @@ namespace Microsoft.Net.Http.Server
uint bytesTransferred = 0;
statusCode = HttpApi.HttpReceiveHttpRequest(
Server.RequestQueue.Handle,
- _nativeRequestContext.RequestBlob->RequestId,
+ _nativeRequestContext.RequestId,
(uint)HttpApi.HTTP_FLAGS.HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
- _nativeRequestContext.RequestBlob,
+ _nativeRequestContext.NativeRequest,
_nativeRequestContext.Size,
&bytesTransferred,
_nativeRequestContext.NativeOverlapped);
- if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER && _nativeRequestContext.RequestBlob->RequestId != 0)
+ if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_INVALID_PARAMETER && _nativeRequestContext.RequestId != 0)
{
// we might get this if somebody stole our RequestId,
// set RequestId to 0 and start all over again with the buffer we just allocated
// BUGBUG: how can someone steal our request ID? seems really bad and in need of fix.
- _nativeRequestContext.RequestBlob->RequestId = 0;
+ _nativeRequestContext.RequestId = 0;
retry = true;
}
else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_MORE_DATA)
{
// 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.RequestBlob->RequestId, bytesTransferred);
+ _nativeRequestContext.Reset(_nativeRequestContext.RequestId, bytesTransferred);
retry = true;
}
else if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS
diff --git a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs
index fb8766996a..14153b285b 100644
--- a/src/Microsoft.Net.Http.Server/AuthenticationManager.cs
+++ b/src/Microsoft.Net.Http.Server/AuthenticationManager.cs
@@ -152,51 +152,5 @@ namespace Microsoft.Net.Http.Server
= StringValues.Concat(context.Response.Headers[HttpKnownHeaderNames.WWWAuthenticate], challenges.ToArray());
}
}
-
- internal static unsafe bool CheckAuthenticated(HttpApi.HTTP_REQUEST_INFO* requestInfo)
- {
- if (requestInfo != null
- && requestInfo->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth
- && requestInfo->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess)
- {
- return true;
- }
- return false;
- }
-
- internal static unsafe ClaimsPrincipal GetUser(HttpApi.HTTP_REQUEST_INFO* requestInfo, int infoCount)
- {
- for (int i = 0; i < infoCount; i++)
- {
- var info = &requestInfo[i];
- if (requestInfo != null
- && info->InfoType == HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeAuth
- && info->pInfo->AuthStatus == HttpApi.HTTP_AUTH_STATUS.HttpAuthStatusSuccess)
- {
- return new WindowsPrincipal(new WindowsIdentity(info->pInfo->AccessToken,
- GetAuthTypeFromRequest(info->pInfo->AuthType).ToString()));
- }
- }
- return new ClaimsPrincipal(new ClaimsIdentity()); // 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());
- }
- }
}
}
diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs b/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs
new file mode 100644
index 0000000000..ed702b7406
--- /dev/null
+++ b/src/Microsoft.Net.Http.Server/NativeInterop/CookedUrl.cs
@@ -0,0 +1,75 @@
+// 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 (c) Microsoft Corporation. All rights reserved.
+//
+//------------------------------------------------------------------------------
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace Microsoft.Net.Http.Server
+{
+ // Note this type should only be used while the request buffer remains pinned
+ internal class CookedUrl
+ {
+ private readonly HttpApi.HTTP_COOKED_URL _nativeCookedUrl;
+
+ internal CookedUrl(HttpApi.HTTP_COOKED_URL nativeCookedUrl)
+ {
+ _nativeCookedUrl = nativeCookedUrl;
+ }
+
+ internal unsafe string GetFullUrl()
+ {
+ if (_nativeCookedUrl.pFullUrl != null && _nativeCookedUrl.FullUrlLength > 0)
+ {
+ return Marshal.PtrToStringUni((IntPtr)_nativeCookedUrl.pFullUrl, _nativeCookedUrl.FullUrlLength / 2);
+ }
+ return null;
+ }
+
+ internal unsafe string GetHost()
+ {
+ if (_nativeCookedUrl.pHost != null && _nativeCookedUrl.HostLength > 0)
+ {
+ return Marshal.PtrToStringUni((IntPtr)_nativeCookedUrl.pHost, _nativeCookedUrl.HostLength / 2);
+ }
+ return null;
+ }
+
+ internal unsafe string GetAbsPath()
+ {
+ if (_nativeCookedUrl.pAbsPath != null && _nativeCookedUrl.AbsPathLength > 0)
+ {
+ return Marshal.PtrToStringUni((IntPtr)_nativeCookedUrl.pAbsPath, _nativeCookedUrl.AbsPathLength / 2);
+ }
+ return null;
+ }
+
+ internal unsafe string GetQueryString()
+ {
+ if (_nativeCookedUrl.pQueryString != null && _nativeCookedUrl.QueryStringLength > 0)
+ {
+ return Marshal.PtrToStringUni((IntPtr)_nativeCookedUrl.pQueryString, _nativeCookedUrl.QueryStringLength / 2);
+ }
+ return null;
+ }
+ }
+}
diff --git a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs
index b50c36a54e..10c736af80 100644
--- a/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs
+++ b/src/Microsoft.Net.Http.Server/NativeInterop/HttpApi.cs
@@ -868,205 +868,5 @@ namespace Microsoft.Net.Http.Server
return supported;
}
}
-
- // Server API
-
- internal static void GetUnknownHeaders(IDictionary unknownHeaders, byte[] memoryBlob,
- int requestOffset, IntPtr originalAddress)
- {
- // Return value.
- fixed (byte* pMemoryBlob = memoryBlob)
- {
- HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
- 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] = 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, int requestOffset, IntPtr originalAddress, int headerIndex)
- {
- fixed (byte* pMemoryBlob = memoryBlob)
- {
- return GetKnownHeader(
- (HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)originalAddress, headerIndex);
- }
- }
-
- // This requires the HTTP_REQUEST to still be pinned in its original location.
- internal static unsafe string GetVerb(HTTP_REQUEST* request)
- {
- 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, request->UnknownVerbLength);
- }
-
- return verb;
- }
-
- 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 + requestOffset);
- 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, int requestOffset, IntPtr originalAddress)
- {
- fixed (byte* pMemoryBlob = memoryBlob)
- {
- HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
- return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pRemoteAddress);
- }
- }
-
- internal static SocketAddress GetLocalEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress)
- {
- fixed (byte* pMemoryBlob = memoryBlob)
- {
- HTTP_REQUEST* request = (HTTP_REQUEST*)(pMemoryBlob + requestOffset);
- return GetEndPoint(memoryBlob, requestOffset, originalAddress, (byte*)request->Address.pLocalAddress);
- }
- }
-
- internal static SocketAddress GetEndPoint(byte[] memoryBlob, int requestOffset, IntPtr originalAddress, byte* source)
- {
- fixed (byte* pMemoryBlob = memoryBlob)
- {
- IntPtr address = source != null ?
- (IntPtr)(pMemoryBlob + requestOffset - (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;
- }
}
}
diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs
index 5072342c42..32a93e8ae6 100644
--- a/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs
+++ b/src/Microsoft.Net.Http.Server/RequestProcessing/NativeRequestContext.cs
@@ -22,9 +22,12 @@
//------------------------------------------------------------------------------
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
-using System.Threading;
+using System.Security.Claims;
+using System.Security.Principal;
+using Microsoft.Extensions.Primitives;
namespace Microsoft.Net.Http.Server
{
@@ -32,8 +35,8 @@ namespace Microsoft.Net.Http.Server
{
private const int DefaultBufferSize = 4096;
private const int AlignmentPadding = 8;
- private HttpApi.HTTP_REQUEST* _memoryBlob;
- private IntPtr _originalBlobAddress;
+ private HttpApi.HTTP_REQUEST* _nativeRequest;
+ private IntPtr _originalBufferAddress;
private byte[] _backingBuffer;
private int _bufferAlignment;
private SafeNativeOverlapped _nativeOverlapped;
@@ -42,125 +45,73 @@ namespace Microsoft.Net.Http.Server
internal NativeRequestContext(AsyncAcceptContext result)
{
_acceptResult = result;
- HttpApi.HTTP_REQUEST* requestBlob = Allocate(0);
- if (requestBlob == null)
- {
- GC.SuppressFinalize(this);
- }
- else
- {
- _memoryBlob = requestBlob;
- }
+ AllocateNativeRequest();
}
- internal SafeNativeOverlapped NativeOverlapped
+ internal SafeNativeOverlapped NativeOverlapped => _nativeOverlapped;
+
+ internal HttpApi.HTTP_REQUEST* NativeRequest
{
get
{
- return _nativeOverlapped;
+ Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins().");
+ return _nativeRequest;
}
}
- internal HttpApi.HTTP_REQUEST* RequestBlob
+ private HttpApi.HTTP_REQUEST_V2* NativeRequestV2
{
get
{
- Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestBlob requested after ReleasePins().");
- return _memoryBlob;
+ Debug.Assert(_nativeRequest != null || _backingBuffer == null, "native request accessed after ReleasePins().");
+ return (HttpApi.HTTP_REQUEST_V2*)_nativeRequest;
}
}
- internal byte[] RequestBuffer
+ 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 _backingBuffer;
+ return NativeRequest->pSslInfo == null ? SslStatus.Insecure :
+ NativeRequest->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert :
+ SslStatus.ClientCert;
}
}
internal uint Size
{
- get
- {
- return (uint)_backingBuffer.Length - AlignmentPadding;
- }
- }
-
- internal int BufferAlignment
- {
- get
- {
- return _bufferAlignment;
- }
- }
-
- internal IntPtr OriginalBlobAddress
- {
- get
- {
- HttpApi.HTTP_REQUEST* blob = _memoryBlob;
- return blob == null ? _originalBlobAddress : (IntPtr)blob;
- }
+ 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(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::ReleasePins()|ReleasePins() called twice.");
- _originalBlobAddress = (IntPtr)_memoryBlob;
- UnsetBlob();
- OnReleasePins();
- }
-
- private void OnReleasePins()
- {
- if (_nativeOverlapped != null)
- {
- SafeNativeOverlapped nativeOverlapped = _nativeOverlapped;
- _nativeOverlapped = null;
- nativeOverlapped.Dispose();
- }
+ 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(_memoryBlob == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins().");
- Dispose(true);
- }
-
- protected void Dispose(bool disposing)
- {
- if (_nativeOverlapped != null)
- {
- Debug.Assert(!disposing, "AsyncRequestContext::Dispose()|Must call ReleasePins() before calling Dispose().");
- _nativeOverlapped.Dispose();
- }
- }
-
- private void SetBlob(HttpApi.HTTP_REQUEST* requestBlob)
- {
- Debug.Assert(_memoryBlob != null || _backingBuffer == null, "RequestContextBase::Dispose()|SetBlob() called after ReleasePins().");
- if (requestBlob == null)
- {
- UnsetBlob();
- return;
- }
-
- if (_memoryBlob == null)
- {
- GC.ReRegisterForFinalize(this);
- }
- _memoryBlob = requestBlob;
- }
-
- private void UnsetBlob()
- {
- if (_memoryBlob != null)
- {
- GC.SuppressFinalize(this);
- }
- _memoryBlob = null;
+ Debug.Assert(_nativeRequest == null, "RequestContextBase::Dispose()|Dispose() called before ReleasePins().");
+ _nativeOverlapped?.Dispose();
}
private void SetBuffer(int size)
@@ -170,34 +121,306 @@ namespace Microsoft.Net.Http.Server
_backingBuffer = new byte[size + AlignmentPadding];
}
- private HttpApi.HTTP_REQUEST* Allocate(uint size)
+ private void AllocateNativeRequest(uint? size = null)
{
// We can't reuse overlapped objects
- if (_nativeOverlapped != null)
- {
- SafeNativeOverlapped nativeOverlapped = _nativeOverlapped;
- _nativeOverlapped = null;
- nativeOverlapped.Dispose();
- }
+ _nativeOverlapped?.Dispose();
- uint newSize = size != 0 ? size : RequestBuffer == null ? DefaultBufferSize : Size;
+ 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, RequestBuffer));
+ boundHandle.AllocateNativeOverlapped(AsyncAcceptContext.IOCallback, _acceptResult, _backingBuffer));
// 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);
+ var requestAddress = Marshal.UnsafeAddrOfPinnedArrayElement(_backingBuffer, 0);
_bufferAlignment = (int)(requestAddress.ToInt64() & 0x07);
- return (HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment);
+ _nativeRequest = (HttpApi.HTTP_REQUEST*)(requestAddress + _bufferAlignment);
}
- internal void Reset(ulong requestId, uint size)
+ internal void Reset(ulong requestId = 0, uint? size = null)
{
- SetBlob(Allocate(size));
- RequestBlob->RequestId = requestId;
+ 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 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 ClaimsPrincipal 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)
+ {
+ return new WindowsPrincipal(new WindowsIdentity(info->pInfo->AccessToken,
+ GetAuthTypeFromRequest(info->pInfo->AuthType).ToString()));
+ }
+ }
+ return new ClaimsPrincipal(new ClaimsIdentity()); // 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.Net.Http.Server/RequestProcessing/Request.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs
index 924b7eef2c..d7fce4acb0 100644
--- a/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs
+++ b/src/Microsoft.Net.Http.Server/RequestProcessing/Request.cs
@@ -25,7 +25,6 @@ using System;
using System.Globalization;
using System.IO;
using System.Net;
-using System.Runtime.InteropServices;
using System.Security.Claims;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
@@ -51,46 +50,27 @@ namespace Microsoft.Net.Http.Server
private bool _isDisposed = false;
- internal unsafe Request(RequestContext requestContext, NativeRequestContext memoryBlob)
+ internal Request(RequestContext requestContext, NativeRequestContext nativeRequestContext)
{
// TODO: Verbose log
RequestContext = requestContext;
- _nativeRequestContext = memoryBlob;
+ _nativeRequestContext = nativeRequestContext;
_contentBoundaryType = BoundaryType.None;
- // Set up some of these now to avoid refcounting on memory blob later.
- RequestId = memoryBlob.RequestBlob->RequestId;
- UConnectionId = memoryBlob.RequestBlob->ConnectionId;
- SslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure :
- memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert :
- SslStatus.ClientCert;
+ RequestId = nativeRequestContext.RequestId;
+ UConnectionId = nativeRequestContext.ConnectionId;
+ SslStatus = nativeRequestContext.SslStatus;
- KnownMethod = memoryBlob.RequestBlob->Verb;
- Method = HttpApi.GetVerb(memoryBlob.RequestBlob);
+ KnownMethod = nativeRequestContext.VerbId;
+ Method = _nativeRequestContext.GetVerb();
- if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0)
- {
- RawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength);
- }
+ RawUrl = nativeRequestContext.GetRawUrl();
- HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl;
- if (cookedUrl.pHost != null && cookedUrl.HostLength > 0)
- {
- // TODO: Unused
- // _cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2);
- }
- var cookedUrlPath = string.Empty;
- if (cookedUrl.pAbsPath != null && cookedUrl.AbsPathLength > 0)
- {
- cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2);
- }
- QueryString = string.Empty;
- if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0)
- {
- QueryString = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2);
- }
+ var cookedUrl = nativeRequestContext.GetCookedUrl();
+ var cookedUrlPath = cookedUrl.GetAbsPath() ?? string.Empty;
+ QueryString = cookedUrl.GetQueryString() ?? string.Empty;
- var prefix = requestContext.Server.Settings.UrlPrefixes.GetPrefix((int)memoryBlob.RequestBlob->UrlContext);
+ var prefix = requestContext.Server.Settings.UrlPrefixes.GetPrefix((int)nativeRequestContext.UrlContext);
var originalPath = RequestUriBuilder.GetRequestPath(RawUrl, cookedUrlPath, RequestContext.Logger);
// 'OPTIONS * HTTP/1.1'
@@ -114,25 +94,11 @@ namespace Microsoft.Net.Http.Server
Path = originalPath.Substring(prefix.Path.Length - 1);
}
- int major = memoryBlob.RequestBlob->Version.MajorVersion;
- int minor = memoryBlob.RequestBlob->Version.MinorVersion;
- if (major == 1 && minor == 1)
- {
- ProtocolVersion = Constants.V1_1;
- }
- else if (major == 1 && minor == 0)
- {
- ProtocolVersion = Constants.V1_0;
- }
- else
- {
- ProtocolVersion = new Version(major, minor);
- }
+ ProtocolVersion = _nativeRequestContext.GetVersion();
Headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext));
- var requestV2 = (HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob;
- User = AuthenticationManager.GetUser(requestV2->pRequestInfo, requestV2->RequestInfoCount);
+ User = nativeRequestContext.GetUser();
// GetTlsTokenBindingInfo(); TODO: https://github.com/aspnet/WebListener/issues/231
@@ -141,33 +107,6 @@ namespace Microsoft.Net.Http.Server
// TODO: Verbose log parameters
}
- internal byte[] RequestBuffer
- {
- get
- {
- CheckDisposed();
- return _nativeRequestContext.RequestBuffer;
- }
- }
-
- internal int BufferAlignment
- {
- get
- {
- CheckDisposed();
- return _nativeRequestContext.BufferAlignment;
- }
- }
-
- internal IntPtr OriginalBlobAddress
- {
- get
- {
- CheckDisposed();
- return _nativeRequestContext.OriginalBlobAddress;
- }
- }
-
internal ulong UConnectionId { get; }
// No ulongs in public APIs...
@@ -260,7 +199,7 @@ namespace Microsoft.Net.Http.Server
{
if (_remoteEndPoint == null)
{
- _remoteEndPoint = HttpApi.GetRemoteEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress);
+ _remoteEndPoint = _nativeRequestContext.GetRemoteEndPoint();
}
return _remoteEndPoint;
@@ -273,7 +212,7 @@ namespace Microsoft.Net.Http.Server
{
if (_localEndPoint == null)
{
- _localEndPoint = HttpApi.GetLocalEndPoint(RequestBuffer, BufferAlignment, OriginalBlobAddress);
+ _localEndPoint = _nativeRequestContext.GetLocalEndPoint();
}
return _localEndPoint;
@@ -356,6 +295,7 @@ namespace Microsoft.Net.Http.Server
// Key: HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_ENABLE_TOKEN_BINDING
// Value: "iexplore.exe"=dword:00000001
// TODO: https://github.com/aspnet/WebListener/issues/231
+ // TODO: https://github.com/aspnet/WebListener/issues/204 Move to NativeRequestContext
/*
private unsafe void GetTlsTokenBindingInfo()
{
@@ -371,6 +311,11 @@ namespace Microsoft.Net.Http.Server
}
}
*/
+ internal uint GetChunks(ref int dataChunkIndex, ref uint dataChunkOffset, byte[] buffer, int offset, int size)
+ {
+ return _nativeRequestContext.GetChunks(ref dataChunkIndex, ref dataChunkOffset, buffer, offset, size);
+ }
+
// should only be called from RequestContext
internal void Dispose()
{
diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs
index a1c526d68b..2b3f1dcafb 100644
--- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs
+++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestHeaders.cs
@@ -85,14 +85,12 @@ namespace Microsoft.Net.Http.Server
private string GetKnownHeader(HttpSysRequestHeader header)
{
- return HttpApi.GetKnownHeader(_requestMemoryBlob.RequestBuffer,
- _requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress, (int)header);
+ return _requestMemoryBlob.GetKnownHeader(header);
}
private void GetUnknownHeaders(IDictionary extra)
{
- HttpApi.GetUnknownHeaders(extra, _requestMemoryBlob.RequestBuffer,
- _requestMemoryBlob.BufferAlignment, _requestMemoryBlob.OriginalBlobAddress);
+ _requestMemoryBlob.GetUnknownHeaders(extra);
}
void IDictionary.Add(string key, StringValues value)
diff --git a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs
index 16324aa487..9ad00ca84d 100644
--- a/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs
+++ b/src/Microsoft.Net.Http.Server/RequestProcessing/RequestStream.cs
@@ -154,9 +154,7 @@ namespace Microsoft.Net.Http.Server
if (_dataChunkIndex != -1)
{
- dataRead = HttpApi.GetChunks(_requestContext.Request.RequestBuffer,
- _requestContext.Request.BufferAlignment, _requestContext.Request.OriginalBlobAddress,
- ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
+ dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
}
if (_dataChunkIndex == -1 && dataRead < size)
@@ -232,8 +230,7 @@ namespace Microsoft.Net.Http.Server
uint dataRead = 0;
if (_dataChunkIndex != -1)
{
- dataRead = HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment,
- _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
+ dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
if (_dataChunkIndex != -1 && dataRead == size)
{
@@ -350,8 +347,7 @@ namespace Microsoft.Net.Http.Server
uint dataRead = 0;
if (_dataChunkIndex != -1)
{
- dataRead = HttpApi.GetChunks(_requestContext.Request.RequestBuffer, _requestContext.Request.BufferAlignment,
- _requestContext.Request.OriginalBlobAddress, ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
+ dataRead = _requestContext.Request.GetChunks(ref _dataChunkIndex, ref _dataChunkOffset, buffer, offset, size);
if (_dataChunkIndex != -1 && dataRead == size)
{
UpdateAfterRead(UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS, dataRead);
diff --git a/src/Microsoft.Net.Http.Server/WebListener.cs b/src/Microsoft.Net.Http.Server/WebListener.cs
index cb72439299..2e2f0cb1f8 100644
--- a/src/Microsoft.Net.Http.Server/WebListener.cs
+++ b/src/Microsoft.Net.Http.Server/WebListener.cs
@@ -319,9 +319,9 @@ namespace Microsoft.Net.Http.Server
internal unsafe bool ValidateRequest(NativeRequestContext requestMemory)
{
// Block potential DOS attacks
- if (requestMemory.RequestBlob->Headers.UnknownHeaderCount > UnknownHeaderLimit)
+ if (requestMemory.UnknownHeaderCount > UnknownHeaderLimit)
{
- SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest, authChallenges: null);
+ SendError(requestMemory.RequestId, HttpStatusCode.BadRequest, authChallenges: null);
return false;
}
return true;
@@ -329,10 +329,9 @@ namespace Microsoft.Net.Http.Server
internal unsafe bool ValidateAuth(NativeRequestContext requestMemory)
{
- var requestV2 = (HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob;
- if (!Settings.Authentication.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo))
+ if (!Settings.Authentication.AllowAnonymous && !requestMemory.CheckAuthenticated())
{
- SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized,
+ SendError(requestMemory.RequestId, HttpStatusCode.Unauthorized,
AuthenticationManager.GenerateChallenges(Settings.Authentication.Schemes));
return false;
}
diff --git a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs
index ff48f77414..0075622980 100644
--- a/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs
+++ b/test/Microsoft.AspNetCore.Server.WebListener.FunctionalTests/ResponseCachingTests.cs
@@ -118,7 +118,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests
}
}
- [Theory]
+ [Theory(Skip = "https://github.com/aspnet/WebListener/issues/210")]
[InlineData("Set-cookie")]
[InlineData("vary")]
[InlineData("pragma")]
@@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Server.WebListener.FunctionalTests
}
}
- [Fact]
+ [Fact(Skip = "https://github.com/aspnet/WebListener/issues/210")]
public async Task Caching_ExpiresWithoutPublic_NotCached()
{
var requestCount = 1;