File: System\ServiceModel\Activation\HostedTransportConfigurationManager.cs
Project: ndp\cdf\src\WCF\System.ServiceModel.Activation\System.ServiceModel.Activation.csproj (System.ServiceModel.Activation)
//----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//----------------------------------------------------------------------------
 
namespace System.ServiceModel.Activation
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Reflection;
    using System.Runtime;
    using System.Runtime.Diagnostics;
    using System.Security;
    using System.Security.Permissions;
    using System.ServiceModel;
    using System.ServiceModel.Configuration;
    using System.ServiceModel.Activation.Diagnostics;
    using System.ServiceModel.Diagnostics.Application;
    using System.Diagnostics.CodeAnalysis;    
 
    class HostedTransportConfigurationManager
    {
        IDictionary<string, HostedTransportConfiguration> configurations = new Dictionary<string, HostedTransportConfiguration>(StringComparer.Ordinal);
 
        // Double-checked locking pattern requires volatile for read/write synchronization
        volatile bool initialized = false;
        MetabaseSettings metabaseSettings;
 
        // Double-checked locking pattern requires volatile for read/write synchronization
        static volatile HostedTransportConfigurationManager singleton;
        static object syncRoot = new object();
  #pragma warning disable 436
        const string WasHostingAssemblyName = "System.ServiceModel.WasHosting, Version=" + ThisAssembly.Version + ", Culture=neutral, PublicKeyToken=" + AssemblyRef.EcmaPublicKey;
        const string MetabaseSettingsIis7FactoryTypeName = "System.ServiceModel.WasHosting.MetabaseSettingsIis7Factory, " + WasHostingAssemblyName;
  #pragma warning restore 436
        const string CreateMetabaseSettingsIis7MethodName = "CreateMetabaseSettings";
 
        HostedTransportConfigurationManager()
        {
            if (!Iis7Helper.IsIis7)
            {
                metabaseSettings = new MetabaseSettingsIis6();
            }
            else
            {
 
                metabaseSettings = CreateWasHostingMetabaseSettings();
            }
        }
 
        HostedTransportConfigurationManager(MetabaseSettings metabaseSettings)
        {
            this.metabaseSettings = metabaseSettings;
        }
 
        [Fx.Tag.SecurityNote(Critical = "Calls Critical methods CreateMetabaseSettings.",
            Safe = "Ensures that only the correct, well-known method is called to construct the metabase settings. No other " +
            "details are leaked, and no control flow or data is allowed in.")]
        [SecuritySafeCritical]
        static MetabaseSettingsIis CreateWasHostingMetabaseSettings()
        {
            Type type = Type.GetType(MetabaseSettingsIis7FactoryTypeName, false);
            if (type == null)
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_MetabaseSettingsIis7TypeNotFound(MetabaseSettingsIis7FactoryTypeName, WasHostingAssemblyName)));
            }                             
            return CreateMetabaseSettings(type);
        }
 
        [SuppressMessage(FxCop.Category.Security, FxCop.Rule.SecureAsserts, Justification = "This is a private SecurityCritical method and its only caller passes in non-user data. Users cannot pass arbitrary data to this code.")]
        [Fx.Tag.SecurityNote(Critical = "Asserts full trust in order to call a well-known internal static in WasHosting.dll." +
            "Caller must ensure that 'type' argument refers to the trusted, well-known Type.")]
        [SecurityCritical]
        static MetabaseSettingsIis CreateMetabaseSettings(Type type)
        {
            object instance = null;
            MethodInfo method = type.GetMethod(CreateMetabaseSettingsIis7MethodName, BindingFlags.NonPublic | BindingFlags.Static);
 
            try
            {
                new PermissionSet(PermissionState.Unrestricted).Assert();
 
                instance = method.Invoke(null, null);
            }
            finally
            {
                PermissionSet.RevertAssert();
            }
 
            if (!(instance is MetabaseSettingsIis))
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_BadMetabaseSettingsIis7Type(type.AssemblyQualifiedName)));
            }
 
            return (MetabaseSettingsIis)instance;
        }
 
        internal static void EnsureInitializedForSimpleApplicationHost(HostedHttpRequestAsyncResult result)
        {
            if (singleton != null)
            {
                return;
            }
 
            lock (syncRoot)
            {
                if (singleton != null)
                    return;
 
                singleton = new HostedTransportConfigurationManager(new MetabaseSettingsCassini(result));
            }
        }
 
        internal static MetabaseSettings MetabaseSettings
        {
            get
            {
                return HostedTransportConfigurationManager.Value.metabaseSettings;
            }
        }
 
        object ThisLock
        {
            get
            {
                return this;
            }
        }
 
        static HostedTransportConfigurationManager Value
        {
            get
            {
                if (singleton == null)
                {
                    lock (syncRoot)
                    {
                        if (singleton == null)
                        {
                            //Ensure ETW tracing is initialized
                            System.ServiceModel.Diagnostics.TraceUtility.SetEtwProviderId();
 
                            if (TD.HostedTransportConfigurationManagerConfigInitStartIsEnabled())
                            {
                                TD.HostedTransportConfigurationManagerConfigInitStart();
                            }
                            ServiceHostingEnvironment.EnsureInitialized();
                            singleton = new HostedTransportConfigurationManager();
                            if (TD.HostedTransportConfigurationManagerConfigInitStopIsEnabled())
                            {
                                TD.HostedTransportConfigurationManagerConfigInitStop();
                            }
                        }
                    }
                }
                return singleton;
            }
        }
 
        void EnsureInitialized()
        {
            if (!initialized)
            {
                lock (ThisLock)
                {
                    if (!initialized)
                    {
                        // Register protocols.
                        foreach (string protocol in metabaseSettings.GetProtocols())
                        {
                            // special case HTTP, it's a legacy protocol
                            if (string.CompareOrdinal(protocol, Uri.UriSchemeHttp) == 0 ||
                                string.CompareOrdinal(protocol, Uri.UriSchemeHttps) == 0)
                            {
                                HttpHostedTransportConfiguration httpConfiguration = null;
                                if (string.CompareOrdinal(protocol, Uri.UriSchemeHttp) == 0)
                                {
                                    httpConfiguration = new HttpHostedTransportConfiguration();
                                }
                                else
                                {
                                    httpConfiguration = new HttpsHostedTransportConfiguration();
                                }
 
                                configurations.Add(protocol, httpConfiguration);
                            }
                            else
                            {
                                if (!Iis7Helper.IsIis7)
                                {
                                    throw Fx.AssertAndThrowFatal("HostedTransportConfigurationManager.EnsureInitialized() protocols other than http and https can only be configured in IIS7");
                                }
                                if (AspNetPartialTrustHelpers.NeedPartialTrustInvoke)
                                {
                                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.PartialTrustNonHttpActivation(protocol, HostingEnvironmentWrapper.ApplicationVirtualPath)));
                                }
                                AddHostedTransportConfigurationIis7(protocol);
                            }
                        }
 
                        initialized = true;
                    }
                }
            }
        }
 
        void AddHostedTransportConfigurationIis7(string protocol)
        {
            HostedTransportConfiguration configuration = null;
            try
            {
                ServiceHostingEnvironmentSection section = ServiceHostingEnvironmentSection.GetSection();
                if (section.TransportConfigurationTypes.ContainsKey(protocol))
                {
                    TransportConfigurationTypeElement element = section.TransportConfigurationTypes[protocol];
                    Debug.Print("HostedTransportConfigurationManager.AddHostedTransportConfigurationIis7() found TransportConfigurationTypes for protocol: " + protocol + " name: " + element.TransportConfigurationType);
 
                    Type type = Type.GetType(element.TransportConfigurationType);
                    configuration = Activator.CreateInstance(type) as HostedTransportConfiguration;
                    configurations.Add(protocol, configuration);
                }
                else
                {
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_ProtocolNoConfiguration(protocol)));
                }
            }
            catch (Exception exception)
            {
                if (!Fx.IsFatal(exception))
                {
                    Debug.Print("HostedTransportConfigurationManager.AddHostedTransportConfigurationIis7() caught exception: " + exception);
                    if (DiagnosticUtility.ShouldTraceError)
                    {
                        TraceUtility.TraceEvent(TraceEventType.Error, TraceCode.WebHostProtocolMisconfigured, SR.TraceCodeWebHostProtocolMisconfigured,
                            new StringTraceRecord("Protocol", protocol),
                            this, exception);
                    }
                }
                throw;
            }
        }
 
        internal static Uri[] GetBaseAddresses(string virtualPath)
        {
            return HostedTransportConfigurationManager.Value.InternalGetBaseAddresses(virtualPath);
        }
 
        internal static HostedTransportConfiguration GetConfiguration(string scheme)
        {
            return HostedTransportConfigurationManager.Value.InternalGetConfiguration(scheme);
        }
 
        Uri[] InternalGetBaseAddresses(string virtualPath)
        {
            EnsureInitialized();
            List<Uri> baseAddresses = new List<Uri>();
            foreach (HostedTransportConfiguration configuration in configurations.Values)
            {
                baseAddresses.AddRange(configuration.GetBaseAddresses(virtualPath));
            }
 
            return baseAddresses.ToArray();
        }
 
        HostedTransportConfiguration InternalGetConfiguration(string scheme)
        {
            EnsureInitialized();
            if (!configurations.ContainsKey(scheme))
            {
                throw FxTrace.Exception.AsError(new InvalidOperationException(SR.Hosting_NotSupportedProtocol(scheme)));
            }
 
            return configurations[scheme];
        }
    }
}