/* * Uses the Config system to get the specified configuraiton * * The following method is the only accessors to the config system, * and it wraps config exceptions with an explanatory HTTP * exception with an error formatter. It also makes sure the client * is not impersonated while accessing the config system. */ private HttpConfigurationRecord GetCompleteConfigRecord(String reqpath, IHttpMapPath configmap) { HttpConfigurationRecord configrecord = null; HttpContext.ImpersonationSuspendContext ictx = Impersonation.SuspendIfClient(); try { try { if (reqpath == null || reqpath.Length == 0 || HttpRuntime.IsPathWithinAppRoot(reqpath)) { // lookup by path using (new HttpContextWrapper(this)) { configrecord = HttpConfigurationSystem.GetComplete(reqpath, _wr); } } else { // if the path is outside of the application (and not site or machine) // then use application config configrecord = HttpConfigurationSystem.GetCompleteForApp(); } } finally { ictx.Resume(); } } catch { // Protect against exception filters throw; } return(configrecord); }
/* * GetConfigurationDependencies * * Returns an array of filenames who are dependancies of the given path. * Used by batch compilation. */ internal string[] InternalGetConfigurationDependencies(String reqPath, IHttpMapPath configMap) { // remove ending "/" if (reqPath != null && reqPath.Length > 0 && reqPath[reqPath.Length - 1] == '/') { reqPath = reqPath.Substring(0, reqPath.Length - 1); } ArrayList configFiles = new ArrayList(); string path; for (path = reqPath;; path = ParentPath(path)) { // escape from root if (path == null) { configFiles.Add(configMap.MachineConfigPath); break; } String configfile; String mappedfile; if (IsPath(path)) { mappedfile = configMap.MapPath(path); } else { mappedfile = null; // means path was not a path } if (IsDirectory(mappedfile)) { // for the directory case, grab the config file configfile = Path.Combine(mappedfile, WebConfigFileName); if (FileUtil.FileExists(configfile)) { configFiles.Add(configfile); } } } string [] returnValue = new string[configFiles.Count]; for (int i = 0; i < configFiles.Count; ++i) { returnValue[i] = (string)configFiles[i]; } return(returnValue); }
static internal void Init(HttpContext context) { // create 'default' mapping in cases when there is no context s_contextlessMapPath = new ContextlessMapPath(); string path = context.Request.ApplicationPath; Debug.Trace("config_verbose", "App path:" + path); s_contextlessMapPath.ApplicationPath = path; IHttpMapPath configMap = context.WorkerRequest; while (path != null) { Debug.Trace("config_verbose", path + ":" + configMap.MapPath(path)); s_contextlessMapPath.Add(path, configMap.MapPath(path)); path = ParentPath(path); } Debug.Trace("config_verbose", "Machine path:" + configMap.MachineConfigPath); s_contextlessMapPath.SetMachineConfigPath(configMap.MachineConfigPath); }
// This function is named after a comment in the original code that sums up what it does nicely. // // now we zip up the path, composing config HttpConfigurationRecord ComposeConfig(String reqPath, IHttpMapPath configmap) { // remove ending "/" if (reqPath != null && reqPath.Length > 0 && reqPath[reqPath.Length - 1] == '/') { reqPath = reqPath.Substring(0, reqPath.Length - 1); } if (configmap == null && reqPath != null) { // // s_contextlessMapPath only works for paths from machine-level to application-level // This is only exposed to internal APIs, so this is just to make sure we don't break ourselves. // Debug.Assert(reqPath != null && (reqPath.Length > s_contextlessMapPath.ApplicationPath.Length || s_contextlessMapPath.ApplicationPath.Substring(0, reqPath.Length) == reqPath)); configmap = s_contextlessMapPath; } // QUICK: look up record in cache (case-insensitive) // // This is the common case because most pages are requested more than once every five minutes // Note: will be null on first invocation // HttpConfigurationRecord configRecord = CacheLookup(reqPath); if (configRecord != null) { return(configRecord); } DateTime utcStart = DateTime.UtcNow; // SLOW: hunt around // // Next, we start from the end of the request path and work our way toward the machine-level config // record. The first record we find is the one we use. Later we'll walk back down the path stack // building all the records that weren't found in the cache. // // Note: On first invocation for this appdomain we won't find anything in the cache, so we'll compose // all config records from machine-level down. // ArrayList pathStack = new ArrayList(); String path = reqPath; HttpConfigurationRecord parentRecord = null; for (;;) { // stack child pathStack.Add(path); // escape from root if (path == null) { break; } // go to parent path = ParentPath(path); // look it up parentRecord = CacheLookup(path); if (parentRecord == null) { configRecord = null; } else { if (parentRecord.IsInheritable) // only inherit from directory ConfigRecords, else keep looking { Debug.Trace("config", "Config located in cache " + QuoteString(path)); break; } configRecord = parentRecord; } } // now we zip down the path, composing config // // We walk down the path ... // For each directory, we build a config record and add a dependency on the config file // The first path that doesn't map to a directory we assume // is a file (leaf in the config system and not inheritable) // Anything left in the path stack after the file* is assumed to // be pathinfo** and is ignored. // // Notes: // * - we never verify the physical file, it's assumed if the mapped path // is not a directory (is this correct behavior?) // ** - pathinfo is the possible junk on the path after the file path: // example: http://localhost/myapp/foo.aspx/bar // /myapp/foo.aspx - file path (see Request.FilePath) // /bar - pathinfo // bool isDir = true; CacheInternal cacheInternal = HttpRuntime.CacheInternal; for (int i = pathStack.Count - 1; i >= 0 && isDir == true; i--) { String configFile = null; String mappedPath = null; Hashtable cachedeps = null; path = (String)pathStack[i]; if (path == null) { mappedPath = ""; if (configmap == null) { configFile = HttpConfigurationSystemBase.MachineConfigurationFilePath; } else { configFile = configmap.MachineConfigPath; } // null MachineConfigPath -> never cache config - always return an empty record. if (configFile == null) { return(HttpConfigurationRecord.Empty); } AddFileDependency(configFile); } else { if (IsPath(path)) { mappedPath = configmap.MapPath(path); if (IsDirectory(mappedPath)) { // for the directory case, grab the config file and a dependency on it configFile = Path.Combine(mappedPath, WebConfigFileName); AddFileDependency(configFile); } else { // otherwise, we're a file and we go ahead and compute as a file isDir = false; // break loop (after record is built) // we need make the cache item dependent on the mapped file location // in case it becomes a directory. if (mappedPath != null) { Debug.Assert(cachedeps == null, "ctracy investigation - cachedeps == null"); cachedeps = new Hashtable(SymbolHashCodeProvider.Default, SymbolEqualComparer.Default); cachedeps[mappedPath] = mappedPath; } } } } configRecord = new HttpConfigurationRecord(configFile, parentRecord, /*mappedPath,*/ isDir, path); string key = CacheKey(path); CacheDependency dependency = GetCacheDependencies(cachedeps, utcStart); Debug.Trace("config_verbose", "Inserting :" + path); if (IsBreakOnUnrecognizedElement) { // If the registry key is set to debug the rare 'Unrecognized Element' // stress error, lets try to reproduce the error by having an absolute // expiry of 5 minutes (this will cause us to re-read config much more // often. Before it took memory pressure. DateTime absouteExpiry = DateTime.UtcNow + new TimeSpan(0, 5, 0); cacheInternal.UtcInsert(key, configRecord, dependency, absouteExpiry, Cache.NoSlidingExpiration); } else { if (configRecord.HasError) { cacheInternal.UtcInsert(key, configRecord, dependency, DateTime.UtcNow.AddSeconds(5), Cache.NoSlidingExpiration); } else { // default: default cache priority, sliding expiration // this will make us rarely expire, config is expensive cacheInternal.UtcInsert(key, configRecord, dependency); } } // This is to wire-up notification of directories who exist (without a config file) and // are then deleted. In this case we don't want to restart the appdomain because no config information has // changed. We do want to remove the cache record and recreate it on the next request. (Something in // the cache record might be assuming the directory still exists.) if (isDir && !FileUtil.FileExists(configFile) && HandlerBase.IsPathAtAppLevel(path) == PathLevel.BelowApp) { //AddDirectoryDependency(mappedPath, path, configRecord); } configRecord.CheckCachedException(); parentRecord = configRecord; } return(configRecord); }
internal /*public*/ static string[] GetConfigurationDependencies(String reqpath, IHttpMapPath configmap) { if (_system == null) { return(null); } return(_system.InternalGetConfigurationDependencies(reqpath, configmap)); }
/* * This static method called by pathmap-aware users of configuration * (namely HttpContext, HttpWorkerRequest) */ internal /*public*/ static HttpConfigurationRecord GetComplete(String reqpath, IHttpMapPath configmap) { if (_system == null) { return(HttpConfigurationRecord.Empty); } return(_system.ComposeConfig(reqpath, configmap)); }