You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,148 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="CustomLoaderHelper.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace System.Web.Hosting {
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Remoting;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
// Used to locate a custom loader implementation within a bin-deployed assembly.
|
||||
|
||||
internal sealed class CustomLoaderHelper : MarshalByRefObject {
|
||||
|
||||
// the first framework version where the custom loader feature was implemented
|
||||
private static readonly string _customLoaderTargetFrameworkName = new FrameworkName(".NETFramework", new Version(4, 5, 1)).ToString();
|
||||
|
||||
private static readonly string _customLoaderAssemblyName = typeof(CustomLoaderHelper).Assembly.FullName;
|
||||
private static readonly string _customLoaderTypeName = typeof(CustomLoaderHelper).FullName;
|
||||
private static readonly Guid IID_ICustomLoader = new Guid("50A3CE65-2F9F-44E9-9094-32C6C928F966");
|
||||
|
||||
// Instances of this type should only ever be created via reflection (see call to CreateObjectAndUnwrap
|
||||
// in GetCustomLoader).
|
||||
private CustomLoaderHelper() { }
|
||||
|
||||
internal static IObjectHandle GetCustomLoader(ICustomLoaderHelperFunctions helperFunctions, string appConfigMetabasePath, string configFilePath, string customLoaderPhysicalPath, out AppDomain newlyCreatedAppDomain) {
|
||||
// Step 1: Does the host allow custom loaders?
|
||||
|
||||
bool? customLoaderIsEnabled = helperFunctions.CustomLoaderIsEnabled;
|
||||
if (customLoaderIsEnabled.HasValue) {
|
||||
if ((bool)customLoaderIsEnabled) {
|
||||
// The custom loader is enabled; move on to the next step.
|
||||
}
|
||||
else {
|
||||
// The custom loader is disabled, fail.
|
||||
throw new NotSupportedException(ApplicationServicesStrings.CustomLoader_ForbiddenByHost);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The host hasn't set a policy, so we'll fall back to our default logic of checking the application's trust level.
|
||||
if (!IsFullyTrusted(helperFunctions, appConfigMetabasePath)) {
|
||||
throw new NotSupportedException(ApplicationServicesStrings.CustomLoader_NotInFullTrust);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Create the new AD
|
||||
|
||||
string binFolderPhysicalPath = helperFunctions.MapPath("/bin/");
|
||||
|
||||
AppDomainSetup setup = new AppDomainSetup() {
|
||||
PrivateBinPathProbe = "*", // disable loading from app base
|
||||
PrivateBinPath = binFolderPhysicalPath,
|
||||
ApplicationBase = helperFunctions.AppPhysicalPath,
|
||||
TargetFrameworkName = _customLoaderTargetFrameworkName
|
||||
};
|
||||
|
||||
if (configFilePath != null) {
|
||||
setup.ConfigurationFile = configFilePath;
|
||||
}
|
||||
|
||||
AppDomain newAppDomainForCustomLoader = AppDomain.CreateDomain("aspnet-custom-loader-" + Guid.NewGuid(), null, setup);
|
||||
try {
|
||||
// Step 3: Instantiate helper in new AD so that we can get a reference to the loader
|
||||
CustomLoaderHelper helper = (CustomLoaderHelper)newAppDomainForCustomLoader.CreateInstanceAndUnwrap(_customLoaderAssemblyName, _customLoaderTypeName,
|
||||
ignoreCase: false,
|
||||
bindingAttr: BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance,
|
||||
binder: null,
|
||||
args: null,
|
||||
culture: null,
|
||||
activationAttributes: null);
|
||||
ObjectHandle ohCustomLoader = helper.GetCustomLoaderImpl(customLoaderPhysicalPath);
|
||||
|
||||
// If we got this far, success!
|
||||
newlyCreatedAppDomain = newAppDomainForCustomLoader;
|
||||
return ohCustomLoader;
|
||||
}
|
||||
catch {
|
||||
// If something went wrong, kill the new AD.
|
||||
AppDomain.Unload(newAppDomainForCustomLoader);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectHandle GetCustomLoaderImpl(string customLoaderPhysicalPath) {
|
||||
// Step 4: Find the implementation in the custom loader assembly
|
||||
|
||||
// Since we have set the private bin path, we can use this call to Assembly.Load
|
||||
// to avoid the load-from context, which has weird behaviors.
|
||||
AssemblyName customLoaderAssemblyName = AssemblyName.GetAssemblyName(customLoaderPhysicalPath);
|
||||
Assembly customLoaderAssembly = Assembly.Load(customLoaderAssemblyName);
|
||||
CustomLoaderAttribute customLoaderAttribute = customLoaderAssembly.GetCustomAttribute<CustomLoaderAttribute>();
|
||||
|
||||
if (customLoaderAttribute == null) {
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ApplicationServicesStrings.CustomLoader_NoAttributeFound, customLoaderAssemblyName));
|
||||
}
|
||||
|
||||
// Step 5: Instantiate the custom loader and return a reference back to native code
|
||||
|
||||
object customLoader = Activator.CreateInstance(customLoaderAttribute.CustomLoaderType);
|
||||
|
||||
// This check isn't strictly necessary since the unmanaged layer will handle QueryInterface failures
|
||||
// appropriately, but we have an opportunity to provide a better error message at this layer.
|
||||
if (!ObjectImplementsComInterface(customLoader, IID_ICustomLoader)) {
|
||||
throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ApplicationServicesStrings.CustomLoader_MustImplementICustomLoader, customLoader.GetType()));
|
||||
}
|
||||
|
||||
return new ObjectHandle(customLoader);
|
||||
}
|
||||
|
||||
private static bool IsFullyTrusted(ICustomLoaderHelperFunctions helperFunctions, string appConfigMetabasePath) {
|
||||
// The managed configuration system hasn't yet been instantiated but the IIS native config system understands
|
||||
// ASP.NET configuration and honors hierarchy and section locking.
|
||||
|
||||
try {
|
||||
// Must exactly match <trust level="Full" />, as this is what ApplicationManager expects.
|
||||
string trustLevel = helperFunctions.GetTrustLevel(appConfigMetabasePath);
|
||||
return String.Equals("Full", trustLevel, StringComparison.Ordinal);
|
||||
}
|
||||
catch {
|
||||
// If any of the sections are locked or there is a config error, bail.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool ObjectImplementsComInterface(object o, Guid iid) {
|
||||
IntPtr pUnknown = IntPtr.Zero;
|
||||
IntPtr pInterface = IntPtr.Zero;
|
||||
|
||||
try {
|
||||
pUnknown = Marshal.GetIUnknownForObject(o); // AddRef
|
||||
int hr = Marshal.QueryInterface(pUnknown, ref iid, out pInterface); // AddRef
|
||||
return (hr == 0 && pInterface != IntPtr.Zero);
|
||||
}
|
||||
finally {
|
||||
if (pUnknown != IntPtr.Zero) {
|
||||
Marshal.Release(pUnknown);
|
||||
}
|
||||
if (pInterface != IntPtr.Zero) {
|
||||
Marshal.Release(pInterface);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user