// // Copyright (c) Microsoft Corporation. All rights reserved. // namespace System.ServiceModel.Channels { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Configuration; using System.Globalization; using System.Net.Http; using System.Reflection; using System.Runtime; using System.Runtime.CompilerServices; using System.Security; using System.Security.Permissions; using System.ServiceModel.Configuration; /// /// Default HTTP message handler factory used by upon creation of an /// for instantiating a set of HTTP message handler types using their default constructors. /// For more complex initialization scenarios, derive from /// and override the method. /// public class HttpMessageHandlerFactory { static readonly Type delegatingHandlerType = typeof(DelegatingHandler); Type[] httpMessageHandlers; ConstructorInfo[] handlerCtors; Func> handlerFunc; /// /// Initializes a new instance of the class given /// a set of HTTP message handler types to instantiate using their default constructors. /// /// An ordered list of HTTP message handler types to be invoked as part of an /// instance. /// HTTP message handler types must derive from and have a public constructor /// taking exactly one argument of type . The handlers are invoked in a /// bottom-up fashion in the incoming path and top-down in the outgoing path. That is, the last entry is called first /// for an incoming request messasge but invoked last for an outgoing response message. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] [MethodImpl(MethodImplOptions.NoInlining)] public HttpMessageHandlerFactory(params Type[] handlers) { if (handlers == null) { throw FxTrace.Exception.ArgumentNull("handlers"); } if (handlers.Length == 0) { throw FxTrace.Exception.Argument("handlers", SR.GetString(SR.InputTypeListEmptyError)); } this.handlerCtors = new ConstructorInfo[handlers.Length]; for (int cnt = 0; cnt < handlers.Length; cnt++) { Type handler = handlers[cnt]; if (handler == null) { throw FxTrace.Exception.Argument( string.Format(CultureInfo.InvariantCulture, "handlers[<<{0}>>]", cnt), SR.GetString(SR.HttpMessageHandlerTypeNotSupported, "null", delegatingHandlerType.Name)); } if (!delegatingHandlerType.IsAssignableFrom(handler) || handler.IsAbstract) { throw FxTrace.Exception.Argument( string.Format(CultureInfo.InvariantCulture, "handlers[<<{0}>>]", cnt), SR.GetString(SR.HttpMessageHandlerTypeNotSupported, handler.Name, delegatingHandlerType.Name)); } ConstructorInfo ctorInfo = handler.GetConstructor(Type.EmptyTypes); if (ctorInfo == null) { throw FxTrace.Exception.Argument( string.Format(CultureInfo.InvariantCulture, "handlers[<<{0}>>]", cnt), SR.GetString(SR.HttpMessageHandlerTypeNotSupported, handler.Name, delegatingHandlerType.Name)); } this.handlerCtors[cnt] = ctorInfo; } this.httpMessageHandlers = handlers; } /// /// Initializes a new instance of the class given /// a function to create a set of instances. /// /// A function to generate an ordered list of instances /// to be invoked as part of an instance. /// The handlers are invoked in a bottom-up fashion in the incoming path and top-down in the outgoing path. That is, /// the last entry is called first for an incoming request messasge but invoked last for an outgoing response message. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] [MethodImpl(MethodImplOptions.NoInlining)] public HttpMessageHandlerFactory(Func> handlers) { if (handlers == null) { throw FxTrace.Exception.ArgumentNull("handlers"); } this.handlerFunc = handlers; } /// /// Initializes a new instance of the class. /// [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] [MethodImpl(MethodImplOptions.NoInlining)] protected HttpMessageHandlerFactory() { } /// /// Creates an instance of an using the HTTP message handlers /// provided in the constructor. /// /// The inner channel represents the destination of the HTTP message channel. /// The HTTP message channel. [PermissionSet(SecurityAction.Demand, Unrestricted = true), SecuritySafeCritical] [MethodImpl(MethodImplOptions.NoInlining)] public HttpMessageHandler Create(HttpMessageHandler innerChannel) { if (innerChannel == null) { throw FxTrace.Exception.ArgumentNull("innerChannel"); } return this.OnCreate(innerChannel); } internal static HttpMessageHandlerFactory CreateFromConfigurationElement(HttpMessageHandlerFactoryElement configElement) { Fx.Assert(configElement != null, "configElement should not be null."); if (!string.IsNullOrWhiteSpace(configElement.Type)) { if (configElement.Handlers != null && configElement.Handlers.Count > 0) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR.GetString(SR.HttpMessageHandlerFactoryConfigInvalid_WithBothTypeAndHandlerList, ConfigurationStrings.MessageHandlerFactory, ConfigurationStrings.Type, ConfigurationStrings.Handlers))); } Type factoryType = HttpChannelUtilities.GetTypeFromAssembliesInCurrentDomain(configElement.Type); if (factoryType == null) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR.GetString(SR.CanNotLoadTypeGotFromConfig, configElement.Type))); } if (!typeof(HttpMessageHandlerFactory).IsAssignableFrom(factoryType) || factoryType.IsAbstract) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ConfigurationErrorsException( SR.GetString( SR.WebSocketElementConfigInvalidHttpMessageHandlerFactoryType, typeof(HttpMessageHandlerFactory).Name, factoryType, typeof(HttpMessageHandlerFactory).AssemblyQualifiedName))); } return Activator.CreateInstance(factoryType) as HttpMessageHandlerFactory; } else { if (configElement.Handlers == null || configElement.Handlers.Count == 0) { return null; } Type[] handlerList = new Type[configElement.Handlers.Count]; for (int i = 0; i < configElement.Handlers.Count; i++) { Type handlerType = HttpChannelUtilities.GetTypeFromAssembliesInCurrentDomain(configElement.Handlers[i].Type); if (handlerType == null) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(SR.GetString(SR.CanNotLoadTypeGotFromConfig, configElement.Handlers[i].Type))); } handlerList[i] = handlerType; } try { return new HttpMessageHandlerFactory(handlerList); } catch (ArgumentException ex) { throw FxTrace.Exception.AsError(new ConfigurationErrorsException(ex.Message, ex)); } } } internal HttpMessageHandlerFactoryElement GenerateConfigurationElement() { if (this.handlerFunc != null) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR.GetString(SR.HttpMessageHandlerFactoryWithFuncCannotGenerateConfig, typeof(HttpMessageHandlerFactory).Name, typeof(Func>).Name))); } Type thisType = this.GetType(); if (thisType != typeof(HttpMessageHandlerFactory)) { return new HttpMessageHandlerFactoryElement { Type = thisType.AssemblyQualifiedName }; } else { if (this.httpMessageHandlers != null) { DelegatingHandlerElementCollection handlerCollection = new DelegatingHandlerElementCollection(); for (int i = 0; i < this.httpMessageHandlers.Length; i++) { handlerCollection.Add(new DelegatingHandlerElement(this.httpMessageHandlers[i])); } return new HttpMessageHandlerFactoryElement { Handlers = handlerCollection }; } } return null; } /// /// Creates an instance of an using the HTTP message handlers /// provided in the constructor. /// /// The inner channel represents the destination of the HTTP message channel. /// The HTTP message channel. protected virtual HttpMessageHandler OnCreate(HttpMessageHandler innerChannel) { if (innerChannel == null) { throw FxTrace.Exception.ArgumentNull("innerChannel"); } // Get handlers either by constructing types or by calling Func IEnumerable handlerInstances = null; try { if (this.handlerFunc != null) { handlerInstances = this.handlerFunc.Invoke(); if (handlerInstances != null) { foreach (DelegatingHandler handler in handlerInstances) { if (handler == null) { throw FxTrace.Exception.Argument("handlers", SR.GetString(SR.DelegatingHandlerArrayFromFuncContainsNullItem, delegatingHandlerType.Name, GetFuncDetails(this.handlerFunc))); } } } } else if (this.handlerCtors != null) { DelegatingHandler[] instances = new DelegatingHandler[this.handlerCtors.Length]; for (int cnt = 0; cnt < this.handlerCtors.Length; cnt++) { instances[cnt] = (DelegatingHandler)this.handlerCtors[cnt].Invoke(Type.EmptyTypes); } handlerInstances = instances; } } catch (TargetInvocationException targetInvocationException) { throw FxTrace.Exception.AsError(targetInvocationException); } // Wire handlers up HttpMessageHandler pipeline = innerChannel; if (handlerInstances != null) { foreach (DelegatingHandler handler in handlerInstances) { if (handler.InnerHandler != null) { throw FxTrace.Exception.Argument("handlers", SR.GetString(SR.DelegatingHandlerArrayHasNonNullInnerHandler, delegatingHandlerType.Name, "InnerHandler", handler.GetType().Name)); } handler.InnerHandler = pipeline; pipeline = handler; } } return pipeline; } static string GetFuncDetails(Func> func) { Fx.Assert(func != null, "Func should not be null."); MethodInfo m = func.Method; Type t = m.DeclaringType; return string.Format(CultureInfo.InvariantCulture, "{0}.{1}", t.FullName, m.Name); } } }