API cleaup, organization

This commit is contained in:
Chris R 2016-07-27 10:29:15 -07:00
parent 3d2e1c4d3e
commit 235ac59551
34 changed files with 495 additions and 739 deletions

View File

@ -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:

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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()

View File

@ -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;

View File

@ -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;

View File

@ -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")]

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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)
{

View File

@ -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;

View File

@ -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,

View File

@ -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)
{

View File

@ -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)

View File

@ -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;
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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

View File

@ -1,4 +1,8 @@
{
"buildOptions": {
"warningsAsErrors": true,
"keyFile": "../../tools/Key.snk"
},
"testRunner": "xunit",
"dependencies": {
"dotnet-test-xunit": "2.2.0-*",

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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);

View File

@ -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"]);

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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();

View File

@ -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();

View File

@ -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;