API cleaup, organization
This commit is contained in:
parent
3d2e1c4d3e
commit
235ac59551
|
|
@ -18,13 +18,13 @@ namespace HelloWorld
|
|||
{
|
||||
using (WebListener listener = new WebListener())
|
||||
{
|
||||
listener.UrlPrefixes.Add(UrlPrefix.Create("http://localhost:8080"));
|
||||
listener.UrlPrefixes.Add("http://localhost:8080");
|
||||
listener.Start();
|
||||
|
||||
Console.WriteLine("Running...");
|
||||
while (true)
|
||||
{
|
||||
RequestContext context = await listener.GetContextAsync();
|
||||
RequestContext context = await listener.AcceptAsync();
|
||||
Console.WriteLine("Accepted");
|
||||
|
||||
// Context:
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@ using System;
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Hosting.Server.Features;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Net.Http.Server;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System.Threading;
|
|||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Server.WebListener;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
internal AuthenticationHandler(RequestContext requestContext)
|
||||
{
|
||||
_requestContext = requestContext;
|
||||
_authSchemes = requestContext.AuthenticationChallenges;
|
||||
_authSchemes = requestContext.Response.AuthenticationChallenges;
|
||||
_customChallenges = AuthenticationSchemes.None;
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +107,7 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
}
|
||||
}
|
||||
// A challenge was issued, it overrides any pre-set auth types.
|
||||
_requestContext.AuthenticationChallenges = _customChallenges;
|
||||
_requestContext.Response.AuthenticationChallenges = _customChallenges;
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
|
||||
internal ITlsConnectionFeature GetTlsConnectionFeature()
|
||||
{
|
||||
return Request.IsSecureConnection ? this : null;
|
||||
return Request.IsHttps ? this : null;
|
||||
}
|
||||
|
||||
byte[] ITlsTokenBindingFeature.GetProvidedTokenBindingId()
|
||||
|
|
@ -338,7 +338,7 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
|
||||
internal ITlsTokenBindingFeature GetTlsTokenBindingFeature()
|
||||
{
|
||||
return Request.IsSecureConnection ? this : null;
|
||||
return Request.IsHttps ? this : null;
|
||||
}
|
||||
|
||||
void IHttpBufferingFeature.DisableRequestBuffering()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@
|
|||
// See the Apache 2 License for the specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
using System;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,8 @@ using Microsoft.Net.Http.Server;
|
|||
|
||||
namespace Microsoft.AspNetCore.Server.WebListener
|
||||
{
|
||||
public class MessagePump : IServer
|
||||
internal class MessagePump : IServer
|
||||
{
|
||||
private static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount;
|
||||
|
||||
private readonly Microsoft.Net.Http.Server.WebListener _listener;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
|
|
@ -48,7 +46,7 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
|
||||
private readonly ServerAddressesFeature _serverAddresses;
|
||||
|
||||
public MessagePump(IOptions<WebListenerOptions> options, ILoggerFactory loggerFactory)
|
||||
internal MessagePump(IOptions<WebListenerOptions> options, ILoggerFactory loggerFactory)
|
||||
{
|
||||
if (options == null)
|
||||
{
|
||||
|
|
@ -66,32 +64,17 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
Features.Set<IServerAddressesFeature>(_serverAddresses);
|
||||
|
||||
_processRequest = new Action<object>(ProcessRequestAsync);
|
||||
_maxAccepts = DefaultMaxAccepts;
|
||||
_maxAccepts = options.Value?.MaxAccepts ?? WebListenerOptions.DefaultMaxAccepts;
|
||||
EnableResponseCaching = options.Value?.EnableResponseCaching ?? true;
|
||||
_shutdownSignal = new ManualResetEvent(false);
|
||||
}
|
||||
|
||||
public Microsoft.Net.Http.Server.WebListener Listener
|
||||
internal Microsoft.Net.Http.Server.WebListener Listener
|
||||
{
|
||||
get { return _listener; }
|
||||
}
|
||||
|
||||
internal int MaxAccepts
|
||||
{
|
||||
get
|
||||
{
|
||||
return _maxAccepts;
|
||||
}
|
||||
set
|
||||
{
|
||||
_maxAccepts = value;
|
||||
if (_listener.IsListening)
|
||||
{
|
||||
ActivateRequestProcessingLimits();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal bool EnableResponseCaching { get; set; } = true;
|
||||
internal bool EnableResponseCaching { get; set; }
|
||||
|
||||
public IFeatureCollection Features { get; }
|
||||
|
||||
|
|
@ -123,7 +106,7 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
|
||||
private void ActivateRequestProcessingLimits()
|
||||
{
|
||||
for (int i = _acceptorCounts; i < MaxAccepts; i++)
|
||||
for (int i = _acceptorCounts; i < _maxAccepts; i++)
|
||||
{
|
||||
ProcessRequestsWorker();
|
||||
}
|
||||
|
|
@ -136,13 +119,13 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
private async void ProcessRequestsWorker()
|
||||
{
|
||||
int workerIndex = Interlocked.Increment(ref _acceptorCounts);
|
||||
while (!_stopping && workerIndex <= MaxAccepts)
|
||||
while (!_stopping && workerIndex <= _maxAccepts)
|
||||
{
|
||||
// Receive a request
|
||||
RequestContext requestContext;
|
||||
try
|
||||
{
|
||||
requestContext = await _listener.GetContextAsync().SupressContext();
|
||||
requestContext = await _listener.AcceptAsync().SupressContext();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
|
|
@ -237,7 +220,6 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_stopping = true;
|
||||
|
|
|
|||
|
|
@ -3,9 +3,11 @@
|
|||
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: AssemblyMetadata("Serviceable", "True")]
|
||||
[assembly: NeutralResourcesLanguage("en-us")]
|
||||
[assembly: AssemblyCompany("Microsoft Corporation.")]
|
||||
[assembly: AssemblyCopyright("© Microsoft Corporation. All rights reserved.")]
|
||||
[assembly: AssemblyProduct("Microsoft ASP.NET Core")]
|
||||
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Server.WebListener.FunctionalTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||
|
|
@ -16,9 +16,6 @@
|
|||
// permissions and limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Hosting.Server;
|
||||
using Microsoft.AspNetCore.Server.WebListener;
|
||||
using Microsoft.AspNetCore.Server.WebListener.Internal;
|
||||
|
|
|
|||
|
|
@ -16,14 +16,17 @@
|
|||
// permissions and limitations under the License.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.AspNetCore.Server.WebListener
|
||||
{
|
||||
public class WebListenerOptions
|
||||
{
|
||||
internal static readonly int DefaultMaxAccepts = 5 * Environment.ProcessorCount;
|
||||
|
||||
public Microsoft.Net.Http.Server.WebListener Listener { get; set; } = new Microsoft.Net.Http.Server.WebListener();
|
||||
|
||||
public int MaxAccepts { get; set; } = DefaultMaxAccepts;
|
||||
|
||||
public bool EnableResponseCaching { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,7 +144,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
internal void SetAuthenticationChallenge(RequestContext context)
|
||||
{
|
||||
IList<string> challenges = GenerateChallenges(context.AuthenticationChallenges);
|
||||
IList<string> challenges = GenerateChallenges(context.Response.AuthenticationChallenges);
|
||||
|
||||
if (challenges.Count > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1105,7 +1105,8 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
private static unsafe string GetVerb(HTTP_REQUEST* request, long fixup)
|
||||
// This requires the HTTP_REQUEST to still be pinned in its original location.
|
||||
internal static unsafe string GetVerb(HTTP_REQUEST* request)
|
||||
{
|
||||
string verb = null;
|
||||
|
||||
|
|
@ -1115,31 +1116,7 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
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, int requestOffset, IntPtr originalAddress)
|
||||
{
|
||||
fixed (byte* pMemoryBlob = memoryBlob)
|
||||
{
|
||||
return GetVerb((HTTP_REQUEST*)(pMemoryBlob + requestOffset), pMemoryBlob - (byte*)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 + requestOffset);
|
||||
if ((int)request->Verb > (int)HTTP_VERB.HttpVerbUnparsed && (int)request->Verb < (int)HTTP_VERB.HttpVerbMaximum)
|
||||
{
|
||||
verb = request->Verb;
|
||||
}
|
||||
verb = HeaderEncoding.GetString(request->pUnknownVerb, request->UnknownVerbLength);
|
||||
}
|
||||
|
||||
return verb;
|
||||
|
|
|
|||
|
|
@ -67,10 +67,12 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
_cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext);
|
||||
_cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken);
|
||||
}
|
||||
}
|
||||
|
||||
internal SafeHandle RequestQueueHandle => _requestContext.Server.RequestQueue.Handle;
|
||||
|
||||
internal X509Certificate2 ClientCert
|
||||
{
|
||||
get
|
||||
|
|
@ -184,8 +186,8 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
uint statusCode =
|
||||
UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate(
|
||||
RequestContext.RequestQueueHandle,
|
||||
RequestContext.Request.ConnectionId,
|
||||
RequestQueueHandle,
|
||||
RequestContext.Request.UConnectionId,
|
||||
(uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE,
|
||||
RequestBlob,
|
||||
size,
|
||||
|
|
@ -263,8 +265,8 @@ namespace Microsoft.Net.Http.Server
|
|||
uint bytesReceived = 0;
|
||||
errorCode =
|
||||
UnsafeNclNativeMethods.HttpApi.HttpReceiveClientCertificate(
|
||||
requestContext.RequestQueueHandle,
|
||||
requestContext.Request.ConnectionId,
|
||||
requestContext.Server.RequestQueue.Handle,
|
||||
requestContext.Request.UConnectionId,
|
||||
(uint)UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE,
|
||||
asyncResult._memoryBlob,
|
||||
asyncResult._size,
|
||||
|
|
|
|||
|
|
@ -22,48 +22,25 @@
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Claims;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.Net.Http.Server
|
||||
{
|
||||
public sealed class Request
|
||||
{
|
||||
private RequestContext _requestContext;
|
||||
private NativeRequestContext _nativeRequestContext;
|
||||
|
||||
private ulong _requestId;
|
||||
private ulong _connectionId;
|
||||
private ulong _contextId;
|
||||
|
||||
private SslStatus _sslStatus;
|
||||
|
||||
private string _httpMethod;
|
||||
private Version _httpVersion;
|
||||
|
||||
// private Uri _requestUri;
|
||||
private string _rawUrl;
|
||||
private string _cookedUrlHost;
|
||||
private string _cookedUrlPath;
|
||||
private string _cookedUrlQuery;
|
||||
private string _pathBase;
|
||||
private string _path;
|
||||
|
||||
private X509Certificate2 _clientCert;
|
||||
private byte[] _providedTokenBindingId;
|
||||
private byte[] _referredTokenBindingId;
|
||||
|
||||
private HeaderCollection _headers;
|
||||
private BoundaryType _contentBoundaryType;
|
||||
private long? _contentLength;
|
||||
private Stream _nativeStream;
|
||||
|
|
@ -71,116 +48,90 @@ namespace Microsoft.Net.Http.Server
|
|||
private SocketAddress _localEndPoint;
|
||||
private SocketAddress _remoteEndPoint;
|
||||
|
||||
private ClaimsPrincipal _user;
|
||||
|
||||
private bool _isDisposed = false;
|
||||
|
||||
internal unsafe Request(RequestContext httpContext, NativeRequestContext memoryBlob)
|
||||
internal unsafe Request(RequestContext requestContext, NativeRequestContext memoryBlob)
|
||||
{
|
||||
// TODO: Verbose log
|
||||
_requestContext = httpContext;
|
||||
RequestContext = requestContext;
|
||||
_nativeRequestContext = memoryBlob;
|
||||
_contentBoundaryType = BoundaryType.None;
|
||||
|
||||
// Set up some of these now to avoid refcounting on memory blob later.
|
||||
_requestId = memoryBlob.RequestBlob->RequestId;
|
||||
_connectionId = memoryBlob.RequestBlob->ConnectionId;
|
||||
_contextId = memoryBlob.RequestBlob->UrlContext;
|
||||
_sslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure :
|
||||
RequestId = memoryBlob.RequestBlob->RequestId;
|
||||
UConnectionId = memoryBlob.RequestBlob->ConnectionId;
|
||||
SslStatus = memoryBlob.RequestBlob->pSslInfo == null ? SslStatus.Insecure :
|
||||
memoryBlob.RequestBlob->pSslInfo->SslClientCertNegotiated == 0 ? SslStatus.NoClientCert :
|
||||
SslStatus.ClientCert;
|
||||
if (memoryBlob.RequestBlob->pRawUrl != null && memoryBlob.RequestBlob->RawUrlLength > 0)
|
||||
{
|
||||
_rawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength);
|
||||
RawUrl = Marshal.PtrToStringAnsi((IntPtr)memoryBlob.RequestBlob->pRawUrl, memoryBlob.RequestBlob->RawUrlLength);
|
||||
}
|
||||
|
||||
UnsafeNclNativeMethods.HttpApi.HTTP_COOKED_URL cookedUrl = memoryBlob.RequestBlob->CookedUrl;
|
||||
if (cookedUrl.pHost != null && cookedUrl.HostLength > 0)
|
||||
{
|
||||
_cookedUrlHost = Marshal.PtrToStringUni((IntPtr)cookedUrl.pHost, cookedUrl.HostLength / 2);
|
||||
// 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);
|
||||
cookedUrlPath = Marshal.PtrToStringUni((IntPtr)cookedUrl.pAbsPath, cookedUrl.AbsPathLength / 2);
|
||||
}
|
||||
QueryString = string.Empty;
|
||||
if (cookedUrl.pQueryString != null && cookedUrl.QueryStringLength > 0)
|
||||
{
|
||||
_cookedUrlQuery = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2);
|
||||
QueryString = Marshal.PtrToStringUni((IntPtr)cookedUrl.pQueryString, cookedUrl.QueryStringLength / 2);
|
||||
}
|
||||
|
||||
UrlPrefix prefix = httpContext.Server.UrlPrefixes.GetPrefix((int)_contextId);
|
||||
string originalPath = RequestPath;
|
||||
var prefix = requestContext.Server.UrlPrefixes.GetPrefix((int)memoryBlob.RequestBlob->UrlContext);
|
||||
var originalPath = RequestUriBuilder.GetRequestPath(RawUrl, cookedUrlPath, RequestContext.Logger);
|
||||
|
||||
// These paths are both unescaped already.
|
||||
if (originalPath.Length == prefix.Path.Length - 1)
|
||||
{
|
||||
// They matched exactly except for the trailing slash.
|
||||
_pathBase = originalPath;
|
||||
_path = string.Empty;
|
||||
PathBase = originalPath;
|
||||
Path = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
// url: /base/path, prefix: /base/, base: /base, path: /path
|
||||
// url: /, prefix: /, base: , path: /
|
||||
_pathBase = originalPath.Substring(0, prefix.Path.Length - 1);
|
||||
_path = originalPath.Substring(prefix.Path.Length - 1);
|
||||
PathBase = originalPath.Substring(0, prefix.Path.Length - 1);
|
||||
Path = originalPath.Substring(prefix.Path.Length - 1);
|
||||
}
|
||||
|
||||
int major = memoryBlob.RequestBlob->Version.MajorVersion;
|
||||
int minor = memoryBlob.RequestBlob->Version.MinorVersion;
|
||||
if (major == 1 && minor == 1)
|
||||
{
|
||||
_httpVersion = Constants.V1_1;
|
||||
ProtocolVersion = Constants.V1_1;
|
||||
}
|
||||
else if (major == 1 && minor == 0)
|
||||
{
|
||||
_httpVersion = Constants.V1_0;
|
||||
ProtocolVersion = Constants.V1_0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpVersion = new Version(major, minor);
|
||||
ProtocolVersion = new Version(major, minor);
|
||||
}
|
||||
|
||||
_httpMethod = UnsafeNclNativeMethods.HttpApi.GetVerb(RequestBuffer, BufferAlignment, OriginalBlobAddress);
|
||||
_headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext));
|
||||
KnownMethod = memoryBlob.RequestBlob->Verb;
|
||||
Method = UnsafeNclNativeMethods.HttpApi.GetVerb(memoryBlob.RequestBlob);
|
||||
Headers = new HeaderCollection(new RequestHeaders(_nativeRequestContext));
|
||||
|
||||
var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)memoryBlob.RequestBlob;
|
||||
_user = AuthenticationManager.GetUser(requestV2->pRequestInfo, requestV2->RequestInfoCount);
|
||||
User = AuthenticationManager.GetUser(requestV2->pRequestInfo, requestV2->RequestInfoCount);
|
||||
|
||||
GetTlsTokenBindingInfo();
|
||||
|
||||
// Finished directly accessing the HTTP_REQUEST structure.
|
||||
_nativeRequestContext.ReleasePins();
|
||||
// TODO: Verbose log parameters
|
||||
}
|
||||
|
||||
internal SslStatus SslStatus
|
||||
{
|
||||
get
|
||||
{
|
||||
return _sslStatus;
|
||||
}
|
||||
}
|
||||
|
||||
public ulong ConnectionId
|
||||
{
|
||||
get
|
||||
{
|
||||
return _connectionId;
|
||||
}
|
||||
}
|
||||
|
||||
internal ulong ContextId
|
||||
{
|
||||
get { return _contextId; }
|
||||
}
|
||||
|
||||
internal RequestContext RequestContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return _requestContext;
|
||||
}
|
||||
}
|
||||
|
||||
internal byte[] RequestBuffer
|
||||
{
|
||||
get
|
||||
|
|
@ -208,26 +159,19 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
// With the leading ?, if any
|
||||
public string QueryString
|
||||
{
|
||||
get
|
||||
{
|
||||
return _cookedUrlQuery ?? string.Empty;
|
||||
}
|
||||
set
|
||||
{
|
||||
_cookedUrlQuery = value;
|
||||
}
|
||||
}
|
||||
internal ulong UConnectionId { get; }
|
||||
|
||||
internal ulong RequestId
|
||||
{
|
||||
get
|
||||
{
|
||||
return _requestId;
|
||||
}
|
||||
}
|
||||
// No ulongs in public APIs...
|
||||
public long ConnectionId => (long)UConnectionId;
|
||||
|
||||
internal ulong RequestId { get; }
|
||||
|
||||
private SslStatus SslStatus { get; }
|
||||
|
||||
private RequestContext RequestContext { get; }
|
||||
|
||||
// With the leading ?, if any
|
||||
public string QueryString { get; }
|
||||
|
||||
public long? ContentLength
|
||||
{
|
||||
|
|
@ -261,20 +205,13 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
public HeaderCollection Headers
|
||||
{
|
||||
get { return _headers; }
|
||||
}
|
||||
public HeaderCollection Headers { get; }
|
||||
|
||||
public string Method
|
||||
{
|
||||
get { return _httpMethod; }
|
||||
}
|
||||
private UnsafeNclNativeMethods.HttpApi.HTTP_VERB KnownMethod { get; }
|
||||
|
||||
public bool IsHeadMethod
|
||||
{
|
||||
get { return string.Equals(_httpMethod, "HEAD", StringComparison.OrdinalIgnoreCase); }
|
||||
}
|
||||
public bool IsHeadMethod => KnownMethod == UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD;
|
||||
|
||||
public string Method { get; }
|
||||
|
||||
public Stream Body
|
||||
{
|
||||
|
|
@ -288,39 +225,15 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
public string PathBase
|
||||
{
|
||||
get { return _pathBase; }
|
||||
}
|
||||
public string PathBase { get; }
|
||||
|
||||
public string Path
|
||||
{
|
||||
get { return _path; }
|
||||
}
|
||||
public string Path { get; }
|
||||
|
||||
public bool IsSecureConnection
|
||||
{
|
||||
get
|
||||
{
|
||||
return _sslStatus != SslStatus.Insecure;
|
||||
}
|
||||
}
|
||||
public bool IsHttps => SslStatus != SslStatus.Insecure;
|
||||
|
||||
public string RawUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
return _rawUrl;
|
||||
}
|
||||
}
|
||||
public string RawUrl { get; }
|
||||
|
||||
public Version ProtocolVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
return _httpVersion;
|
||||
}
|
||||
}
|
||||
public Version ProtocolVersion { get; }
|
||||
|
||||
public bool HasEntityBody
|
||||
{
|
||||
|
|
@ -358,65 +271,24 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
public IPAddress RemoteIpAddress
|
||||
{
|
||||
get { return RemoteEndPoint.GetIPAddress(); }
|
||||
}
|
||||
// TODO: Lazy cache?
|
||||
public IPAddress RemoteIpAddress => RemoteEndPoint.GetIPAddress();
|
||||
|
||||
public IPAddress LocalIpAddress
|
||||
{
|
||||
get { return LocalEndPoint.GetIPAddress(); }
|
||||
}
|
||||
public IPAddress LocalIpAddress => LocalEndPoint.GetIPAddress();
|
||||
|
||||
public int RemotePort
|
||||
{
|
||||
get { return RemoteEndPoint.GetPort(); }
|
||||
}
|
||||
public int RemotePort => RemoteEndPoint.GetPort();
|
||||
|
||||
public int LocalPort
|
||||
{
|
||||
get { return LocalEndPoint.GetPort(); }
|
||||
}
|
||||
public int LocalPort => LocalEndPoint.GetPort();
|
||||
|
||||
public string Scheme
|
||||
{
|
||||
get { return IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; }
|
||||
}
|
||||
public string Scheme => IsHttps ? Constants.HttpsScheme : Constants.HttpScheme;
|
||||
|
||||
internal string RequestPath
|
||||
{
|
||||
get
|
||||
{
|
||||
return RequestUriBuilder.GetRequestPath(_rawUrl, _cookedUrlPath, RequestContext.Logger);
|
||||
}
|
||||
}
|
||||
// HTTP.Sys allows you to upgrade anything to opaque unless content-length > 0 or chunked are specified.
|
||||
// TODO: >= Win8 check https://github.com/aspnet/WebListener/issues/215
|
||||
internal bool IsUpgradable => !HasEntityBody;
|
||||
|
||||
internal bool IsUpgradable
|
||||
{
|
||||
get
|
||||
{
|
||||
// HTTP.Sys allows you to upgrade anything to opaque unless content-length > 0 or chunked are specified.
|
||||
return !HasEntityBody;
|
||||
}
|
||||
}
|
||||
public string ContentType => Headers[HttpKnownHeaderNames.ContentType];
|
||||
|
||||
public string ContentType
|
||||
{
|
||||
get
|
||||
{
|
||||
return Headers[HttpKnownHeaderNames.ContentType];
|
||||
}
|
||||
}
|
||||
|
||||
internal ClaimsPrincipal User
|
||||
{
|
||||
get { return _user; }
|
||||
}
|
||||
|
||||
internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod()
|
||||
{
|
||||
return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, BufferAlignment, OriginalBlobAddress);
|
||||
}
|
||||
internal ClaimsPrincipal User { get; }
|
||||
|
||||
// Populates the client certificate. The result may be null if there is no client cert.
|
||||
// TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to
|
||||
|
|
@ -435,7 +307,7 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
ClientCertLoader certLoader = new ClientCertLoader(RequestContext, cancellationToken);
|
||||
var certLoader = new ClientCertLoader(RequestContext, cancellationToken);
|
||||
try
|
||||
{
|
||||
await certLoader.LoadClientCertificateAsync().SupressContext();
|
||||
|
|
@ -489,40 +361,19 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
// Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be
|
||||
// disposed.
|
||||
internal void DetachBlob(NativeRequestContext memoryBlob)
|
||||
{
|
||||
if (memoryBlob != null && (object)memoryBlob == (object)_nativeRequestContext)
|
||||
{
|
||||
_nativeRequestContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Finalizes ownership of the memory blob. DetachBlob can't be called after this.
|
||||
internal void ReleasePins()
|
||||
{
|
||||
_nativeRequestContext.ReleasePins();
|
||||
}
|
||||
|
||||
// should only be called from RequestContext
|
||||
internal void Dispose()
|
||||
{
|
||||
// TODO: Verbose log
|
||||
_isDisposed = true;
|
||||
NativeRequestContext memoryBlob = _nativeRequestContext;
|
||||
if (memoryBlob != null)
|
||||
{
|
||||
memoryBlob.Dispose();
|
||||
_nativeRequestContext = null;
|
||||
}
|
||||
_nativeRequestContext.Dispose();
|
||||
if (_nativeStream != null)
|
||||
{
|
||||
_nativeStream.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
internal void CheckDisposed()
|
||||
private void CheckDisposed()
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@
|
|||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Authentication.ExtendedProtection;
|
||||
using System.Security.Claims;
|
||||
using System.Threading;
|
||||
|
|
@ -36,47 +34,31 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
public sealed class RequestContext : IDisposable
|
||||
{
|
||||
internal static readonly Action<object> AbortDelegate = Abort;
|
||||
private static readonly Action<object> AbortDelegate = Abort;
|
||||
|
||||
private WebListener _server;
|
||||
private Request _request;
|
||||
private Response _response;
|
||||
private NativeRequestContext _memoryBlob;
|
||||
private bool _disposed;
|
||||
private CancellationTokenSource _requestAbortSource;
|
||||
private CancellationToken? _disconnectToken;
|
||||
private bool _disposed;
|
||||
|
||||
internal RequestContext(WebListener server, NativeRequestContext memoryBlob)
|
||||
{
|
||||
// TODO: Verbose log
|
||||
_server = server;
|
||||
Server = server;
|
||||
_memoryBlob = memoryBlob;
|
||||
_request = new Request(this, _memoryBlob);
|
||||
_response = new Response(this);
|
||||
_request.ReleasePins();
|
||||
AuthenticationChallenges = server.AuthenticationManager.AuthenticationSchemes & ~AuthenticationSchemes.AllowAnonymous;
|
||||
Request = new Request(this, _memoryBlob);
|
||||
Response = new Response(this);
|
||||
}
|
||||
|
||||
public Request Request
|
||||
{
|
||||
get
|
||||
{
|
||||
return _request;
|
||||
}
|
||||
}
|
||||
internal WebListener Server { get; }
|
||||
|
||||
public Response Response
|
||||
{
|
||||
get
|
||||
{
|
||||
return _response;
|
||||
}
|
||||
}
|
||||
internal ILogger Logger => Server.Logger;
|
||||
|
||||
public ClaimsPrincipal User
|
||||
{
|
||||
get { return _request.User; }
|
||||
}
|
||||
public Request Request { get; }
|
||||
|
||||
public Response Response { get; }
|
||||
|
||||
public ClaimsPrincipal User => Request.User;
|
||||
|
||||
public CancellationToken DisconnectToken
|
||||
{
|
||||
|
|
@ -86,7 +68,7 @@ namespace Microsoft.Net.Http.Server
|
|||
// We need to be able to dispose of the registrations each request to prevent leaks.
|
||||
if (!_disconnectToken.HasValue)
|
||||
{
|
||||
var connectionDisconnectToken = _server.DisconnectListener.GetTokenForConnection(Request.ConnectionId);
|
||||
var connectionDisconnectToken = Server.DisconnectListener.GetTokenForConnection(Request.UConnectionId);
|
||||
|
||||
if (connectionDisconnectToken.CanBeCanceled)
|
||||
{
|
||||
|
|
@ -102,64 +84,29 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
internal WebListener Server
|
||||
{
|
||||
get
|
||||
{
|
||||
return _server;
|
||||
}
|
||||
}
|
||||
|
||||
internal ILogger Logger
|
||||
{
|
||||
get { return Server.Logger; }
|
||||
}
|
||||
|
||||
internal SafeHandle RequestQueueHandle
|
||||
{
|
||||
get
|
||||
{
|
||||
return _server.RequestQueue.Handle;
|
||||
}
|
||||
}
|
||||
|
||||
internal ulong RequestId
|
||||
{
|
||||
get
|
||||
{
|
||||
return Request.RequestId;
|
||||
}
|
||||
}
|
||||
|
||||
public unsafe Guid TraceIdentifier
|
||||
{
|
||||
get
|
||||
{
|
||||
// This is the base GUID used by HTTP.SYS for generating the activity ID.
|
||||
// HTTP.SYS overwrites the first 8 bytes of the base GUID with RequestId to generate ETW activity ID.
|
||||
|
||||
var guid = new Guid(0xffcb4c93, 0xa57f, 0x453c, 0xb6, 0x3f, 0x84, 0x71, 0xc, 0x79, 0x67, 0xbb);
|
||||
*((ulong*)&guid) = Request.RequestId;
|
||||
return guid;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authentication challengest that will be added to the response if the status code is 401.
|
||||
/// This must be a subset of the AuthenticationSchemes enabled on the server.
|
||||
/// </summary>
|
||||
public AuthenticationSchemes AuthenticationChallenges { get; set; }
|
||||
|
||||
public bool IsUpgradableRequest
|
||||
{
|
||||
get { return _request.IsUpgradable; }
|
||||
}
|
||||
public bool IsUpgradableRequest => Request.IsUpgradable;
|
||||
|
||||
public Task<Stream> UpgradeAsync()
|
||||
{
|
||||
if (!IsUpgradableRequest || _response.HasStarted)
|
||||
if (!IsUpgradableRequest)
|
||||
{
|
||||
throw new InvalidOperationException("This request cannot be upgraded. It is incompatible, or the response has already started.");
|
||||
throw new InvalidOperationException("This request cannot be upgraded, it is incompatible.");
|
||||
}
|
||||
if (Response.HasStarted)
|
||||
{
|
||||
throw new InvalidOperationException("This request cannot be upgraded, the response has already started.");
|
||||
}
|
||||
|
||||
// Set the status code and reason phrase
|
||||
|
|
@ -176,19 +123,22 @@ namespace Microsoft.Net.Http.Server
|
|||
// TODO: Public when needed
|
||||
internal bool TryGetChannelBinding(ref ChannelBinding value)
|
||||
{
|
||||
if (!Request.IsSecureConnection)
|
||||
if (!Request.IsHttps)
|
||||
{
|
||||
LogHelper.LogDebug(Logger, "TryGetChannelBinding", "Channel binding requires HTTPS.");
|
||||
return false;
|
||||
}
|
||||
|
||||
value = ClientCertLoader.GetChannelBindingFromTls(Server.RequestQueue, Request.ConnectionId, Logger);
|
||||
value = ClientCertLoader.GetChannelBindingFromTls(Server.RequestQueue, Request.UConnectionId, Logger);
|
||||
|
||||
Debug.Assert(value != null, "GetChannelBindingFromTls returned null even though OS supposedly supports Extended Protection");
|
||||
LogHelper.LogInfo(Logger, "Channel binding retrieved.");
|
||||
return value != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Flushes and completes the response.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
|
|
@ -204,14 +154,17 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
_requestAbortSource.Dispose();
|
||||
}
|
||||
_response.Dispose();
|
||||
Response.Dispose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
_request.Dispose();
|
||||
Request.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Forcibly terminate and dispose the request, closing the connection if necessary.
|
||||
/// </summary>
|
||||
public void Abort()
|
||||
{
|
||||
// May be called from Dispose() code path, don't check _disposed.
|
||||
|
|
@ -229,8 +182,8 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
_requestAbortSource.Dispose();
|
||||
}
|
||||
ForceCancelRequest(RequestQueueHandle, _request.RequestId);
|
||||
_request.Dispose();
|
||||
ForceCancelRequest();
|
||||
Request.Dispose();
|
||||
}
|
||||
|
||||
private static void Abort(object state)
|
||||
|
|
@ -239,30 +192,25 @@ namespace Microsoft.Net.Http.Server
|
|||
context.Abort();
|
||||
}
|
||||
|
||||
// This is only called while processing incoming requests. We don't have to worry about canceling
|
||||
// any response writes.
|
||||
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification =
|
||||
"It is safe to ignore the return value on a cancel operation because the connection is being closed")]
|
||||
internal static void CancelRequest(SafeHandle requestQueueHandle, ulong requestId)
|
||||
internal CancellationTokenRegistration RegisterForCancellation(CancellationToken cancellationToken)
|
||||
{
|
||||
UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(requestQueueHandle, requestId,
|
||||
IntPtr.Zero);
|
||||
return cancellationToken.Register(AbortDelegate, this);
|
||||
}
|
||||
|
||||
// The request is being aborted, but large writes may be in progress. Cancel them.
|
||||
internal void ForceCancelRequest(SafeHandle requestQueueHandle, ulong requestId)
|
||||
internal void ForceCancelRequest()
|
||||
{
|
||||
try
|
||||
{
|
||||
uint statusCode = UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(requestQueueHandle, requestId,
|
||||
IntPtr.Zero);
|
||||
var statusCode = UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(Server.RequestQueue.Handle,
|
||||
Request.RequestId, IntPtr.Zero);
|
||||
|
||||
// Either the connection has already dropped, or the last write is in progress.
|
||||
// The requestId becomes invalid as soon as the last Content-Length write starts.
|
||||
// The only way to cancel now is with CancelIoEx.
|
||||
if (statusCode == UnsafeNclNativeMethods.ErrorCodes.ERROR_CONNECTION_INVALID)
|
||||
{
|
||||
_response.CancelLastWrite(requestQueueHandle);
|
||||
Response.CancelLastWrite();
|
||||
}
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ using System.IO;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.Net.Http.Server
|
||||
{
|
||||
|
|
@ -48,6 +49,12 @@ namespace Microsoft.Net.Http.Server
|
|||
get { return _requestContext; }
|
||||
}
|
||||
|
||||
private SafeHandle RequestQueueHandle => RequestContext.Server.RequestQueue.Handle;
|
||||
|
||||
private ulong RequestId => RequestContext.Request.RequestId;
|
||||
|
||||
private ILogger Logger => RequestContext.Server.Logger;
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
|
|
@ -173,8 +180,8 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
statusCode =
|
||||
UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody(
|
||||
_requestContext.RequestQueueHandle,
|
||||
_requestContext.RequestId,
|
||||
RequestQueueHandle,
|
||||
RequestId,
|
||||
flags,
|
||||
(IntPtr)(pBuffer + offset),
|
||||
(uint)size,
|
||||
|
|
@ -186,7 +193,7 @@ namespace Microsoft.Net.Http.Server
|
|||
if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS && statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_HANDLE_EOF)
|
||||
{
|
||||
Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode));
|
||||
LogHelper.LogException(_requestContext.Logger, "Read", exception);
|
||||
LogHelper.LogException(Logger, "Read", exception);
|
||||
Abort();
|
||||
throw exception;
|
||||
}
|
||||
|
|
@ -256,8 +263,8 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
statusCode =
|
||||
UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody(
|
||||
_requestContext.RequestQueueHandle,
|
||||
_requestContext.RequestId,
|
||||
RequestQueueHandle,
|
||||
RequestId,
|
||||
flags,
|
||||
asyncResult.PinnedBuffer,
|
||||
(uint)size,
|
||||
|
|
@ -266,7 +273,7 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.LogException(_requestContext.Logger, "BeginRead", e);
|
||||
LogHelper.LogException(Logger, "BeginRead", e);
|
||||
asyncResult.Dispose();
|
||||
throw;
|
||||
}
|
||||
|
|
@ -282,7 +289,7 @@ namespace Microsoft.Net.Http.Server
|
|||
else
|
||||
{
|
||||
Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode));
|
||||
LogHelper.LogException(_requestContext.Logger, "BeginRead", exception);
|
||||
LogHelper.LogException(Logger, "BeginRead", exception);
|
||||
Abort();
|
||||
throw exception;
|
||||
}
|
||||
|
|
@ -368,7 +375,7 @@ namespace Microsoft.Net.Http.Server
|
|||
var cancellationRegistration = default(CancellationTokenRegistration);
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext);
|
||||
cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken);
|
||||
}
|
||||
|
||||
asyncResult = new RequestStreamAsyncResult(this, null, null, buffer, offset, dataRead, cancellationRegistration);
|
||||
|
|
@ -380,8 +387,8 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
statusCode =
|
||||
UnsafeNclNativeMethods.HttpApi.HttpReceiveRequestEntityBody(
|
||||
_requestContext.RequestQueueHandle,
|
||||
_requestContext.RequestId,
|
||||
RequestQueueHandle,
|
||||
RequestId,
|
||||
flags,
|
||||
asyncResult.PinnedBuffer,
|
||||
(uint)size,
|
||||
|
|
@ -392,7 +399,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
asyncResult.Dispose();
|
||||
Abort();
|
||||
LogHelper.LogException(_requestContext.Logger, "ReadAsync", e);
|
||||
LogHelper.LogException(Logger, "ReadAsync", e);
|
||||
throw;
|
||||
}
|
||||
|
||||
|
|
@ -409,7 +416,7 @@ namespace Microsoft.Net.Http.Server
|
|||
else
|
||||
{
|
||||
Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode));
|
||||
LogHelper.LogException(_requestContext.Logger, "ReadAsync", exception);
|
||||
LogHelper.LogException(Logger, "ReadAsync", exception);
|
||||
Abort();
|
||||
throw exception;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,14 +22,12 @@
|
|||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
|
@ -38,26 +36,26 @@ using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods;
|
|||
|
||||
namespace Microsoft.Net.Http.Server
|
||||
{
|
||||
public sealed unsafe class Response
|
||||
public sealed class Response
|
||||
{
|
||||
private ResponseState _responseState;
|
||||
private HeaderCollection _headers;
|
||||
private string _reasonPhrase;
|
||||
private ResponseStream _nativeStream;
|
||||
private AuthenticationSchemes _authChallenges;
|
||||
private TimeSpan? _cacheTtl;
|
||||
private long _expectedBodyLength;
|
||||
private BoundaryType _boundaryType;
|
||||
private HttpApi.HTTP_RESPONSE_V2 _nativeResponse;
|
||||
private IList<Tuple<Func<object, Task>, object>> _onStartingActions;
|
||||
private IList<Tuple<Func<object, Task>, object>> _onCompletedActions;
|
||||
|
||||
private RequestContext _requestContext;
|
||||
private bool _bufferingEnabled;
|
||||
|
||||
internal Response(RequestContext requestContext)
|
||||
{
|
||||
// TODO: Verbose log
|
||||
_requestContext = requestContext;
|
||||
_headers = new HeaderCollection();
|
||||
RequestContext = requestContext;
|
||||
Headers = new HeaderCollection();
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
|
@ -65,14 +63,13 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
if (_responseState >= ResponseState.StartedSending)
|
||||
{
|
||||
_requestContext.Abort();
|
||||
throw new InvalidOperationException("The response has already been sent. Request Aborted.");
|
||||
}
|
||||
// We haven't started yet, or we're just buffered, we can clear any data, headers, and state so
|
||||
// that we can start over (e.g. to write an error message).
|
||||
_nativeResponse = new HttpApi.HTTP_RESPONSE_V2();
|
||||
_headers.IsReadOnly = false;
|
||||
_headers.Clear();
|
||||
Headers.IsReadOnly = false;
|
||||
Headers.Clear();
|
||||
_reasonPhrase = null;
|
||||
_boundaryType = BoundaryType.None;
|
||||
_nativeResponse.Response_V1.StatusCode = (ushort)HttpStatusCode.OK;
|
||||
|
|
@ -81,10 +78,11 @@ namespace Microsoft.Net.Http.Server
|
|||
_responseState = ResponseState.Created;
|
||||
_onStartingActions = new List<Tuple<Func<object, Task>, object>>();
|
||||
_onCompletedActions = new List<Tuple<Func<object, Task>, object>>();
|
||||
_bufferingEnabled = _requestContext.Server.BufferResponses;
|
||||
_bufferingEnabled = RequestContext.Server.BufferResponses;
|
||||
_expectedBodyLength = 0;
|
||||
_nativeStream = null;
|
||||
CacheTtl = null;
|
||||
_cacheTtl = null;
|
||||
_authChallenges = RequestContext.Server.AuthenticationManager.AuthenticationSchemes & ~AuthenticationSchemes.AllowAnonymous;
|
||||
}
|
||||
|
||||
private enum ResponseState
|
||||
|
|
@ -96,30 +94,19 @@ namespace Microsoft.Net.Http.Server
|
|||
Closed,
|
||||
}
|
||||
|
||||
private RequestContext RequestContext
|
||||
{
|
||||
get
|
||||
{
|
||||
return _requestContext;
|
||||
}
|
||||
}
|
||||
private RequestContext RequestContext { get; }
|
||||
|
||||
private Request Request
|
||||
{
|
||||
get
|
||||
{
|
||||
return RequestContext.Request;
|
||||
}
|
||||
}
|
||||
private Request Request => RequestContext.Request;
|
||||
|
||||
public int StatusCode
|
||||
{
|
||||
get { return _nativeResponse.Response_V1.StatusCode; }
|
||||
set
|
||||
{
|
||||
// Http.Sys automatically sends 100 Continue responses when you read from the request body.
|
||||
if (value <= 100 || 999 < value)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value", value, string.Format(Resources.Exception_InvalidStatusCode, value));
|
||||
throw new ArgumentOutOfRangeException(nameof(value), value, string.Format(Resources.Exception_InvalidStatusCode, value));
|
||||
}
|
||||
CheckResponseStarted();
|
||||
_nativeResponse.Response_V1.StatusCode = (ushort)value;
|
||||
|
|
@ -157,26 +144,39 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
internal string GetReasonPhrase(int statusCode)
|
||||
/// <summary>
|
||||
/// The authentication challenges that will be added to the response if the status code is 401.
|
||||
/// This must be a subset of the AuthenticationSchemes enabled on the server.
|
||||
/// </summary>
|
||||
public AuthenticationSchemes AuthenticationChallenges
|
||||
{
|
||||
get { return _authChallenges; }
|
||||
set
|
||||
{
|
||||
CheckResponseStarted();
|
||||
_authChallenges = value;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetReasonPhrase(int statusCode)
|
||||
{
|
||||
string reasonPhrase = ReasonPhrase;
|
||||
if (string.IsNullOrWhiteSpace(reasonPhrase))
|
||||
{
|
||||
// if the user hasn't set this, generated on the fly, if possible.
|
||||
// We know this one is safe, no need to verify it as in the setter.
|
||||
// If the user hasn't set this then it is generated on the fly if possible.
|
||||
reasonPhrase = HttpReasonPhrase.Get(statusCode) ?? string.Empty;
|
||||
}
|
||||
return reasonPhrase;
|
||||
}
|
||||
|
||||
// We MUST NOT send message-body when we send responses with these Status codes
|
||||
private static readonly int[] NoResponseBody = { 100, 101, 204, 205, 304 };
|
||||
private static readonly int[] StatusWithNoResponseBody = { 100, 101, 204, 205, 304 };
|
||||
|
||||
private static bool CanSendResponseBody(int responseCode)
|
||||
{
|
||||
for (int i = 0; i < NoResponseBody.Length; i++)
|
||||
for (int i = 0; i < StatusWithNoResponseBody.Length; i++)
|
||||
{
|
||||
if (responseCode == NoResponseBody[i])
|
||||
if (responseCode == StatusWithNoResponseBody[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
@ -184,10 +184,7 @@ namespace Microsoft.Net.Http.Server
|
|||
return true;
|
||||
}
|
||||
|
||||
public HeaderCollection Headers
|
||||
{
|
||||
get { return _headers; }
|
||||
}
|
||||
public HeaderCollection Headers { get; }
|
||||
|
||||
internal long ExpectedBodyLength
|
||||
{
|
||||
|
|
@ -261,6 +258,20 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enable kernel caching for the response with the given timeout. Http.Sys determines if the response
|
||||
/// can be cached.
|
||||
/// </summary>
|
||||
public TimeSpan? CacheTtl
|
||||
{
|
||||
get { return _cacheTtl; }
|
||||
set
|
||||
{
|
||||
CheckResponseStarted();
|
||||
_cacheTtl = value;
|
||||
}
|
||||
}
|
||||
|
||||
// should only be called from RequestContext
|
||||
internal void Dispose()
|
||||
{
|
||||
|
|
@ -276,13 +287,17 @@ namespace Microsoft.Net.Http.Server
|
|||
_responseState = ResponseState.Closed;
|
||||
}
|
||||
|
||||
// old API, now private, and helper methods
|
||||
|
||||
internal BoundaryType BoundaryType
|
||||
{
|
||||
get { return _boundaryType; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates if the response status, reason, and headers are prepared to send and can
|
||||
/// no longer be modified. This is caused by the first write to the response body. However,
|
||||
/// the response may not have been flushed to the network yet if the body is buffered.
|
||||
/// See HasStartedSending.
|
||||
/// </summary>
|
||||
public bool HasStarted
|
||||
{
|
||||
get { return _responseState >= ResponseState.Started; }
|
||||
|
|
@ -301,13 +316,14 @@ namespace Microsoft.Net.Http.Server
|
|||
get { return _responseState >= ResponseState.ComputedHeaders; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates the initial response has been flushed to the network and can no longer be modified or Reset.
|
||||
/// </summary>
|
||||
public bool HasStartedSending
|
||||
{
|
||||
get { return _responseState >= ResponseState.StartedSending; }
|
||||
}
|
||||
|
||||
public TimeSpan? CacheTtl { get; set; }
|
||||
|
||||
private void EnsureResponseStream()
|
||||
{
|
||||
if (_nativeStream == null)
|
||||
|
|
@ -389,11 +405,10 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
|
||||
var cachePolicy = new HttpApi.HTTP_CACHE_POLICY();
|
||||
var cacheTtl = CacheTtl;
|
||||
if (cacheTtl.HasValue && cacheTtl.Value > TimeSpan.Zero)
|
||||
if (_cacheTtl.HasValue && _cacheTtl.Value > TimeSpan.Zero)
|
||||
{
|
||||
cachePolicy.Policy = HttpApi.HTTP_CACHE_POLICY_TYPE.HttpCachePolicyTimeToLive;
|
||||
cachePolicy.SecondsToLive = (uint)Math.Min(cacheTtl.Value.Ticks / TimeSpan.TicksPerSecond, Int32.MaxValue);
|
||||
cachePolicy.SecondsToLive = (uint)Math.Min(_cacheTtl.Value.Ticks / TimeSpan.TicksPerSecond, Int32.MaxValue);
|
||||
}
|
||||
|
||||
byte[] reasonPhraseBytes = HeaderEncoding.GetBytes(reasonPhrase);
|
||||
|
|
@ -405,7 +420,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
statusCode =
|
||||
HttpApi.HttpSendHttpResponse(
|
||||
RequestContext.RequestQueueHandle,
|
||||
RequestContext.Server.RequestQueue.Handle,
|
||||
Request.RequestId,
|
||||
(uint)flags,
|
||||
pResponse,
|
||||
|
|
@ -471,7 +486,7 @@ namespace Microsoft.Net.Http.Server
|
|||
var responseContentLength = ContentLength;
|
||||
var responseCloseSet = Matches(Constants.Close, responseConnectionString);
|
||||
var responseChunkedSet = Matches(Constants.Chunked, transferEncodingString);
|
||||
var statusCanHaveBody = CanSendResponseBody(_requestContext.Response.StatusCode);
|
||||
var statusCanHaveBody = CanSendResponseBody(RequestContext.Response.StatusCode);
|
||||
|
||||
// Determine if the connection will be kept alive or closed.
|
||||
var keepConnectionAlive = true;
|
||||
|
|
@ -540,7 +555,7 @@ namespace Microsoft.Net.Http.Server
|
|||
return string.Equals(knownValue, input?.Trim(), StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private List<GCHandle> SerializeHeaders(bool isOpaqueUpgrade)
|
||||
private unsafe List<GCHandle> SerializeHeaders(bool isOpaqueUpgrade)
|
||||
{
|
||||
Headers.IsReadOnly = true; // Prohibit further modifications.
|
||||
HttpApi.HTTP_UNKNOWN_HEADER[] unknownHeaders = null;
|
||||
|
|
@ -736,12 +751,9 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
internal void CancelLastWrite(SafeHandle requestQueueHandle)
|
||||
internal void CancelLastWrite()
|
||||
{
|
||||
if (_nativeStream != null)
|
||||
{
|
||||
_nativeStream.CancelLastWrite(requestQueueHandle);
|
||||
}
|
||||
_nativeStream?.CancelLastWrite();
|
||||
}
|
||||
|
||||
public Task SendFileAsync(string path, long offset, long? count, CancellationToken cancel)
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ using System.IO;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using static Microsoft.Net.Http.Server.UnsafeNclNativeMethods;
|
||||
|
||||
namespace Microsoft.Net.Http.Server
|
||||
|
|
@ -56,6 +57,12 @@ namespace Microsoft.Net.Http.Server
|
|||
get { return _requestContext; }
|
||||
}
|
||||
|
||||
private SafeHandle RequestQueueHandle => RequestContext.Server.RequestQueue.Handle;
|
||||
|
||||
private ulong RequestId => RequestContext.Request.RequestId;
|
||||
|
||||
private ILogger Logger => RequestContext.Server.Logger;
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get
|
||||
|
|
@ -125,7 +132,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
_requestContext.Abort();
|
||||
// This is logged rather than thrown because it is too late for an exception to be visible in user code.
|
||||
LogHelper.LogError(_requestContext.Logger, "ResponseStream::Dispose", "Fewer bytes were written than were specified in the Content-Length.");
|
||||
LogHelper.LogError(Logger, "ResponseStream::Dispose", "Fewer bytes were written than were specified in the Content-Length.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -153,8 +160,8 @@ namespace Microsoft.Net.Http.Server
|
|||
fixed (HttpApi.HTTP_DATA_CHUNK* pDataChunks = dataChunks)
|
||||
{
|
||||
statusCode = HttpApi.HttpSendResponseEntityBody(
|
||||
_requestContext.RequestQueueHandle,
|
||||
_requestContext.RequestId,
|
||||
RequestQueueHandle,
|
||||
RequestId,
|
||||
(uint)flags,
|
||||
(ushort)dataChunks.Length,
|
||||
pDataChunks,
|
||||
|
|
@ -182,7 +189,7 @@ namespace Microsoft.Net.Http.Server
|
|||
&& (!endOfRequest || (statusCode != ErrorCodes.ERROR_CONNECTION_INVALID && statusCode != ErrorCodes.ERROR_INVALID_PARAMETER)))
|
||||
{
|
||||
Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode));
|
||||
LogHelper.LogException(_requestContext.Logger, "Flush", exception);
|
||||
LogHelper.LogException(Logger, "Flush", exception);
|
||||
Abort();
|
||||
throw exception;
|
||||
}
|
||||
|
|
@ -287,7 +294,7 @@ namespace Microsoft.Net.Http.Server
|
|||
var cancellationRegistration = default(CancellationTokenRegistration);
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext);
|
||||
cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken);
|
||||
}
|
||||
|
||||
var flags = ComputeLeftToWrite();
|
||||
|
|
@ -311,8 +318,8 @@ namespace Microsoft.Net.Http.Server
|
|||
else
|
||||
{
|
||||
statusCode = HttpApi.HttpSendResponseEntityBody(
|
||||
_requestContext.RequestQueueHandle,
|
||||
_requestContext.RequestId,
|
||||
RequestQueueHandle,
|
||||
RequestId,
|
||||
(uint)flags,
|
||||
asyncResult.DataChunkCount,
|
||||
asyncResult.DataChunks,
|
||||
|
|
@ -325,7 +332,7 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.LogException(_requestContext.Logger, "FlushAsync", e);
|
||||
LogHelper.LogException(Logger, "FlushAsync", e);
|
||||
asyncResult.Dispose();
|
||||
Abort();
|
||||
throw;
|
||||
|
|
@ -341,7 +348,7 @@ namespace Microsoft.Net.Http.Server
|
|||
else
|
||||
{
|
||||
Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode));
|
||||
LogHelper.LogException(_requestContext.Logger, "FlushAsync", exception);
|
||||
LogHelper.LogException(Logger, "FlushAsync", exception);
|
||||
Abort();
|
||||
throw exception;
|
||||
}
|
||||
|
|
@ -408,8 +415,7 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
if (_leftToWrite == long.MinValue)
|
||||
{
|
||||
UnsafeNclNativeMethods.HttpApi.HTTP_VERB method = _requestContext.Request.GetKnownMethod();
|
||||
if (method == UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD)
|
||||
if (_requestContext.Request.IsHeadMethod)
|
||||
{
|
||||
_leftToWrite = 0;
|
||||
}
|
||||
|
|
@ -578,7 +584,7 @@ namespace Microsoft.Net.Http.Server
|
|||
var cancellationRegistration = default(CancellationTokenRegistration);
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
cancellationRegistration = cancellationToken.Register(RequestContext.AbortDelegate, _requestContext);
|
||||
cancellationRegistration = RequestContext.RegisterForCancellation(cancellationToken);
|
||||
}
|
||||
|
||||
uint statusCode;
|
||||
|
|
@ -615,8 +621,8 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
// TODO: If opaque then include the buffer data flag.
|
||||
statusCode = HttpApi.HttpSendResponseEntityBody(
|
||||
_requestContext.RequestQueueHandle,
|
||||
_requestContext.RequestId,
|
||||
RequestQueueHandle,
|
||||
RequestId,
|
||||
(uint)flags,
|
||||
asyncResult.DataChunkCount,
|
||||
asyncResult.DataChunks,
|
||||
|
|
@ -629,7 +635,7 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.LogException(_requestContext.Logger, "SendFileAsync", e);
|
||||
LogHelper.LogException(Logger, "SendFileAsync", e);
|
||||
asyncResult.Dispose();
|
||||
Abort();
|
||||
throw;
|
||||
|
|
@ -645,7 +651,7 @@ namespace Microsoft.Net.Http.Server
|
|||
else
|
||||
{
|
||||
Exception exception = new IOException(string.Empty, new WebListenerException((int)statusCode));
|
||||
LogHelper.LogException(_requestContext.Logger, "SendFileAsync", exception);
|
||||
LogHelper.LogException(Logger, "SendFileAsync", exception);
|
||||
Abort();
|
||||
throw exception;
|
||||
}
|
||||
|
|
@ -713,12 +719,12 @@ namespace Microsoft.Net.Http.Server
|
|||
// Sync can only be Canceled by CancelSynchronousIo, but we don't attempt this right now.
|
||||
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", Justification =
|
||||
"It is safe to ignore the return value on a cancel operation because the connection is being closed")]
|
||||
internal unsafe void CancelLastWrite(SafeHandle requestQueueHandle)
|
||||
internal unsafe void CancelLastWrite()
|
||||
{
|
||||
ResponseStreamAsyncResult asyncState = _lastWrite;
|
||||
if (asyncState != null && !asyncState.IsCompleted)
|
||||
{
|
||||
UnsafeNclNativeMethods.CancelIoEx(requestQueueHandle, asyncState.NativeOverlapped);
|
||||
UnsafeNclNativeMethods.CancelIoEx(RequestQueueHandle, asyncState.NativeOverlapped);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
// -----------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Net.Http.Server
|
||||
|
|
@ -53,8 +52,6 @@ namespace Microsoft.Net.Http.Server
|
|||
//
|
||||
// No initialization is required because a value of zero indicates that system defaults should be used.
|
||||
_timeouts = new int[5];
|
||||
|
||||
LoadConfigurationSettings();
|
||||
}
|
||||
|
||||
#region Properties
|
||||
|
|
@ -72,11 +69,11 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody);
|
||||
return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody, value);
|
||||
SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.EntityBody, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -95,11 +92,11 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody);
|
||||
return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody, value);
|
||||
SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.DrainEntityBody, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -113,11 +110,11 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue);
|
||||
return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue, value);
|
||||
SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.RequestQueue, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -132,11 +129,11 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection);
|
||||
return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection, value);
|
||||
SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.IdleConnection, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -152,17 +149,19 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
get
|
||||
{
|
||||
return GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait);
|
||||
return GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait);
|
||||
}
|
||||
set
|
||||
{
|
||||
SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait, value);
|
||||
SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The minimum send rate, in bytes-per-second, for the response. The default response send rate is 150
|
||||
/// bytes-per-second.
|
||||
///
|
||||
/// Use 0 to indicate that system defaults should be used.
|
||||
///
|
||||
/// To disable this timer set it to UInt32.MaxValue
|
||||
/// </summary>
|
||||
|
|
@ -181,60 +180,27 @@ namespace Microsoft.Net.Http.Server
|
|||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
SetServerTimeout(_timeouts, (uint)value);
|
||||
SetServerTimeouts(_timeouts, (uint)value);
|
||||
_minSendBytesPerSecond = (uint)value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
// Initial values come from the config. The values can then be overridden using this public API.
|
||||
private void LoadConfigurationSettings()
|
||||
{
|
||||
long[] configTimeouts = new long[_timeouts.Length + 1]; // SettingsSectionInternal.Section.HttpListenerTimeouts;
|
||||
Debug.Assert(configTimeouts != null);
|
||||
Debug.Assert(configTimeouts.Length == (_timeouts.Length + 1));
|
||||
|
||||
bool setNonDefaults = false;
|
||||
for (int i = 0; i < _timeouts.Length; i++)
|
||||
{
|
||||
if (configTimeouts[i] != 0)
|
||||
{
|
||||
Debug.Assert(configTimeouts[i] <= ushort.MaxValue, "Timeout out of range: " + configTimeouts[i]);
|
||||
_timeouts[i] = (int)configTimeouts[i];
|
||||
setNonDefaults = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (configTimeouts[5] != 0)
|
||||
{
|
||||
Debug.Assert(configTimeouts[5] <= uint.MaxValue, "Timeout out of range: " + configTimeouts[5]);
|
||||
_minSendBytesPerSecond = (uint)configTimeouts[5];
|
||||
setNonDefaults = true;
|
||||
}
|
||||
|
||||
if (setNonDefaults)
|
||||
{
|
||||
SetServerTimeout(_timeouts, _minSendBytesPerSecond);
|
||||
}
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private TimeSpan GetTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type)
|
||||
private TimeSpan GetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type)
|
||||
{
|
||||
// Since we maintain local state, GET is local.
|
||||
return new TimeSpan(0, 0, (int)_timeouts[(int)type]);
|
||||
}
|
||||
|
||||
private void SetTimespanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type, TimeSpan value)
|
||||
private void SetTimeSpanTimeout(UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE type, TimeSpan value)
|
||||
{
|
||||
Int64 timeoutValue;
|
||||
|
||||
// All timeouts are defined as USHORT in native layer (except MinSendRate, which is ULONG). Make sure that
|
||||
// timeout value is within range.
|
||||
|
||||
timeoutValue = Convert.ToInt64(value.TotalSeconds);
|
||||
var timeoutValue = Convert.ToInt64(value.TotalSeconds);
|
||||
|
||||
if (timeoutValue < 0 || timeoutValue > ushort.MaxValue)
|
||||
{
|
||||
|
|
@ -243,17 +209,15 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
// Use local state to get values for other timeouts. Call into the native layer and if that
|
||||
// call succeeds, update local state.
|
||||
|
||||
int[] currentTimeouts = _timeouts;
|
||||
currentTimeouts[(int)type] = (int)timeoutValue;
|
||||
SetServerTimeout(currentTimeouts, _minSendBytesPerSecond);
|
||||
var newTimeouts = (int[])_timeouts.Clone();
|
||||
newTimeouts[(int)type] = (int)timeoutValue;
|
||||
SetServerTimeouts(newTimeouts, _minSendBytesPerSecond);
|
||||
_timeouts[(int)type] = (int)timeoutValue;
|
||||
}
|
||||
|
||||
private unsafe void SetServerTimeout(int[] timeouts, uint minSendBytesPerSecond)
|
||||
private unsafe void SetServerTimeouts(int[] timeouts, uint minSendBytesPerSecond)
|
||||
{
|
||||
UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO timeoutinfo =
|
||||
new UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO();
|
||||
var timeoutinfo = new UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_LIMIT_INFO();
|
||||
|
||||
timeoutinfo.Flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_PROPERTY_FLAG_PRESENT;
|
||||
timeoutinfo.DrainEntityBody =
|
||||
|
|
@ -268,7 +232,7 @@ namespace Microsoft.Net.Http.Server
|
|||
(ushort)timeouts[(int)UnsafeNclNativeMethods.HttpApi.HTTP_TIMEOUT_TYPE.HeaderWait];
|
||||
timeoutinfo.MinSendRate = minSendBytesPerSecond;
|
||||
|
||||
IntPtr infoptr = new IntPtr(&timeoutinfo);
|
||||
var infoptr = new IntPtr(&timeoutinfo);
|
||||
|
||||
_server.UrlGroup.SetProperty(
|
||||
UnsafeNclNativeMethods.HttpApi.HTTP_SERVER_PROPERTY.HttpServerTimeoutsProperty,
|
||||
|
|
|
|||
|
|
@ -138,17 +138,6 @@ namespace Microsoft.Net.Http.Server
|
|||
get { return _logger; }
|
||||
}
|
||||
|
||||
public UrlPrefixCollection UrlPrefixes
|
||||
{
|
||||
get { return _urlPrefixes; }
|
||||
}
|
||||
|
||||
public bool BufferResponses
|
||||
{
|
||||
get { return _bufferResponses; }
|
||||
set { _bufferResponses = value; }
|
||||
}
|
||||
|
||||
internal UrlGroup UrlGroup
|
||||
{
|
||||
get { return _urlGroup; }
|
||||
|
|
@ -164,29 +153,7 @@ namespace Microsoft.Net.Http.Server
|
|||
get { return _disconnectListener; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exposes the Http.Sys timeout configurations. These may also be configured in the registry.
|
||||
/// </summary>
|
||||
public TimeoutManager TimeoutManager
|
||||
{
|
||||
get { return _timeoutManager; }
|
||||
}
|
||||
|
||||
public AuthenticationManager AuthenticationManager
|
||||
{
|
||||
get { return _authManager; }
|
||||
}
|
||||
|
||||
internal static bool IsSupported
|
||||
{
|
||||
get { return UnsafeNclNativeMethods.HttpApi.Supported; }
|
||||
}
|
||||
|
||||
public bool IsListening
|
||||
{
|
||||
get { return _state == State.Started; }
|
||||
}
|
||||
|
||||
// TODO: https://github.com/aspnet/WebListener/issues/173
|
||||
internal bool IgnoreWriteExceptions
|
||||
{
|
||||
get { return _ignoreWriteExceptions; }
|
||||
|
|
@ -197,6 +164,38 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
public UrlPrefixCollection UrlPrefixes
|
||||
{
|
||||
get { return _urlPrefixes; }
|
||||
}
|
||||
|
||||
public bool BufferResponses
|
||||
{
|
||||
get { return _bufferResponses; }
|
||||
set { _bufferResponses = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exposes the Http.Sys timeout configurations. These may also be configured in the registry.
|
||||
/// </summary>
|
||||
public TimeoutManager TimeoutManager
|
||||
{
|
||||
get { return _timeoutManager; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Http.Sys authentication settings.
|
||||
/// </summary>
|
||||
public AuthenticationManager AuthenticationManager
|
||||
{
|
||||
get { return _authManager; }
|
||||
}
|
||||
|
||||
public bool IsListening
|
||||
{
|
||||
get { return _state == State.Started; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the maximum number of requests that will be queued up in Http.Sys.
|
||||
/// </summary>
|
||||
|
|
@ -208,6 +207,8 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
throw new ArgumentOutOfRangeException("limit", limit, string.Empty);
|
||||
}
|
||||
|
||||
// Don't try to change it if the new limit is the same
|
||||
if ((!_requestQueueLength.HasValue && limit == DefaultRequestQueueLength)
|
||||
|| (_requestQueueLength.HasValue && limit == _requestQueueLength.Value))
|
||||
{
|
||||
|
|
@ -218,6 +219,9 @@ namespace Microsoft.Net.Http.Server
|
|||
_requestQueue.SetLengthLimit(_requestQueueLength.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start accepting incoming requests.
|
||||
/// </summary>
|
||||
public void Start()
|
||||
{
|
||||
CheckDisposed();
|
||||
|
|
@ -298,7 +302,6 @@ namespace Microsoft.Net.Http.Server
|
|||
Dispose(true);
|
||||
}
|
||||
|
||||
// old API, now private, and helper methods
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing)
|
||||
|
|
@ -350,31 +353,10 @@ namespace Microsoft.Net.Http.Server
|
|||
_serverSession.Dispose();
|
||||
}
|
||||
|
||||
internal unsafe bool ValidateRequest(NativeRequestContext requestMemory)
|
||||
{
|
||||
// Block potential DOS attacks
|
||||
if (requestMemory.RequestBlob->Headers.UnknownHeaderCount > UnknownHeaderLimit)
|
||||
{
|
||||
SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest, authChallenges: null);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal unsafe bool ValidateAuth(NativeRequestContext requestMemory)
|
||||
{
|
||||
var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob;
|
||||
if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo))
|
||||
{
|
||||
SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized,
|
||||
AuthenticationManager.GenerateChallenges(AuthenticationManager.AuthenticationSchemes));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
[SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by callback")]
|
||||
public Task<RequestContext> GetContextAsync()
|
||||
/// <summary>
|
||||
/// Accept a request from the incoming request queue.
|
||||
/// </summary>
|
||||
public Task<RequestContext> AcceptAsync()
|
||||
{
|
||||
AsyncAcceptContext asyncResult = null;
|
||||
try
|
||||
|
|
@ -404,6 +386,29 @@ namespace Microsoft.Net.Http.Server
|
|||
return asyncResult.Task;
|
||||
}
|
||||
|
||||
internal unsafe bool ValidateRequest(NativeRequestContext requestMemory)
|
||||
{
|
||||
// Block potential DOS attacks
|
||||
if (requestMemory.RequestBlob->Headers.UnknownHeaderCount > UnknownHeaderLimit)
|
||||
{
|
||||
SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.BadRequest, authChallenges: null);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
internal unsafe bool ValidateAuth(NativeRequestContext requestMemory)
|
||||
{
|
||||
var requestV2 = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)requestMemory.RequestBlob;
|
||||
if (!AuthenticationManager.AllowAnonymous && !AuthenticationManager.CheckAuthenticated(requestV2->pRequestInfo))
|
||||
{
|
||||
SendError(requestMemory.RequestBlob->RequestId, HttpStatusCode.Unauthorized,
|
||||
AuthenticationManager.GenerateChallenges(AuthenticationManager.AuthenticationSchemes));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private unsafe void SendError(ulong requestId, HttpStatusCode httpStatusCode, IList<string> authChallenges)
|
||||
{
|
||||
UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2 httpResponse = new UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE_V2();
|
||||
|
|
@ -494,7 +499,7 @@ namespace Microsoft.Net.Http.Server
|
|||
if (statusCode != UnsafeNclNativeMethods.ErrorCodes.ERROR_SUCCESS)
|
||||
{
|
||||
// if we fail to send a 401 something's seriously wrong, abort the request
|
||||
RequestContext.CancelRequest(_requestQueue.Handle, requestId);
|
||||
UnsafeNclNativeMethods.HttpApi.HttpCancelHttpRequest(_requestQueue.Handle, requestId, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
{
|
||||
"buildOptions": {
|
||||
"warningsAsErrors": true,
|
||||
"keyFile": "../../tools/Key.snk"
|
||||
},
|
||||
"testRunner": "xunit",
|
||||
"dependencies": {
|
||||
"dotnet-test-xunit": "2.2.0-*",
|
||||
|
|
|
|||
|
|
@ -25,16 +25,16 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
if (authType == AuthenticationSchemes.AllowAnonymous)
|
||||
{
|
||||
Assert.Equal(AuthenticationSchemes.None, context.AuthenticationChallenges);
|
||||
Assert.Equal(AuthenticationSchemes.None, context.Response.AuthenticationChallenges);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
Assert.Equal(authType, context.Response.AuthenticationChallenges);
|
||||
}
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -57,7 +57,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var contextTask = server.GetContextAsync(); // Fails when the server shuts down, the challenge happens internally.
|
||||
var contextTask = server.AcceptAsync(); // Fails when the server shuts down, the challenge happens internally.
|
||||
var response = await responseTask;
|
||||
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
|
||||
Assert.Equal(authType.ToString(), response.Headers.WwwAuthenticate.ToString(), StringComparer.OrdinalIgnoreCase);
|
||||
|
|
@ -77,10 +77,10 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
Assert.Equal(authType, context.Response.AuthenticationChallenges);
|
||||
context.Response.StatusCode = 401;
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -104,10 +104,10 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
Assert.Equal(authType, context.Response.AuthenticationChallenges);
|
||||
context.Response.StatusCode = 401;
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -130,17 +130,17 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address, useDefaultCredentials: true);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
Assert.Equal(authType, context.Response.AuthenticationChallenges);
|
||||
context.Response.StatusCode = 401;
|
||||
context.Dispose();
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.True(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
Assert.Equal(authType, context.Response.AuthenticationChallenges);
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
|
|
@ -161,10 +161,10 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address, useDefaultCredentials: true);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.True(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(authType, context.AuthenticationChallenges);
|
||||
Assert.Equal(authType, context.Response.AuthenticationChallenges);
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
|
|
@ -181,10 +181,10 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address, useDefaultCredentials: true);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.True(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(AuthenticationSchemes.Kerberos, context.AuthenticationChallenges);
|
||||
Assert.Equal(AuthenticationSchemes.Kerberos, context.Response.AuthenticationChallenges);
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
|
|
@ -201,10 +201,10 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.NotNull(context.User);
|
||||
Assert.False(context.User.Identity.IsAuthenticated);
|
||||
Assert.Equal(AuthenticationSchemes.Kerberos, context.AuthenticationChallenges);
|
||||
Assert.Equal(AuthenticationSchemes.Kerberos, context.Response.AuthenticationChallenges);
|
||||
context.Response.StatusCode = 401;
|
||||
context.Dispose();
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(Address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Dispose();
|
||||
|
||||
string response = await responseTask;
|
||||
|
|
@ -36,7 +36,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(Address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] body = Encoding.UTF8.GetBytes("Hello World");
|
||||
context.Response.ContentLength = body.Length;
|
||||
await context.Response.Body.WriteAsync(body, 0, body.Length);
|
||||
|
|
@ -54,7 +54,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(Address, "Hello World");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
string input = new StreamReader(context.Request.Body).ReadToEnd();
|
||||
Assert.Equal("Hello World", input);
|
||||
context.Response.ContentLength = 11;
|
||||
|
|
@ -75,7 +75,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(Address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var cert = await context.Request.GetClientCertificateAsync();
|
||||
Assert.Null(cert);
|
||||
context.Dispose();
|
||||
|
|
@ -94,7 +94,7 @@ namespace Microsoft.Net.Http.Server
|
|||
Assert.NotNull(clientCert);
|
||||
Task<string> responseTask = SendRequestAsync(Address, clientCert);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var cert = await context.Request.GetClientCertificateAsync();
|
||||
Assert.NotNull(cert);
|
||||
context.Dispose();
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> clientTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] body = Encoding.UTF8.GetBytes("Hello World");
|
||||
context.Response.Body.Write(body, 0, body.Length);
|
||||
|
||||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<Stream> clientTask = SendOpaqueRequestAsync("GET", address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.True(context.IsUpgradableRequest);
|
||||
context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket
|
||||
Stream serverStream = await context.UpgradeAsync();
|
||||
|
|
@ -88,7 +88,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<Stream> clientTask = SendOpaqueRequestAsync(method, address, extraHeader);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.True(context.IsUpgradableRequest);
|
||||
context.Response.Headers["Upgrade"] = "WebSocket"; // Win8.1 blocks anything but WebSocket
|
||||
Stream serverStream = await context.UpgradeAsync();
|
||||
|
|
@ -128,7 +128,7 @@ namespace Microsoft.Net.Http.Server
|
|||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
var clientTask = SendOpaqueRequestAsync(method, address, extraHeader);
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.False(context.IsUpgradableRequest);
|
||||
context.Dispose();
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, "Hello World");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[100];
|
||||
int read = context.Request.Body.Read(input, 0, input.Length);
|
||||
context.Response.ContentLength = read;
|
||||
|
|
@ -41,7 +41,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, "Hello World");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[100];
|
||||
int read = await context.Request.Body.ReadAsync(input, 0, input.Length);
|
||||
context.Response.ContentLength = read;
|
||||
|
|
@ -60,7 +60,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, "Hello World");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[100];
|
||||
int read = context.Request.Body.EndRead(context.Request.Body.BeginRead(input, 0, input.Length, null, null));
|
||||
context.Response.ContentLength = read;
|
||||
|
|
@ -80,7 +80,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, "Hello World");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[100];
|
||||
Assert.Throws<ArgumentNullException>("buffer", () => context.Request.Body.Read(null, 0, 1));
|
||||
Assert.Throws<ArgumentOutOfRangeException>("offset", () => context.Request.Body.Read(input, -1, 1));
|
||||
|
|
@ -105,7 +105,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, content);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[10];
|
||||
int read = context.Request.Body.Read(input, 0, input.Length);
|
||||
Assert.Equal(5, read);
|
||||
|
|
@ -128,7 +128,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, content);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[10];
|
||||
int read = await context.Request.Body.ReadAsync(input, 0, input.Length);
|
||||
Assert.Equal(5, read);
|
||||
|
|
@ -150,7 +150,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendSocketRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[11];
|
||||
int read = await context.Request.Body.ReadAsync(input, 0, input.Length);
|
||||
Assert.Equal(10, read);
|
||||
|
|
@ -176,7 +176,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, "Hello World");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
|
||||
byte[] input = new byte[10];
|
||||
var cts = new CancellationTokenSource();
|
||||
|
|
@ -201,7 +201,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, content);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[10];
|
||||
var cts = new CancellationTokenSource();
|
||||
int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token);
|
||||
|
|
@ -225,7 +225,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, content);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[10];
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(5));
|
||||
|
|
@ -250,7 +250,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, content);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[10];
|
||||
var cts = new CancellationTokenSource();
|
||||
int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token);
|
||||
|
|
@ -275,7 +275,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address, content);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[10];
|
||||
var cts = new CancellationTokenSource();
|
||||
int read = await context.Request.Body.ReadAsync(input, 0, input.Length, cts.Token);
|
||||
|
|
@ -303,7 +303,7 @@ namespace Microsoft.Net.Http.Server
|
|||
var client = new HttpClient();
|
||||
var responseTask = client.PostAsync(address, content);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] input = new byte[10];
|
||||
int read = await context.Request.Body.ReadAsync(input, 0, input.Length, context.DisconnectToken);
|
||||
Assert.False(context.DisconnectToken.IsCancellationRequested);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var requestHeaders = context.Request.Headers;
|
||||
// NOTE: The System.Net client only sends the Connection: keep-alive header on the first connection per service-point.
|
||||
// Assert.Equal(2, requestHeaders.Count);
|
||||
|
|
@ -46,7 +46,7 @@ namespace Microsoft.Net.Http.Server
|
|||
string[] customValues = new string[] { "custom1, and custom2", "custom3" };
|
||||
Task responseTask = SendRequestAsync(address, "Custom-Header", customValues);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var requestHeaders = context.Request.Headers;
|
||||
Assert.Equal(4, requestHeaders.Count);
|
||||
Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]);
|
||||
|
|
@ -73,7 +73,7 @@ namespace Microsoft.Net.Http.Server
|
|||
string[] customValues = new string[] { "custom1, and custom测试2", "custom3" };
|
||||
Task responseTask = SendRequestAsync(address, "Custom-Header", customValues);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var requestHeaders = context.Request.Headers;
|
||||
Assert.Equal(4, requestHeaders.Count);
|
||||
Assert.Equal(new Uri(address).Authority, requestHeaders["Host"]);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(root + "/basepath/SomePath?SomeQuery");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
|
||||
// General fields
|
||||
var request = context.Request;
|
||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(root + requestPath);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
|
||||
// General fields
|
||||
var request = context.Request;
|
||||
|
|
@ -92,7 +92,7 @@ namespace Microsoft.Net.Http.Server
|
|||
using (var server = Utilities.CreateHttpServerReturnRoot("/", out root))
|
||||
{
|
||||
var responseTask = SendSocketRequestAsync(root, requestPath);
|
||||
var contextTask = server.GetContextAsync();
|
||||
var contextTask = server.AcceptAsync();
|
||||
var response = await responseTask;
|
||||
var responseStatusCode = response.Substring(9); // Skip "HTTP/1.1 "
|
||||
Assert.Equal("400", responseStatusCode);
|
||||
|
|
@ -106,7 +106,7 @@ namespace Microsoft.Net.Http.Server
|
|||
using (var server = Utilities.CreateHttpServerReturnRoot("/", out root))
|
||||
{
|
||||
var responseTask = SendSocketRequestAsync(root, "/%252F");
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.Equal("/%2F", context.Request.Path);
|
||||
}
|
||||
}
|
||||
|
|
@ -142,7 +142,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
Task<string> responseTask = SendRequestAsync(root + requestUri);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var request = context.Request;
|
||||
|
||||
Assert.Equal(expectedPath, request.Path);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.ShouldBuffer = true;
|
||||
context.Response.Body.Write(new byte[10], 0, 10);
|
||||
await context.Response.Body.WriteAsync(new byte[10], 0, 10);
|
||||
|
|
@ -47,7 +47,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.ShouldBuffer = false;
|
||||
context.Response.Body.Write(new byte[10], 0, 10);
|
||||
await context.Response.Body.WriteAsync(new byte[10], 0, 10);
|
||||
|
|
@ -71,7 +71,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Body.Write(new byte[10], 0, 10);
|
||||
context.Response.Body.Flush();
|
||||
await context.Response.Body.WriteAsync(new byte[10], 0, 10);
|
||||
|
|
@ -94,7 +94,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["transfeR-Encoding"] = "CHunked";
|
||||
Stream stream = context.Response.Body;
|
||||
var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n");
|
||||
|
|
@ -119,7 +119,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = " 30 ";
|
||||
Stream stream = context.Response.Body;
|
||||
#if NET451
|
||||
|
|
@ -150,12 +150,12 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = " 20 ";
|
||||
context.Dispose();
|
||||
#if !NETCOREAPP1_0
|
||||
// HttpClient retries the request because it didn't get a response.
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = " 20 ";
|
||||
context.Dispose();
|
||||
#endif
|
||||
|
|
@ -171,13 +171,13 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = " 20 ";
|
||||
context.Response.Body.Write(new byte[5], 0, 5);
|
||||
context.Dispose();
|
||||
#if !NETCOREAPP1_0
|
||||
// HttpClient retries the request because it didn't get a response.
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = " 20 ";
|
||||
context.Response.Body.Write(new byte[5], 0, 5);
|
||||
context.Dispose();
|
||||
|
|
@ -194,14 +194,14 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = " 10 ";
|
||||
context.Response.Body.Write(new byte[5], 0, 5);
|
||||
Assert.Throws<InvalidOperationException>(() => context.Response.Body.Write(new byte[6], 0, 6));
|
||||
context.Dispose();
|
||||
#if !NETCOREAPP1_0
|
||||
// HttpClient retries the request because it didn't get a response.
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = " 10 ";
|
||||
context.Response.Body.Write(new byte[5], 0, 5);
|
||||
Assert.Throws<InvalidOperationException>(() => context.Response.Body.Write(new byte[6], 0, 6));
|
||||
|
|
@ -219,7 +219,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = " 10 ";
|
||||
context.Response.Body.Write(new byte[10], 0, 10);
|
||||
Assert.Throws<ObjectDisposedException>(() => context.Response.Body.Write(new byte[6], 0, 6));
|
||||
|
|
@ -244,7 +244,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Body.Write(new byte[10], 0, 0);
|
||||
Assert.True(context.Response.HasStarted);
|
||||
await context.Response.Body.WriteAsync(new byte[10], 0, 0);
|
||||
|
|
@ -268,7 +268,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.ShouldBuffer = true;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
|
@ -299,7 +299,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.ShouldBuffer = true;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
|
|
@ -330,7 +330,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var cts = new CancellationTokenSource();
|
||||
// First write sends headers
|
||||
await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token);
|
||||
|
|
@ -351,7 +351,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(1));
|
||||
// First write sends headers
|
||||
|
|
@ -373,7 +373,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
// First write sends headers
|
||||
|
|
@ -395,7 +395,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var cts = new CancellationTokenSource();
|
||||
// First write sends headers
|
||||
await context.Response.Body.WriteAsync(new byte[10], 0, 10, cts.Token);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
// Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
// Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -64,7 +64,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -93,7 +93,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -124,7 +124,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.Headers["age"] = "12345";
|
||||
|
|
@ -156,7 +156,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(0);
|
||||
|
|
@ -169,7 +169,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
// Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -190,7 +190,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromMilliseconds(900);
|
||||
|
|
@ -203,7 +203,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
// Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -224,7 +224,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(-10);
|
||||
|
|
@ -237,7 +237,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
// Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -258,7 +258,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.MaxValue;
|
||||
|
|
@ -285,7 +285,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -315,7 +315,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -329,7 +329,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -348,7 +348,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -363,7 +363,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -382,7 +382,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.ContentLength = 10;
|
||||
|
|
@ -411,7 +411,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -425,7 +425,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -444,7 +444,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.ContentLength =_fileLength;
|
||||
|
|
@ -482,7 +482,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
var responseTask = SendRequestAsync(address + status);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.StatusCode = status;
|
||||
context.Response.Headers["x-request-count"] = status.ToString();
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
|
|
@ -533,7 +533,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address, method);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = context.Request.Method + "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -546,7 +546,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address, method);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = context.Request.Method + "2";
|
||||
// Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -592,7 +592,7 @@ namespace Microsoft.Net.Http.Server
|
|||
// Cache the first response
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = context.Request.Method + "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -606,7 +606,7 @@ namespace Microsoft.Net.Http.Server
|
|||
// Try to clear the cache with a second request
|
||||
responseTask = SendRequestAsync(address, method);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = context.Request.Method + "2";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Dispose();
|
||||
|
|
@ -637,7 +637,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address, "GET", "x-vary", "vary1");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.Headers["vary"] = "x-vary";
|
||||
|
|
@ -668,7 +668,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -681,7 +681,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123");
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Dispose();
|
||||
|
|
@ -702,7 +702,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -715,7 +715,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address, "GET", "Authorization", "Basic abc123");
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Dispose();
|
||||
|
|
@ -738,7 +738,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address, "GET", "Pragma", "no-cache");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -767,7 +767,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -795,7 +795,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address, "GET", "Cache-Control", "no-cache");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -823,7 +823,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -851,7 +851,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -879,7 +879,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.CacheTtl = TimeSpan.FromSeconds(10);
|
||||
|
|
@ -906,7 +906,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address, "GET", "Range", "bytes=0-10");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.StatusCode = 206;
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
|
|
@ -923,7 +923,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address, "GET", "Range", "bytes=0-10");
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Response.StatusCode = 206;
|
||||
context.Response.Headers["x-request-count"] = "2";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
|
|
@ -951,7 +951,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.ContentLength = 100;
|
||||
|
|
@ -981,7 +981,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.ContentLength = 100;
|
||||
|
|
@ -1011,7 +1011,7 @@ namespace Microsoft.Net.Http.Server
|
|||
var responseLength = _fileLength / 2; // Make sure it handles partial files.
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.ContentLength = responseLength;
|
||||
|
|
@ -1043,7 +1043,7 @@ namespace Microsoft.Net.Http.Server
|
|||
var responseLength = _fileLength / 2; // Make sure it handles partial files.
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["x-request-count"] = "1";
|
||||
context.Response.Headers["content-type"] = "some/thing"; // Http.sys requires a content-type to cache
|
||||
context.Response.ContentLength = responseLength;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
|
|
@ -44,7 +44,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address, usehttp11: false);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendHeadRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
|
|
@ -89,7 +89,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendHeadRequestAsync(address, usehttp11: false);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
|
|
@ -112,7 +112,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendHeadRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.ContentLength = 20;
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -135,7 +135,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.StatusCode = 204; // No Content
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendHeadRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.StatusCode = 204; // No Content
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ namespace Microsoft.Net.Http.Server
|
|||
WebRequest request = WebRequest.Create(address);
|
||||
Task<WebResponse> responseTask = request.GetResponseAsync();
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var responseHeaders = context.Response.Headers;
|
||||
responseHeaders["WWW-Authenticate"] = "custom1";
|
||||
context.Dispose();
|
||||
|
|
@ -207,7 +207,7 @@ namespace Microsoft.Net.Http.Server
|
|||
WebRequest request = WebRequest.Create(address);
|
||||
Task<WebResponse> responseTask = request.GetResponseAsync();
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var responseHeaders = context.Response.Headers;
|
||||
responseHeaders["WWW-Authenticate"] = new[] { "custom1, and custom2", "custom3" };
|
||||
context.Dispose();
|
||||
|
|
@ -236,7 +236,7 @@ namespace Microsoft.Net.Http.Server
|
|||
WebRequest request = WebRequest.Create(address);
|
||||
Task<WebResponse> responseTask = request.GetResponseAsync();
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var responseHeaders = context.Response.Headers;
|
||||
responseHeaders["Custom-Header1"] = new[] { "custom1, and custom2", "custom3" };
|
||||
context.Dispose();
|
||||
|
|
@ -264,7 +264,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var responseHeaders = context.Response.Headers;
|
||||
responseHeaders["Connection"] = "Close";
|
||||
context.Dispose();
|
||||
|
|
@ -284,7 +284,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address, usehttp11: false);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
|
|
@ -307,7 +307,7 @@ namespace Microsoft.Net.Http.Server
|
|||
request.Version = new Version(1, 0);
|
||||
Task<HttpResponseMessage> responseTask = client.SendAsync(request);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var responseHeaders = context.Response.Headers;
|
||||
responseHeaders["Transfer-Encoding"] = "chunked";
|
||||
var responseBytes = Encoding.ASCII.GetBytes("10\r\nManually Chunked\r\n0\r\n\r\n");
|
||||
|
|
@ -335,7 +335,7 @@ namespace Microsoft.Net.Http.Server
|
|||
// Http.Sys does not support 1.0 keep-alives.
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address, usehttp11: false, sendKeepAlive: true);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
|
|
@ -353,7 +353,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var responseHeaders = context.Response.Headers;
|
||||
|
||||
responseHeaders["Custom1"] = new[] { "value1a", "value1b" };
|
||||
|
|
@ -389,7 +389,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var responseHeaders = context.Response.Headers;
|
||||
|
||||
responseHeaders["Custom1"] = new[] { "value1a", "value1b" };
|
||||
|
|
@ -443,7 +443,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
|
||||
var responseHeaders = context.Response.Headers;
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await Assert.ThrowsAsync<FileNotFoundException>(() =>
|
||||
context.Response.SendFileAsync("Missing.txt", 0, null, CancellationToken.None));
|
||||
context.Dispose();
|
||||
|
|
@ -49,7 +49,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
|
@ -134,7 +134,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -155,7 +155,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(
|
||||
() => context.Response.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None));
|
||||
context.Dispose();
|
||||
|
|
@ -172,7 +172,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(
|
||||
() => context.Response.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None));
|
||||
context.Dispose();
|
||||
|
|
@ -189,7 +189,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -214,7 +214,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(emptyFilePath, 0, null, CancellationToken.None);
|
||||
Assert.True(context.Response.HasStartedSending);
|
||||
await context.Response.Body.WriteAsync(new byte[10], 0, 10, CancellationToken.None);
|
||||
|
|
@ -238,7 +238,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = FileLength.ToString();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
|
||||
|
|
@ -260,7 +260,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = "10";
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
|
@ -283,7 +283,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = "0";
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.Equal(200, context.Response.StatusCode);
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -38,7 +38,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.StatusCode = 201;
|
||||
// TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value
|
||||
context.Dispose();
|
||||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.StatusCode = 201;
|
||||
context.Response.ReasonPhrase = "CustomReasonPhrase";
|
||||
// TODO: env["owin.ResponseProtocol"] = "HTTP/1.0"; // Http.Sys ignores this value
|
||||
|
|
@ -81,7 +81,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.StatusCode = 901;
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { context.Response.StatusCode = 100; });
|
||||
context.Dispose();
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => { context.Response.StatusCode = 0; });
|
||||
context.Dispose();
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
|
|
@ -39,7 +39,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<string> responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.ContentLength = 11;
|
||||
using (var writer = new StreamWriter(context.Response.Body))
|
||||
{
|
||||
|
|
@ -59,7 +59,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address, "Hello World");
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
string input = new StreamReader(context.Request.Body).ReadToEnd();
|
||||
Assert.Equal("Hello World", input);
|
||||
context.Response.ContentLength = 11;
|
||||
|
|
@ -86,7 +86,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = client.GetAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var ct = context.DisconnectToken;
|
||||
Assert.True(ct.CanBeCanceled, "CanBeCanceled");
|
||||
Assert.False(ct.IsCancellationRequested, "IsCancellationRequested");
|
||||
|
|
@ -115,7 +115,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var ct = context.DisconnectToken;
|
||||
Assert.True(ct.CanBeCanceled, "CanBeCanceled");
|
||||
Assert.False(ct.IsCancellationRequested, "IsCancellationRequested");
|
||||
|
|
@ -125,7 +125,7 @@ namespace Microsoft.Net.Http.Server
|
|||
Assert.True(ct.IsCancellationRequested, "IsCancellationRequested");
|
||||
#if !NETCOREAPP1_0
|
||||
// HttpClient re-tries the request because it doesn't know if the request was received.
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
context.Abort();
|
||||
#endif
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => responseTask);
|
||||
|
|
@ -143,7 +143,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
var ct = context.DisconnectToken;
|
||||
Assert.True(ct.CanBeCanceled, "CanBeCanceled");
|
||||
Assert.False(ct.IsCancellationRequested, "IsCancellationRequested");
|
||||
|
|
@ -174,7 +174,7 @@ namespace Microsoft.Net.Http.Server
|
|||
server.SetRequestQueueLimit(1001);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
context.Dispose();
|
||||
|
||||
var response = await responseTask;
|
||||
|
|
@ -190,7 +190,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.Equal(string.Empty, context.Request.PathBase);
|
||||
Assert.Equal("/", context.Request.Path);
|
||||
context.Dispose();
|
||||
|
|
@ -203,7 +203,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
Assert.Equal("/pathbase", context.Request.PathBase);
|
||||
Assert.Equal("/", context.Request.Path);
|
||||
context.Dispose();
|
||||
|
|
@ -223,7 +223,7 @@ namespace Microsoft.Net.Http.Server
|
|||
server.UrlPrefixes.Add(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.Equal("/pathbase", context.Request.PathBase);
|
||||
Assert.Equal("/", context.Request.Path);
|
||||
context.Dispose();
|
||||
|
|
@ -235,7 +235,7 @@ namespace Microsoft.Net.Http.Server
|
|||
|
||||
responseTask = SendRequestAsync(address);
|
||||
|
||||
context = await server.GetContextAsync();
|
||||
context = await server.AcceptAsync();
|
||||
Assert.Equal(string.Empty, context.Request.PathBase);
|
||||
Assert.Equal("/pathbase/", context.Request.Path);
|
||||
context.Dispose();
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<HttpResponseMessage> clientTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
byte[] body = Encoding.UTF8.GetBytes("Hello World");
|
||||
context.Response.Body.Write(body, 0, body.Length);
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<WebSocket> clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address));
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.True(context.IsUpgradableRequest);
|
||||
WebSocket serverWebSocket = await context.AcceptWebSocketAsync();
|
||||
WebSocket clientWebSocket = await clientTask;
|
||||
|
|
@ -61,7 +61,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
Task<WebSocket> clientTask = SendWebSocketRequestAsync(ConvertToWebSocketAddress(address));
|
||||
|
||||
var context = await server.GetContextAsync();
|
||||
var context = await server.AcceptAsync();
|
||||
Assert.True(context.IsWebSocketRequest());
|
||||
WebSocket serverWebSocket = await context.AcceptWebSocketAsync();
|
||||
WebSocket clientWebSocket = await clientTask;
|
||||
|
|
|
|||
Loading…
Reference in New Issue