zoukankan      html  css  js  c++  java
  • asp.net core 3.1 源码学习 http相关

    一、IFeatureCollection

      表示Http特性的集合,该集合存放一些http相关特性,如IHttpRequestFeature、IHttpResponseFeature

      当构建HttpContext、HttpRequest、HttpResponse对象时,会从这些特性里面解析构建对应的类

    public interface IFeatureCollection : IEnumerable<KeyValuePair<Type, object>>
        {
            /// <summary>
            /// Indicates if the collection can be modified.
            /// </summary>
            bool IsReadOnly { get; }
    
            /// <summary>
            /// Incremented for each modification and can be used to verify cached results.
            /// </summary>
            int Revision { get; }
    
            /// <summary>
            /// Gets or sets a given feature. Setting a null value removes the feature.
            /// </summary>
            /// <param name="key"></param>
            /// <returns>The requested feature, or null if it is not present.</returns>
            object this[Type key] { get; set; }
    
            /// <summary>
            /// Retrieves the requested feature from the collection.
            /// </summary>
            /// <typeparam name="TFeature">The feature key.</typeparam>
            /// <returns>The requested feature, or null if it is not present.</returns>
            TFeature Get<TFeature>();
    
            /// <summary>
            /// Sets the given feature in the collection.
            /// </summary>
            /// <typeparam name="TFeature">The feature key.</typeparam>
            /// <param name="instance">The feature value.</param>
            void Set<TFeature>(TFeature instance);
        }
    public class FeatureCollection : IFeatureCollection
        {
            private static KeyComparer FeatureKeyComparer = new KeyComparer();
            private readonly IFeatureCollection _defaults;
            private IDictionary<Type, object> _features;
            private volatile int _containerRevision;
    
            public FeatureCollection()
            {
            }
    
            public FeatureCollection(IFeatureCollection defaults)
            {
                _defaults = defaults;
            }
    
            public virtual int Revision
            {
                get { return _containerRevision + (_defaults?.Revision ?? 0); }
            }
    
            public bool IsReadOnly { get { return false; } }
    
            public object this[Type key]
            {
                get
                {
                    if (key == null)
                    {
                        throw new ArgumentNullException(nameof(key));
                    }
    
                    object result;
                    return _features != null && _features.TryGetValue(key, out result) ? result : _defaults?[key];
                }
                set
                {
                    if (key == null)
                    {
                        throw new ArgumentNullException(nameof(key));
                    }
    
                    if (value == null)
                    {
                        if (_features != null && _features.Remove(key))
                        {
                            _containerRevision++;
                        }
                        return;
                    }
    
                    if (_features == null)
                    {
                        _features = new Dictionary<Type, object>();
                    }
                    _features[key] = value;
                    _containerRevision++;
                }
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
    
            public IEnumerator<KeyValuePair<Type, object>> GetEnumerator()
            {
                if (_features != null)
                {
                    foreach (var pair in _features)
                    {
                        yield return pair;
                    }
                }
    
                if (_defaults != null)
                {
                    // Don't return features masked by the wrapper.
                    foreach (var pair in _features == null ? _defaults : _defaults.Except(_features, FeatureKeyComparer))
                    {
                        yield return pair;
                    }
                }
            }
    
            public TFeature Get<TFeature>()
            {
                return (TFeature)this[typeof(TFeature)];
            }
    
            public void Set<TFeature>(TFeature instance)
            {
                this[typeof(TFeature)] = instance;
            }
    
            private class KeyComparer : IEqualityComparer<KeyValuePair<Type, object>>
            {
                public bool Equals(KeyValuePair<Type, object> x, KeyValuePair<Type, object> y)
                {
                    return x.Key.Equals(y.Key);
                }
    
                public int GetHashCode(KeyValuePair<Type, object> obj)
                {
                    return obj.Key.GetHashCode();
                }
            }
        }

    HttpRequest

    /// <summary>
        /// Represents the incoming side of an individual HTTP request.
        /// </summary>
        public abstract class HttpRequest
        {
            /// <summary>
            /// Gets the <see cref="HttpContext"/> for this request.
            /// </summary>
            public abstract HttpContext HttpContext { get; }
    
            /// <summary>
            /// Gets or sets the HTTP method.
            /// </summary>
            /// <returns>The HTTP method.</returns>
            public abstract string Method { get; set; }
    
            /// <summary>
            /// Gets or sets the HTTP request scheme.
            /// </summary>
            /// <returns>The HTTP request scheme.</returns>
            public abstract string Scheme { get; set; }
    
            /// <summary>
            /// Returns true if the RequestScheme is https.
            /// </summary>
            /// <returns>true if this request is using https; otherwise, false.</returns>
            public abstract bool IsHttps { get; set; }
    
            /// <summary>
            /// Gets or sets the Host header. May include the port.
            /// </summary>
            /// <return>The Host header.</return>
            public abstract HostString Host { get; set; }
    
            /// <summary>
            /// Gets or sets the RequestPathBase.
            /// </summary>
            /// <returns>The RequestPathBase.</returns>
            public abstract PathString PathBase { get; set; }
    
            /// <summary>
            /// Gets or sets the request path from RequestPath.
            /// </summary>
            /// <returns>The request path from RequestPath.</returns>
            public abstract PathString Path { get; set; }
    
            /// <summary>
            /// Gets or sets the raw query string used to create the query collection in Request.Query.
            /// </summary>
            /// <returns>The raw query string.</returns>
            public abstract QueryString QueryString { get; set; }
    
            /// <summary>
            /// Gets the query value collection parsed from Request.QueryString.
            /// </summary>
            /// <returns>The query value collection parsed from Request.QueryString.</returns>
            public abstract IQueryCollection Query { get; set; }
    
            /// <summary>
            /// Gets or sets the request protocol (e.g. HTTP/1.1).
            /// </summary>
            /// <returns>The request protocol.</returns>
            public abstract string Protocol { get; set; }
    
            /// <summary>
            /// Gets the request headers.
            /// </summary>
            /// <returns>The request headers.</returns>
            public abstract IHeaderDictionary Headers { get; }
    
            /// <summary>
            /// Gets the collection of Cookies for this request.
            /// </summary>
            /// <returns>The collection of Cookies for this request.</returns>
            public abstract IRequestCookieCollection Cookies { get; set; }
    
            /// <summary>
            /// Gets or sets the Content-Length header.
            /// </summary>
            /// <returns>The value of the Content-Length header, if any.</returns>
            public abstract long? ContentLength { get; set; }
    
            /// <summary>
            /// Gets or sets the Content-Type header.
            /// </summary>
            /// <returns>The Content-Type header.</returns>
            public abstract string ContentType { get; set; }
    
            /// <summary>
            /// Gets or sets the request body <see cref="Stream"/>.
            /// </summary>
            /// <value>The request body <see cref="Stream"/>.</value>
            public abstract Stream Body { get; set; }
    
            /// <summary>
            /// Gets the request body <see cref="PipeReader"/>.
            /// </summary>
            /// <value>The request body <see cref="PipeReader"/>.</value>
            public virtual PipeReader BodyReader { get => throw new NotImplementedException();  }
    
            /// <summary>
            /// Checks the Content-Type header for form types.
            /// </summary>
            /// <returns>true if the Content-Type header represents a form content type; otherwise, false.</returns>
            public abstract bool HasFormContentType { get; }
    
            /// <summary>
            /// Gets or sets the request body as a form.
            /// </summary>
            public abstract IFormCollection Form { get; set; }
    
            /// <summary>
            /// Reads the request body if it is a form.
            /// </summary>
            /// <returns></returns>
            public abstract Task<IFormCollection> ReadFormAsync(CancellationToken cancellationToken = new CancellationToken());
    
            /// <summary>
            /// Gets the collection of route values for this request.
            /// </summary>
            /// <returns>The collection of route values for this request.</returns>
            public virtual RouteValueDictionary RouteValues { get; set; }
        }

    HttpResponse

    /// <summary>
        /// Represents the outgoing side of an individual HTTP request.
        /// </summary>
        public abstract class HttpResponse
        {
            private static readonly Func<object, Task> _callbackDelegate = callback => ((Func<Task>)callback)();
            private static readonly Func<object, Task> _disposeDelegate = disposable =>
            {
                ((IDisposable)disposable).Dispose();
                return Task.CompletedTask;
            };
    
            private static readonly Func<object, Task> _disposeAsyncDelegate = disposable => ((IAsyncDisposable)disposable).DisposeAsync().AsTask();
    
            /// <summary>
            /// Gets the <see cref="HttpContext"/> for this response.
            /// </summary>
            public abstract HttpContext HttpContext { get; }
    
            /// <summary>
            /// Gets or sets the HTTP response code.
            /// </summary>
            public abstract int StatusCode { get; set; }
    
            /// <summary>
            /// Gets the response headers.
            /// </summary>
            public abstract IHeaderDictionary Headers { get; }
    
            /// <summary>
            /// Gets or sets the response body <see cref="Stream"/>.
            /// </summary>
            public abstract Stream Body { get; set; }
    
            /// <summary>
            /// Gets the response body <see cref="PipeWriter"/>
            /// </summary>
            /// <value>The response body <see cref="PipeWriter"/>.</value>
            public virtual PipeWriter BodyWriter { get => throw new NotImplementedException(); }
    
            /// <summary>
            /// Gets or sets the value for the <c>Content-Length</c> response header.
            /// </summary>
            public abstract long? ContentLength { get; set; }
    
            /// <summary>
            /// Gets or sets the value for the <c>Content-Type</c> response header.
            /// </summary>
            public abstract string ContentType { get; set; }
    
            /// <summary>
            /// Gets an object that can be used to manage cookies for this response.
            /// </summary>
            public abstract IResponseCookies Cookies { get; }
    
            /// <summary>
            /// Gets a value indicating whether response headers have been sent to the client.
            /// </summary>
            public abstract bool HasStarted { get; }
    
            /// <summary>
            /// Adds a delegate to be invoked just before response headers will be sent to the client.
            /// </summary>
            /// <param name="callback">The delegate to execute.</param>
            /// <param name="state">A state object to capture and pass back to the delegate.</param>
            public abstract void OnStarting(Func<object, Task> callback, object state);
    
            /// <summary>
            /// Adds a delegate to be invoked just before response headers will be sent to the client.
            /// </summary>
            /// <param name="callback">The delegate to execute.</param>
            public virtual void OnStarting(Func<Task> callback) => OnStarting(_callbackDelegate, callback);
    
            /// <summary>
            /// Adds a delegate to be invoked after the response has finished being sent to the client.
            /// </summary>
            /// <param name="callback">The delegate to invoke.</param>
            /// <param name="state">A state object to capture and pass back to the delegate.</param>
            public abstract void OnCompleted(Func<object, Task> callback, object state);
    
            /// <summary>
            /// Registers an object for disposal by the host once the request has finished processing.
            /// </summary>
            /// <param name="disposable">The object to be disposed.</param>
            public virtual void RegisterForDispose(IDisposable disposable) => OnCompleted(_disposeDelegate, disposable);
    
            /// <summary>
            /// Registers an object for asynchronous disposal by the host once the request has finished processing.
            /// </summary>
            /// <param name="disposable">The object to be disposed asynchronously.</param>
            public virtual void RegisterForDisposeAsync(IAsyncDisposable disposable) => OnCompleted(_disposeAsyncDelegate, disposable);
    
            /// <summary>
            /// Adds a delegate to be invoked after the response has finished being sent to the client.
            /// </summary>
            /// <param name="callback">The delegate to invoke.</param>
            public virtual void OnCompleted(Func<Task> callback) => OnCompleted(_callbackDelegate, callback);
    
            /// <summary>
            /// Returns a temporary redirect response (HTTP 302) to the client.
            /// </summary>
            /// <param name="location">The URL to redirect the client to. This must be properly encoded for use in http headers
            /// where only ASCII characters are allowed.</param>
            public virtual void Redirect(string location) => Redirect(location, permanent: false);
    
            /// <summary>
            /// Returns a redirect response (HTTP 301 or HTTP 302) to the client.
            /// </summary>
            /// <param name="location">The URL to redirect the client to. This must be properly encoded for use in http headers
            /// where only ASCII characters are allowed.</param>
            /// <param name="permanent"><c>True</c> if the redirect is permanent (301), otherwise <c>false</c> (302).</param>
            public abstract void Redirect(string location, bool permanent);
    
            /// <summary>
            /// Starts the response by calling OnStarting() and making headers unmodifiable.
            /// </summary>
            /// <param name="cancellationToken"></param>
            public virtual Task StartAsync(CancellationToken cancellationToken = default) { throw new NotImplementedException(); }
    
            /// <summary>
            /// Flush any remaining response headers, data, or trailers.
            /// This may throw if the response is in an invalid state such as a Content-Length mismatch.
            /// </summary>
            /// <returns></returns>
            public virtual Task CompleteAsync() { throw new NotImplementedException(); }
        }

    HttpContext

    /// <summary>
        /// Encapsulates all HTTP-specific information about an individual HTTP request.
        /// </summary>
        public abstract class HttpContext
        {
            /// <summary>
            /// Gets the collection of HTTP features provided by the server and middleware available on this request.
            /// </summary>
            public abstract IFeatureCollection Features { get; }
    
            /// <summary>
            /// Gets the <see cref="HttpRequest"/> object for this request.
            /// </summary>
            public abstract HttpRequest Request { get; }
    
            /// <summary>
            /// Gets the <see cref="HttpResponse"/> object for this request.
            /// </summary>
            public abstract HttpResponse Response { get; }
    
            /// <summary>
            /// Gets information about the underlying connection for this request.
            /// </summary>
            public abstract ConnectionInfo Connection { get; }
    
            /// <summary>
            /// Gets an object that manages the establishment of WebSocket connections for this request.
            /// </summary>
            public abstract WebSocketManager WebSockets { get; }
    
            /// <summary>
            /// Gets or sets the user for this request.
            /// </summary>
            public abstract ClaimsPrincipal User { get; set; }
    
            /// <summary>
            /// Gets or sets a key/value collection that can be used to share data within the scope of this request.
            /// </summary>
            public abstract IDictionary<object, object> Items { get; set; }
    
            /// <summary>
            /// Gets or sets the <see cref="IServiceProvider"/> that provides access to the request's service container.
            /// </summary>
            public abstract IServiceProvider RequestServices { get; set; }
    
            /// <summary>
            /// Notifies when the connection underlying this request is aborted and thus request operations should be
            /// cancelled.
            /// </summary>
            public abstract CancellationToken RequestAborted { get; set; }
    
            /// <summary>
            /// Gets or sets a unique identifier to represent this request in trace logs.
            /// </summary>
            public abstract string TraceIdentifier { get; set; }
    
            /// <summary>
            /// Gets or sets the object used to manage user session data for this request.
            /// </summary>
            public abstract ISession Session { get; set; }
    
            /// <summary>
            /// Aborts the connection underlying this request.
            /// </summary>
            public abstract void Abort();
        }

    DefaultHttpContext

    public sealed class DefaultHttpContext : HttpContext
        {
            // Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624
            private readonly static Func<IFeatureCollection, IItemsFeature> _newItemsFeature = f => new ItemsFeature();
            private readonly static Func<DefaultHttpContext, IServiceProvidersFeature> _newServiceProvidersFeature = context => new RequestServicesFeature(context, context.ServiceScopeFactory);
            private readonly static Func<IFeatureCollection, IHttpAuthenticationFeature> _newHttpAuthenticationFeature = f => new HttpAuthenticationFeature();
            private readonly static Func<IFeatureCollection, IHttpRequestLifetimeFeature> _newHttpRequestLifetimeFeature = f => new HttpRequestLifetimeFeature();
            private readonly static Func<IFeatureCollection, ISessionFeature> _newSessionFeature = f => new DefaultSessionFeature();
            private readonly static Func<IFeatureCollection, ISessionFeature> _nullSessionFeature = f => null;
            private readonly static Func<IFeatureCollection, IHttpRequestIdentifierFeature> _newHttpRequestIdentifierFeature = f => new HttpRequestIdentifierFeature();
    
            private FeatureReferences<FeatureInterfaces> _features;
    
            private readonly DefaultHttpRequest _request;
            private readonly DefaultHttpResponse _response;
    
            private DefaultConnectionInfo _connection;
            private DefaultWebSocketManager _websockets;
    
            public DefaultHttpContext()
                : this(new FeatureCollection())
            {
                Features.Set<IHttpRequestFeature>(new HttpRequestFeature());
                Features.Set<IHttpResponseFeature>(new HttpResponseFeature());
                Features.Set<IHttpResponseBodyFeature>(new StreamResponseBodyFeature(Stream.Null));
            }
    
            public DefaultHttpContext(IFeatureCollection features)
            {
                _features.Initalize(features);
                _request = new DefaultHttpRequest(this);
                _response = new DefaultHttpResponse(this);
            }
    
            public void Initialize(IFeatureCollection features)
            {
                var revision = features.Revision;
                _features.Initalize(features, revision);
                _request.Initialize(revision);
                _response.Initialize(revision);
                _connection?.Initialize(features, revision);
                _websockets?.Initialize(features, revision);
            }
    
            public void Uninitialize()
            {
                _features = default;
                _request.Uninitialize();
                _response.Uninitialize();
                _connection?.Uninitialize();
                _websockets?.Uninitialize();
            }
    
            public FormOptions FormOptions { get; set; }
    
            public IServiceScopeFactory ServiceScopeFactory { get; set; }
    
            private IItemsFeature ItemsFeature =>
                _features.Fetch(ref _features.Cache.Items, _newItemsFeature);
    
            private IServiceProvidersFeature ServiceProvidersFeature =>
                _features.Fetch(ref _features.Cache.ServiceProviders, this, _newServiceProvidersFeature);
    
            private IHttpAuthenticationFeature HttpAuthenticationFeature =>
                _features.Fetch(ref _features.Cache.Authentication, _newHttpAuthenticationFeature);
    
            private IHttpRequestLifetimeFeature LifetimeFeature =>
                _features.Fetch(ref _features.Cache.Lifetime, _newHttpRequestLifetimeFeature);
    
            private ISessionFeature SessionFeature =>
                _features.Fetch(ref _features.Cache.Session, _newSessionFeature);
    
            private ISessionFeature SessionFeatureOrNull =>
                _features.Fetch(ref _features.Cache.Session, _nullSessionFeature);
    
    
            private IHttpRequestIdentifierFeature RequestIdentifierFeature =>
                _features.Fetch(ref _features.Cache.RequestIdentifier, _newHttpRequestIdentifierFeature);
    
            public override IFeatureCollection Features => _features.Collection ?? ContextDisposed();
    
            public override HttpRequest Request => _request;
    
            public override HttpResponse Response => _response;
    
            public override ConnectionInfo Connection => _connection ?? (_connection = new DefaultConnectionInfo(_features.Collection));
    
            public override WebSocketManager WebSockets => _websockets ?? (_websockets = new DefaultWebSocketManager(_features.Collection));
    
            public override ClaimsPrincipal User
            {
                get
                {
                    var user = HttpAuthenticationFeature.User;
                    if (user == null)
                    {
                        user = new ClaimsPrincipal(new ClaimsIdentity());
                        HttpAuthenticationFeature.User = user;
                    }
                    return user;
                }
                set { HttpAuthenticationFeature.User = value; }
            }
    
            public override IDictionary<object, object> Items
            {
                get { return ItemsFeature.Items; }
                set { ItemsFeature.Items = value; }
            }
    
            public override IServiceProvider RequestServices
            {
                get { return ServiceProvidersFeature.RequestServices; }
                set { ServiceProvidersFeature.RequestServices = value; }
            }
    
            public override CancellationToken RequestAborted
            {
                get { return LifetimeFeature.RequestAborted; }
                set { LifetimeFeature.RequestAborted = value; }
            }
    
            public override string TraceIdentifier
            {
                get { return RequestIdentifierFeature.TraceIdentifier; }
                set { RequestIdentifierFeature.TraceIdentifier = value; }
            }
    
            public override ISession Session
            {
                get
                {
                    var feature = SessionFeatureOrNull;
                    if (feature == null)
                    {
                        throw new InvalidOperationException("Session has not been configured for this application " +
                            "or request.");
                    }
                    return feature.Session;
                }
                set
                {
                    SessionFeature.Session = value;
                }
            }
    
            // This property exists because of backwards compatibility.
            // We send an anonymous object with an HttpContext property
            // via DiagnosticListener in various events throughout the pipeline. Instead
            // we just send the HttpContext to avoid extra allocations
            [EditorBrowsable(EditorBrowsableState.Never)]
            public HttpContext HttpContext => this;
    
            public override void Abort()
            {
                LifetimeFeature.Abort();
            }
    
            private static IFeatureCollection ContextDisposed()
            {
                ThrowContextDisposed();
                return null;
            }
    
            private static void ThrowContextDisposed()
            {
                throw new ObjectDisposedException(nameof(HttpContext), $"Request has finished and {nameof(HttpContext)} disposed.");
            }
    
            struct FeatureInterfaces
            {
                public IItemsFeature Items;
                public IServiceProvidersFeature ServiceProviders;
                public IHttpAuthenticationFeature Authentication;
                public IHttpRequestLifetimeFeature Lifetime;
                public ISessionFeature Session;
                public IHttpRequestIdentifierFeature RequestIdentifier;
            }
        }

    DefaultHttpRequest

    internal sealed class DefaultHttpRequest : HttpRequest
        {
            private const string Http = "http";
            private const string Https = "https";
    
            // Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624
            private readonly static Func<IFeatureCollection, IHttpRequestFeature> _nullRequestFeature = f => null;
            private readonly static Func<IFeatureCollection, IQueryFeature> _newQueryFeature = f => new QueryFeature(f);
            private readonly static Func<DefaultHttpRequest, IFormFeature> _newFormFeature = r => new FormFeature(r, r._context.FormOptions ?? FormOptions.Default);
            private readonly static Func<IFeatureCollection, IRequestCookiesFeature> _newRequestCookiesFeature = f => new RequestCookiesFeature(f);
            private readonly static Func<IFeatureCollection, IRouteValuesFeature> _newRouteValuesFeature = f => new RouteValuesFeature();
            private readonly static Func<HttpContext, IRequestBodyPipeFeature> _newRequestBodyPipeFeature = context => new RequestBodyPipeFeature(context);
    
            private readonly DefaultHttpContext _context;
            private FeatureReferences<FeatureInterfaces> _features;
    
            public DefaultHttpRequest(DefaultHttpContext context)
            {
                _context = context;
                _features.Initalize(context.Features);
            }
    
            public void Initialize()
            {
                _features.Initalize(_context.Features);
            }
    
            public void Initialize(int revision)
            {
                _features.Initalize(_context.Features, revision);
            }
    
            public void Uninitialize()
            {
                _features = default;
            }
    
            public override HttpContext HttpContext => _context;
    
            private IHttpRequestFeature HttpRequestFeature =>
                _features.Fetch(ref _features.Cache.Request, _nullRequestFeature);
    
            private IQueryFeature QueryFeature =>
                _features.Fetch(ref _features.Cache.Query, _newQueryFeature);
    
            private IFormFeature FormFeature =>
                _features.Fetch(ref _features.Cache.Form, this, _newFormFeature);
    
            private IRequestCookiesFeature RequestCookiesFeature =>
                _features.Fetch(ref _features.Cache.Cookies, _newRequestCookiesFeature);
    
            private IRouteValuesFeature RouteValuesFeature =>
                _features.Fetch(ref _features.Cache.RouteValues, _newRouteValuesFeature);
    
            private IRequestBodyPipeFeature RequestBodyPipeFeature =>
                _features.Fetch(ref _features.Cache.BodyPipe, this.HttpContext, _newRequestBodyPipeFeature);
    
            public override PathString PathBase
            {
                get { return new PathString(HttpRequestFeature.PathBase); }
                set { HttpRequestFeature.PathBase = value.Value; }
            }
    
            public override PathString Path
            {
                get { return new PathString(HttpRequestFeature.Path); }
                set { HttpRequestFeature.Path = value.Value; }
            }
    
            public override QueryString QueryString
            {
                get { return new QueryString(HttpRequestFeature.QueryString); }
                set { HttpRequestFeature.QueryString = value.Value; }
            }
    
            public override long? ContentLength
            {
                get { return Headers.ContentLength; }
                set { Headers.ContentLength = value; }
            }
    
            public override Stream Body
            {
                get { return HttpRequestFeature.Body; }
                set { HttpRequestFeature.Body = value; }
            }
    
            public override string Method
            {
                get { return HttpRequestFeature.Method; }
                set { HttpRequestFeature.Method = value; }
            }
    
            public override string Scheme
            {
                get { return HttpRequestFeature.Scheme; }
                set { HttpRequestFeature.Scheme = value; }
            }
    
            public override bool IsHttps
            {
                get { return string.Equals(Https, Scheme, StringComparison.OrdinalIgnoreCase); }
                set { Scheme = value ? Https : Http; }
            }
    
            public override HostString Host
            {
                get { return HostString.FromUriComponent(Headers[HeaderNames.Host]); }
                set { Headers[HeaderNames.Host] = value.ToUriComponent(); }
            }
    
            public override IQueryCollection Query
            {
                get { return QueryFeature.Query; }
                set { QueryFeature.Query = value; }
            }
    
            public override string Protocol
            {
                get { return HttpRequestFeature.Protocol; }
                set { HttpRequestFeature.Protocol = value; }
            }
    
            public override IHeaderDictionary Headers
            {
                get { return HttpRequestFeature.Headers; }
            }
    
            public override IRequestCookieCollection Cookies
            {
                get { return RequestCookiesFeature.Cookies; }
                set { RequestCookiesFeature.Cookies = value; }
            }
    
            public override string ContentType
            {
                get { return Headers[HeaderNames.ContentType]; }
                set { Headers[HeaderNames.ContentType] = value; }
            }
    
            public override bool HasFormContentType
            {
                get { return FormFeature.HasFormContentType; }
            }
    
            public override IFormCollection Form
            {
                get { return FormFeature.ReadForm(); }
                set { FormFeature.Form = value; }
            }
    
            public override Task<IFormCollection> ReadFormAsync(CancellationToken cancellationToken)
            {
                return FormFeature.ReadFormAsync(cancellationToken);
            }
    
            public override RouteValueDictionary RouteValues
            {
                get { return RouteValuesFeature.RouteValues; }
                set { RouteValuesFeature.RouteValues = value; }
            }
    
            public override PipeReader BodyReader
            {
                get { return RequestBodyPipeFeature.Reader; }
            }
    
            struct FeatureInterfaces
            {
                public IHttpRequestFeature Request;
                public IQueryFeature Query;
                public IFormFeature Form;
                public IRequestCookiesFeature Cookies;
                public IRouteValuesFeature RouteValues;
                public IRequestBodyPipeFeature BodyPipe;
            }
        }

    DefaultHttpResponse

    internal sealed class DefaultHttpResponse : HttpResponse
        {
            // Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624
            private readonly static Func<IFeatureCollection, IHttpResponseFeature> _nullResponseFeature = f => null;
            private readonly static Func<IFeatureCollection, IHttpResponseBodyFeature> _nullResponseBodyFeature = f => null;
            private readonly static Func<IFeatureCollection, IResponseCookiesFeature> _newResponseCookiesFeature = f => new ResponseCookiesFeature(f);
    
            private readonly DefaultHttpContext _context;
            private FeatureReferences<FeatureInterfaces> _features;
    
            public DefaultHttpResponse(DefaultHttpContext context)
            {
                _context = context;
                _features.Initalize(context.Features);
            }
    
            public void Initialize()
            {
                _features.Initalize(_context.Features);
            }
    
            public void Initialize(int revision)
            {
                _features.Initalize(_context.Features, revision);
            }
    
            public void Uninitialize()
            {
                _features = default;
            }
    
            private IHttpResponseFeature HttpResponseFeature =>
                _features.Fetch(ref _features.Cache.Response, _nullResponseFeature);
    
            private IHttpResponseBodyFeature HttpResponseBodyFeature =>
                _features.Fetch(ref _features.Cache.ResponseBody, _nullResponseBodyFeature);
    
            private IResponseCookiesFeature ResponseCookiesFeature =>
                _features.Fetch(ref _features.Cache.Cookies, _newResponseCookiesFeature);
    
            public override HttpContext HttpContext { get { return _context; } }
    
            public override int StatusCode
            {
                get { return HttpResponseFeature.StatusCode; }
                set { HttpResponseFeature.StatusCode = value; }
            }
    
            public override IHeaderDictionary Headers
            {
                get { return HttpResponseFeature.Headers; }
            }
    
            public override Stream Body
            {
                get { return HttpResponseBodyFeature.Stream; }
                set
                {
                    var otherFeature = _features.Collection.Get<IHttpResponseBodyFeature>();
                    if (otherFeature is StreamResponseBodyFeature streamFeature
                        && streamFeature.PriorFeature != null
                        && object.ReferenceEquals(value, streamFeature.PriorFeature.Stream))
                    {
                        // They're reverting the stream back to the prior one. Revert the whole feature.
                        _features.Collection.Set(streamFeature.PriorFeature);
                        // CompleteAsync is registered with HttpResponse.OnCompleted and there's no way to unregister it.
                        // Prevent it from running by marking as disposed.
                        streamFeature.Dispose();
                        return;
                    }
    
                    var feature = new StreamResponseBodyFeature(value, otherFeature);
                    OnCompleted(feature.CompleteAsync);
                    _features.Collection.Set<IHttpResponseBodyFeature>(feature);
                }
            }
    
            public override long? ContentLength
            {
                get { return Headers.ContentLength; }
                set { Headers.ContentLength = value; }
            }
    
            public override string ContentType
            {
                get
                {
                    return Headers[HeaderNames.ContentType];
                }
                set
                {
                    if (string.IsNullOrEmpty(value))
                    {
                        HttpResponseFeature.Headers.Remove(HeaderNames.ContentType);
                    }
                    else
                    {
                        HttpResponseFeature.Headers[HeaderNames.ContentType] = value;
                    }
                }
            }
    
            public override IResponseCookies Cookies
            {
                get { return ResponseCookiesFeature.Cookies; }
            }
    
            public override bool HasStarted
            {
                get { return HttpResponseFeature.HasStarted; }
            }
    
            public override PipeWriter BodyWriter
            {
                get { return HttpResponseBodyFeature.Writer; }
            }
    
            public override void OnStarting(Func<object, Task> callback, object state)
            {
                if (callback == null)
                {
                    throw new ArgumentNullException(nameof(callback));
                }
    
                HttpResponseFeature.OnStarting(callback, state);
            }
    
            public override void OnCompleted(Func<object, Task> callback, object state)
            {
                if (callback == null)
                {
                    throw new ArgumentNullException(nameof(callback));
                }
    
                HttpResponseFeature.OnCompleted(callback, state);
            }
    
            public override void Redirect(string location, bool permanent)
            {
                if (permanent)
                {
                    HttpResponseFeature.StatusCode = 301;
                }
                else
                {
                    HttpResponseFeature.StatusCode = 302;
                }
    
                Headers[HeaderNames.Location] = location;
            }
    
            public override Task StartAsync(CancellationToken cancellationToken = default)
            {
                if (HasStarted)
                {
                    return Task.CompletedTask;
                }
    
                return HttpResponseBodyFeature.StartAsync(cancellationToken);
            }
    
            public override Task CompleteAsync() => HttpResponseBodyFeature.CompleteAsync();
    
            struct FeatureInterfaces
            {
                public IHttpResponseFeature Response;
                public IHttpResponseBodyFeature ResponseBody;
                public IResponseCookiesFeature Cookies;
            }
        }
  • 相关阅读:
    监控代码运行时长 -- StopWatch用法例程
    验证码处理算法(一)
    Linux下安装JDK及相关配置
    JAVA爬虫---验证码识别技术(一)
    JAVA4大线程池
    海量数据去重(上亿数据去重)
    python协程与异步协程
    解决WinSCP连接虚拟机
    生产消费者模式与python+redis实例运用(中级篇)
    生产消费者模式与python+redis实例运用(基础篇)
  • 原文地址:https://www.cnblogs.com/lanpingwang/p/12640981.html
Copyright © 2011-2022 走看看