// Scans the <configSections> section of a configuration file. The function is recursive // to traverse arbitrarily nested config groups. // // <sectionGroup name="foo"> // <sectionGroup name="bar"> // <section name="fooBarSection" type="..." /> // ... // // Note: This function valiates that the factory record has not been // declared before in a parent record. (it does not check // current record, which allows you to update list) // private void ScanFactoriesRecursive(XmlUtil xmlUtil, string parentConfigKey, Hashtable factoryList) { // discard any accumulated local errors xmlUtil.SchemaErrors.ResetLocalErrors(); int depth = xmlUtil.Reader.Depth; xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific); while (xmlUtil.Reader.Depth == depth + 1) { bool positionedAtNextElement = false; switch (xmlUtil.Reader.Name) { // // Handle <sectionGroup name="groupName" [type="typename"] /> // case KEYWORD_SECTIONGROUP: { string tagName = null; string typeName = null; int lineNumber = xmlUtil.Reader.LineNumber; while (xmlUtil.Reader.MoveToNextAttribute()) { switch (xmlUtil.Reader.Name) { case KEYWORD_SECTIONGROUP_NAME: tagName = xmlUtil.Reader.Value; VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false); break; case KEYWORD_SECTIONGROUP_TYPE: xmlUtil.VerifyAndGetNonEmptyStringAttribute(ExceptionAction.Local, out typeName); break; default: xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.Local); break; } } xmlUtil.Reader.MoveToElement(); // if on an attribute move back to the element if (!xmlUtil.VerifyRequiredAttribute( tagName, KEYWORD_SECTIONGROUP_NAME, ExceptionAction.NonSpecific)) { // // Without a name, we cannot continue parsing the sections and groups within. // Skip the entire section. // xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true); xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific); } else { string configKey = CombineConfigKey(parentConfigKey, tagName); FactoryRecord factoryRecord = (FactoryRecord) factoryList[configKey]; if (factoryRecord != null) { // Error: duplicate sectionGroup declaration xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined_at_this_level, tagName), xmlUtil), ExceptionAction.Local); } else { FactoryRecord parentFactoryRecord = _parent.FindFactoryRecord(configKey, true); if (parentFactoryRecord != null) { configKey = parentFactoryRecord.ConfigKey; // make sure that an ancestor has not defined a section with the same name as the group if ( !parentFactoryRecord.IsGroup || !parentFactoryRecord.IsEquivalentSectionGroupFactory(Host, typeName)) { xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined, tagName), xmlUtil), ExceptionAction.Local); parentFactoryRecord = null; } } if (parentFactoryRecord != null) { factoryRecord = parentFactoryRecord.CloneSectionGroup(typeName, xmlUtil.Filename, lineNumber); } else { factoryRecord = new FactoryRecord(configKey, parentConfigKey, tagName, typeName, xmlUtil.Filename, lineNumber); } factoryList[configKey] = factoryRecord; } // Add any errors we may have encountered factoryRecord.AddErrors(xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true)); // continue recursive scan ScanFactoriesRecursive(xmlUtil, configKey, factoryList); } continue; } case KEYWORD_SECTION: { string tagName = null; string typeName = null; ConfigurationAllowDefinition allowDefinition = ConfigurationAllowDefinition.Everywhere; ConfigurationAllowExeDefinition allowExeDefinition = ConfigurationAllowExeDefinition.MachineToApplication; bool allowLocation = true; bool restartOnExternalChanges = true; bool requirePermission = true; bool gotType = false; // parse section attributes int lineNumber = xmlUtil.Reader.LineNumber; while (xmlUtil.Reader.MoveToNextAttribute()) { switch (xmlUtil.Reader.Name) { case KEYWORD_SECTION_NAME: tagName = xmlUtil.Reader.Value; VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false); break; case KEYWORD_SECTION_TYPE: xmlUtil.VerifyAndGetNonEmptyStringAttribute(ExceptionAction.Local, out typeName); gotType = true; break; case KEYWORD_SECTION_ALLOWLOCATION: xmlUtil.VerifyAndGetBooleanAttribute( ExceptionAction.Local, true, out allowLocation); break; case KEYWORD_SECTION_ALLOWEXEDEFINITION: try { allowExeDefinition = AllowExeDefinitionToEnum(xmlUtil.Reader.Value, xmlUtil); } catch (ConfigurationException ce) { xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local); } break; case KEYWORD_SECTION_ALLOWDEFINITION: try { allowDefinition = AllowDefinitionToEnum(xmlUtil.Reader.Value, xmlUtil); } catch (ConfigurationException ce) { xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local); } break; case KEYWORD_SECTION_RESTARTONEXTERNALCHANGES: xmlUtil.VerifyAndGetBooleanAttribute( ExceptionAction.Local, true, out restartOnExternalChanges); break; case KEYWORD_SECTION_REQUIREPERMISSION: xmlUtil.VerifyAndGetBooleanAttribute( ExceptionAction.Local, true, out requirePermission); break; default: xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.Local); break; } } xmlUtil.Reader.MoveToElement(); // if on an attribute move back to the element if (!xmlUtil.VerifyRequiredAttribute( tagName, KEYWORD_SECTION_NAME, ExceptionAction.NonSpecific)) { // // Without a name, we cannot continue to create a factoryRecord. // xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true); } else { // Verify that the Type attribute was present. // Note that 'typeName' will be null if the attribute was present // but specified as an empty string. if (!gotType) { xmlUtil.AddErrorRequiredAttribute(KEYWORD_SECTION_TYPE, ExceptionAction.Local); } string configKey = CombineConfigKey(parentConfigKey, tagName); FactoryRecord factoryRecord = (FactoryRecord) factoryList[configKey]; if (factoryRecord != null) { // Error: duplicate section declaration xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined_at_this_level, tagName), xmlUtil), ExceptionAction.Local); } else { FactoryRecord parentFactoryRecord = _parent.FindFactoryRecord(configKey, true); if (parentFactoryRecord != null) { configKey = parentFactoryRecord.ConfigKey; // make sure that an ancestor has not defined a section with the same name as the group if (parentFactoryRecord.IsGroup) { xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined, tagName), xmlUtil), ExceptionAction.Local); parentFactoryRecord = null; } else if (!parentFactoryRecord.IsEquivalentSectionFactory(Host, typeName, allowLocation, allowDefinition, allowExeDefinition, restartOnExternalChanges, requirePermission)) { xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_tag_name_already_defined, tagName), xmlUtil), ExceptionAction.Local); parentFactoryRecord = null; } } if (parentFactoryRecord != null) { // Note - Clone will propagate the IsFromTrustedConfigRecord bit, // which is what we want - if this record is a duplicate of an ancestor, // the ancestor may be from a trusted config record. factoryRecord = parentFactoryRecord.CloneSection(xmlUtil.Filename, lineNumber); } else { factoryRecord = new FactoryRecord( configKey, parentConfigKey, tagName, typeName, allowLocation, allowDefinition, allowExeDefinition, restartOnExternalChanges, requirePermission, _flags[IsTrusted], false, // isUndeclared xmlUtil.Filename, lineNumber); } factoryList[configKey] = factoryRecord; } // Add any errors we may have encountered factoryRecord.AddErrors(xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true)); } } break; case KEYWORD_REMOVE: { string name = null; int lineNumber = -1; // parse attributes while (xmlUtil.Reader.MoveToNextAttribute()) { if (xmlUtil.Reader.Name != KEYWORD_SECTION_NAME) { xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.NonSpecific); } name = xmlUtil.Reader.Value; lineNumber = xmlUtil.Reader.LineNumber; } xmlUtil.Reader.MoveToElement(); if (xmlUtil.VerifyRequiredAttribute( name, KEYWORD_SECTION_NAME, ExceptionAction.NonSpecific)) { VerifySectionName(name, xmlUtil, ExceptionAction.NonSpecific, false); } } break; case KEYWORD_CLEAR: { xmlUtil.VerifyNoUnrecognizedAttributes(ExceptionAction.NonSpecific); } break; default: xmlUtil.AddErrorUnrecognizedElement(ExceptionAction.NonSpecific); xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific); positionedAtNextElement = true; break; } if (!positionedAtNextElement) { // Need to read to next element, and check if an unrecognized child // element is found. xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific); // unrecognized children are not allowed in <configSections> if (xmlUtil.Reader.Depth > depth + 1) { xmlUtil.AddErrorUnrecognizedElement(ExceptionAction.NonSpecific); // Lets try to backup to where we are suppose to be while (xmlUtil.Reader.Depth > (depth + 1)) { xmlUtil.ReadToNextElement(); } } } } }
private void ScanLocationSection(XmlUtil xmlUtil) { string locationSubPath = null; bool allowOverride = true; bool inheritInChildApp = true; int errorCountBeforeScan = xmlUtil.SchemaErrors.GlobalErrorCount; // Get the location section attributes while (xmlUtil.Reader.MoveToNextAttribute()) { switch (xmlUtil.Reader.Name) { case KEYWORD_LOCATION_PATH: locationSubPath = xmlUtil.Reader.Value; break; case KEYWORD_LOCATION_ALLOWOVERRIDE: xmlUtil.VerifyAndGetBooleanAttribute( ExceptionAction.Global, true, out allowOverride); break; case KEYWORD_LOCATION_INHERITINCHILDAPPLICATIONS: xmlUtil.VerifyAndGetBooleanAttribute( ExceptionAction.Global, true, out inheritInChildApp); break; default: xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.Global); break; } } xmlUtil.Reader.MoveToElement(); // if on an attribute move back to the element try { locationSubPath = NormalizeLocationSubPath(locationSubPath, xmlUtil); // // if (locationSubPath == null && !inheritInChildApp && Host.IsDefinitionAllowed(_configPath, ConfigurationAllowDefinition.MachineToWebRoot, ConfigurationAllowExeDefinition.MachineOnly)) { throw new ConfigurationErrorsException(SR.GetString(SR.Location_invalid_inheritInChildApplications_in_machine_or_root_web_config), xmlUtil); } } catch (ConfigurationErrorsException ce) { xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Global); } // Skip over this location section if there are errors if (xmlUtil.SchemaErrors.GlobalErrorCount > errorCountBeforeScan) { xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific); return; } // Scan elements of the location section if the path is the current path. // We do not add <location path="." /> to the _locationSections list. if (locationSubPath == null) { ScanSectionsRecursive(xmlUtil, string.Empty, true, null, !allowOverride, !inheritInChildApp); return; } // Skip over location sections for client config if (!_flags[SupportsLocation]) { xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific); return; } AddLocation(locationSubPath); ScanSectionsRecursive(xmlUtil, string.Empty, true, locationSubPath, !allowOverride, !inheritInChildApp); }
private Hashtable ScanFactories(XmlUtil xmlUtil) { Hashtable factoryList; factoryList = new Hashtable(); if (xmlUtil.Reader.NodeType != XmlNodeType.Element || xmlUtil.Reader.Name != KEYWORD_CONFIGURATION) { string safeFilename = ConfigurationErrorsException.AlwaysSafeFilename(((IConfigErrorInfo)xmlUtil).Filename); throw new ConfigurationErrorsException( SR.GetString(SR.Config_file_doesnt_have_root_configuration, safeFilename), xmlUtil); } // Ignore xmlns attribute while (xmlUtil.Reader.MoveToNextAttribute()) { switch (xmlUtil.Reader.Name) { case KEYWORD_XMLNS: if (xmlUtil.Reader.Value == KEYWORD_CONFIGURATION_NAMESPACE) { _flags[NamespacePresentInFile] = true; _flags[NamespacePresentCurrent] = true; } else { ConfigurationErrorsException ce; ce = new ConfigurationErrorsException( SR.GetString(SR.Config_namespace_invalid, xmlUtil.Reader.Value, KEYWORD_CONFIGURATION_NAMESPACE), xmlUtil); xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Global); } break; default: xmlUtil.AddErrorUnrecognizedAttribute(ExceptionAction.NonSpecific); break; } } // move to first child of <configuration> xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific); if (xmlUtil.Reader.Depth == 1 && xmlUtil.Reader.Name == KEYWORD_CONFIGSECTIONS) { xmlUtil.VerifyNoUnrecognizedAttributes(ExceptionAction.NonSpecific); ScanFactoriesRecursive(xmlUtil, string.Empty, factoryList); } return factoryList; }