Re-layer the feature interfaces.
This commit is contained in:
parent
ab7e4cb3c8
commit
c6c5dd6fbf
|
|
@ -518,7 +518,8 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
{
|
{
|
||||||
// TODO: Make disconnect registration lazy
|
// TODO: Make disconnect registration lazy
|
||||||
RegisterForDisconnectNotification(requestContext);
|
RegisterForDisconnectNotification(requestContext);
|
||||||
await _appFunc(requestContext.Features).SupressContext();
|
FeatureContext featureContext = new FeatureContext(requestContext);
|
||||||
|
await _appFunc(featureContext.Features).SupressContext();
|
||||||
await requestContext.ProcessResponseAsync().SupressContext();
|
await requestContext.ProcessResponseAsync().SupressContext();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,338 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
#if NET45
|
||||||
|
using System.Security.Cryptography.X509Certificates;
|
||||||
|
#endif
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNet.FeatureModel;
|
||||||
|
using Microsoft.AspNet.HttpFeature;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNet.Server.WebListener
|
||||||
|
{
|
||||||
|
internal class FeatureContext : IHttpRequestInformation, IHttpConnection, IHttpResponseInformation, IHttpSendFile
|
||||||
|
#if NET45
|
||||||
|
, IHttpTransportLayerSecurity
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
private RequestContext _requestContext;
|
||||||
|
private FeatureCollection _features;
|
||||||
|
|
||||||
|
private Stream _requestBody;
|
||||||
|
private IDictionary<string, string[]> _requestHeaders;
|
||||||
|
private string _scheme;
|
||||||
|
private string _httpMethod;
|
||||||
|
private string _httpProtocolVersion;
|
||||||
|
private string _query;
|
||||||
|
private string _pathBase;
|
||||||
|
private string _path;
|
||||||
|
#if NET45
|
||||||
|
private IPAddress _remoteIpAddress;
|
||||||
|
private IPAddress _localIpAddress;
|
||||||
|
#endif
|
||||||
|
private int? _remotePort;
|
||||||
|
private int? _localPort;
|
||||||
|
private bool? _isLocal;
|
||||||
|
#if NET45
|
||||||
|
private X509Certificate _clientCert;
|
||||||
|
#endif
|
||||||
|
private Stream _responseStream;
|
||||||
|
private IDictionary<string, string[]> _responseHeaders;
|
||||||
|
|
||||||
|
internal FeatureContext(RequestContext requestContext)
|
||||||
|
{
|
||||||
|
_requestContext = requestContext;
|
||||||
|
_features = new FeatureCollection();
|
||||||
|
PopulateFeatures();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IFeatureCollection Features
|
||||||
|
{
|
||||||
|
get { return _features; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Request Request
|
||||||
|
{
|
||||||
|
get { return _requestContext.Request; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private Response Response
|
||||||
|
{
|
||||||
|
get { return _requestContext.Response; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PopulateFeatures()
|
||||||
|
{
|
||||||
|
_features.Add(typeof(IHttpRequestInformation), this);
|
||||||
|
_features.Add(typeof(IHttpConnection), this);
|
||||||
|
if (Request.IsSecureConnection)
|
||||||
|
{
|
||||||
|
#if NET45
|
||||||
|
// TODO: Should this feature be conditional? Should we add this for HTTP requests?
|
||||||
|
_features.Add(typeof(IHttpTransportLayerSecurity), this);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
_features.Add(typeof(IHttpResponseInformation), this);
|
||||||
|
_features.Add(typeof(IHttpSendFile), this);
|
||||||
|
|
||||||
|
// TODO:
|
||||||
|
// _environment.CallCancelled = _cts.Token;
|
||||||
|
// _environment.User = _request.User;
|
||||||
|
// Opaque/WebSockets
|
||||||
|
// Channel binding
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Server
|
||||||
|
_environment.Listener = _server;
|
||||||
|
_environment.ConnectionId = _request.ConnectionId;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
#region IHttpRequestInformation
|
||||||
|
|
||||||
|
Stream IHttpRequestInformation.Body
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_requestBody == null)
|
||||||
|
{
|
||||||
|
_requestBody = Request.Body;
|
||||||
|
}
|
||||||
|
return _requestBody;
|
||||||
|
}
|
||||||
|
set { _requestBody = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
IDictionary<string, string[]> IHttpRequestInformation.Headers
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_requestHeaders == null)
|
||||||
|
{
|
||||||
|
_requestHeaders = Request.Headers;
|
||||||
|
}
|
||||||
|
return _requestHeaders;
|
||||||
|
}
|
||||||
|
set { _requestHeaders = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
string IHttpRequestInformation.Method
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_httpMethod == null)
|
||||||
|
{
|
||||||
|
_httpMethod = Request.Method;
|
||||||
|
}
|
||||||
|
return _httpMethod;
|
||||||
|
}
|
||||||
|
set { _httpMethod = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
string IHttpRequestInformation.Path
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_path == null)
|
||||||
|
{
|
||||||
|
_path = Request.Path;
|
||||||
|
}
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
set { _path = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
string IHttpRequestInformation.PathBase
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_pathBase == null)
|
||||||
|
{
|
||||||
|
_pathBase = Request.PathBase;
|
||||||
|
}
|
||||||
|
return _pathBase;
|
||||||
|
}
|
||||||
|
set { _pathBase = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
string IHttpRequestInformation.Protocol
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_httpProtocolVersion == null)
|
||||||
|
{
|
||||||
|
_httpProtocolVersion = Request.Protocol;
|
||||||
|
}
|
||||||
|
return _httpProtocolVersion;
|
||||||
|
}
|
||||||
|
set { _httpProtocolVersion = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
string IHttpRequestInformation.QueryString
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_query == null)
|
||||||
|
{
|
||||||
|
_query = Request.QueryString;
|
||||||
|
}
|
||||||
|
return _query;
|
||||||
|
}
|
||||||
|
set { _query = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
string IHttpRequestInformation.Scheme
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_scheme == null)
|
||||||
|
{
|
||||||
|
_scheme = Request.Scheme;
|
||||||
|
}
|
||||||
|
return _scheme;
|
||||||
|
}
|
||||||
|
set { _scheme = value; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region IHttpConnection
|
||||||
|
bool IHttpConnection.IsLocal
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_isLocal == null)
|
||||||
|
{
|
||||||
|
_isLocal = Request.IsLocal;
|
||||||
|
}
|
||||||
|
return _isLocal.Value;
|
||||||
|
}
|
||||||
|
set { _isLocal = value; }
|
||||||
|
}
|
||||||
|
#if NET45
|
||||||
|
IPAddress IHttpConnection.LocalIpAddress
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_localIpAddress == null)
|
||||||
|
{
|
||||||
|
_localIpAddress = Request.LocalIpAddress;
|
||||||
|
}
|
||||||
|
return _localIpAddress;
|
||||||
|
}
|
||||||
|
set { _localIpAddress = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
IPAddress IHttpConnection.RemoteIpAddress
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_remoteIpAddress == null)
|
||||||
|
{
|
||||||
|
_remoteIpAddress = Request.RemoteIpAddress;
|
||||||
|
}
|
||||||
|
return _remoteIpAddress;
|
||||||
|
}
|
||||||
|
set { _remoteIpAddress = value; }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
int IHttpConnection.LocalPort
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_localPort == null)
|
||||||
|
{
|
||||||
|
_localPort = Request.LocalPort;
|
||||||
|
}
|
||||||
|
return _localPort.Value;
|
||||||
|
}
|
||||||
|
set { _localPort = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
int IHttpConnection.RemotePort
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_remotePort == null)
|
||||||
|
{
|
||||||
|
_remotePort = Request.RemotePort;
|
||||||
|
}
|
||||||
|
return _remotePort.Value;
|
||||||
|
}
|
||||||
|
set { _remotePort = value; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
#region IHttpTransportLayerSecurity
|
||||||
|
#if NET45
|
||||||
|
X509Certificate IHttpTransportLayerSecurity.ClientCertificate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_clientCert == null)
|
||||||
|
{
|
||||||
|
_clientCert = Request.GetClientCertificateAsync().Result; // TODO: Sync;
|
||||||
|
}
|
||||||
|
return _clientCert;
|
||||||
|
}
|
||||||
|
set { _clientCert = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task IHttpTransportLayerSecurity.LoadAsync()
|
||||||
|
{
|
||||||
|
if (_clientCert == null)
|
||||||
|
{
|
||||||
|
_clientCert = await Request.GetClientCertificateAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endregion
|
||||||
|
#region IHttpResponseInformation
|
||||||
|
Stream IHttpResponseInformation.Body
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_responseStream == null)
|
||||||
|
{
|
||||||
|
_responseStream = Response.Body;
|
||||||
|
}
|
||||||
|
return _responseStream;
|
||||||
|
}
|
||||||
|
set { _responseStream = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
IDictionary<string, string[]> IHttpResponseInformation.Headers
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_responseHeaders == null)
|
||||||
|
{
|
||||||
|
_responseHeaders = Response.Headers;
|
||||||
|
}
|
||||||
|
return _responseHeaders;
|
||||||
|
}
|
||||||
|
set { _responseHeaders = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void IHttpResponseInformation.OnSendingHeaders(Action<object> callback, object state)
|
||||||
|
{
|
||||||
|
Response.OnSendingHeaders(callback, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
string IHttpResponseInformation.ReasonPhrase
|
||||||
|
{
|
||||||
|
get { return Response.ReasonPhrase; }
|
||||||
|
set { Response.ReasonPhrase = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
int IHttpResponseInformation.StatusCode
|
||||||
|
{
|
||||||
|
get { return Response.StatusCode; }
|
||||||
|
set { Response.StatusCode = value; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
Task IHttpSendFile.SendFileAsync(string path, long offset, long? length, CancellationToken cancellation)
|
||||||
|
{
|
||||||
|
return Response.SendFileAsync(path, offset, length, cancellation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,17 +11,15 @@ using System.IO;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
#if NET45
|
#if NET45
|
||||||
using System.Security.Authentication.ExtendedProtection;
|
|
||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
#endif
|
#endif
|
||||||
using System.Security.Principal;
|
using System.Security.Principal;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.HttpFeature;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Server.WebListener
|
namespace Microsoft.AspNet.Server.WebListener
|
||||||
{
|
{
|
||||||
internal sealed class Request : IHttpRequestInformation, IHttpConnection, IHttpTransportLayerSecurity, IDisposable
|
internal sealed class Request : IDisposable
|
||||||
{
|
{
|
||||||
private RequestContext _requestContext;
|
private RequestContext _requestContext;
|
||||||
private NativeRequestContext _nativeRequestContext;
|
private NativeRequestContext _nativeRequestContext;
|
||||||
|
|
@ -31,11 +29,9 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
private ulong _contextId;
|
private ulong _contextId;
|
||||||
|
|
||||||
private SslStatus _sslStatus;
|
private SslStatus _sslStatus;
|
||||||
private string _scheme;
|
|
||||||
|
|
||||||
private string _httpMethod;
|
private string _httpMethod;
|
||||||
private Version _httpVersion;
|
private Version _httpVersion;
|
||||||
private string _httpProtocolVersion;
|
|
||||||
|
|
||||||
// private Uri _requestUri;
|
// private Uri _requestUri;
|
||||||
private string _rawUrl;
|
private string _rawUrl;
|
||||||
|
|
@ -53,17 +49,9 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
private BoundaryType _contentBoundaryType;
|
private BoundaryType _contentBoundaryType;
|
||||||
private long _contentLength;
|
private long _contentLength;
|
||||||
private Stream _nativeStream;
|
private Stream _nativeStream;
|
||||||
private Stream _requestStream;
|
|
||||||
|
|
||||||
private SocketAddress _localEndPoint;
|
private SocketAddress _localEndPoint;
|
||||||
private SocketAddress _remoteEndPoint;
|
private SocketAddress _remoteEndPoint;
|
||||||
#if NET45
|
|
||||||
private IPAddress _remoteIpAddress;
|
|
||||||
private IPAddress _localIpAddress;
|
|
||||||
#endif
|
|
||||||
private int? _remotePort;
|
|
||||||
private int? _localPort;
|
|
||||||
private bool? _isLocal;
|
|
||||||
|
|
||||||
private IPrincipal _user;
|
private IPrincipal _user;
|
||||||
|
|
||||||
|
|
@ -215,25 +203,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if NET45
|
|
||||||
X509Certificate IHttpTransportLayerSecurity.ClientCertificate
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_clientCert == null)
|
|
||||||
{
|
|
||||||
// TODO: Sync
|
|
||||||
((IHttpTransportLayerSecurity)this).LoadAsync().Wait();
|
|
||||||
}
|
|
||||||
return _clientCert;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_clientCert = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO: Move this to the constructor, that's where it will be called.
|
// TODO: Move this to the constructor, that's where it will be called.
|
||||||
internal long ContentLength64
|
internal long ContentLength64
|
||||||
{
|
{
|
||||||
|
|
@ -270,33 +239,15 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
|
|
||||||
public IDictionary<string, string[]> Headers
|
public IDictionary<string, string[]> Headers
|
||||||
{
|
{
|
||||||
get
|
get { return _headers; }
|
||||||
{
|
|
||||||
return _headers;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException("value");
|
|
||||||
}
|
|
||||||
_headers = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Method
|
public string Method
|
||||||
{
|
{
|
||||||
get
|
get { return _httpMethod; }
|
||||||
{
|
|
||||||
return _httpMethod;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_httpMethod = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Stream NativeStream
|
public Stream Body
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
@ -309,60 +260,25 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream Body
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_requestStream == null)
|
|
||||||
{
|
|
||||||
// TODO: Move this to the constructor (or a lazy Env dictionary)
|
|
||||||
_requestStream = NativeStream;
|
|
||||||
}
|
|
||||||
return _requestStream;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_requestStream = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string PathBase
|
public string PathBase
|
||||||
{
|
{
|
||||||
get
|
get { return _pathBase; }
|
||||||
{
|
|
||||||
return _pathBase;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_pathBase = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Path
|
public string Path
|
||||||
{
|
{
|
||||||
get
|
get { return _path; }
|
||||||
{
|
|
||||||
return _path;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_path = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsLocal
|
public bool IsLocal
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!_isLocal.HasValue)
|
#if NET45
|
||||||
{
|
return LocalEndPoint.GetIPAddress().Equals(RemoteEndPoint.GetIPAddress());
|
||||||
_isLocal = LocalEndPoint.GetIPAddress().Equals(RemoteEndPoint.GetIPAddress());
|
#else
|
||||||
}
|
throw new NotImplementedException();
|
||||||
return _isLocal.Value;
|
#endif
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_isLocal = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -394,30 +310,19 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (_httpProtocolVersion == null)
|
if (_httpVersion.Major == 1)
|
||||||
{
|
{
|
||||||
if (_httpVersion.Major == 1)
|
if (_httpVersion.Minor == 1)
|
||||||
{
|
{
|
||||||
if (_httpVersion.Minor == 1)
|
return "HTTP/1.1";
|
||||||
{
|
|
||||||
_httpProtocolVersion = "HTTP/1.1";
|
|
||||||
}
|
|
||||||
else if (_httpVersion.Minor == 0)
|
|
||||||
{
|
|
||||||
_httpProtocolVersion = "HTTP/1.0";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else if (_httpVersion.Minor == 0)
|
||||||
{
|
{
|
||||||
_httpProtocolVersion = "HTTP/" + _httpVersion.ToString(2);
|
return "HTTP/1.0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _httpProtocolVersion;
|
|
||||||
}
|
return "HTTP/" + _httpVersion.ToString(2);
|
||||||
set
|
|
||||||
{
|
|
||||||
// TODO: Set _httpVersion?
|
|
||||||
_httpProtocolVersion = value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -432,7 +337,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal SocketAddress RemoteEndPoint
|
private SocketAddress RemoteEndPoint
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
@ -445,7 +350,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal SocketAddress LocalEndPoint
|
private SocketAddress LocalEndPoint
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
@ -457,85 +362,30 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
return _localEndPoint;
|
return _localEndPoint;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if NET45
|
||||||
public IPAddress RemoteIpAddress
|
public IPAddress RemoteIpAddress
|
||||||
{
|
{
|
||||||
get
|
get { return RemoteEndPoint.GetIPAddress(); }
|
||||||
{
|
|
||||||
if (_remoteIpAddress == null)
|
|
||||||
{
|
|
||||||
_remoteIpAddress = RemoteEndPoint.GetIPAddress();
|
|
||||||
}
|
|
||||||
return _remoteIpAddress;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_remoteIpAddress = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IPAddress LocalIpAddress
|
public IPAddress LocalIpAddress
|
||||||
{
|
{
|
||||||
get
|
get { return LocalEndPoint.GetIPAddress(); }
|
||||||
{
|
|
||||||
if (_localIpAddress == null)
|
|
||||||
{
|
|
||||||
_localIpAddress = LocalEndPoint.GetIPAddress();
|
|
||||||
}
|
|
||||||
return _localIpAddress;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_localIpAddress = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
public int RemotePort
|
public int RemotePort
|
||||||
{
|
{
|
||||||
get
|
get { return RemoteEndPoint.GetPort(); }
|
||||||
{
|
|
||||||
if (!_remotePort.HasValue)
|
|
||||||
{
|
|
||||||
_remotePort = RemoteEndPoint.GetPort();
|
|
||||||
}
|
|
||||||
return _remotePort.Value;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_remotePort = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int LocalPort
|
public int LocalPort
|
||||||
{
|
{
|
||||||
get
|
get { return LocalEndPoint.GetPort(); }
|
||||||
{
|
|
||||||
if (!_localPort.HasValue)
|
|
||||||
{
|
|
||||||
_localPort = LocalEndPoint.GetPort();
|
|
||||||
}
|
|
||||||
return _localPort.Value;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_localPort = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Scheme
|
public string Scheme
|
||||||
{
|
{
|
||||||
get
|
get { return IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; }
|
||||||
{
|
|
||||||
if (_scheme == null)
|
|
||||||
{
|
|
||||||
_scheme = IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme;
|
|
||||||
}
|
|
||||||
return _scheme;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_scheme = value;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
internal Uri RequestUri
|
internal Uri RequestUri
|
||||||
|
|
@ -594,21 +444,21 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if NET45
|
||||||
// Populates the client certificate. The result may be null if there is no client cert.
|
// 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
|
// TODO: Does it make sense for this to be invoked multiple times (e.g. renegotiate)? Client and server code appear to
|
||||||
// enable this, but it's unclear what Http.Sys would do.
|
// enable this, but it's unclear what Http.Sys would do.
|
||||||
async Task IHttpTransportLayerSecurity.LoadAsync()
|
public async Task<X509Certificate> GetClientCertificateAsync()
|
||||||
{
|
{
|
||||||
if (SslStatus == SslStatus.Insecure)
|
if (SslStatus == SslStatus.Insecure)
|
||||||
{
|
{
|
||||||
// Non-SSL
|
// Non-SSL
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
// TODO: Verbose log
|
// TODO: Verbose log
|
||||||
#if NET45
|
|
||||||
if (_clientCert != null)
|
if (_clientCert != null)
|
||||||
{
|
{
|
||||||
return;
|
return _clientCert;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientCertLoader certLoader = new ClientCertLoader(RequestContext);
|
ClientCertLoader certLoader = new ClientCertLoader(RequestContext);
|
||||||
|
|
@ -630,10 +480,9 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
}
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
#else
|
return _clientCert;
|
||||||
throw new NotImplementedException();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// Use this to save the blob from dispose if this object was never used (never given to a user) and is about to be
|
// 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.
|
// disposed.
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,9 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Diagnostics.Contracts;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Security.Authentication.ExtendedProtection;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.FeatureModel;
|
|
||||||
using Microsoft.AspNet.HttpFeature;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Server.WebListener
|
namespace Microsoft.AspNet.Server.WebListener
|
||||||
{
|
{
|
||||||
|
|
@ -27,7 +21,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
{
|
{
|
||||||
private static readonly string[] ZeroContentLength = new[] { "0" };
|
private static readonly string[] ZeroContentLength = new[] { "0" };
|
||||||
|
|
||||||
private FeatureCollection _features;
|
|
||||||
private OwinWebListener _server;
|
private OwinWebListener _server;
|
||||||
private Request _request;
|
private Request _request;
|
||||||
private Response _response;
|
private Response _response;
|
||||||
|
|
@ -44,18 +37,9 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
_request = new Request(this, _memoryBlob);
|
_request = new Request(this, _memoryBlob);
|
||||||
_response = new Response(this);
|
_response = new Response(this);
|
||||||
_cts = new CancellationTokenSource();
|
_cts = new CancellationTokenSource();
|
||||||
|
|
||||||
_features = new FeatureCollection();
|
|
||||||
PopulateFeatures();
|
|
||||||
|
|
||||||
_request.ReleasePins();
|
_request.ReleasePins();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IFeatureCollection Features
|
|
||||||
{
|
|
||||||
get { return _features; }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Request Request
|
internal Request Request
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
|
|
@ -100,31 +84,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
return Request.RequestId;
|
return Request.RequestId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulateFeatures()
|
|
||||||
{
|
|
||||||
_features.Add(typeof(IHttpRequestInformation), Request);
|
|
||||||
_features.Add(typeof(IHttpConnection), Request);
|
|
||||||
if (Request.IsSecureConnection)
|
|
||||||
{
|
|
||||||
// TODO: Should this feature be conditional? Should we add this for HTTP requests?
|
|
||||||
_features.Add(typeof(IHttpTransportLayerSecurity), Request);
|
|
||||||
}
|
|
||||||
_features.Add(typeof(IHttpResponseInformation), Response);
|
|
||||||
_features.Add(typeof(IHttpSendFile), Response);
|
|
||||||
|
|
||||||
// TODO:
|
|
||||||
// _environment.CallCancelled = _cts.Token;
|
|
||||||
// _environment.User = _request.User;
|
|
||||||
// Opaque/WebSockets
|
|
||||||
// Channel binding
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Server
|
|
||||||
_environment.Listener = _server;
|
|
||||||
_environment.ConnectionId = _request.ConnectionId;
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
/*
|
/*
|
||||||
public bool TryGetOpaqueUpgrade(ref Action<IDictionary<string, object>, OpaqueFunc> value)
|
public bool TryGetOpaqueUpgrade(ref Action<IDictionary<string, object>, OpaqueFunc> value)
|
||||||
{
|
{
|
||||||
|
|
@ -265,7 +224,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
|
|
||||||
Request.SwitchToOpaqueMode();
|
Request.SwitchToOpaqueMode();
|
||||||
Response.SwitchToOpaqueMode();
|
Response.SwitchToOpaqueMode();
|
||||||
opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.NativeStream, Response.NativeStream);
|
opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.Body, Response.Body);
|
||||||
|
|
||||||
return opaqueEnv;
|
return opaqueEnv;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,23 +8,19 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNet.HttpFeature;
|
|
||||||
|
|
||||||
namespace Microsoft.AspNet.Server.WebListener
|
namespace Microsoft.AspNet.Server.WebListener
|
||||||
{
|
{
|
||||||
internal sealed unsafe class Response : IHttpResponseInformation, IHttpSendFile, IDisposable
|
internal sealed unsafe class Response : IDisposable
|
||||||
{
|
{
|
||||||
private ResponseState _responseState;
|
private ResponseState _responseState;
|
||||||
private IDictionary<string, string[]> _headers;
|
private IDictionary<string, string[]> _headers;
|
||||||
private string _reasonPhrase;
|
private string _reasonPhrase;
|
||||||
private ResponseStream _nativeStream;
|
private ResponseStream _nativeStream;
|
||||||
private Stream _responseStream;
|
|
||||||
private long _contentLength;
|
private long _contentLength;
|
||||||
private BoundaryType _boundaryType;
|
private BoundaryType _boundaryType;
|
||||||
private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE _nativeResponse;
|
private UnsafeNclNativeMethods.HttpApi.HTTP_RESPONSE _nativeResponse;
|
||||||
|
|
@ -79,17 +75,31 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
{
|
{
|
||||||
throw new ArgumentOutOfRangeException("value", value, string.Format(Resources.Exception_InvalidStatusCode, value));
|
throw new ArgumentOutOfRangeException("value", value, string.Format(Resources.Exception_InvalidStatusCode, value));
|
||||||
}
|
}
|
||||||
|
CheckResponseStarted();
|
||||||
_nativeResponse.StatusCode = (ushort)value;
|
_nativeResponse.StatusCode = (ushort)value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CheckResponseStarted()
|
||||||
|
{
|
||||||
|
if (_responseState >= ResponseState.SentHeaders)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Headers already sent.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string ReasonPhrase
|
public string ReasonPhrase
|
||||||
{
|
{
|
||||||
get { return _reasonPhrase; }
|
get { return _reasonPhrase; }
|
||||||
set { _reasonPhrase = value; }
|
set
|
||||||
|
{
|
||||||
|
// TODO: Validate user input for illegal chars, length limit, etc.?
|
||||||
|
CheckResponseStarted();
|
||||||
|
_reasonPhrase = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ResponseStream NativeStream
|
internal ResponseStream Body
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
@ -99,25 +109,8 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Stream Body
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_responseStream == null)
|
|
||||||
{
|
|
||||||
_responseStream = NativeStream;
|
|
||||||
}
|
|
||||||
return _responseStream;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_responseStream = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal string GetReasonPhrase(int statusCode)
|
internal string GetReasonPhrase(int statusCode)
|
||||||
{
|
{
|
||||||
// TODO: Validate user input for illegal chars, length limit, etc.?
|
|
||||||
string reasonPhrase = ReasonPhrase;
|
string reasonPhrase = ReasonPhrase;
|
||||||
if (string.IsNullOrWhiteSpace(reasonPhrase))
|
if (string.IsNullOrWhiteSpace(reasonPhrase))
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -89,6 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
uint statusCode;
|
uint statusCode;
|
||||||
unsafe
|
unsafe
|
||||||
{
|
{
|
||||||
|
// TODO: Don't add MoreData flag if content-length == 0?
|
||||||
flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
|
flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
|
||||||
statusCode = _requestContext.Response.SendHeaders(null, null, flags, false);
|
statusCode = _requestContext.Response.SendHeaders(null, null, flags, false);
|
||||||
}
|
}
|
||||||
|
|
@ -120,6 +121,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
||||||
// TODO: Real cancellation
|
// TODO: Real cancellation
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
|
// TODO: Don't add MoreData flag if content-length == 0?
|
||||||
flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
|
flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
|
||||||
ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, null, 0, 0, _requestContext.Response.BoundaryType == BoundaryType.Chunked, false);
|
ResponseStreamAsyncResult asyncResult = new ResponseStreamAsyncResult(this, null, null, null, 0, 0, _requestContext.Response.BoundaryType == BoundaryType.Chunked, false);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue