// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
namespace WixToolset.Iis
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Xml.Linq;
using WixToolset.Data;
using WixToolset.Extensibility;
using WixToolset.Extensibility.Data;
using WixToolset.Iis.Symbols;
///
/// The compiler for the WiX Toolset Internet Information Services Extension.
///
public sealed class IIsCompiler : BaseCompilerExtension
{
public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/iis";
///
/// Types of objects that custom HTTP Headers can be applied to.
///
/// Note that this must be kept in sync with the eHttpHeaderParentType in scahttpheader.h.
private enum HttpHeaderParentType
{
/// Custom HTTP Header is to be applied to a Web Virtual Directory.
WebVirtualDir = 1,
/// Custom HTTP Header is to be applied to a Web Site.
WebSite = 2,
}
///
/// Types of objects that MimeMaps can be applied to.
///
/// Note that this must be kept in sync with the eMimeMapParentType in scamimemap.h.
private enum MimeMapParentType
{
/// MimeMap is to be applied to a Web Virtual Directory.
WebVirtualDir = 1,
WebSite = 2,
}
///
/// Types of objects that custom WebErrors can be applied to.
///
/// Note that this must be kept in sync with the eWebErrorParentType in scaweberror.h.
private enum WebErrorParentType
{
/// Custom WebError is to be applied to a Web Virtual Directory.
WebVirtualDir = 1,
/// Custom WebError is to be applied to a Web Site.
WebSite = 2,
}
///
/// Processes an element for the Compiler.
///
/// Source line number for the parent element.
/// Parent element of element to process.
/// Element to process.
/// Extra information about the context in which this element is being parsed.
public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary context)
{
switch (parentElement.Name.LocalName)
{
case "Component":
var componentId = context["ComponentId"];
switch (element.Name.LocalName)
{
case "Certificate":
this.ParseCertificateElement(intermediate, section, element, componentId);
break;
case "WebAppPool":
this.ParseWebAppPoolElement(intermediate, section, element, componentId);
break;
case "WebDir":
this.ParseWebDirElement(intermediate, section, element, componentId, null);
break;
case "WebFilter":
this.ParseWebFilterElement(intermediate, section, element, componentId, null);
break;
case "WebProperty":
this.ParseWebPropertyElement(intermediate, section, element, componentId);
break;
case "WebServiceExtension":
this.ParseWebServiceExtensionElement(intermediate, section, element, componentId);
break;
case "WebSite":
this.ParseWebSiteElement(intermediate, section, element, componentId);
break;
case "WebVirtualDir":
this.ParseWebVirtualDirElement(intermediate, section, element, componentId, null, null);
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
break;
case "Fragment":
case "Module":
case "Package":
switch (element.Name.LocalName)
{
case "WebApplication":
this.ParseWebApplicationElement(intermediate, section, element);
break;
case "WebAppPool":
this.ParseWebAppPoolElement(intermediate, section, element, null);
break;
case "WebDirProperties":
this.ParseWebDirPropertiesElement(intermediate, section, element, null);
break;
case "WebLog":
this.ParseWebLogElement(intermediate, section, element);
break;
case "WebSite":
this.ParseWebSiteElement(intermediate, section, element, null);
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
break;
default:
this.ParseHelper.UnexpectedElement(parentElement, element);
break;
}
}
///
/// Parses a certificate element.
///
/// Element to parse.
/// Identifier for parent component.
private void ParseCertificateElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
int attributes = 8; // SCA_CERT_ATTRIBUTE_VITAL
string binaryRef = null;
string certificatePath = null;
string name = null;
string pfxPassword = null;
int storeLocation = 0;
string storeName = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "BinaryRef":
attributes |= 2; // SCA_CERT_ATTRIBUTE_BINARYDATA
binaryRef = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Binary, binaryRef);
break;
case "CertificatePath":
certificatePath = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Overwrite":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 4; // SCA_CERT_ATTRIBUTE_OVERWRITE
}
else
{
attributes &= ~4; // SCA_CERT_ATTRIBUTE_OVERWRITE
}
break;
case "PFXPassword":
pfxPassword = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Request":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 1; // SCA_CERT_ATTRIBUTE_REQUEST
}
else
{
attributes &= ~1; // SCA_CERT_ATTRIBUTE_REQUEST
}
break;
case "StoreLocation":
var storeLocationValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (0 < storeLocationValue.Length)
{
switch (storeLocationValue)
{
case "currentUser":
storeLocation = 1; // SCA_CERTSYSTEMSTORE_CURRENTUSER
break;
case "localMachine":
storeLocation = 2; // SCA_CERTSYSTEMSTORE_LOCALMACHINE
break;
default:
storeLocation = -1;
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "StoreLocation", storeLocationValue, "currentUser", "localMachine"));
break;
}
}
break;
case "StoreName":
var storeNameValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (0 < storeNameValue.Length)
{
switch (storeNameValue)
{
case "ca":
storeName = "CA";
break;
case "my":
case "personal":
storeName = "MY";
break;
case "request":
storeName = "REQUEST";
break;
case "root":
storeName = "Root";
break;
case "otherPeople":
storeName = "AddressBook";
break;
case "trustedPeople":
storeName = "TrustedPeople";
break;
case "trustedPublisher":
storeName = "TrustedPublisher";
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "StoreName", storeNameValue, "ca", "my", "request", "root", "otherPeople", "trustedPeople", "trustedPublisher"));
break;
}
}
break;
case "Vital":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 8; // SCA_CERT_ATTRIBUTE_VITAL
}
else
{
attributes &= ~8; // SCA_CERT_ATTRIBUTE_VITAL
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("crt", componentId, binaryRef, certificatePath);
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
if (0 == storeLocation)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "StoreLocation"));
}
if (null == storeName)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "StoreName"));
}
if (null != binaryRef && null != certificatePath)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "BinaryRef", "CertificatePath", certificatePath));
}
else if (null == binaryRef && null == certificatePath)
{
this.Messaging.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, element.Name.LocalName, "BinaryRef", "CertificatePath"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
// Reference InstallCertificates and UninstallCertificates since nothing will happen without them
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4InstallCertificates", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4UninstallCertificates", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
this.ParseHelper.EnsureTable(section, sourceLineNumbers, IisTableDefinitions.CertificateHash); // Certificate CustomActions require the CertificateHash table
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new CertificateSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Name = name,
StoreLocation = storeLocation,
StoreName = storeName,
Attributes = attributes,
BinaryRef = binaryRef,
CertificatePath = certificatePath,
PFXPassword = pfxPassword,
});
}
}
///
/// Parses a CertificateRef extension element.
///
/// Element to parse.
/// Identifier for parent web site.
private void ParseCertificateRefElement(Intermediate intermediate, IntermediateSection section, XElement element, string webId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.Certificate, id.Id);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.Certificate, id.Id);
section.AddSymbol(new IIsWebSiteCertificatesSymbol(sourceLineNumbers)
{
WebRef = webId,
CertificateRef = id.Id,
});
}
}
///
/// Parses a mime map element.
///
/// Element to parse.
/// Identifier for parent symbol.
/// Type that parentId refers to.
private void ParseMimeMapElement(Intermediate intermediate, IntermediateSection section, XElement element, string parentId, MimeMapParentType parentType)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string extension = null;
string type = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Extension":
extension = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Type":
type = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("imm", parentId, type, extension);
}
if (null == extension)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Extension"));
}
else if (0 < extension.Length)
{
if (!extension.StartsWith(".", StringComparison.Ordinal))
{
this.Messaging.Write(IIsErrors.MimeMapExtensionMissingPeriod(sourceLineNumbers, element.Name.LocalName, "Extension", extension));
}
}
if (null == type)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Type"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new IIsMimeMapSymbol(sourceLineNumbers, id)
{
ParentType = (int)parentType,
ParentValue = parentId,
MimeType = type,
Extension = extension,
});
}
}
///
/// Parses a recycle time element.
///
/// Element to parse.
/// Recycle time value.
private string ParseRecycleTimeElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
string value = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Value":
value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == value)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Value"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
return value;
}
///
/// Parses a web address element.
///
/// Element to parse.
/// Identifier of parent web site.
/// Identifier for web address.
private string ParseWebAddressElement(Intermediate intermediate, IntermediateSection section, XElement element, string parentWeb)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string header = null;
string ip = null;
string port = null;
var secure = false;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Header":
header = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "IP":
ip = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Port":
port = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Secure":
secure = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("iwa", parentWeb, ip, port);
}
if (null == port)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Port"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new IIsWebAddressSymbol(sourceLineNumbers, id)
{
WebRef = parentWeb,
IP = ip,
Port = port,
Header = header,
Secure = secure ? 1 : 0,
});
}
return id?.Id;
}
///
/// Parses a web application element.
///
/// Element to parse.
/// Identifier for web application.
private string ParseWebApplicationElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
var allowSessions = YesNoDefaultType.Default;
string appPool = null;
var buffer = YesNoDefaultType.Default;
var clientDebugging = YesNoDefaultType.Default;
string defaultScript = null;
int isolation = 0;
string name = null;
var parentPaths = YesNoDefaultType.Default;
var scriptTimeout = CompilerConstants.IntegerNotSet;
var sessionTimeout = CompilerConstants.IntegerNotSet;
var serverDebugging = YesNoDefaultType.Default;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "AllowSessions":
allowSessions = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
break;
case "Buffer":
buffer = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
break;
case "ClientDebugging":
clientDebugging = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
break;
case "DefaultScript":
defaultScript = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (0 < defaultScript.Length)
{
switch (defaultScript)
{
case "JScript":
case "VBScript":
// these are valid values
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, defaultScript, "JScript", "VBScript"));
break;
}
}
break;
case "Isolation":
string isolationValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (0 < isolationValue.Length)
{
switch (isolationValue)
{
case "low":
isolation = 0;
break;
case "medium":
isolation = 2;
break;
case "high":
isolation = 1;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, isolationValue, "low", "medium", "high"));
break;
}
}
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "ParentPaths":
parentPaths = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
break;
case "ScriptTimeout":
scriptTimeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
break;
case "ServerDebugging":
serverDebugging = this.ParseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attrib);
break;
case "SessionTimeout":
sessionTimeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
break;
case "WebAppPool":
appPool = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsAppPool, appPool);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("wap", name, appPool);
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
else if (-1 != name.IndexOf("\\", StringComparison.Ordinal))
{
this.Messaging.Write(IIsErrors.IllegalCharacterInAttributeValue(sourceLineNumbers, element.Name.LocalName, "Name", name, '\\'));
}
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
switch (child.Name.LocalName)
{
case "WebApplicationExtension":
this.ParseWebApplicationExtensionElement(intermediate, section, child, id?.Id);
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (!this.Messaging.EncounteredError)
{
var symbol = section.AddSymbol(new IIsWebApplicationSymbol(sourceLineNumbers, id)
{
Name = name,
Isolation = isolation,
DefaultScript = defaultScript,
AppPoolRef = appPool,
});
if (YesNoDefaultType.Default != allowSessions)
{
symbol.AllowSessions = YesNoDefaultType.Yes == allowSessions ? 1 : 0;
}
if (CompilerConstants.IntegerNotSet != sessionTimeout)
{
symbol.SessionTimeout = sessionTimeout;
}
if (YesNoDefaultType.Default != buffer)
{
symbol.Buffer = YesNoDefaultType.Yes == buffer ? 1 : 0;
}
if (YesNoDefaultType.Default != parentPaths)
{
symbol.ParentPaths = YesNoDefaultType.Yes == parentPaths ? 1 : 0;
}
if (CompilerConstants.IntegerNotSet != scriptTimeout)
{
symbol.ScriptTimeout = scriptTimeout;
}
if (YesNoDefaultType.Default != serverDebugging)
{
symbol.ServerDebugging = YesNoDefaultType.Yes == serverDebugging ? 1 : 0;
}
if (YesNoDefaultType.Default != clientDebugging)
{
symbol.ClientDebugging = YesNoDefaultType.Yes == clientDebugging ? 1 : 0;
}
}
return id?.Id;
}
///
/// Parses a web application extension element.
///
/// Element to parse.
/// Identifier for parent web application.
private void ParseWebApplicationExtensionElement(Intermediate intermediate, IntermediateSection section, XElement element, string application)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
int attributes = 0;
string executable = null;
string extension = null;
string verbs = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "CheckPath":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 4;
}
else
{
attributes &= ~4;
}
break;
case "Executable":
executable = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Extension":
extension = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Script":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 1;
}
else
{
attributes &= ~1;
}
break;
case "Verbs":
verbs = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
var symbol = section.AddSymbol(new IIsWebApplicationExtensionSymbol(sourceLineNumbers)
{
ApplicationRef = application,
Extension = extension,
Verbs = verbs,
Executable = executable,
});
if (0 < attributes)
{
symbol.Attributes = attributes;
}
}
}
///
/// Parses web application pool element.
///
/// Element to parse.
/// Optional identifier of parent component.
private void ParseWebAppPoolElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
int attributes = 0;
var cpuAction = CompilerConstants.IntegerNotSet;
string cpuMon = null;
var idleTimeout = CompilerConstants.IntegerNotSet;
int maxCpuUsage = 0;
var maxWorkerProcs = CompilerConstants.IntegerNotSet;
string managedRuntimeVersion = null;
string managedPipelineMode = null;
string name = null;
var privateMemory = CompilerConstants.IntegerNotSet;
var queueLimit = CompilerConstants.IntegerNotSet;
var recycleMinutes = CompilerConstants.IntegerNotSet;
var recycleRequests = CompilerConstants.IntegerNotSet;
string recycleTimes = null;
var refreshCpu = CompilerConstants.IntegerNotSet;
string user = null;
var virtualMemory = CompilerConstants.IntegerNotSet;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "CpuAction":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
var cpuActionValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (0 < cpuActionValue.Length)
{
switch (cpuActionValue)
{
case "shutdown":
cpuAction = 1;
break;
case "none":
cpuAction = 0;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, cpuActionValue, "shutdown", "none"));
break;
}
}
break;
case "Identity":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
var identityValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (0 < identityValue.Length)
{
switch (identityValue)
{
case "networkService":
attributes |= 1;
break;
case "localService":
attributes |= 2;
break;
case "localSystem":
attributes |= 4;
break;
case "other":
attributes |= 8;
break;
case "applicationPoolIdentity":
attributes |= 0x10;
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, identityValue, "networkService", "localService", "localSystem", "other", "applicationPoolIdentity"));
break;
}
}
break;
case "IdleTimeout":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
idleTimeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
break;
case "ManagedPipelineMode":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
managedPipelineMode = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (!String.IsNullOrEmpty(managedPipelineMode))
{
switch (managedPipelineMode)
{
// In 3.5 we allowed lower case values (per camel case enum style), we now use formatted fields,
// so the value needs to match exactly what we pass in to IIS which uses pascal case.
case "classic":
managedPipelineMode = "Classic";
break;
case "integrated":
managedPipelineMode = "Integrated";
break;
case "Classic":
break;
case "Integrated":
break;
default:
if (!this.ParseHelper.ContainsProperty(managedPipelineMode))
{
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName, managedPipelineMode, "Classic", "Integrated"));
}
break;
}
}
break;
case "ManagedRuntimeVersion":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
managedRuntimeVersion = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "MaxCpuUsage":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
maxCpuUsage = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100);
break;
case "MaxWorkerProcesses":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
maxWorkerProcs = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "PrivateMemory":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
privateMemory = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 4294967);
break;
case "QueueLimit":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
queueLimit = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
break;
case "RecycleMinutes":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
recycleMinutes = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
break;
case "RecycleRequests":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
recycleRequests = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
break;
case "RefreshCpu":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
refreshCpu = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
break;
case "User":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
user = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", user);
break;
case "VirtualMemory":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
virtualMemory = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 4294967);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("iap", name, componentId, user);
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
if (null == user && 8 == (attributes & 0x1F))
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "User", "Identity", "other"));
}
if (null != user && 8 != (attributes & 0x1F))
{
this.Messaging.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, element.Name.LocalName, "User", user, "Identity", "other"));
}
cpuMon = maxCpuUsage.ToString(CultureInfo.InvariantCulture.NumberFormat);
if (CompilerConstants.IntegerNotSet != refreshCpu)
{
cpuMon = String.Concat(cpuMon, ",", refreshCpu.ToString(CultureInfo.InvariantCulture.NumberFormat));
if (CompilerConstants.IntegerNotSet != cpuAction)
{
cpuMon = String.Concat(cpuMon, ",", cpuAction.ToString(CultureInfo.InvariantCulture.NumberFormat));
}
}
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
switch (child.Name.LocalName)
{
case "RecycleTime":
if (null == componentId)
{
var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, element.Name.LocalName));
}
if (null == recycleTimes)
{
recycleTimes = this.ParseRecycleTimeElement(intermediate, section, child);
}
else
{
recycleTimes = String.Concat(recycleTimes, ",", this.ParseRecycleTimeElement(intermediate, section, child));
}
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (null != componentId)
{
// Reference ConfigureIIs since nothing will happen without it
this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
}
if (!this.Messaging.EncounteredError)
{
var symbol = section.AddSymbol(new IIsAppPoolSymbol(sourceLineNumbers, id)
{
Name = name,
ComponentRef = componentId,
Attributes = attributes,
UserRef = user,
RecycleTimes = recycleTimes,
CPUMon = cpuMon,
ManagedRuntimeVersion = managedRuntimeVersion,
ManagedPipelineMode = managedPipelineMode,
});
if (CompilerConstants.IntegerNotSet != recycleMinutes)
{
symbol.RecycleMinutes = recycleMinutes;
}
if (CompilerConstants.IntegerNotSet != recycleRequests)
{
symbol.RecycleRequests = recycleRequests;
}
if (CompilerConstants.IntegerNotSet != idleTimeout)
{
symbol.IdleTimeout = idleTimeout;
}
if (CompilerConstants.IntegerNotSet != queueLimit)
{
symbol.QueueLimit = queueLimit;
}
if (CompilerConstants.IntegerNotSet != maxWorkerProcs)
{
symbol.MaxProc = maxWorkerProcs;
}
if (CompilerConstants.IntegerNotSet != virtualMemory)
{
symbol.VirtualMemory = virtualMemory;
}
if (CompilerConstants.IntegerNotSet != privateMemory)
{
symbol.PrivateMemory = privateMemory;
}
}
}
///
/// Parses a web directory element.
///
/// Element to parse.
/// Identifier for parent component.
/// Optional identifier for parent web site.
private void ParseWebDirElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentWeb)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string dirProperties = null;
string path = null;
string application = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "DirProperties":
dirProperties = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
break;
case "Path":
path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "WebApplication":
application = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "WebSite":
if (null != parentWeb)
{
this.Messaging.Write(IIsErrors.WebSiteAttributeUnderWebSite(sourceLineNumbers, element.Name.LocalName));
}
parentWeb = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebSite, parentWeb);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("iwd", componentId, parentWeb, dirProperties, application);
}
if (null == path)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
}
if (null == parentWeb)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "WebSite"));
}
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
switch (child.Name.LocalName)
{
case "WebApplication":
if (null != application)
{
this.Messaging.Write(IIsErrors.WebApplicationAlreadySpecified(childSourceLineNumbers, element.Name.LocalName));
}
application = this.ParseWebApplicationElement(intermediate, section, child);
break;
case "WebDirProperties":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
string childWebDirProperties = this.ParseWebDirPropertiesElement(intermediate, section, child, componentId);
if (null == dirProperties)
{
dirProperties = childWebDirProperties;
}
else
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, child.Name.LocalName, "DirProperties", child.Name.LocalName));
}
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (null == dirProperties)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "DirProperties"));
}
if (null != application)
{
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebApplication, application);
}
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebDirProperties, dirProperties);
// Reference ConfigureIIs since nothing will happen without it
this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new IIsWebDirSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
WebRef = parentWeb,
Path = path,
DirPropertiesRef = dirProperties,
ApplicationRef = application,
});
}
}
///
/// Parses a web directory properties element.
///
/// Element to parse.
/// The identifier for this WebDirProperties.
private string ParseWebDirPropertiesElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
int access = 0;
var accessSet = false;
int accessSSLFlags = 0;
var accessSSLFlagsSet = false;
string anonymousUser = null;
var aspDetailedError = YesNoType.NotSet;
string authenticationProviders = null;
int authorization = 0;
var authorizationSet = false;
string cacheControlCustom = null;
var cacheControlMaxAge = CompilerConstants.LongNotSet;
string defaultDocuments = null;
string httpExpires = null;
var iisControlledPassword = false;
var index = YesNoType.NotSet;
var logVisits = YesNoType.NotSet;
var notCustomError = YesNoType.NotSet;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "AnonymousUser":
anonymousUser = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, "User", anonymousUser);
break;
case "AspDetailedError":
aspDetailedError = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "AuthenticationProviders":
authenticationProviders = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "CacheControlCustom":
cacheControlCustom = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "CacheControlMaxAge":
cacheControlMaxAge = this.ParseHelper.GetAttributeLongValue(sourceLineNumbers, attrib, 0, uint.MaxValue); // 4294967295 (uint.MaxValue) represents unlimited
break;
case "ClearCustomError":
notCustomError = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "DefaultDocuments":
defaultDocuments = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "HttpExpires":
httpExpires = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "IIsControlledPassword":
iisControlledPassword = YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "Index":
index = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
case "LogVisits":
logVisits = this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib);
break;
// Access attributes
case "Execute":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
access |= 4;
}
else
{
access &= ~4;
}
accessSet = true;
break;
case "Read":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
access |= 1;
}
else
{
access &= ~1;
}
accessSet = true;
break;
case "Script":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
access |= 512;
}
else
{
access &= ~512;
}
accessSet = true;
break;
case "Write":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
access |= 2;
}
else
{
access &= ~2;
}
accessSet = true;
break;
// AccessSSL Attributes
case "AccessSSL":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
accessSSLFlags |= 8;
}
else
{
accessSSLFlags &= ~8;
}
accessSSLFlagsSet = true;
break;
case "AccessSSL128":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
accessSSLFlags |= 256;
}
else
{
accessSSLFlags &= ~256;
}
accessSSLFlagsSet = true;
break;
case "AccessSSLMapCert":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
accessSSLFlags |= 128;
}
else
{
accessSSLFlags &= ~128;
}
accessSSLFlagsSet = true;
break;
case "AccessSSLNegotiateCert":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
accessSSLFlags |= 32;
}
else
{
accessSSLFlags &= ~32;
}
accessSSLFlagsSet = true;
break;
case "AccessSSLRequireCert":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
accessSSLFlags |= 64;
}
else
{
accessSSLFlags &= ~64;
}
accessSSLFlagsSet = true;
break;
// Authorization attributes
case "AnonymousAccess":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
authorization |= 1;
}
else
{
authorization &= ~1;
}
authorizationSet = true;
break;
case "BasicAuthentication":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
authorization |= 2;
}
else
{
authorization &= ~2;
}
authorizationSet = true;
break;
case "DigestAuthentication":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
authorization |= 16;
}
else
{
authorization &= ~16;
}
authorizationSet = true;
break;
case "PassportAuthentication":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
authorization |= 64;
}
else
{
authorization &= ~64;
}
authorizationSet = true;
break;
case "WindowsAuthentication":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
authorization |= 4;
}
else
{
authorization &= ~4;
}
authorizationSet = true;
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
if (null == componentId)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
id = Identifier.Invalid;
}
else
{
id = this.ParseHelper.CreateIdentifier("wdp", componentId);
}
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
var symbol = section.AddSymbol(new IIsWebDirPropertiesSymbol(sourceLineNumbers, id)
{
AnonymousUserRef = anonymousUser,
IIsControlledPassword = iisControlledPassword ? 1 : 0,
DefaultDoc = defaultDocuments,
HttpExpires = httpExpires,
CacheControlCustom = cacheControlCustom,
});
if (accessSet)
{
symbol.Access = access;
}
if (authorizationSet)
{
symbol.Authorization = authorization;
}
if (YesNoType.NotSet != logVisits)
{
symbol.LogVisits = YesNoType.Yes == logVisits ? 1 : 0;
}
if (YesNoType.NotSet != index)
{
symbol.Index = YesNoType.Yes == index ? 1 : 0;
}
if (YesNoType.NotSet != aspDetailedError)
{
symbol.AspDetailedError = YesNoType.Yes == aspDetailedError ? 1 : 0;
}
if (CompilerConstants.LongNotSet != cacheControlMaxAge)
{
symbol.CacheControlMaxAge = unchecked((int)cacheControlMaxAge);
}
if (YesNoType.NotSet != notCustomError)
{
symbol.NoCustomError = YesNoType.Yes == notCustomError ? 1 : 0;
}
if (accessSSLFlagsSet)
{
symbol.AccessSSLFlags = accessSSLFlags;
}
if (null != authenticationProviders)
{
symbol.AuthenticationProviders = authenticationProviders;
}
}
return id?.Id;
}
///
/// Parses a web error element.
///
/// Element to parse.
/// Type of the parent.
/// Id of the parent.
private void ParseWebErrorElement(Intermediate intermediate, IntermediateSection section, XElement element, WebErrorParentType parentType, string parent)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
var errorCode = CompilerConstants.IntegerNotSet;
string file = null;
string url = null;
var subCode = CompilerConstants.IntegerNotSet;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "ErrorCode":
errorCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 400, 599);
break;
case "File":
file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "SubCode":
subCode = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
break;
case "URL":
url = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (CompilerConstants.IntegerNotSet == errorCode)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "ErrorCode"));
errorCode = CompilerConstants.IllegalInteger;
}
if (CompilerConstants.IntegerNotSet == subCode)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "SubCode"));
subCode = CompilerConstants.IllegalInteger;
}
if (String.IsNullOrEmpty(file) && String.IsNullOrEmpty(url))
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "File", "URL"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
// Reference ConfigureIIs since nothing will happen without it
this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new IIsWebErrorSymbol(sourceLineNumbers)
{
ErrorCode = errorCode,
SubCode = subCode,
ParentType = (int)parentType,
ParentValue = parent,
File = file,
URL = url,
});
}
}
///
/// Parses a web filter element.
///
/// Element to parse.
/// Identifier of parent component.
/// Optional identifier of parent web site.
private void ParseWebFilterElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentWeb)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string description = null;
int flags = 0;
var loadOrder = CompilerConstants.IntegerNotSet;
string name = null;
string path = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Description":
description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Flags":
flags = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, int.MaxValue);
break;
case "LoadOrder":
string loadOrderValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (0 < loadOrderValue.Length)
{
switch (loadOrderValue)
{
case "first":
loadOrder = 0;
break;
case "last":
loadOrder = -1;
break;
default:
loadOrder = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue);
break;
}
}
break;
case "Name":
name = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Path":
path = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "WebSite":
if (null != parentWeb)
{
this.Messaging.Write(IIsErrors.WebSiteAttributeUnderWebSite(sourceLineNumbers, element.Name.LocalName));
}
parentWeb = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebSite, parentWeb);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("ifl", name, componentId, path, parentWeb);
}
if (null == name)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
if (null == path)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Path"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
// Reference ConfigureIIs since nothing will happen without it
this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
if (!this.Messaging.EncounteredError)
{
var symbol = section.AddSymbol(new IIsFilterSymbol(sourceLineNumbers, id)
{
Name = name,
ComponentRef = componentId,
Path = path,
WebRef = parentWeb,
Description = description,
Flags = flags,
});
if (CompilerConstants.IntegerNotSet != loadOrder)
{
symbol.LoadOrder = loadOrder;
}
}
}
///
/// Parses web log element.
///
/// Node to be parsed.
private void ParseWebLogElement(Intermediate intermediate, IntermediateSection section, XElement element)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string type = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Type":
var typeValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if (0 < typeValue.Length)
{
switch (typeValue)
{
case "IIS":
type = "Microsoft IIS Log File Format";
break;
case "NCSA":
type = "NCSA Common Log File Format";
break;
case "none":
type = "none";
break;
case "ODBC":
type = "ODBC Logging";
break;
case "W3C":
type = "W3C Extended Log File Format";
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Type", typeValue, "IIS", "NCSA", "none", "ODBC", "W3C"));
break;
}
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Id"));
}
if (null == type)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Type"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new IIsWebLogSymbol(sourceLineNumbers, id)
{
Format = type,
});
}
}
///
/// Parses a web property element.
///
/// Element to parse.
/// Identifier for parent component.
private void ParseWebPropertyElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string value = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Value":
value = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
switch (id?.Id)
{
case "ETagChangeNumber":
case "MaxGlobalBandwidth":
// Must specify a value for these
if (null == value)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Value", "Id", id.Id));
}
break;
case "IIs5IsolationMode":
case "LogInUTF8":
// Can't specify a value for these
if (null != value)
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, element.Name.LocalName, "Value", "Id", id.Id));
}
break;
default:
this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, element.Name.LocalName, "Id", id?.Id, "ETagChangeNumber", "IIs5IsolationMode", "LogInUTF8", "MaxGlobalBandwidth"));
break;
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
// Reference ConfigureIIs since nothing will happen without it
this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new IIsPropertySymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Attributes = 0,
Value = value,
});
}
}
///
/// Parses a web service extension element.
///
/// Element to parse.
/// Identifier for parent component.
private void ParseWebServiceExtensionElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
int attributes = 0;
string description = null;
string file = null;
string group = null;
foreach (XAttribute attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Allow":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 1;
}
else
{
attributes &= ~1;
}
break;
case "Description":
description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "File":
file = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Group":
group = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "UIDeletable":
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes |= 2;
}
else
{
attributes &= ~2;
}
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("iwe", componentId, file);
}
if (null == file)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "File"));
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
// Reference ConfigureIIs since nothing will happen without it
this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new IIsWebServiceExtensionSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
File = file,
Description = description,
Group = group,
Attributes = attributes,
});
}
}
///
/// Parses a web site element.
///
/// Element to parse.
/// Optional identifier of parent component.
private void ParseWebSiteElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string application = null;
int attributes = 0;
var connectionTimeout = CompilerConstants.IntegerNotSet;
string description = null;
string directory = null;
string dirProperties = null;
string keyAddress = null;
string log = null;
string siteId = null;
var sequence = CompilerConstants.IntegerNotSet;
var state = CompilerConstants.IntegerNotSet;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "AutoStart":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
state = 2;
}
else if (state != 1)
{
state = 0;
}
break;
case "ConfigureIfExists":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
if (YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
attributes &= ~2;
}
else
{
attributes |= 2;
}
break;
case "ConnectionTimeout":
connectionTimeout = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, short.MaxValue);
break;
case "Description":
description = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Directory":
directory = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, directory);
break;
case "DirProperties":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
dirProperties = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "SiteId":
siteId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
if ("*" == siteId)
{
siteId = "-1";
}
break;
case "Sequence":
sequence = this.ParseHelper.GetAttributeIntegerValue(sourceLineNumbers, attrib, 1, short.MaxValue);
break;
case "StartOnInstall":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
// when state is set to 2 it implies 1, so don't set it to 1
if (2 != state && YesNoType.Yes == this.ParseHelper.GetAttributeYesNoValue(sourceLineNumbers, attrib))
{
state = 1;
}
else if (2 != state)
{
state = 0;
}
break;
case "WebApplication":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
application = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "WebLog":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalAttributeWithoutComponent(sourceLineNumbers, element.Name.LocalName, attrib.Name.LocalName));
}
log = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebLog, log);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("iws", description, componentId, siteId, application);
}
if (null == description)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Description"));
}
if (null == directory && null != componentId)
{
this.Messaging.Write(IIsErrors.RequiredAttributeUnderComponent(sourceLineNumbers, element.Name.LocalName, "Directory"));
}
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
switch (child.Name.LocalName)
{
case "CertificateRef":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
this.ParseCertificateRefElement(intermediate, section, child, id?.Id);
break;
case "HttpHeader":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
this.ParseHttpHeaderElement(intermediate, section, child, HttpHeaderParentType.WebSite, id?.Id);
break;
case "WebAddress":
string address = this.ParseWebAddressElement(intermediate, section, child, id?.Id);
if (null == keyAddress)
{
keyAddress = address;
}
break;
case "WebApplication":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
if (null != application)
{
this.Messaging.Write(IIsErrors.WebApplicationAlreadySpecified(childSourceLineNumbers, element.Name.LocalName));
}
application = this.ParseWebApplicationElement(intermediate, section, child);
break;
case "WebDir":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
this.ParseWebDirElement(intermediate, section, child, componentId, id?.Id);
break;
case "WebDirProperties":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
string childWebDirProperties = this.ParseWebDirPropertiesElement(intermediate, section, child, componentId);
if (null == dirProperties)
{
dirProperties = childWebDirProperties;
}
else
{
this.Messaging.Write(ErrorMessages.IllegalParentAttributeWhenNested(sourceLineNumbers, "WebSite", "DirProperties", child.Name.LocalName));
}
break;
case "WebError":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
this.ParseWebErrorElement(intermediate, section, child, WebErrorParentType.WebSite, id?.Id);
break;
case "WebFilter":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
this.ParseWebFilterElement(intermediate, section, child, componentId, id?.Id);
break;
case "WebVirtualDir":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
this.ParseWebVirtualDirElement(intermediate, section, child, componentId, id?.Id, null);
break;
case "MimeMap":
this.ParseMimeMapElement(intermediate, section, child, id?.Id, MimeMapParentType.WebSite);
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (null == keyAddress)
{
this.Messaging.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, element.Name.LocalName, "WebAddress"));
}
if (null != application)
{
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebApplication, application);
}
if (null != dirProperties)
{
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebDirProperties, dirProperties);
}
if (null != componentId)
{
// Reference ConfigureIIs since nothing will happen without it
this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
}
if (!this.Messaging.EncounteredError)
{
var symbol = section.AddSymbol(new IIsWebSiteSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
Description = description,
DirectoryRef = directory,
KeyAddressRef = keyAddress,
DirPropertiesRef = dirProperties,
ApplicationRef = application,
LogRef = log,
WebsiteId = siteId,
});
if (CompilerConstants.IntegerNotSet != connectionTimeout)
{
symbol.ConnectionTimeout = connectionTimeout;
}
if (CompilerConstants.IntegerNotSet != state)
{
symbol.State = state;
}
if (0 != attributes)
{
symbol.Attributes = attributes;
}
if (CompilerConstants.IntegerNotSet != sequence)
{
symbol.Sequence = sequence;
}
}
}
///
/// Parses a HTTP Header element.
///
/// Element to parse.
/// Type of the parent.
/// Id of the parent.
private void ParseHttpHeaderElement(Intermediate intermediate, IntermediateSection section, XElement element, HttpHeaderParentType parentType, string parent)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string headerName = null;
string headerValue = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Name":
headerName = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Value":
headerValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == headerName)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Name"));
}
else if (null == id)
{
id = this.ParseHelper.CreateIdentifierFromFilename(headerName);
}
this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, element);
// Reference ConfigureIIs since nothing will happen without it
this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new IIsHttpHeaderSymbol(sourceLineNumbers, id)
{
HttpHeader = id.Id,
ParentType = (int)parentType,
ParentValue = parent,
Name = headerName,
Value = headerValue,
Attributes = 0,
});
}
}
///
/// Parses a virtual directory element.
///
/// Element to parse.
/// Identifier of parent component.
/// Identifier of parent web site.
/// Alias of the parent web site.
private void ParseWebVirtualDirElement(Intermediate intermediate, IntermediateSection section, XElement element, string componentId, string parentWeb, string parentAlias)
{
var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(element);
Identifier id = null;
string alias = null;
string application = null;
string directory = null;
string dirProperties = null;
foreach (var attrib in element.Attributes())
{
if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
{
switch (attrib.Name.LocalName)
{
case "Id":
id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
break;
case "Alias":
alias = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "Directory":
directory = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, directory);
break;
case "DirProperties":
dirProperties = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "WebApplication":
application = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
break;
case "WebSite":
if (null != parentWeb)
{
this.Messaging.Write(IIsErrors.WebSiteAttributeUnderWebSite(sourceLineNumbers, element.Name.LocalName));
}
parentWeb = this.ParseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebSite, parentWeb);
break;
default:
this.ParseHelper.UnexpectedAttribute(element, attrib);
break;
}
}
else
{
this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, element, attrib);
}
}
if (null == id)
{
id = this.ParseHelper.CreateIdentifier("wvd", alias, directory, dirProperties, application, parentWeb);
}
if (null == alias)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Alias"));
}
else if (-1 != alias.IndexOf("\\", StringComparison.Ordinal))
{
this.Messaging.Write(IIsErrors.IllegalCharacterInAttributeValue(sourceLineNumbers, element.Name.LocalName, "Alias", alias, '\\'));
}
if (null == directory)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "Directory"));
}
if (null == parentWeb)
{
this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, element.Name.LocalName, "WebSite"));
}
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(sourceLineNumbers, element.Name.LocalName));
}
if (null != parentAlias)
{
alias = String.Concat(parentAlias, "/", alias);
}
foreach (var child in element.Elements())
{
if (this.Namespace == child.Name.Namespace)
{
var childSourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(child);
switch (child.Name.LocalName)
{
case "WebApplication":
if (null != application)
{
this.Messaging.Write(IIsErrors.WebApplicationAlreadySpecified(childSourceLineNumbers, element.Name.LocalName));
}
application = this.ParseWebApplicationElement(intermediate, section, child);
break;
case "WebDirProperties":
if (null == componentId)
{
this.Messaging.Write(IIsErrors.IllegalElementWithoutComponent(childSourceLineNumbers, child.Name.LocalName));
}
string childWebDirProperties = this.ParseWebDirPropertiesElement(intermediate, section, child, componentId);
if (null == dirProperties)
{
dirProperties = childWebDirProperties;
}
else
{
this.Messaging.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, child.Name.LocalName, "DirProperties", child.Name.LocalName));
}
break;
case "WebError":
this.ParseWebErrorElement(intermediate, section, child, WebErrorParentType.WebVirtualDir, id?.Id);
break;
case "WebVirtualDir":
this.ParseWebVirtualDirElement(intermediate, section, child, componentId, parentWeb, alias);
break;
case "HttpHeader":
this.ParseHttpHeaderElement(intermediate, section, child, HttpHeaderParentType.WebVirtualDir, id?.Id);
break;
case "MimeMap":
this.ParseMimeMapElement(intermediate, section, child, id?.Id, MimeMapParentType.WebVirtualDir);
break;
default:
this.ParseHelper.UnexpectedElement(element, child);
break;
}
}
else
{
this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, element, child);
}
}
if (null != dirProperties)
{
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebDirProperties, dirProperties);
}
if (null != application)
{
this.ParseHelper.CreateSimpleReference(section, sourceLineNumbers, IisSymbolDefinitions.IIsWebApplication, application);
}
// Reference ConfigureIIs since nothing will happen without it
this.AddReferenceToConfigureIIs(section, sourceLineNumbers);
if (!this.Messaging.EncounteredError)
{
section.AddSymbol(new IIsWebVirtualDirSymbol(sourceLineNumbers, id)
{
ComponentRef = componentId,
WebRef = parentWeb,
Alias = alias,
DirectoryRef = directory,
DirPropertiesRef = dirProperties,
ApplicationRef = application,
});
}
}
private void AddReferenceToConfigureIIs(IntermediateSection section, SourceLineNumber sourceLineNumbers)
{
this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4ConfigureIIs", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
}
}
}