private void ScanSectionsRecursive( XmlUtil xmlUtil, string parentConfigKey, bool inLocation, string locationSubPath, bool lockChildren, bool skipInChildApps) { // discard any accumulated local errors xmlUtil.SchemaErrors.ResetLocalErrors(); int depth; // only move to child nodes when not on first level (we've already passed the first <configsections>) if (parentConfigKey.Length == 0 && !inLocation) { depth = 0; } else { depth = xmlUtil.Reader.Depth; xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific); } while (xmlUtil.Reader.Depth == depth + 1) { string tagName = xmlUtil.Reader.Name; // // Check for reserved elements before looking up the factory, // which may have the same name if it is in error. // if (tagName == KEYWORD_CONFIGSECTIONS) { // Error: duplicate <configSections> tag, or <configSections> not the first tag under <configuration> xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_client_config_too_many_configsections_elements, tagName), xmlUtil), ExceptionAction.NonSpecific); xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific); continue; } if (tagName == KEYWORD_LOCATION) { if (parentConfigKey.Length > 0 || inLocation) { // Error: <location> section not at top level xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_location_location_not_allowed), xmlUtil), ExceptionAction.Global); xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific); } else { // Recurse into the location section ScanLocationSection(xmlUtil); } continue; } string configKey = CombineConfigKey(parentConfigKey, tagName); FactoryRecord factoryRecord = FindFactoryRecord(configKey, true); if (factoryRecord == null) { // // if (!ClassFlags[ClassIgnoreLocalErrors]) { xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_unrecognized_configuration_section, configKey), xmlUtil), ExceptionAction.Local); } VerifySectionName(tagName, xmlUtil, ExceptionAction.Local, false); factoryRecord = new FactoryRecord( configKey, parentConfigKey, tagName, typeof(DefaultSection).AssemblyQualifiedName, true, // allowLocation ConfigurationAllowDefinition.Everywhere, ConfigurationAllowExeDefinition.MachineToRoamingUser, true, // restartOnExternalChanges true, // requirePermission _flags[IsTrusted], true, // isUndeclared null, -1); // Add any errors we may have encountered to the factory record, // so that child config that also refer to this unrecognized section // get the error. factoryRecord.AddErrors(xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(true)); // Add the factory to the list of factories EnsureFactories()[configKey] = factoryRecord; } if (factoryRecord.IsGroup) { // // Section Group // if (factoryRecord.HasErrors) { xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific); } else { if (xmlUtil.Reader.AttributeCount > 0) { while (xmlUtil.Reader.MoveToNextAttribute()) { if (IsReservedAttributeName(xmlUtil.Reader.Name)) { xmlUtil.AddErrorReservedAttribute(ExceptionAction.NonSpecific); } } xmlUtil.Reader.MoveToElement(); // if on an attribute move back to the element } // Recurse into group definition ScanSectionsRecursive(xmlUtil, configKey, inLocation, locationSubPath, lockChildren, skipInChildApps); } } else { // // Section // configKey = factoryRecord.ConfigKey; string fileName = xmlUtil.Filename; int lineNumber = xmlUtil.LineNumber; string rawXml = null; string configSource = null; string configSourceStreamName = null; object configSourceStreamVersion = null; string protectionProviderName = null; bool isSectionLocked = false; bool positionedAtNextElement = false; bool isFileInput = (locationSubPath == null); if (!factoryRecord.HasErrors) { // We have a valid factoryRecord for a section if (inLocation && factoryRecord.AllowLocation == false) { xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_section_cannot_be_used_in_location), xmlUtil), ExceptionAction.Local); } // Verify correctness for file inputs. if (isFileInput) { // Verify that the section is unique SectionRecord sectionRecord = GetSectionRecord(configKey, true); if (sectionRecord != null && sectionRecord.HasFileInput) { xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_sections_must_be_unique), xmlUtil), ExceptionAction.Local); } // Verify that the definition is allowed. try { VerifyDefinitionAllowed(factoryRecord, _configPath, xmlUtil); } catch (ConfigurationException ce) { xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local); } } // Verify that section is unlocked, both for file and location inputs. try { VerifySectionUnlocked(configKey, xmlUtil); } catch (ConfigurationException ce) { isSectionLocked = true; xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local); } // check for configSource or protectionProvider if (xmlUtil.Reader.AttributeCount >= 1) { // First do all the attributes reading without advancing the reader. string configSourceAttribute = xmlUtil.Reader.GetAttribute(KEYWORD_CONFIGSOURCE); if (configSourceAttribute != null) { try { configSource = NormalizeConfigSource(configSourceAttribute, xmlUtil); } catch (ConfigurationException ce) { xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local); } if (xmlUtil.Reader.AttributeCount != 1) { // Error: elements with configSource should not have other attributes xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_source_syntax_error), xmlUtil), ExceptionAction.Local); } } string protectionProviderAttribute = xmlUtil.Reader.GetAttribute(KEYWORD_PROTECTION_PROVIDER); if (protectionProviderAttribute != null) { try { protectionProviderName = ValidateProtectionProviderAttribute(protectionProviderAttribute, xmlUtil); } catch (ConfigurationException ce) { xmlUtil.SchemaErrors.AddError(ce, ExceptionAction.Local); } if (xmlUtil.Reader.AttributeCount != 1) { // Error: elements with protectionProvider should not have other attributes xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Protection_provider_syntax_error), xmlUtil), ExceptionAction.Local); } } // The 2nd part of the configSource check requires advancing the reader. // Please note that this part should be done only AFTER all other attributes // checking are done. if (configSourceAttribute != null) { if (!xmlUtil.Reader.IsEmptyElement) { while (xmlUtil.Reader.Read()) { XmlNodeType t = xmlUtil.Reader.NodeType; if (t == XmlNodeType.EndElement) break; if (t != XmlNodeType.Comment) { // Error: elements with configSource should not subelements other than comments xmlUtil.SchemaErrors.AddError( new ConfigurationErrorsException(SR.GetString(SR.Config_source_syntax_error), xmlUtil), ExceptionAction.Local); if (t == XmlNodeType.Element) { xmlUtil.StrictSkipToOurParentsEndElement(ExceptionAction.NonSpecific); } else { xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific); } positionedAtNextElement = true; break; } } } } } if (configSource != null) { try { try { configSourceStreamName = Host.GetStreamNameForConfigSource(ConfigStreamInfo.StreamName, configSource); } catch (Exception e) { throw ExceptionUtil.WrapAsConfigException(SR.GetString(SR.Config_source_invalid), e, xmlUtil); } ValidateUniqueConfigSource(configKey, configSourceStreamName, configSource, xmlUtil); configSourceStreamVersion = MonitorStream(configKey, configSource, configSourceStreamName); } catch (ConfigurationException ex) { xmlUtil.SchemaErrors.AddError(ex, ExceptionAction.Local); } } // // prefetch the raw xml // if (!xmlUtil.SchemaErrors.HasLocalErrors) { if (configSource == null && ShouldPrefetchRawXml(factoryRecord)) { Debug.Assert(!positionedAtNextElement, "!positionedAtNextElement"); rawXml = xmlUtil.CopySection(); if (xmlUtil.Reader.NodeType != XmlNodeType.Element) { xmlUtil.VerifyIgnorableNodeType(ExceptionAction.NonSpecific); xmlUtil.StrictReadToNextElement(ExceptionAction.NonSpecific); } positionedAtNextElement = true; } } } // Get the list of errors before advancing the reader List<ConfigurationException> localErrors = xmlUtil.SchemaErrors.RetrieveAndResetLocalErrors(isFileInput); // advance the reader to the next element if (!positionedAtNextElement) { xmlUtil.StrictSkipToNextElement(ExceptionAction.NonSpecific); } // Add the input either to: // 1. The file input at the current config level, or // 2. LocationSections, where it will be used in sub paths bool addInput = true; if (isFileInput) { // If isFileInput==true, Input added will be used against this config level. // Need to check if we need to skip it due to inheritInChildApplications. if (ShouldSkipDueToInheritInChildApplications(skipInChildApps)) { addInput = false; } } else { if (!_flags[SupportsLocation]) { // Skip if we have a location input but we don't support location tag. addInput = false; } } if (addInput) { string targetConfigPath = (locationSubPath == null) ? _configPath : null; SectionXmlInfo sectionXmlInfo = new SectionXmlInfo( configKey, _configPath, targetConfigPath, locationSubPath, fileName, lineNumber, ConfigStreamInfo.StreamVersion, rawXml, configSource, configSourceStreamName, configSourceStreamVersion, protectionProviderName, lockChildren, skipInChildApps); if (locationSubPath == null) { // // Add this file input to the section record // // We've already checked for locked above, so use skip the second check // and set the locked bit. SectionRecord sectionRecord = EnsureSectionRecordUnsafe(configKey, true); Debug.Assert(!sectionRecord.Locked || isSectionLocked, "!sectionRecord.Locked || isSectionLocked"); if (isSectionLocked) { sectionRecord.Locked = true; } SectionInput fileInput = new SectionInput(sectionXmlInfo, localErrors); sectionRecord.AddFileInput(fileInput); } else { // // Add this location input to this list of location sections // LocationSectionRecord locationSectionRecord = new LocationSectionRecord(sectionXmlInfo, localErrors); EnsureLocationSections().Add(locationSectionRecord); } } } } }