394 lines
16 KiB
C#
394 lines
16 KiB
C#
|
//------------------------------------------------------------------------------
|
||
|
// <copyright file="ExpressServerConfig.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
namespace System.Web.Configuration {
|
||
|
using System.Configuration;
|
||
|
using System.Collections;
|
||
|
using System.Globalization;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Text;
|
||
|
using System.Threading;
|
||
|
using System.Web.Caching;
|
||
|
using System.Web.Util;
|
||
|
using System.Web.Hosting;
|
||
|
|
||
|
//
|
||
|
// Uses IIS Express native config
|
||
|
//
|
||
|
internal sealed class ExpressServerConfig : IServerConfig, IServerConfig2, IConfigMapPath, IConfigMapPath2, IDisposable {
|
||
|
static object s_initLock = new Object();
|
||
|
static ExpressServerConfig s_instance;
|
||
|
|
||
|
NativeConfig _nativeConfig;
|
||
|
string _currentAppSiteName;
|
||
|
|
||
|
// called by HostingEnvironment to initiliaze the singleton config
|
||
|
// instance for the domain
|
||
|
static internal IServerConfig GetInstance(string version) {
|
||
|
if (s_instance == null) {
|
||
|
lock (s_initLock) {
|
||
|
if (s_instance == null) {
|
||
|
if (Thread.GetDomain().IsDefaultAppDomain()) {
|
||
|
throw new InvalidOperationException();
|
||
|
}
|
||
|
s_instance = new ExpressServerConfig(version);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return s_instance;
|
||
|
}
|
||
|
|
||
|
static ExpressServerConfig() {
|
||
|
HttpRuntime.ForceStaticInit();
|
||
|
}
|
||
|
|
||
|
private ExpressServerConfig() {
|
||
|
// hidden
|
||
|
}
|
||
|
|
||
|
internal ExpressServerConfig(string version) {
|
||
|
if (version == null) {
|
||
|
throw new ArgumentNullException("version");
|
||
|
}
|
||
|
_nativeConfig = new NativeConfig(version);
|
||
|
}
|
||
|
|
||
|
string CurrentAppSiteName {
|
||
|
get {
|
||
|
string name = _currentAppSiteName;
|
||
|
if (name == null) {
|
||
|
name = HostingEnvironment.SiteNameNoDemand;
|
||
|
if (name == null) {
|
||
|
name = _nativeConfig.GetSiteNameFromId(ProcessHostConfigUtils.DEFAULT_SITE_ID_UINT);
|
||
|
}
|
||
|
_currentAppSiteName = name;
|
||
|
}
|
||
|
return name;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void IDisposable.Dispose() {
|
||
|
NativeConfig nativeConfig = _nativeConfig;
|
||
|
_nativeConfig = null;
|
||
|
if (nativeConfig != null) {
|
||
|
nativeConfig.Dispose();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
string IServerConfig.GetSiteNameFromSiteID(string siteID) {
|
||
|
uint siteIDValue;
|
||
|
|
||
|
if (!UInt32.TryParse(siteID, out siteIDValue)) {
|
||
|
Debug.Assert(false, "siteID is not numeric");
|
||
|
return String.Empty;
|
||
|
}
|
||
|
|
||
|
return _nativeConfig.GetSiteNameFromId(siteIDValue);
|
||
|
}
|
||
|
|
||
|
// if appHost is null, we use the site name for the current application
|
||
|
string IServerConfig.MapPath(IApplicationHost appHost, VirtualPath path) {
|
||
|
string siteName = (appHost == null) ? CurrentAppSiteName : appHost.GetSiteName();
|
||
|
string physicalPath = _nativeConfig.MapPathDirect(siteName, path);
|
||
|
if (FileUtil.IsSuspiciousPhysicalPath(physicalPath)) {
|
||
|
throw new InvalidOperationException(SR.GetString(SR.Cannot_map_path, path.VirtualPathString));
|
||
|
}
|
||
|
return physicalPath;
|
||
|
}
|
||
|
|
||
|
string[] IServerConfig.GetVirtualSubdirs(VirtualPath path, bool inApp) {
|
||
|
// WOS 1956227: PERF: inactive applications on the web server degrade Working Set by 10%
|
||
|
// It is very expensive to get a list of subdirs not in the application if there are a lot of applications,
|
||
|
// so instead, use ProcessHostServerConfig.IsWithinApp to check if a particular path is in the app.
|
||
|
if (inApp == false) {
|
||
|
throw new NotSupportedException();
|
||
|
}
|
||
|
|
||
|
string vpath = path.VirtualPathString;
|
||
|
string [] dirList = null;
|
||
|
int dirListCount = 0;
|
||
|
|
||
|
IntPtr pAppCollection = IntPtr.Zero;
|
||
|
IntPtr pBstr = IntPtr.Zero;
|
||
|
int cBstr = 0;
|
||
|
try {
|
||
|
int count = 0;
|
||
|
int result = _nativeConfig.MgdGetAppCollection(CurrentAppSiteName, vpath, out pBstr, out cBstr, out pAppCollection, out count);
|
||
|
if (result < 0 || pBstr == IntPtr.Zero) {
|
||
|
throw new InvalidOperationException(SR.GetString(SR.Cant_Enumerate_NativeDirs, result));
|
||
|
}
|
||
|
string appRoot = StringUtil.StringFromWCharPtr(pBstr, cBstr);
|
||
|
Marshal.FreeBSTR(pBstr);
|
||
|
pBstr = IntPtr.Zero;
|
||
|
cBstr = 0;
|
||
|
dirList = new string[count];
|
||
|
|
||
|
int lenNoTrailingSlash = vpath.Length;
|
||
|
if (vpath[lenNoTrailingSlash - 1] == '/') {
|
||
|
lenNoTrailingSlash--;
|
||
|
}
|
||
|
int lenAppRoot = appRoot.Length;
|
||
|
string appRootRelativePath = (lenNoTrailingSlash > lenAppRoot) ? vpath.Substring(lenAppRoot, lenNoTrailingSlash - lenAppRoot) : String.Empty;
|
||
|
|
||
|
for (uint index = 0; index < count; index++) {
|
||
|
result = UnsafeIISMethods.MgdGetNextVPath(pAppCollection, index, out pBstr, out cBstr);
|
||
|
if (result < 0 || pBstr == IntPtr.Zero) {
|
||
|
throw new InvalidOperationException(SR.GetString(SR.Cant_Enumerate_NativeDirs, result));
|
||
|
}
|
||
|
// if cBstr = 1, then pBstr = "/" and can be ignored
|
||
|
string subVdir = (cBstr > 1) ? StringUtil.StringFromWCharPtr(pBstr, cBstr) : null;
|
||
|
Marshal.FreeBSTR(pBstr);
|
||
|
pBstr = IntPtr.Zero;
|
||
|
cBstr = 0;
|
||
|
|
||
|
// only put the subVdir in our list if it is a subdirectory of the specified vpath
|
||
|
if (subVdir != null && subVdir.Length > appRootRelativePath.Length) {
|
||
|
if (appRootRelativePath.Length == 0) {
|
||
|
if (subVdir.IndexOf('/', 1) == -1) {
|
||
|
dirList[dirListCount++] = subVdir.Substring(1);
|
||
|
}
|
||
|
}
|
||
|
else if (StringUtil.EqualsIgnoreCase(appRootRelativePath, 0, subVdir, 0, appRootRelativePath.Length)) {
|
||
|
int nextSlashIndex = subVdir.IndexOf('/', 1 + appRootRelativePath.Length);
|
||
|
if (nextSlashIndex > -1) {
|
||
|
dirList[dirListCount++] = subVdir.Substring(appRootRelativePath.Length + 1, nextSlashIndex - appRootRelativePath.Length);
|
||
|
}
|
||
|
else {
|
||
|
dirList[dirListCount++] = subVdir.Substring(appRootRelativePath.Length + 1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
if (pAppCollection != IntPtr.Zero) {
|
||
|
Marshal.Release(pAppCollection);
|
||
|
pAppCollection = IntPtr.Zero;
|
||
|
}
|
||
|
if (pBstr != IntPtr.Zero) {
|
||
|
Marshal.FreeBSTR(pBstr);
|
||
|
pBstr = IntPtr.Zero;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
string[] subdirs = null;
|
||
|
if (dirListCount > 0) {
|
||
|
subdirs = new string[dirListCount];
|
||
|
for (int i = 0; i < subdirs.Length; i++) {
|
||
|
subdirs[i] = dirList[i];
|
||
|
}
|
||
|
}
|
||
|
return subdirs;
|
||
|
}
|
||
|
|
||
|
bool IServerConfig2.IsWithinApp(string virtualPath) {
|
||
|
return _nativeConfig.MgdIsWithinApp(CurrentAppSiteName, HttpRuntime.AppDomainAppVirtualPathString, virtualPath);
|
||
|
}
|
||
|
|
||
|
bool IServerConfig.GetUncUser(IApplicationHost appHost, VirtualPath path, out string username, out string password) {
|
||
|
bool foundCreds = false;
|
||
|
username = null;
|
||
|
password = null;
|
||
|
|
||
|
IntPtr pBstrUserName = IntPtr.Zero;
|
||
|
int cBstrUserName = 0;
|
||
|
IntPtr pBstrPassword = IntPtr.Zero;
|
||
|
int cBstrPassword = 0;
|
||
|
|
||
|
try {
|
||
|
int result = _nativeConfig.MgdGetVrPathCreds( appHost.GetSiteName(),
|
||
|
path.VirtualPathString,
|
||
|
out pBstrUserName,
|
||
|
out cBstrUserName,
|
||
|
out pBstrPassword,
|
||
|
out cBstrPassword);
|
||
|
if (result == 0) {
|
||
|
username = (cBstrUserName > 0) ? StringUtil.StringFromWCharPtr(pBstrUserName, cBstrUserName) : null;
|
||
|
password = (cBstrPassword > 0) ? StringUtil.StringFromWCharPtr(pBstrPassword, cBstrPassword) : null;
|
||
|
foundCreds = (!String.IsNullOrEmpty(username) && !String.IsNullOrEmpty(password));
|
||
|
}
|
||
|
}
|
||
|
finally {
|
||
|
if (pBstrUserName != IntPtr.Zero) {
|
||
|
Marshal.FreeBSTR(pBstrUserName);
|
||
|
}
|
||
|
if (pBstrPassword != IntPtr.Zero) {
|
||
|
Marshal.FreeBSTR(pBstrPassword);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return foundCreds;
|
||
|
}
|
||
|
|
||
|
long IServerConfig.GetW3WPMemoryLimitInKB() {
|
||
|
long limit = 0;
|
||
|
|
||
|
int result = UnsafeIISMethods.MgdGetMemoryLimitKB( out limit );
|
||
|
if (result < 0)
|
||
|
return 0;
|
||
|
|
||
|
return limit;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// IConfigMapPath
|
||
|
//
|
||
|
|
||
|
string IConfigMapPath.GetMachineConfigFilename() {
|
||
|
return HttpConfigurationSystem.MachineConfigurationFilePath;
|
||
|
}
|
||
|
|
||
|
string IConfigMapPath.GetRootWebConfigFilename() {
|
||
|
return HttpConfigurationSystem.RootWebConfigurationFilePath;
|
||
|
}
|
||
|
|
||
|
private void GetPathConfigFilenameWorker(string siteID, VirtualPath path, out string directory, out string baseName) {
|
||
|
directory = MapPathCaching(siteID, path);
|
||
|
if (directory != null) {
|
||
|
baseName = HttpConfigurationSystem.WebConfigFileName;
|
||
|
}
|
||
|
else {
|
||
|
baseName = null;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void IConfigMapPath.GetPathConfigFilename(
|
||
|
string siteID, string path, out string directory, out string baseName) {
|
||
|
GetPathConfigFilenameWorker(siteID, VirtualPath.Create(path), out directory, out baseName);
|
||
|
}
|
||
|
|
||
|
// IConfigMapPath2 VirtualPath variant
|
||
|
void IConfigMapPath2.GetPathConfigFilename(
|
||
|
string siteID,
|
||
|
VirtualPath path,
|
||
|
out string directory,
|
||
|
out string baseName) {
|
||
|
GetPathConfigFilenameWorker(siteID, path, out directory, out baseName);
|
||
|
}
|
||
|
|
||
|
void IConfigMapPath.GetDefaultSiteNameAndID(out string siteName, out string siteID) {
|
||
|
siteID = ProcessHostConfigUtils.DEFAULT_SITE_ID_STRING;
|
||
|
siteName = _nativeConfig.GetSiteNameFromId(ProcessHostConfigUtils.DEFAULT_SITE_ID_UINT);
|
||
|
}
|
||
|
|
||
|
void IConfigMapPath.ResolveSiteArgument(string siteArgument, out string siteName, out string siteID) {
|
||
|
if ( String.IsNullOrEmpty(siteArgument) ||
|
||
|
StringUtil.EqualsIgnoreCase(siteArgument, ProcessHostConfigUtils.DEFAULT_SITE_ID_STRING) ||
|
||
|
StringUtil.EqualsIgnoreCase(siteArgument, _nativeConfig.GetSiteNameFromId(ProcessHostConfigUtils.DEFAULT_SITE_ID_UINT))) {
|
||
|
|
||
|
siteName = _nativeConfig.GetSiteNameFromId(ProcessHostConfigUtils.DEFAULT_SITE_ID_UINT);
|
||
|
siteID = ProcessHostConfigUtils.DEFAULT_SITE_ID_STRING;
|
||
|
}
|
||
|
else {
|
||
|
siteName = String.Empty;
|
||
|
siteID = String.Empty;
|
||
|
|
||
|
string resolvedName = null;
|
||
|
if (IISMapPath.IsSiteId(siteArgument)) {
|
||
|
uint id;
|
||
|
|
||
|
if (UInt32.TryParse(siteArgument, out id)) {
|
||
|
resolvedName = _nativeConfig.GetSiteNameFromId(id);
|
||
|
}
|
||
|
}
|
||
|
// try to resolve the string
|
||
|
else {
|
||
|
uint id = _nativeConfig.MgdResolveSiteName(siteArgument);
|
||
|
if (id != 0) {
|
||
|
siteID = id.ToString(CultureInfo.InvariantCulture);
|
||
|
siteName = siteArgument;
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!String.IsNullOrEmpty(resolvedName)) {
|
||
|
siteName = resolvedName;
|
||
|
siteID = siteArgument;
|
||
|
}
|
||
|
else {
|
||
|
siteName = siteArgument;
|
||
|
siteID = String.Empty;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Debug.Assert(!String.IsNullOrEmpty(siteName), "!String.IsNullOrEmpty(siteName), siteArg=" + siteArgument);
|
||
|
}
|
||
|
|
||
|
private string MapPathWorker(string siteID, VirtualPath path) {
|
||
|
return MapPathCaching(siteID, path);
|
||
|
}
|
||
|
|
||
|
// IConfigMapPath2 variant with VirtualPath
|
||
|
string IConfigMapPath2.MapPath(string siteID, VirtualPath path) {
|
||
|
return MapPathWorker(siteID, path);
|
||
|
}
|
||
|
|
||
|
string IConfigMapPath.MapPath(string siteID, string path) {
|
||
|
return MapPathWorker(siteID, VirtualPath.Create(path));
|
||
|
}
|
||
|
|
||
|
string IConfigMapPath.GetAppPathForPath(string siteID, string path) {
|
||
|
VirtualPath resolved = GetAppPathForPathWorker(siteID, VirtualPath.Create(path));
|
||
|
return resolved.VirtualPathString;
|
||
|
}
|
||
|
|
||
|
// IConfigMapPath2 variant with VirtualPath
|
||
|
VirtualPath IConfigMapPath2.GetAppPathForPath(string siteID, VirtualPath path) {
|
||
|
return GetAppPathForPathWorker(siteID, path);
|
||
|
}
|
||
|
|
||
|
VirtualPath GetAppPathForPathWorker(string siteID, VirtualPath path) {
|
||
|
uint siteValue = 0;
|
||
|
if (!UInt32.TryParse(siteID, out siteValue)) {
|
||
|
return VirtualPath.RootVirtualPath;
|
||
|
}
|
||
|
|
||
|
IntPtr pBstr = IntPtr.Zero;
|
||
|
int cBstr = 0;
|
||
|
string appPath;
|
||
|
try {
|
||
|
int result = _nativeConfig.MgdGetAppPathForPath(siteValue, path.VirtualPathString, out pBstr, out cBstr);
|
||
|
appPath = (result == 0 && cBstr > 0) ? StringUtil.StringFromWCharPtr(pBstr, cBstr) : null;
|
||
|
}
|
||
|
finally {
|
||
|
if (pBstr != IntPtr.Zero) {
|
||
|
Marshal.FreeBSTR(pBstr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (appPath != null) ? VirtualPath.Create(appPath) : VirtualPath.RootVirtualPath;
|
||
|
}
|
||
|
|
||
|
private string MapPathCaching(string siteID, VirtualPath path) {
|
||
|
// do we need caching for the designer?
|
||
|
string physicalPath = _nativeConfig.MapPathDirect(((IServerConfig)this).GetSiteNameFromSiteID(siteID), path);
|
||
|
|
||
|
if (physicalPath != null && physicalPath.Length == 2 && physicalPath[1] == ':')
|
||
|
physicalPath += "\\";
|
||
|
|
||
|
// Throw if the resulting physical path is not canonical, to prevent potential
|
||
|
// security issues (VSWhidbey 418125)
|
||
|
|
||
|
if (HttpRuntime.IsMapPathRelaxed) {
|
||
|
physicalPath = HttpRuntime.GetRelaxedMapPathResult(physicalPath);
|
||
|
}
|
||
|
|
||
|
if (FileUtil.IsSuspiciousPhysicalPath(physicalPath)) {
|
||
|
if (HttpRuntime.IsMapPathRelaxed) {
|
||
|
physicalPath = HttpRuntime.GetRelaxedMapPathResult(null);
|
||
|
} else {
|
||
|
throw new HttpException(SR.GetString(SR.Cannot_map_path, path));
|
||
|
}
|
||
|
}
|
||
|
return physicalPath;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|