// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Linq; using System.Net.WebSockets; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.FeatureModel; using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Infrastructure; using Microsoft.AspNet.Http.Security; using Microsoft.AspNet.HttpFeature; using Microsoft.AspNet.HttpFeature.Security; using Microsoft.AspNet.PipelineCore.Infrastructure; using Microsoft.AspNet.PipelineCore.Security; namespace Microsoft.AspNet.PipelineCore { public class DefaultHttpContext : HttpContext { private static IList EmptyList = new List(); private readonly HttpRequest _request; private readonly HttpResponse _response; private FeatureReference _items; private FeatureReference _serviceProviders; private FeatureReference _authentication; private FeatureReference _lifetime; private FeatureReference _webSockets; private IFeatureCollection _features; public DefaultHttpContext(IFeatureCollection features) { _features = features; _request = new DefaultHttpRequest(this, features); _response = new DefaultHttpResponse(this, features); _items = FeatureReference.Default; _serviceProviders = FeatureReference.Default; _authentication = FeatureReference.Default; _lifetime = FeatureReference.Default; _webSockets = FeatureReference.Default; } IItemsFeature ItemsFeature { get { return _items.Fetch(_features) ?? _items.Update(_features, new ItemsFeature()); } } IServiceProvidersFeature ServiceProvidersFeature { get { return _serviceProviders.Fetch(_features) ?? _serviceProviders.Update(_features, new ServiceProvidersFeature()); } } private IHttpAuthenticationFeature HttpAuthenticationFeature { get { return _authentication.Fetch(_features) ?? _authentication.Update(_features, new HttpAuthenticationFeature()); } } private IHttpRequestLifetimeFeature LifetimeFeature { get { return _lifetime.Fetch(_features); } } private IHttpWebSocketFeature WebSocketFeature { get { return _webSockets.Fetch(_features); } } public override HttpRequest Request { get { return _request; } } public override HttpResponse Response { get { return _response; } } 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 Items { get { return ItemsFeature.Items; } } public override IServiceProvider ApplicationServices { get { return ServiceProvidersFeature.ApplicationServices; } set { ServiceProvidersFeature.ApplicationServices = value; } } public override IServiceProvider RequestServices { get { return ServiceProvidersFeature.RequestServices; } set { ServiceProvidersFeature.RequestServices = value; } } public int Revision { get { return _features.Revision; } } public override CancellationToken RequestAborted { get { var lifetime = LifetimeFeature; if (lifetime != null) { return lifetime.RequestAborted; } return CancellationToken.None; } } public override bool IsWebSocketRequest { get { var webSocketFeature = WebSocketFeature; return webSocketFeature != null && webSocketFeature.IsWebSocketRequest; } } public override IList WebSocketRequestedProtocols { get { return Request.Headers.GetValues(Constants.Headers.WebSocketSubProtocols) ?? EmptyList; } } public override void Abort() { var lifetime = LifetimeFeature; if (lifetime != null) { lifetime.Abort(); } } public override void Dispose() { // REVIEW: is this necessary? is the environment "owned" by the context? _features.Dispose(); } public override object GetFeature(Type type) { object value; return _features.TryGetValue(type, out value) ? value : null; } public override void SetFeature(Type type, object instance) { _features[type] = instance; } public override IEnumerable GetAuthenticationTypes() { var handler = HttpAuthenticationFeature.Handler; if (handler == null) { return new AuthenticationDescription[0]; } var authTypeContext = new AuthTypeContext(); handler.GetDescriptions(authTypeContext); return authTypeContext.Results; } public override IEnumerable Authenticate(IEnumerable authenticationTypes) { if (authenticationTypes == null) { throw new ArgumentNullException(); } var handler = HttpAuthenticationFeature.Handler; var authenticateContext = new AuthenticateContext(authenticationTypes); if (handler != null) { handler.Authenticate(authenticateContext); } // Verify all types ack'd IEnumerable leftovers = authenticationTypes.Except(authenticateContext.Accepted); if (leftovers.Any()) { throw new InvalidOperationException("The following authentication types were not accepted: " + string.Join(", ", leftovers)); } return authenticateContext.Results; } public override async Task> AuthenticateAsync(IEnumerable authenticationTypes) { if (authenticationTypes == null) { throw new ArgumentNullException(); } var handler = HttpAuthenticationFeature.Handler; var authenticateContext = new AuthenticateContext(authenticationTypes); if (handler != null) { await handler.AuthenticateAsync(authenticateContext); } // Verify all types ack'd IEnumerable leftovers = authenticationTypes.Except(authenticateContext.Accepted); if (leftovers.Any()) { throw new InvalidOperationException("The following authentication types were not accepted: " + string.Join(", ", leftovers)); } return authenticateContext.Results; } public override Task AcceptWebSocketAsync(string subProtocol) { var webSocketFeature = WebSocketFeature; if (WebSocketFeature == null) { throw new NotSupportedException("WebSockets are not supported"); } return WebSocketFeature.AcceptAsync(new WebSocketAcceptContext() { SubProtocol = subProtocol } ); } } }