From 60f09fbc939d36195f0142909d23263b726d1e64 Mon Sep 17 00:00:00 2001 From: Chris Ross Date: Mon, 31 Mar 2014 12:47:28 -0700 Subject: [PATCH] Make lower level public API. Layering. --- samples/HelloWorld/Program.cs | 104 ++++++++------ .../OwinWebListener.cs | 8 +- .../RequestProcessing/BoundaryType.cs | 8 +- .../RequestProcessing/EntitySendFormat.cs | 17 --- .../RequestProcessing/FeatureContext.cs | 14 +- .../RequestProcessing/Request.cs | 77 +++++----- .../RequestProcessing/RequestContext.cs | 47 ++----- .../RequestProcessing/Response.cs | 131 ++++++++++++------ .../RequestProcessing/ResponseStream.cs | 6 +- .../WebListenerException.cs | 19 +-- .../WebListenerWrapper.cs | 11 +- .../System/ComponentModel/Win32Exception.cs | 112 --------------- .../project.json | 3 +- 13 files changed, 236 insertions(+), 321 deletions(-) delete mode 100644 src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs delete mode 100644 src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs diff --git a/samples/HelloWorld/Program.cs b/samples/HelloWorld/Program.cs index 5e176ff7ee..829908c001 100644 --- a/samples/HelloWorld/Program.cs +++ b/samples/HelloWorld/Program.cs @@ -1,55 +1,69 @@ using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; using System.Text; -using System.Threading.Tasks; using Microsoft.AspNet.Server.WebListener; -using AppFunc = System.Func, System.Threading.Tasks.Task>; - -public class Program +namespace HelloWorld { - public static void Main(string[] args) + public class Program { - using (CreateServer(new AppFunc(HelloWorldApp))) + public static void Main(string[] args) { - Console.WriteLine("Running, press enter to exit..."); - Console.ReadLine(); + using (OwinWebListener listener = new OwinWebListener()) + { + listener.UrlPrefixes.Add(UrlPrefix.Create("http://localhost:8080")); + listener.Start(); + + Console.WriteLine("Running..."); + while (true) + { + RequestContext context = listener.GetContextAsync().Result; + Console.WriteLine("Accepted"); + + // Context: + // context.User; + // context.DisconnectToken + // context.Dispose() + // context.Abort(); + + // Request + // context.Request.ProtocolVersion + // context.Request.IsLocal + // context.Request.Headers // TODO: Header helpers? + // context.Request.Method + // context.Request.Body + // Content-Length - long? + // Content-Type - string + // IsSecureConnection + // HasEntityBody + + // TODO: Request fields + // Content-Encoding - Encoding + // Host + // Client certs - GetCertAsync, CertErrors + // Cookies + // KeepAlive + // QueryString (parsed) + // RequestTraceIdentifier + // RawUrl + // URI + // IsWebSocketRequest + // LocalEndpoint vs LocalIP & LocalPort + // RemoteEndpoint vs RemoteIP & RemotePort + // AcceptTypes string[] + // ServiceName + // TransportContext + + // Response + byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now); + + context.Response.ContentLength = bytes.Length; + context.Response.ContentType = "text/plain"; + + context.Response.Body.Write(bytes, 0, bytes.Length); + context.Dispose(); + } + } } } - - private static IDisposable CreateServer(AppFunc app) - { - IDictionary properties = new Dictionary(); - IList> addresses = new List>(); - properties["host.Addresses"] = addresses; - - IDictionary address = new Dictionary(); - addresses.Add(address); - - address["scheme"] = "http"; - address["host"] = "localhost"; - address["port"] = "8080"; - address["path"] = string.Empty; - - return OwinServerFactory.Create(app, properties); - } - - public static Task HelloWorldApp(IDictionary environment) - { - string responseText = "Hello World"; - byte[] responseBytes = Encoding.UTF8.GetBytes(responseText); - - // See http://owin.org/spec/owin-1.0.0.html for standard environment keys. - Stream responseStream = (Stream)environment["owin.ResponseBody"]; - IDictionary responseHeaders = - (IDictionary)environment["owin.ResponseHeaders"]; - - responseHeaders["Content-Length"] = new string[] { responseBytes.Length.ToString(CultureInfo.InvariantCulture) }; - responseHeaders["Content-Type"] = new string[] { "text/plain" }; - - return responseStream.WriteAsync(responseBytes, 0, responseBytes.Length); - } -} +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs index cc76380f53..bdb7a0ba83 100644 --- a/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs +++ b/src/Microsoft.AspNet.Server.WebListener/OwinWebListener.cs @@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Server.WebListener // The native request queue private long? _requestQueueLength; - internal OwinWebListener() + public OwinWebListener() { if (!UnsafeNclNativeMethods.HttpApi.Supported) { @@ -149,7 +149,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal bool IsListening + public bool IsListening { get { @@ -332,7 +332,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal void Start() + public void Start() { CheckDisposed(); @@ -639,7 +639,7 @@ namespace Microsoft.AspNet.Server.WebListener } [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Disposed by callback")] - internal Task GetContextAsync() + public Task GetContextAsync() { AsyncAcceptContext asyncResult = null; try diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs index 6d9ca0b4e2..d6f4fd2007 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/BoundaryType.cs @@ -8,11 +8,9 @@ namespace Microsoft.AspNet.Server.WebListener { internal enum BoundaryType { - ContentLength = 0, // Content-Length: XXX + None = 0, Chunked = 1, // Transfer-Encoding: chunked - Raw = 2, // the app is responsible for sending the correct headers and body encoding - Multipart = 3, - None = 4, - Invalid = 5, + ContentLength = 2, // Content-Length: XXX + Invalid = 3, } } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs deleted file mode 100644 index f6861f9bd6..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/EntitySendFormat.cs +++ /dev/null @@ -1,17 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -namespace Microsoft.AspNet.Server.WebListener -{ - internal enum EntitySendFormat - { - ContentLength = 0, // Content-Length: XXX - Chunked = 1, // Transfer-Encoding: chunked - /* - Raw = 2, // the app is responsible for sending the correct headers and body encoding - */ - } -} diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs index 786256daab..81f20ef260 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/FeatureContext.cs @@ -163,7 +163,19 @@ namespace Microsoft.AspNet.Server.WebListener { if (_httpProtocolVersion == null) { - _httpProtocolVersion = Request.Protocol; + if (Request.ProtocolVersion.Major == 1) + { + if (Request.ProtocolVersion.Minor == 1) + { + _httpProtocolVersion = "HTTP/1.1"; + } + else if (Request.ProtocolVersion.Minor == 0) + { + _httpProtocolVersion = "HTTP/1.0"; + } + } + + _httpProtocolVersion = "HTTP/" + Request.ProtocolVersion.ToString(2); } return _httpProtocolVersion; } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs index 2136b96bae..3535dc3612 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Request.cs @@ -19,7 +19,7 @@ using System.Threading.Tasks; namespace Microsoft.AspNet.Server.WebListener { - internal sealed class Request : IDisposable + public sealed class Request { private RequestContext _requestContext; private NativeRequestContext _nativeRequestContext; @@ -47,7 +47,7 @@ namespace Microsoft.AspNet.Server.WebListener private IDictionary _headers; private BoundaryType _contentBoundaryType; - private long _contentLength; + private long? _contentLength; private Stream _nativeStream; private SocketAddress _localEndPoint; @@ -202,32 +202,30 @@ namespace Microsoft.AspNet.Server.WebListener } } - // TODO: Move this to the constructor, that's where it will be called. - internal long ContentLength64 + public long? ContentLength { get { if (_contentBoundaryType == BoundaryType.None) { string transferEncoding = Headers.Get(HttpKnownHeaderNames.TransferEncoding) ?? string.Empty; - if ("chunked".Equals(transferEncoding.Trim(), StringComparison.OrdinalIgnoreCase)) + if (string.Equals("chunked", transferEncoding.Trim(), StringComparison.OrdinalIgnoreCase)) { _contentBoundaryType = BoundaryType.Chunked; - _contentLength = -1; } else { - _contentLength = 0; - _contentBoundaryType = BoundaryType.ContentLength; string length = Headers.Get(HttpKnownHeaderNames.ContentLength) ?? string.Empty; - if (length != null) + long value; + if (long.TryParse(length.Trim(), NumberStyles.None, + CultureInfo.InvariantCulture.NumberFormat, out value)) { - if (!long.TryParse(length.Trim(), NumberStyles.None, - CultureInfo.InvariantCulture.NumberFormat, out _contentLength)) - { - _contentLength = 0; - _contentBoundaryType = BoundaryType.Invalid; - } + _contentBoundaryType = BoundaryType.ContentLength; + _contentLength = value; + } + else + { + _contentBoundaryType = BoundaryType.Invalid; } } } @@ -252,7 +250,6 @@ namespace Microsoft.AspNet.Server.WebListener { if (_nativeStream == null) { - // TODO: Move this to the constructor (or a lazy Env dictionary) _nativeStream = HasEntityBody ? new RequestStream(RequestContext) : Stream.Null; } return _nativeStream; @@ -281,7 +278,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal bool IsSecureConnection + public bool IsSecureConnection { get { @@ -297,7 +294,7 @@ namespace Microsoft.AspNet.Server.WebListener } } */ - internal Version ProtocolVersion + public Version ProtocolVersion { get { @@ -305,34 +302,13 @@ namespace Microsoft.AspNet.Server.WebListener } } - public string Protocol + public bool HasEntityBody { get { - if (_httpVersion.Major == 1) - { - if (_httpVersion.Minor == 1) - { - return "HTTP/1.1"; - } - else if (_httpVersion.Minor == 0) - { - return "HTTP/1.0"; - } - } - - return "HTTP/" + _httpVersion.ToString(2); - } - } - - // TODO: Move this to the constructor - internal bool HasEntityBody - { - get - { - // accessing the ContentLength property delay creates m_BoundaryType - return (ContentLength64 > 0 && _contentBoundaryType == BoundaryType.ContentLength) || - _contentBoundaryType == BoundaryType.Chunked || _contentBoundaryType == BoundaryType.Multipart; + // accessing the ContentLength property delay creates _contentBoundaryType + return (ContentLength.HasValue && ContentLength.Value > 0 && _contentBoundaryType == BoundaryType.ContentLength) + || _contentBoundaryType == BoundaryType.Chunked; } } @@ -418,6 +394,14 @@ namespace Microsoft.AspNet.Server.WebListener } } + public string ContentType + { + get + { + return Headers.Get(HttpKnownHeaderNames.ContentLength); + } + } + internal IPrincipal User { get { return _user; } @@ -443,6 +427,11 @@ namespace Microsoft.AspNet.Server.WebListener #endif } + internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod() + { + return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(RequestBuffer, OriginalBlobAddress); + } + #if NET45 // 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 @@ -500,7 +489,7 @@ namespace Microsoft.AspNet.Server.WebListener } // should only be called from RequestContext - public void Dispose() + internal void Dispose() { // TODO: Verbose log _isDisposed = true; diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs index b326432b45..1325eaed14 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/RequestContext.cs @@ -6,9 +6,9 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using System.Security.Principal; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Logging; @@ -17,14 +17,11 @@ namespace Microsoft.AspNet.Server.WebListener { using OpaqueFunc = Func, Task>; - internal sealed class RequestContext : IDisposable + public sealed class RequestContext : IDisposable { - private static readonly string[] ZeroContentLength = new[] { "0" }; - private OwinWebListener _server; private Request _request; private Response _response; - private CancellationTokenSource _cts; private NativeRequestContext _memoryBlob; private OpaqueFunc _opaqueCallback; private bool _disposed; @@ -38,11 +35,10 @@ namespace Microsoft.AspNet.Server.WebListener _memoryBlob = memoryBlob; _request = new Request(this, _memoryBlob); _response = new Response(this); - _cts = new CancellationTokenSource(); _request.ReleasePins(); } - internal Request Request + public Request Request { get { @@ -50,7 +46,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal Response Response + public Response Response { get { @@ -58,7 +54,12 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal CancellationToken DisconnectToken + public IPrincipal User + { + get { return _request.User; } + } + + public CancellationToken DisconnectToken { get { @@ -146,32 +147,20 @@ namespace Microsoft.AspNet.Server.WebListener finally { _request.Dispose(); - _cts.Dispose(); } } - internal void Abort() + public void Abort() { + // May be called from Dispose() code path, don't check _disposed. // TODO: Verbose log _disposed = true; - try - { - _cts.Cancel(); - } - catch (ObjectDisposedException) - { - } - catch (AggregateException) + if (_disconnectRegistration.HasValue) { + _disconnectRegistration.Value.Dispose(); } ForceCancelRequest(RequestQueueHandle, _request.RequestId); _request.Dispose(); - _cts.Dispose(); - } - - internal UnsafeNclNativeMethods.HttpApi.HTTP_VERB GetKnownMethod() - { - return UnsafeNclNativeMethods.HttpApi.GetKnownVerb(Request.RequestBuffer, Request.OriginalBlobAddress); } // This is only called while processing incoming requests. We don't have to worry about cancelling @@ -256,13 +245,5 @@ namespace Microsoft.AspNet.Server.WebListener return opaqueEnv; } - - internal void SetFatalResponse() - { - Response.StatusCode = 500; - Response.ReasonPhrase = string.Empty; - Response.Headers.Clear(); - Response.Headers.Add(HttpKnownHeaderNames.ContentLength, ZeroContentLength); - } } } diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs index 1db2216f9c..2364e2a777 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/Response.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; +using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Threading; @@ -15,8 +16,10 @@ using System.Threading.Tasks; namespace Microsoft.AspNet.Server.WebListener { - internal sealed unsafe class Response : IDisposable + public sealed unsafe class Response { + private static readonly string[] ZeroContentLength = new[] { "0" }; + private ResponseState _responseState; private IDictionary _headers; private string _reasonPhrase; @@ -99,7 +102,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal ResponseStream Body + public Stream Body { get { @@ -136,14 +139,6 @@ namespace Microsoft.AspNet.Server.WebListener return true; } - internal EntitySendFormat EntitySendFormat - { - get - { - return (EntitySendFormat)_boundaryType; - } - } - public IDictionary Headers { get { return _headers; } @@ -157,7 +152,7 @@ namespace Microsoft.AspNet.Server.WebListener } } - internal long ContentLength64 + internal long CalculatedLength { get { @@ -165,6 +160,73 @@ namespace Microsoft.AspNet.Server.WebListener } } + // Header accessors + public long? ContentLength + { + get + { + string contentLengthString = Headers.Get(HttpKnownHeaderNames.ContentLength); + long contentLength; + if (!string.IsNullOrWhiteSpace(contentLengthString)) + { + contentLengthString = contentLengthString.Trim(); + if (string.Equals("0", contentLengthString, StringComparison.Ordinal)) + { + return 0; + } + else if (long.TryParse(contentLengthString, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out contentLength)) + { + return contentLength; + } + } + return null; + } + set + { + CheckResponseStarted(); + if (!value.HasValue) + { + Headers.Remove(HttpKnownHeaderNames.ContentLength); + } + else + { + if (value.Value < 0) + { + throw new ArgumentOutOfRangeException("value", value.Value, "Cannot be negative."); + } + + if (value.Value == 0) + { + Headers[HttpKnownHeaderNames.ContentLength] = ZeroContentLength; + } + else + { + Headers[HttpKnownHeaderNames.ContentLength] = new[] { value.Value.ToString(CultureInfo.InvariantCulture) }; + } + } + } + } + + public string ContentType + { + get + { + return Headers.Get(HttpKnownHeaderNames.ContentLength); + } + set + { + CheckResponseStarted(); + if (string.IsNullOrEmpty(value)) + { + Headers.Remove(HttpKnownHeaderNames.ContentType); + } + else + { + Headers[HttpKnownHeaderNames.ContentType] = new[] { value }; + } + } + } + private Version GetProtocolVersion() { /* @@ -203,24 +265,17 @@ namespace Microsoft.AspNet.Server.WebListener return Request.ProtocolVersion; } - public void Dispose() + // should only be called from RequestContext + internal void Dispose() { - Dispose(true); - } - - private void Dispose(bool disposing) - { - if (disposing) + if (_responseState >= ResponseState.Closed) { - if (_responseState >= ResponseState.Closed) - { - return; - } - // TODO: Verbose log - EnsureResponseStream(); - _nativeStream.Dispose(); - _responseState = ResponseState.Closed; + return; } + // TODO: Verbose log + EnsureResponseStream(); + _nativeStream.Dispose(); + _responseState = ResponseState.Closed; } // old API, now private, and helper methods @@ -434,7 +489,7 @@ namespace Microsoft.AspNet.Server.WebListener } // Content-Length takes priority - string contentLengthString = Headers.Get(HttpKnownHeaderNames.ContentLength); + long? contentLength = ContentLength; string transferEncodingString = Headers.Get(HttpKnownHeaderNames.TransferEncoding); if (responseVersion == Constants.V1_0 && !string.IsNullOrEmpty(transferEncodingString) @@ -445,27 +500,14 @@ namespace Microsoft.AspNet.Server.WebListener transferEncodingString = null; } - if (!string.IsNullOrWhiteSpace(contentLengthString)) + if (contentLength.HasValue) { - contentLengthString = contentLengthString.Trim(); - if (string.Equals("0", contentLengthString, StringComparison.Ordinal)) + _contentLength = contentLength.Value; + _boundaryType = BoundaryType.ContentLength; + if (_contentLength == 0) { - _boundaryType = BoundaryType.ContentLength; - _contentLength = 0; flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; } - else if (long.TryParse(contentLengthString, NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out _contentLength)) - { - _boundaryType = BoundaryType.ContentLength; - if (_contentLength == 0) - { - flags = UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.NONE; - } - } - else - { - _boundaryType = BoundaryType.Invalid; - } } else if (!string.IsNullOrWhiteSpace(transferEncodingString) && string.Equals("chunked", transferEncodingString.Trim(), StringComparison.OrdinalIgnoreCase)) @@ -509,7 +551,6 @@ namespace Microsoft.AspNet.Server.WebListener } // Also, Keep-Alive vs Connection Close - if (!keepAlive) { if (!closeSet) diff --git a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs index 45c3d698ff..8d49f85ca3 100644 --- a/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs +++ b/src/Microsoft.AspNet.Server.WebListener/RequestProcessing/ResponseStream.cs @@ -195,14 +195,14 @@ namespace Microsoft.AspNet.Server.WebListener } if (_leftToWrite == long.MinValue) { - UnsafeNclNativeMethods.HttpApi.HTTP_VERB method = _requestContext.GetKnownMethod(); + UnsafeNclNativeMethods.HttpApi.HTTP_VERB method = _requestContext.Request.GetKnownMethod(); if (method == UnsafeNclNativeMethods.HttpApi.HTTP_VERB.HttpVerbHEAD) { _leftToWrite = 0; } - else if (_requestContext.Response.EntitySendFormat == EntitySendFormat.ContentLength) + else if (_requestContext.Response.BoundaryType == BoundaryType.ContentLength) { - _leftToWrite = _requestContext.Response.ContentLength64; + _leftToWrite = _requestContext.Response.CalculatedLength; } else { diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs index 19a7b78a6e..63c5f1713e 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerException.cs @@ -1,19 +1,18 @@ //------------------------------------------------------------------------------ -// +// // Copyright (c) Microsoft Corporation. All rights reserved. // //------------------------------------------------------------------------------ using System; using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; namespace Microsoft.AspNet.Server.WebListener { -#if NET45 - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] -#endif - internal class WebListenerException : Win32Exception + [SuppressMessage("Microsoft.Usage", "CA2237:MarkISerializableTypesWithSerializable")] + public class WebListenerException : Win32Exception { internal WebListenerException() : base(Marshal.GetLastWin32Error()) @@ -29,12 +28,14 @@ namespace Microsoft.AspNet.Server.WebListener : base(errorCode, message) { } - +#if NET45 + // the base class returns the HResult with this property + // we need the Win32 Error Code, hence the override. public override int ErrorCode +#else + public int ErrorCode +#endif { - // the base class returns the HResult with this property - // we need the Win32 Error Code, hence the override. - get { return NativeErrorCode; diff --git a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs index 1986d8d3de..e274221a13 100644 --- a/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs +++ b/src/Microsoft.AspNet.Server.WebListener/WebListenerWrapper.cs @@ -139,7 +139,7 @@ namespace Microsoft.AspNet.Server.WebListener else { // We haven't sent a response yet, try to send a 500 Internal Server Error - requestContext.SetFatalResponse(); + SetFatalResponse(requestContext); } } requestContext.Dispose(); @@ -148,10 +148,17 @@ namespace Microsoft.AspNet.Server.WebListener { LogHelper.LogException(_logger, "ProcessRequestAsync", ex); requestContext.Abort(); - requestContext.Dispose(); } } + private static void SetFatalResponse(RequestContext context) + { + context.Response.StatusCode = 500; + context.Response.ReasonPhrase = string.Empty; + context.Response.Headers.Clear(); + context.Response.ContentLength = 0; + } + public void Dispose() { _listener.Dispose(); diff --git a/src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs b/src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs deleted file mode 100644 index 108303ee2c..0000000000 --- a/src/Microsoft.AspNet.Server.WebListener/fx/System/ComponentModel/Win32Exception.cs +++ /dev/null @@ -1,112 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// -//------------------------------------------------------------------------------ - -#if !NET45 - -using System.Runtime.InteropServices; -using System.Text; - -namespace System.ComponentModel -{ - internal class Win32Exception : ExternalException - { - /// - /// Represents the Win32 error code associated with this exception. This - /// field is read-only. - /// - private readonly int nativeErrorCode; - - /// - /// Initializes a new instance of the class with the last Win32 error - /// that occured. - /// - public Win32Exception() - : this(Marshal.GetLastWin32Error()) - { - } - /// - /// Initializes a new instance of the class with the specified error. - /// - public Win32Exception(int error) - : this(error, GetErrorMessage(error)) - { - } - /// - /// Initializes a new instance of the class with the specified error and the - /// specified detailed description. - /// - public Win32Exception(int error, string message) - : base(message) - { - nativeErrorCode = error; - } - - /// - /// Initializes a new instance of the Exception class with a specified error message. - /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. - /// - public Win32Exception(string message) - : this(Marshal.GetLastWin32Error(), message) - { - } - - /// - /// Initializes a new instance of the Exception class with a specified error message and a - /// reference to the inner exception that is the cause of this exception. - /// FxCop CA1032: Multiple constructors are required to correctly implement a custom exception. - /// - public Win32Exception(string message, Exception innerException) - : base(message, innerException) - { - nativeErrorCode = Marshal.GetLastWin32Error(); - } - - - /// - /// Represents the Win32 error code associated with this exception. This - /// field is read-only. - /// - public int NativeErrorCode - { - get - { - return nativeErrorCode; - } - } - - private static string GetErrorMessage(int error) - { - //get the system error message... - string errorMsg = ""; - StringBuilder sb = new StringBuilder(256); - int result = SafeNativeMethods.FormatMessage( - SafeNativeMethods.FORMAT_MESSAGE_IGNORE_INSERTS | - SafeNativeMethods.FORMAT_MESSAGE_FROM_SYSTEM | - SafeNativeMethods.FORMAT_MESSAGE_ARGUMENT_ARRAY, - IntPtr.Zero, (uint)error, 0, sb, sb.Capacity + 1, - null); - if (result != 0) - { - int i = sb.Length; - while (i > 0) - { - char ch = sb[i - 1]; - if (ch > 32 && ch != '.') break; - i--; - } - errorMsg = sb.ToString(0, i); - } - else - { - errorMsg = "Unknown error (0x" + Convert.ToString(error, 16) + ")"; - } - - return errorMsg; - } - } -} - -#endif \ No newline at end of file diff --git a/src/Microsoft.AspNet.Server.WebListener/project.json b/src/Microsoft.AspNet.Server.WebListener/project.json index 5fe79763d7..82efe0ab48 100644 --- a/src/Microsoft.AspNet.Server.WebListener/project.json +++ b/src/Microsoft.AspNet.Server.WebListener/project.json @@ -37,7 +37,8 @@ "System.Threading": "4.0.0.0", "System.Threading.Overlapped": "4.0.0.0", "System.Threading.Tasks": "4.0.10.0", - "System.Threading.ThreadPool": "4.0.10.0" + "System.Threading.ThreadPool": "4.0.10.0", + "Microsoft.Win32.Primitives": "4.0.0.0" } } }