aboutsummaryrefslogtreecommitdiff
path: root/src/wixext/HttpCompiler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/wixext/HttpCompiler.cs')
-rw-r--r--src/wixext/HttpCompiler.cs280
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
3namespace 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}