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
|
||||
RegisterForDisconnectNotification(requestContext);
|
||||
await _appFunc(requestContext.Features).SupressContext();
|
||||
FeatureContext featureContext = new FeatureContext(requestContext);
|
||||
await _appFunc(featureContext.Features).SupressContext();
|
||||
await requestContext.ProcessResponseAsync().SupressContext();
|
||||
}
|
||||
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.Runtime.InteropServices;
|
||||
#if NET45
|
||||
using System.Security.Authentication.ExtendedProtection;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
#endif
|
||||
using System.Security.Principal;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.HttpFeature;
|
||||
|
||||
namespace Microsoft.AspNet.Server.WebListener
|
||||
{
|
||||
internal sealed class Request : IHttpRequestInformation, IHttpConnection, IHttpTransportLayerSecurity, IDisposable
|
||||
internal sealed class Request : IDisposable
|
||||
{
|
||||
private RequestContext _requestContext;
|
||||
private NativeRequestContext _nativeRequestContext;
|
||||
|
|
@ -31,11 +29,9 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
private ulong _contextId;
|
||||
|
||||
private SslStatus _sslStatus;
|
||||
private string _scheme;
|
||||
|
||||
private string _httpMethod;
|
||||
private Version _httpVersion;
|
||||
private string _httpProtocolVersion;
|
||||
|
||||
// private Uri _requestUri;
|
||||
private string _rawUrl;
|
||||
|
|
@ -53,17 +49,9 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
private BoundaryType _contentBoundaryType;
|
||||
private long _contentLength;
|
||||
private Stream _nativeStream;
|
||||
private Stream _requestStream;
|
||||
|
||||
private SocketAddress _localEndPoint;
|
||||
private SocketAddress _remoteEndPoint;
|
||||
#if NET45
|
||||
private IPAddress _remoteIpAddress;
|
||||
private IPAddress _localIpAddress;
|
||||
#endif
|
||||
private int? _remotePort;
|
||||
private int? _localPort;
|
||||
private bool? _isLocal;
|
||||
|
||||
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.
|
||||
internal long ContentLength64
|
||||
{
|
||||
|
|
@ -270,33 +239,15 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
|
||||
public IDictionary<string, string[]> Headers
|
||||
{
|
||||
get
|
||||
{
|
||||
return _headers;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
_headers = value;
|
||||
}
|
||||
get { return _headers; }
|
||||
}
|
||||
|
||||
public string Method
|
||||
{
|
||||
get
|
||||
{
|
||||
return _httpMethod;
|
||||
}
|
||||
set
|
||||
{
|
||||
_httpMethod = value;
|
||||
}
|
||||
get { return _httpMethod; }
|
||||
}
|
||||
|
||||
internal Stream NativeStream
|
||||
public Stream Body
|
||||
{
|
||||
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
|
||||
{
|
||||
get
|
||||
{
|
||||
return _pathBase;
|
||||
}
|
||||
set
|
||||
{
|
||||
_pathBase = value;
|
||||
}
|
||||
get { return _pathBase; }
|
||||
}
|
||||
|
||||
public string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
return _path;
|
||||
}
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
}
|
||||
get { return _path; }
|
||||
}
|
||||
|
||||
public bool IsLocal
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_isLocal.HasValue)
|
||||
{
|
||||
_isLocal = LocalEndPoint.GetIPAddress().Equals(RemoteEndPoint.GetIPAddress());
|
||||
}
|
||||
return _isLocal.Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isLocal = value;
|
||||
#if NET45
|
||||
return LocalEndPoint.GetIPAddress().Equals(RemoteEndPoint.GetIPAddress());
|
||||
#else
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -394,30 +310,19 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
{
|
||||
get
|
||||
{
|
||||
if (_httpProtocolVersion == null)
|
||||
if (_httpVersion.Major == 1)
|
||||
{
|
||||
if (_httpVersion.Major == 1)
|
||||
if (_httpVersion.Minor == 1)
|
||||
{
|
||||
if (_httpVersion.Minor == 1)
|
||||
{
|
||||
_httpProtocolVersion = "HTTP/1.1";
|
||||
}
|
||||
else if (_httpVersion.Minor == 0)
|
||||
{
|
||||
_httpProtocolVersion = "HTTP/1.0";
|
||||
}
|
||||
return "HTTP/1.1";
|
||||
}
|
||||
else
|
||||
else if (_httpVersion.Minor == 0)
|
||||
{
|
||||
_httpProtocolVersion = "HTTP/" + _httpVersion.ToString(2);
|
||||
return "HTTP/1.0";
|
||||
}
|
||||
}
|
||||
return _httpProtocolVersion;
|
||||
}
|
||||
set
|
||||
{
|
||||
// TODO: Set _httpVersion?
|
||||
_httpProtocolVersion = value;
|
||||
|
||||
return "HTTP/" + _httpVersion.ToString(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -432,7 +337,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
}
|
||||
}
|
||||
|
||||
internal SocketAddress RemoteEndPoint
|
||||
private SocketAddress RemoteEndPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
@ -445,7 +350,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
}
|
||||
}
|
||||
|
||||
internal SocketAddress LocalEndPoint
|
||||
private SocketAddress LocalEndPoint
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
@ -457,85 +362,30 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
return _localEndPoint;
|
||||
}
|
||||
}
|
||||
|
||||
#if NET45
|
||||
public IPAddress RemoteIpAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_remoteIpAddress == null)
|
||||
{
|
||||
_remoteIpAddress = RemoteEndPoint.GetIPAddress();
|
||||
}
|
||||
return _remoteIpAddress;
|
||||
}
|
||||
set
|
||||
{
|
||||
_remoteIpAddress = value;
|
||||
}
|
||||
get { return RemoteEndPoint.GetIPAddress(); }
|
||||
}
|
||||
|
||||
public IPAddress LocalIpAddress
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_localIpAddress == null)
|
||||
{
|
||||
_localIpAddress = LocalEndPoint.GetIPAddress();
|
||||
}
|
||||
return _localIpAddress;
|
||||
}
|
||||
set
|
||||
{
|
||||
_localIpAddress = value;
|
||||
}
|
||||
get { return LocalEndPoint.GetIPAddress(); }
|
||||
}
|
||||
|
||||
#endif
|
||||
public int RemotePort
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_remotePort.HasValue)
|
||||
{
|
||||
_remotePort = RemoteEndPoint.GetPort();
|
||||
}
|
||||
return _remotePort.Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
_remotePort = value;
|
||||
}
|
||||
get { return RemoteEndPoint.GetPort(); }
|
||||
}
|
||||
|
||||
public int LocalPort
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_localPort.HasValue)
|
||||
{
|
||||
_localPort = LocalEndPoint.GetPort();
|
||||
}
|
||||
return _localPort.Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
_localPort = value;
|
||||
}
|
||||
get { return LocalEndPoint.GetPort(); }
|
||||
}
|
||||
|
||||
public string Scheme
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_scheme == null)
|
||||
{
|
||||
_scheme = IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme;
|
||||
}
|
||||
return _scheme;
|
||||
}
|
||||
set
|
||||
{
|
||||
_scheme = value;
|
||||
}
|
||||
get { return IsSecureConnection ? Constants.HttpsScheme : Constants.HttpScheme; }
|
||||
}
|
||||
/*
|
||||
internal Uri RequestUri
|
||||
|
|
@ -594,21 +444,21 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
#endif
|
||||
}
|
||||
|
||||
#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
|
||||
// enable this, but it's unclear what Http.Sys would do.
|
||||
async Task IHttpTransportLayerSecurity.LoadAsync()
|
||||
public async Task<X509Certificate> GetClientCertificateAsync()
|
||||
{
|
||||
if (SslStatus == SslStatus.Insecure)
|
||||
{
|
||||
// Non-SSL
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
// TODO: Verbose log
|
||||
#if NET45
|
||||
if (_clientCert != null)
|
||||
{
|
||||
return;
|
||||
return _clientCert;
|
||||
}
|
||||
|
||||
ClientCertLoader certLoader = new ClientCertLoader(RequestContext);
|
||||
|
|
@ -630,10 +480,9 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
}
|
||||
throw;
|
||||
}
|
||||
#else
|
||||
throw new NotImplementedException();
|
||||
#endif
|
||||
return _clientCert;
|
||||
}
|
||||
#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
|
||||
// disposed.
|
||||
|
|
|
|||
|
|
@ -8,15 +8,9 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Diagnostics.Contracts;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security.Authentication.ExtendedProtection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.FeatureModel;
|
||||
using Microsoft.AspNet.HttpFeature;
|
||||
|
||||
namespace Microsoft.AspNet.Server.WebListener
|
||||
{
|
||||
|
|
@ -27,7 +21,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
{
|
||||
private static readonly string[] ZeroContentLength = new[] { "0" };
|
||||
|
||||
private FeatureCollection _features;
|
||||
private OwinWebListener _server;
|
||||
private Request _request;
|
||||
private Response _response;
|
||||
|
|
@ -44,18 +37,9 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
_request = new Request(this, _memoryBlob);
|
||||
_response = new Response(this);
|
||||
_cts = new CancellationTokenSource();
|
||||
|
||||
_features = new FeatureCollection();
|
||||
PopulateFeatures();
|
||||
|
||||
_request.ReleasePins();
|
||||
}
|
||||
|
||||
internal IFeatureCollection Features
|
||||
{
|
||||
get { return _features; }
|
||||
}
|
||||
|
||||
internal Request Request
|
||||
{
|
||||
get
|
||||
|
|
@ -100,31 +84,6 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
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)
|
||||
{
|
||||
|
|
@ -265,7 +224,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
|
||||
Request.SwitchToOpaqueMode();
|
||||
Response.SwitchToOpaqueMode();
|
||||
opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.NativeStream, Response.NativeStream);
|
||||
opaqueEnv[Constants.OpaqueStreamKey] = new OpaqueStream(Request.Body, Response.Body);
|
||||
|
||||
return opaqueEnv;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,23 +8,19 @@ using System;
|
|||
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.AspNet.HttpFeature;
|
||||
|
||||
namespace Microsoft.AspNet.Server.WebListener
|
||||
{
|
||||
internal sealed unsafe class Response : IHttpResponseInformation, IHttpSendFile, IDisposable
|
||||
internal sealed unsafe class Response : IDisposable
|
||||
{
|
||||
private ResponseState _responseState;
|
||||
private IDictionary<string, string[]> _headers;
|
||||
private string _reasonPhrase;
|
||||
private ResponseStream _nativeStream;
|
||||
private Stream _responseStream;
|
||||
private long _contentLength;
|
||||
private BoundaryType _boundaryType;
|
||||
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));
|
||||
}
|
||||
CheckResponseStarted();
|
||||
_nativeResponse.StatusCode = (ushort)value;
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckResponseStarted()
|
||||
{
|
||||
if (_responseState >= ResponseState.SentHeaders)
|
||||
{
|
||||
throw new InvalidOperationException("Headers already sent.");
|
||||
}
|
||||
}
|
||||
|
||||
public string 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
|
||||
{
|
||||
|
|
@ -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)
|
||||
{
|
||||
// TODO: Validate user input for illegal chars, length limit, etc.?
|
||||
string reasonPhrase = ReasonPhrase;
|
||||
if (string.IsNullOrWhiteSpace(reasonPhrase))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
uint statusCode;
|
||||
unsafe
|
||||
{
|
||||
// TODO: Don't add MoreData flag if content-length == 0?
|
||||
flags |= UnsafeNclNativeMethods.HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
|
||||
statusCode = _requestContext.Response.SendHeaders(null, null, flags, false);
|
||||
}
|
||||
|
|
@ -120,6 +121,7 @@ namespace Microsoft.AspNet.Server.WebListener
|
|||
// TODO: Real cancellation
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
// TODO: Don't add MoreData flag if content-length == 0?
|
||||
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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue