diff options
Diffstat (limited to 'src/wixext/HttpCompiler.cs')
-rw-r--r-- | src/wixext/HttpCompiler.cs | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/src/wixext/HttpCompiler.cs b/src/wixext/HttpCompiler.cs new file mode 100644 index 00000000..c694ccde --- /dev/null +++ b/src/wixext/HttpCompiler.cs | |||
@@ -0,0 +1,280 @@ | |||
1 | // 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. | ||
2 | |||
3 | namespace WixToolset.Extensions | ||
4 | { | ||
5 | using System; | ||
6 | using System.Collections.Generic; | ||
7 | using System.Globalization; | ||
8 | using System.Xml.Linq; | ||
9 | using WixToolset.Data; | ||
10 | using WixToolset.Extensibility; | ||
11 | |||
12 | /// <summary> | ||
13 | /// The compiler for the WiX Toolset Http Extension. | ||
14 | /// </summary> | ||
15 | public sealed class HttpCompiler : CompilerExtension | ||
16 | { | ||
17 | /// <summary> | ||
18 | /// Instantiate a new HttpCompiler. | ||
19 | /// </summary> | ||
20 | public HttpCompiler() | ||
21 | { | ||
22 | this.Namespace = "http://wixtoolset.org/schemas/v4/wxs/http"; | ||
23 | } | ||
24 | |||
25 | /// <summary> | ||
26 | /// Processes an element for the Compiler. | ||
27 | /// </summary> | ||
28 | /// <param name="sourceLineNumbers">Source line number for the parent element.</param> | ||
29 | /// <param name="parentElement">Parent element of element to process.</param> | ||
30 | /// <param name="element">Element to process.</param> | ||
31 | /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param> | ||
32 | public override void ParseElement(XElement parentElement, XElement element, IDictionary<string, string> context) | ||
33 | { | ||
34 | switch (parentElement.Name.LocalName) | ||
35 | { | ||
36 | case "ServiceInstall": | ||
37 | string serviceInstallName = context["ServiceInstallName"]; | ||
38 | string serviceUser = String.IsNullOrEmpty(serviceInstallName) ? null : String.Concat("NT SERVICE\\", serviceInstallName); | ||
39 | string serviceComponentId = context["ServiceInstallComponentId"]; | ||
40 | |||
41 | switch (element.Name.LocalName) | ||
42 | { | ||
43 | case "UrlReservation": | ||
44 | this.ParseUrlReservationElement(element, serviceComponentId, serviceUser); | ||
45 | break; | ||
46 | default: | ||
47 | this.Core.UnexpectedElement(parentElement, element); | ||
48 | break; | ||
49 | } | ||
50 | break; | ||
51 | case "Component": | ||
52 | string componentId = context["ComponentId"]; | ||
53 | |||
54 | switch (element.Name.LocalName) | ||
55 | { | ||
56 | case "UrlReservation": | ||
57 | this.ParseUrlReservationElement(element, componentId, null); | ||
58 | break; | ||
59 | default: | ||
60 | this.Core.UnexpectedElement(parentElement, element); | ||
61 | break; | ||
62 | } | ||
63 | break; | ||
64 | default: | ||
65 | this.Core.UnexpectedElement(parentElement, element); | ||
66 | break; | ||
67 | } | ||
68 | } | ||
69 | |||
70 | /// <summary> | ||
71 | /// Parses a UrlReservation element. | ||
72 | /// </summary> | ||
73 | /// <param name="node">The element to parse.</param> | ||
74 | /// <param name="componentId">Identifier of the component that owns this URL reservation.</param> | ||
75 | /// <param name="securityPrincipal">The security principal of the parent element (null if nested under Component).</param> | ||
76 | private void ParseUrlReservationElement(XElement node, string componentId, string securityPrincipal) | ||
77 | { | ||
78 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
79 | Identifier id = null; | ||
80 | int handleExisting = HttpConstants.heReplace; | ||
81 | string handleExistingValue = null; | ||
82 | string sddl = null; | ||
83 | string url = null; | ||
84 | bool foundACE = false; | ||
85 | |||
86 | foreach (XAttribute attrib in node.Attributes()) | ||
87 | { | ||
88 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | ||
89 | { | ||
90 | switch (attrib.Name.LocalName) | ||
91 | { | ||
92 | case "Id": | ||
93 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
94 | break; | ||
95 | case "HandleExisting": | ||
96 | handleExistingValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
97 | switch (handleExistingValue) | ||
98 | { | ||
99 | case "replace": | ||
100 | handleExisting = HttpConstants.heReplace; | ||
101 | break; | ||
102 | case "ignore": | ||
103 | handleExisting = HttpConstants.heIgnore; | ||
104 | break; | ||
105 | case "fail": | ||
106 | handleExisting = HttpConstants.heFail; | ||
107 | break; | ||
108 | default: | ||
109 | this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "HandleExisting", handleExistingValue, "replace", "ignore", "fail")); | ||
110 | break; | ||
111 | } | ||
112 | break; | ||
113 | case "Sddl": | ||
114 | sddl = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
115 | break; | ||
116 | case "Url": | ||
117 | url = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
118 | break; | ||
119 | default: | ||
120 | this.Core.UnexpectedAttribute(node, attrib); | ||
121 | break; | ||
122 | } | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | this.Core.ParseExtensionAttribute(node, attrib); | ||
127 | } | ||
128 | } | ||
129 | |||
130 | // Need the element ID for child element processing, so generate now if not authored. | ||
131 | if (null == id) | ||
132 | { | ||
133 | id = this.Core.CreateIdentifier("url", componentId, securityPrincipal, url); | ||
134 | } | ||
135 | |||
136 | // Parse UrlAce children. | ||
137 | foreach (XElement child in node.Elements()) | ||
138 | { | ||
139 | if (this.Namespace == child.Name.Namespace) | ||
140 | { | ||
141 | switch (child.Name.LocalName) | ||
142 | { | ||
143 | case "UrlAce": | ||
144 | if (null != sddl) | ||
145 | { | ||
146 | this.Core.OnMessage(WixErrors.IllegalParentAttributeWhenNested(sourceLineNumbers, "UrlReservation", "Sddl", "UrlAce")); | ||
147 | } | ||
148 | else | ||
149 | { | ||
150 | foundACE = true; | ||
151 | this.ParseUrlAceElement(child, id.Id, securityPrincipal); | ||
152 | } | ||
153 | break; | ||
154 | default: | ||
155 | this.Core.UnexpectedElement(node, child); | ||
156 | break; | ||
157 | } | ||
158 | } | ||
159 | else | ||
160 | { | ||
161 | this.Core.ParseExtensionElement(node, child); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | // Url is required. | ||
166 | if (null == url) | ||
167 | { | ||
168 | this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Url")); | ||
169 | } | ||
170 | |||
171 | // Security is required. | ||
172 | if (null == sddl && !foundACE) | ||
173 | { | ||
174 | this.Core.OnMessage(HttpErrors.NoSecuritySpecified(sourceLineNumbers)); | ||
175 | } | ||
176 | |||
177 | if (!this.Core.EncounteredError) | ||
178 | { | ||
179 | Row row = this.Core.CreateRow(sourceLineNumbers, "WixHttpUrlReservation"); | ||
180 | row[0] = id.Id; | ||
181 | row[1] = handleExisting; | ||
182 | row[2] = sddl; | ||
183 | row[3] = url; | ||
184 | row[4] = componentId; | ||
185 | |||
186 | if (this.Core.CurrentPlatform == Platform.ARM) | ||
187 | { | ||
188 | // Ensure ARM version of the CA is referenced. | ||
189 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixSchedHttpUrlReservationsInstall_ARM"); | ||
190 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixSchedHttpUrlReservationsUninstall_ARM"); | ||
191 | } | ||
192 | else | ||
193 | { | ||
194 | // All other supported platforms use x86. | ||
195 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixSchedHttpUrlReservationsInstall"); | ||
196 | this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", "WixSchedHttpUrlReservationsUninstall"); | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | |||
201 | /// <summary> | ||
202 | /// Parses a UrlAce element. | ||
203 | /// </summary> | ||
204 | /// <param name="node">The element to parse.</param> | ||
205 | /// <param name="urlReservationId">The URL reservation ID.</param> | ||
206 | /// <param name="defaultSecurityPrincipal">The default security principal.</param> | ||
207 | private void ParseUrlAceElement(XElement node, string urlReservationId, string defaultSecurityPrincipal) | ||
208 | { | ||
209 | SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
210 | Identifier id = null; | ||
211 | string securityPrincipal = defaultSecurityPrincipal; | ||
212 | int rights = HttpConstants.GENERIC_ALL; | ||
213 | string rightsValue = null; | ||
214 | |||
215 | foreach (XAttribute attrib in node.Attributes()) | ||
216 | { | ||
217 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace) | ||
218 | { | ||
219 | switch (attrib.Name.LocalName) | ||
220 | { | ||
221 | case "Id": | ||
222 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
223 | break; | ||
224 | case "SecurityPrincipal": | ||
225 | securityPrincipal = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
226 | break; | ||
227 | case "Rights": | ||
228 | rightsValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
229 | switch (rightsValue) | ||
230 | { | ||
231 | case "all": | ||
232 | rights = HttpConstants.GENERIC_ALL; | ||
233 | break; | ||
234 | case "delegate": | ||
235 | rights = HttpConstants.GENERIC_WRITE; | ||
236 | break; | ||
237 | case "register": | ||
238 | rights = HttpConstants.GENERIC_EXECUTE; | ||
239 | break; | ||
240 | default: | ||
241 | this.Core.OnMessage(WixErrors.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Rights", rightsValue, "all", "delegate", "register")); | ||
242 | break; | ||
243 | } | ||
244 | break; | ||
245 | default: | ||
246 | this.Core.UnexpectedAttribute(node, attrib); | ||
247 | break; | ||
248 | } | ||
249 | } | ||
250 | else | ||
251 | { | ||
252 | this.Core.ParseExtensionAttribute(node, attrib); | ||
253 | } | ||
254 | } | ||
255 | |||
256 | // Generate Id now if not authored. | ||
257 | if (null == id) | ||
258 | { | ||
259 | id = this.Core.CreateIdentifier("ace", urlReservationId, securityPrincipal, rightsValue); | ||
260 | } | ||
261 | |||
262 | this.Core.ParseForExtensionElements(node); | ||
263 | |||
264 | // SecurityPrincipal is required. | ||
265 | if (null == securityPrincipal) | ||
266 | { | ||
267 | this.Core.OnMessage(WixErrors.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SecurityPrincipal")); | ||
268 | } | ||
269 | |||
270 | if (!this.Core.EncounteredError) | ||
271 | { | ||
272 | Row row = this.Core.CreateRow(sourceLineNumbers, "WixHttpUrlAce"); | ||
273 | row[0] = id.Id; | ||
274 | row[1] = urlReservationId; | ||
275 | row[2] = securityPrincipal; | ||
276 | row[3] = rights; | ||
277 | } | ||
278 | } | ||
279 | } | ||
280 | } | ||