summaryrefslogtreecommitdiff
path: root/src/ext/Http/wixext
diff options
context:
space:
mode:
Diffstat (limited to 'src/ext/Http/wixext')
-rw-r--r--src/ext/Http/wixext/HttpCompiler.cs383
-rw-r--r--src/ext/Http/wixext/HttpConstants.cs15
-rw-r--r--src/ext/Http/wixext/HttpDecompiler.cs137
-rw-r--r--src/ext/Http/wixext/HttpErrors.cs31
-rw-r--r--src/ext/Http/wixext/HttpExtensionData.cs30
-rw-r--r--src/ext/Http/wixext/HttpExtensionFactory.cs18
-rw-r--r--src/ext/Http/wixext/HttpTableDefinitions.cs60
-rw-r--r--src/ext/Http/wixext/HttpWindowsInstallerBackendBinderExtension.cs13
-rw-r--r--src/ext/Http/wixext/Symbols/HandleExisting.cs14
-rw-r--r--src/ext/Http/wixext/Symbols/HttpSymbolDefinitions.cs47
-rw-r--r--src/ext/Http/wixext/Symbols/WixHttpSniSslCertSymbol.cs95
-rw-r--r--src/ext/Http/wixext/Symbols/WixHttpUrlAceSymbol.cs63
-rw-r--r--src/ext/Http/wixext/Symbols/WixHttpUrlReservationSymbol.cs71
-rw-r--r--src/ext/Http/wixext/WixToolset.Http.wixext.csproj31
-rw-r--r--src/ext/Http/wixext/WixToolset.Http.wixext.targets11
15 files changed, 1019 insertions, 0 deletions
diff --git a/src/ext/Http/wixext/HttpCompiler.cs b/src/ext/Http/wixext/HttpCompiler.cs
new file mode 100644
index 00000000..6c572470
--- /dev/null
+++ b/src/ext/Http/wixext/HttpCompiler.cs
@@ -0,0 +1,383 @@
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.Http
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Xml.Linq;
8 using WixToolset.Data;
9 using WixToolset.Extensibility;
10 using WixToolset.Extensibility.Data;
11 using WixToolset.Http.Symbols;
12
13 /// <summary>
14 /// The compiler for the WiX Toolset Http Extension.
15 /// </summary>
16 public sealed class HttpCompiler : BaseCompilerExtension
17 {
18 public override XNamespace Namespace => "http://wixtoolset.org/schemas/v4/wxs/http";
19
20 /// <summary>
21 /// Processes an element for the Compiler.
22 /// </summary>
23 /// <param name="sourceLineNumbers">Source line number for the parent element.</param>
24 /// <param name="parentElement">Parent element of element to process.</param>
25 /// <param name="element">Element to process.</param>
26 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
27 public override void ParseElement(Intermediate intermediate, IntermediateSection section, XElement parentElement, XElement element, IDictionary<string, string> context)
28 {
29 switch (parentElement.Name.LocalName)
30 {
31 case "ServiceInstall":
32 var serviceInstallName = context["ServiceInstallName"];
33 var serviceUser = String.IsNullOrEmpty(serviceInstallName) ? null : String.Concat("NT SERVICE\\", serviceInstallName);
34 var serviceComponentId = context["ServiceInstallComponentId"];
35
36 switch (element.Name.LocalName)
37 {
38 case "UrlReservation":
39 this.ParseUrlReservationElement(intermediate, section, element, serviceComponentId, serviceUser);
40 break;
41 default:
42 this.ParseHelper.UnexpectedElement(parentElement, element);
43 break;
44 }
45 break;
46 case "Component":
47 string componentId = context["ComponentId"];
48
49 switch (element.Name.LocalName)
50 {
51 case "SniSslCertificate":
52 this.ParseSniSslCertificateElement(intermediate, section, element, componentId);
53 break;
54
55 case "UrlReservation":
56 this.ParseUrlReservationElement(intermediate, section, element, componentId, null);
57 break;
58 default:
59 this.ParseHelper.UnexpectedElement(parentElement, element);
60 break;
61 }
62 break;
63 default:
64 this.ParseHelper.UnexpectedElement(parentElement, element);
65 break;
66 }
67 }
68
69 /// <summary>
70 /// Parses a SniSsl element.
71 /// </summary>
72 /// <param name="node">The element to parse.</param>
73 /// <param name="componentId">Identifier of the component that owns this SNI SSL Certificate.</param>
74 private void ParseSniSslCertificateElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentId)
75 {
76 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
77 Identifier id = null;
78 string host = null;
79 string port = null;
80 string appId = null;
81 string store = null;
82 string thumbprint = null;
83 var handleExisting = HandleExisting.Replace;
84 string handleExistingValue = null;
85
86 foreach (var 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.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
94 break;
95 case "AppId":
96 appId = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
97 break;
98 case "HandleExisting":
99 handleExistingValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
100 switch (handleExistingValue)
101 {
102 case "replace":
103 handleExisting = HandleExisting.Replace;
104 break;
105 case "ignore":
106 handleExisting = HandleExisting.Ignore;
107 break;
108 case "fail":
109 handleExisting = HandleExisting.Fail;
110 break;
111 default:
112 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "HandleExisting", handleExistingValue, "replace", "ignore", "fail"));
113 break;
114 }
115 break;
116 case "Host":
117 host = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
118 break;
119 case "Port":
120 port = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
121 break;
122 case "Store":
123 store = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
124 break;
125 case "Thumbprint":
126 thumbprint = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
127 break;
128 default:
129 this.ParseHelper.UnexpectedAttribute(node, attrib);
130 break;
131 }
132 }
133 else
134 {
135 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
136 }
137 }
138
139 // Need the element ID for child element processing, so generate now if not authored.
140 if (null == id)
141 {
142 id = this.ParseHelper.CreateIdentifier("ssl", componentId, host, port);
143 }
144
145 // Required attributes.
146 if (null == host)
147 {
148 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Host"));
149 }
150
151 if (null == port)
152 {
153 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Port"));
154 }
155
156 if (null == thumbprint)
157 {
158 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Thumbprint"));
159 }
160
161 // Parse unknown children.
162 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
163
164 if (!this.Messaging.EncounteredError)
165 {
166 section.AddSymbol(new WixHttpSniSslCertSymbol(sourceLineNumbers, id)
167 {
168 Host = host,
169 Port = port,
170 Thumbprint = thumbprint,
171 AppId = appId,
172 Store = store,
173 HandleExisting = handleExisting,
174 ComponentRef = componentId,
175 });
176
177 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedHttpSniSslCertsInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
178 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedHttpSniSslCertsUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
179 }
180 }
181
182 /// <summary>
183 /// Parses a UrlReservation element.
184 /// </summary>
185 /// <param name="node">The element to parse.</param>
186 /// <param name="componentId">Identifier of the component that owns this URL reservation.</param>
187 /// <param name="securityPrincipal">The security principal of the parent element (null if nested under Component).</param>
188 private void ParseUrlReservationElement(Intermediate intermediate, IntermediateSection section, XElement node, string componentId, string securityPrincipal)
189 {
190 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
191 Identifier id = null;
192 var handleExisting = HandleExisting.Replace;
193 string sddl = null;
194 string url = null;
195 var foundACE = false;
196
197 foreach (var attrib in node.Attributes())
198 {
199 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
200 {
201 switch (attrib.Name.LocalName)
202 {
203 case "Id":
204 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
205 break;
206 case "HandleExisting":
207 var handleExistingValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
208 switch (handleExistingValue)
209 {
210 case "replace":
211 handleExisting = HandleExisting.Replace;
212 break;
213 case "ignore":
214 handleExisting = HandleExisting.Ignore;
215 break;
216 case "fail":
217 handleExisting = HandleExisting.Fail;
218 break;
219 default:
220 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "HandleExisting", handleExistingValue, "replace", "ignore", "fail"));
221 break;
222 }
223 break;
224 case "Sddl":
225 sddl = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
226 break;
227 case "Url":
228 url = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
229 break;
230 default:
231 this.ParseHelper.UnexpectedAttribute(node, attrib);
232 break;
233 }
234 }
235 else
236 {
237 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
238 }
239 }
240
241 // Need the element ID for child element processing, so generate now if not authored.
242 if (null == id)
243 {
244 id = this.ParseHelper.CreateIdentifier("url", componentId, securityPrincipal, url);
245 }
246
247 // Parse UrlAce children.
248 foreach (var child in node.Elements())
249 {
250 if (this.Namespace == child.Name.Namespace)
251 {
252 switch (child.Name.LocalName)
253 {
254 case "UrlAce":
255 if (null != sddl)
256 {
257 this.Messaging.Write(ErrorMessages.IllegalParentAttributeWhenNested(sourceLineNumbers, "UrlReservation", "Sddl", "UrlAce"));
258 }
259 else
260 {
261 foundACE = true;
262 this.ParseUrlAceElement(intermediate, section, child, id.Id, securityPrincipal);
263 }
264 break;
265 default:
266 this.ParseHelper.UnexpectedElement(node, child);
267 break;
268 }
269 }
270 else
271 {
272 this.ParseHelper.ParseExtensionElement(this.Context.Extensions, intermediate, section, node, child);
273 }
274 }
275
276 // Url is required.
277 if (null == url)
278 {
279 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Url"));
280 }
281
282 // Security is required.
283 if (null == sddl && !foundACE)
284 {
285 this.Messaging.Write(HttpErrors.NoSecuritySpecified(sourceLineNumbers));
286 }
287
288 if (!this.Messaging.EncounteredError)
289 {
290 section.AddSymbol(new WixHttpUrlReservationSymbol(sourceLineNumbers, id)
291 {
292 HandleExisting = handleExisting,
293 Sddl = sddl,
294 Url = url,
295 ComponentRef = componentId,
296 });
297
298 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedHttpUrlReservationsInstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
299 this.ParseHelper.CreateCustomActionReference(sourceLineNumbers, section, "Wix4SchedHttpUrlReservationsUninstall", this.Context.Platform, CustomActionPlatforms.X86 | CustomActionPlatforms.X64 | CustomActionPlatforms.ARM64);
300 }
301 }
302
303 /// <summary>
304 /// Parses a UrlAce element.
305 /// </summary>
306 /// <param name="node">The element to parse.</param>
307 /// <param name="urlReservationId">The URL reservation ID.</param>
308 /// <param name="defaultSecurityPrincipal">The default security principal.</param>
309 private void ParseUrlAceElement(Intermediate intermediate, IntermediateSection section, XElement node, string urlReservationId, string defaultSecurityPrincipal)
310 {
311 var sourceLineNumbers = this.ParseHelper.GetSourceLineNumbers(node);
312 Identifier id = null;
313 var securityPrincipal = defaultSecurityPrincipal;
314 var rights = HttpConstants.GENERIC_ALL;
315 string rightsValue = null;
316
317 foreach (var attrib in node.Attributes())
318 {
319 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || this.Namespace == attrib.Name.Namespace)
320 {
321 switch (attrib.Name.LocalName)
322 {
323 case "Id":
324 id = this.ParseHelper.GetAttributeIdentifier(sourceLineNumbers, attrib);
325 break;
326 case "SecurityPrincipal":
327 securityPrincipal = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
328 break;
329 case "Rights":
330 rightsValue = this.ParseHelper.GetAttributeValue(sourceLineNumbers, attrib);
331 switch (rightsValue)
332 {
333 case "all":
334 rights = HttpConstants.GENERIC_ALL;
335 break;
336 case "delegate":
337 rights = HttpConstants.GENERIC_WRITE;
338 break;
339 case "register":
340 rights = HttpConstants.GENERIC_EXECUTE;
341 break;
342 default:
343 this.Messaging.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, "Rights", rightsValue, "all", "delegate", "register"));
344 break;
345 }
346 break;
347 default:
348 this.ParseHelper.UnexpectedAttribute(node, attrib);
349 break;
350 }
351 }
352 else
353 {
354 this.ParseHelper.ParseExtensionAttribute(this.Context.Extensions, intermediate, section, node, attrib);
355 }
356 }
357
358 // Generate Id now if not authored.
359 if (null == id)
360 {
361 id = this.ParseHelper.CreateIdentifier("ace", urlReservationId, securityPrincipal, rightsValue);
362 }
363
364 this.ParseHelper.ParseForExtensionElements(this.Context.Extensions, intermediate, section, node);
365
366 // SecurityPrincipal is required.
367 if (null == securityPrincipal)
368 {
369 this.Messaging.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "SecurityPrincipal"));
370 }
371
372 if (!this.Messaging.EncounteredError)
373 {
374 section.AddSymbol(new WixHttpUrlAceSymbol(sourceLineNumbers, id)
375 {
376 WixHttpUrlReservationRef = urlReservationId,
377 SecurityPrincipal = securityPrincipal,
378 Rights = rights,
379 });
380 }
381 }
382 }
383}
diff --git a/src/ext/Http/wixext/HttpConstants.cs b/src/ext/Http/wixext/HttpConstants.cs
new file mode 100644
index 00000000..5fb42d86
--- /dev/null
+++ b/src/ext/Http/wixext/HttpConstants.cs
@@ -0,0 +1,15 @@
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.Http
4{
5 using System;
6
7 internal static class HttpConstants
8 {
9 // from winnt.h
10 public const int GENERIC_ALL = 0x10000000;
11 public const int GENERIC_EXECUTE = 0x20000000;
12 public const int GENERIC_WRITE = 0x40000000;
13
14 }
15}
diff --git a/src/ext/Http/wixext/HttpDecompiler.cs b/src/ext/Http/wixext/HttpDecompiler.cs
new file mode 100644
index 00000000..8991ec2f
--- /dev/null
+++ b/src/ext/Http/wixext/HttpDecompiler.cs
@@ -0,0 +1,137 @@
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.Http
4{
5#if TODO_CONSIDER_DECOMPILER
6 using System;
7 using System.Collections;
8 using System.Diagnostics;
9 using System.Globalization;
10 using WixToolset.Data;
11 using WixToolset.Extensibility;
12 using Http = WixToolset.Extensions.Serialize.Http;
13 using Wix = WixToolset.Data.Serialize;
14
15 /// <summary>
16 /// The decompiler for the WiX Toolset Http Extension.
17 /// </summary>
18 public sealed class HttpDecompiler : DecompilerExtension
19 {
20 /// <summary>
21 /// Creates a decompiler for Http Extension.
22 /// </summary>
23 public HttpDecompiler()
24 {
25 this.TableDefinitions = HttpExtensionData.GetExtensionTableDefinitions();
26 }
27
28 /// <summary>
29 /// Get the extensions library to be removed.
30 /// </summary>
31 /// <param name="tableDefinitions">Table definitions for library.</param>
32 /// <returns>Library to remove from decompiled output.</returns>
33 public override Library GetLibraryToRemove(TableDefinitionCollection tableDefinitions)
34 {
35 return HttpExtensionData.GetExtensionLibrary(tableDefinitions);
36 }
37
38 /// <summary>
39 /// Decompiles an extension table.
40 /// </summary>
41 /// <param name="table">The table to decompile.</param>
42 public override void DecompileTable(Table table)
43 {
44 switch (table.Name)
45 {
46 case "WixHttpUrlReservation":
47 this.DecompileWixHttpUrlReservationTable(table);
48 break;
49 case "WixHttpUrlAce":
50 this.DecompileWixHttpUrlAceTable(table);
51 break;
52 default:
53 base.DecompileTable(table);
54 break;
55 }
56 }
57
58 /// <summary>
59 /// Decompile the WixHttpUrlReservation table.
60 /// </summary>
61 /// <param name="table">The table to decompile.</param>
62 private void DecompileWixHttpUrlReservationTable(Table table)
63 {
64 foreach (Row row in table.Rows)
65 {
66 Http.UrlReservation urlReservation = new Http.UrlReservation();
67 urlReservation.Id = (string)row[0];
68 switch((int)row[1])
69 {
70 case HttpConstants.heReplace:
71 default:
72 urlReservation.HandleExisting = Http.UrlReservation.HandleExistingType.replace;
73 break;
74 case HttpConstants.heIgnore:
75 urlReservation.HandleExisting = Http.UrlReservation.HandleExistingType.ignore;
76 break;
77 case HttpConstants.heFail:
78 urlReservation.HandleExisting = Http.UrlReservation.HandleExistingType.fail;
79 break;
80 }
81 urlReservation.Sddl = (string)row[2];
82 urlReservation.Url = (string)row[3];
83
84 Wix.Component component = (Wix.Component)this.Core.GetIndexedElement("Component", (string)row[4]);
85 if (null != component)
86 {
87 component.AddChild(urlReservation);
88 }
89 else
90 {
91 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerConstants.PrimaryKeyDelimiter), "Component_", (string)row[2], "Component"));
92 }
93 this.Core.IndexElement(row, urlReservation);
94 }
95 }
96
97
98 /// <summary>
99 /// Decompile the WixHttpUrlAce table.
100 /// </summary>
101 /// <param name="table">The table to decompile.</param>
102 private void DecompileWixHttpUrlAceTable(Table table)
103 {
104 foreach (Row row in table.Rows)
105 {
106 Http.UrlAce urlace = new Http.UrlAce();
107 urlace.Id = (string)row[0];
108 urlace.SecurityPrincipal = (string)row[2];
109 switch (Convert.ToInt32(row[3]))
110 {
111 case HttpConstants.GENERIC_ALL:
112 default:
113 urlace.Rights = Http.UrlAce.RightsType.all;
114 break;
115 case HttpConstants.GENERIC_EXECUTE:
116 urlace.Rights = Http.UrlAce.RightsType.register;
117 break;
118 case HttpConstants.GENERIC_WRITE:
119 urlace.Rights = Http.UrlAce.RightsType.@delegate;
120 break;
121 }
122
123 string reservationId = (string)row[1];
124 Http.UrlReservation urlReservation = (Http.UrlReservation)this.Core.GetIndexedElement("WixHttpUrlReservation", reservationId);
125 if (null != urlReservation)
126 {
127 urlReservation.AddChild(urlace);
128 }
129 else
130 {
131 this.Core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, urlace.Id, "WixHttpUrlReservation_", reservationId, "WixHttpUrlReservation"));
132 }
133 }
134 }
135 }
136#endif
137}
diff --git a/src/ext/Http/wixext/HttpErrors.cs b/src/ext/Http/wixext/HttpErrors.cs
new file mode 100644
index 00000000..e87adf54
--- /dev/null
+++ b/src/ext/Http/wixext/HttpErrors.cs
@@ -0,0 +1,31 @@
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.Http
4{
5 using System;
6 using System.Resources;
7 using WixToolset.Data;
8
9 public static class HttpErrors
10 {
11 public static Message NoSecuritySpecified(SourceLineNumber sourceLineNumbers)
12 {
13 return Message(sourceLineNumbers, Ids.NoSecuritySpecified, "The UrlReservation element doesn't identify the security for the reservation. You must either specify the Sddl attribute, or provide child UrlAce elements.");
14 }
15
16 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
17 {
18 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args);
19 }
20
21 private static Message Message(SourceLineNumber sourceLineNumber, Ids id, ResourceManager resourceManager, string resourceName, params object[] args)
22 {
23 return new Message(sourceLineNumber, MessageLevel.Error, (int)id, resourceManager, resourceName, args);
24 }
25
26 public enum Ids
27 {
28 NoSecuritySpecified = 6701,
29 }
30 }
31}
diff --git a/src/ext/Http/wixext/HttpExtensionData.cs b/src/ext/Http/wixext/HttpExtensionData.cs
new file mode 100644
index 00000000..04e3dcee
--- /dev/null
+++ b/src/ext/Http/wixext/HttpExtensionData.cs
@@ -0,0 +1,30 @@
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.Http
4{
5 using WixToolset.Data;
6 using WixToolset.Extensibility;
7
8 /// <summary>
9 /// The WiX Toolset Http Extension.
10 /// </summary>
11 public sealed class HttpExtensionData : BaseExtensionData
12 {
13 /// <summary>
14 /// Gets the default culture.
15 /// </summary>
16 /// <value>The default culture.</value>
17 public override string DefaultCulture => "en-US";
18
19 public override bool TryGetSymbolDefinitionByName(string name, out IntermediateSymbolDefinition symbolDefinition)
20 {
21 symbolDefinition = HttpSymbolDefinitions.ByName(name);
22 return symbolDefinition != null;
23 }
24
25 public override Intermediate GetLibrary(ISymbolDefinitionCreator symbolDefinitions)
26 {
27 return Intermediate.Load(typeof(HttpExtensionData).Assembly, "WixToolset.Http.http.wixlib", symbolDefinitions);
28 }
29 }
30}
diff --git a/src/ext/Http/wixext/HttpExtensionFactory.cs b/src/ext/Http/wixext/HttpExtensionFactory.cs
new file mode 100644
index 00000000..ad7d84d0
--- /dev/null
+++ b/src/ext/Http/wixext/HttpExtensionFactory.cs
@@ -0,0 +1,18 @@
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.Http
4{
5 using System;
6 using System.Collections.Generic;
7 using WixToolset.Extensibility;
8
9 public class HttpExtensionFactory : BaseExtensionFactory
10 {
11 protected override IReadOnlyCollection<Type> ExtensionTypes => new[]
12 {
13 typeof(HttpCompiler),
14 typeof(HttpExtensionData),
15 typeof(HttpWindowsInstallerBackendBinderExtension),
16 };
17 }
18}
diff --git a/src/ext/Http/wixext/HttpTableDefinitions.cs b/src/ext/Http/wixext/HttpTableDefinitions.cs
new file mode 100644
index 00000000..431b9a33
--- /dev/null
+++ b/src/ext/Http/wixext/HttpTableDefinitions.cs
@@ -0,0 +1,60 @@
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.Http
4{
5 using WixToolset.Data.WindowsInstaller;
6
7 public static class HttpTableDefinitions
8 {
9 public static readonly TableDefinition WixHttpSniSslCert = new TableDefinition(
10 "Wix4HttpSniSslCert",
11 HttpSymbolDefinitions.WixHttpSniSslCert,
12 new[]
13 {
14 new ColumnDefinition("Wix4HttpSniSslCert", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "The non-localized primary key for the table.", modularizeType: ColumnModularizeType.Column),
15 new ColumnDefinition("Host", ColumnType.String, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Host for the SNI SSL certificate.", modularizeType: ColumnModularizeType.Property),
16 new ColumnDefinition("Port", ColumnType.String, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "Port for the SNI SSL certificate.", modularizeType: ColumnModularizeType.Property),
17 new ColumnDefinition("Thumbprint", ColumnType.String, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "humbprint of the SNI SSL certificate to find.", modularizeType: ColumnModularizeType.Property),
18 new ColumnDefinition("AppId", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Optional application id for the SNI SSL certificate.", modularizeType: ColumnModularizeType.Property),
19 new ColumnDefinition("Store", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Optional application id for the SNI SSL certificate.", modularizeType: ColumnModularizeType.Property),
20 new ColumnDefinition("HandleExisting", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 2, description: "The behavior when trying to install a SNI SSL certificate and it already exists."),
21 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table referencing the component that controls the URL reservation.", modularizeType: ColumnModularizeType.Column),
22 },
23 symbolIdIsPrimaryKey: true
24 );
25
26 public static readonly TableDefinition WixHttpUrlReservation = new TableDefinition(
27 "Wix4HttpUrlReservation",
28 HttpSymbolDefinitions.WixHttpUrlReservation,
29 new[]
30 {
31 new ColumnDefinition("Wix4HttpUrlReservation", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "The non-localized primary key for the table.", modularizeType: ColumnModularizeType.Column),
32 new ColumnDefinition("HandleExisting", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 2, description: "The behavior when trying to install a URL reservation and it already exists."),
33 new ColumnDefinition("Sddl", ColumnType.String, 0, primaryKey: false, nullable: true, ColumnCategory.Formatted, description: "Security descriptor for the URL reservation.", modularizeType: ColumnModularizeType.Property),
34 new ColumnDefinition("Url", ColumnType.String, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "URL to be reserved.", modularizeType: ColumnModularizeType.Property),
35 new ColumnDefinition("Component_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "Component", keyColumn: 1, description: "Foreign key into the Component table referencing the component that controls the URL reservation.", modularizeType: ColumnModularizeType.Column),
36 },
37 symbolIdIsPrimaryKey: true
38 );
39
40 public static readonly TableDefinition WixHttpUrlAce = new TableDefinition(
41 "Wix4HttpUrlAce",
42 HttpSymbolDefinitions.WixHttpUrlAce,
43 new[]
44 {
45 new ColumnDefinition("Wix4HttpUrlAce", ColumnType.String, 72, primaryKey: true, nullable: false, ColumnCategory.Identifier, description: "The non-localized primary key for the table.", modularizeType: ColumnModularizeType.Column),
46 new ColumnDefinition("WixHttpUrlReservation_", ColumnType.String, 72, primaryKey: false, nullable: false, ColumnCategory.Identifier, keyTable: "WixHttpUrlReservation", keyColumn: 1, description: "Foreign key into the WixHttpUrlReservation table.", modularizeType: ColumnModularizeType.Column),
47 new ColumnDefinition("SecurityPrincipal", ColumnType.String, 0, primaryKey: false, nullable: false, ColumnCategory.Formatted, description: "The security principal for this ACE.", modularizeType: ColumnModularizeType.Property),
48 new ColumnDefinition("Rights", ColumnType.Number, 4, primaryKey: false, nullable: false, ColumnCategory.Unknown, minValue: 0, maxValue: 1073741824, description: "The rights for this ACE."),
49 },
50 symbolIdIsPrimaryKey: true
51 );
52
53 public static readonly TableDefinition[] All = new[]
54 {
55 WixHttpSniSslCert,
56 WixHttpUrlReservation,
57 WixHttpUrlAce,
58 };
59 }
60}
diff --git a/src/ext/Http/wixext/HttpWindowsInstallerBackendBinderExtension.cs b/src/ext/Http/wixext/HttpWindowsInstallerBackendBinderExtension.cs
new file mode 100644
index 00000000..8e4f1a96
--- /dev/null
+++ b/src/ext/Http/wixext/HttpWindowsInstallerBackendBinderExtension.cs
@@ -0,0 +1,13 @@
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.Http
4{
5 using System.Collections.Generic;
6 using WixToolset.Data.WindowsInstaller;
7 using WixToolset.Extensibility;
8
9 public class HttpWindowsInstallerBackendBinderExtension : BaseWindowsInstallerBackendBinderExtension
10 {
11 public override IReadOnlyCollection<TableDefinition> TableDefinitions => HttpTableDefinitions.All;
12 }
13}
diff --git a/src/ext/Http/wixext/Symbols/HandleExisting.cs b/src/ext/Http/wixext/Symbols/HandleExisting.cs
new file mode 100644
index 00000000..0d70cebc
--- /dev/null
+++ b/src/ext/Http/wixext/Symbols/HandleExisting.cs
@@ -0,0 +1,14 @@
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.Http.Symbols
4{
5 /// <summary>
6 /// Must match constants in wixhttpca.cpp
7 /// </summary>
8 public enum HandleExisting
9 {
10 Replace = 0,
11 Ignore = 1,
12 Fail = 2,
13 }
14}
diff --git a/src/ext/Http/wixext/Symbols/HttpSymbolDefinitions.cs b/src/ext/Http/wixext/Symbols/HttpSymbolDefinitions.cs
new file mode 100644
index 00000000..2aa03468
--- /dev/null
+++ b/src/ext/Http/wixext/Symbols/HttpSymbolDefinitions.cs
@@ -0,0 +1,47 @@
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.Http
4{
5 using System;
6 using WixToolset.Data;
7
8 public enum HttpSymbolDefinitionType
9 {
10 WixHttpSniSslCert,
11 WixHttpUrlAce,
12 WixHttpUrlReservation,
13 }
14
15 public static partial class HttpSymbolDefinitions
16 {
17 public static readonly Version Version = new Version("4.0.0");
18
19 public static IntermediateSymbolDefinition ByName(string name)
20 {
21 if (!Enum.TryParse(name, out HttpSymbolDefinitionType type))
22 {
23 return null;
24 }
25
26 return ByType(type);
27 }
28
29 public static IntermediateSymbolDefinition ByType(HttpSymbolDefinitionType type)
30 {
31 switch (type)
32 {
33 case HttpSymbolDefinitionType.WixHttpSniSslCert:
34 return HttpSymbolDefinitions.WixHttpSniSslCert;
35
36 case HttpSymbolDefinitionType.WixHttpUrlAce:
37 return HttpSymbolDefinitions.WixHttpUrlAce;
38
39 case HttpSymbolDefinitionType.WixHttpUrlReservation:
40 return HttpSymbolDefinitions.WixHttpUrlReservation;
41
42 default:
43 throw new ArgumentOutOfRangeException(nameof(type));
44 }
45 }
46 }
47}
diff --git a/src/ext/Http/wixext/Symbols/WixHttpSniSslCertSymbol.cs b/src/ext/Http/wixext/Symbols/WixHttpSniSslCertSymbol.cs
new file mode 100644
index 00000000..ec67a089
--- /dev/null
+++ b/src/ext/Http/wixext/Symbols/WixHttpSniSslCertSymbol.cs
@@ -0,0 +1,95 @@
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.Http
4{
5 using WixToolset.Data;
6 using WixToolset.Http.Symbols;
7
8 public static partial class HttpSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixHttpSniSslCert = new IntermediateSymbolDefinition(
11 HttpSymbolDefinitionType.WixHttpSniSslCert.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixHttpSniSslCertSymbolFields.Host), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixHttpSniSslCertSymbolFields.Port), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixHttpSniSslCertSymbolFields.Thumbprint), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(WixHttpSniSslCertSymbolFields.AppId), IntermediateFieldType.String),
18 new IntermediateFieldDefinition(nameof(WixHttpSniSslCertSymbolFields.Store), IntermediateFieldType.String),
19 new IntermediateFieldDefinition(nameof(WixHttpSniSslCertSymbolFields.HandleExisting), IntermediateFieldType.Number),
20 new IntermediateFieldDefinition(nameof(WixHttpSniSslCertSymbolFields.ComponentRef), IntermediateFieldType.String),
21 },
22 typeof(WixHttpSniSslCertSymbol));
23 }
24}
25
26namespace WixToolset.Http.Symbols
27{
28 using WixToolset.Data;
29
30 public enum WixHttpSniSslCertSymbolFields
31 {
32 Host,
33 Port,
34 Thumbprint,
35 AppId,
36 Store,
37 HandleExisting,
38 ComponentRef,
39 }
40
41 public class WixHttpSniSslCertSymbol : IntermediateSymbol
42 {
43 public WixHttpSniSslCertSymbol() : base(HttpSymbolDefinitions.WixHttpSniSslCert, null, null)
44 {
45 }
46
47 public WixHttpSniSslCertSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(HttpSymbolDefinitions.WixHttpSniSslCert, sourceLineNumber, id)
48 {
49 }
50
51 public IntermediateField this[WixHttpSniSslCertSymbolFields index] => this.Fields[(int)index];
52
53 public string Host
54 {
55 get => this.Fields[(int)WixHttpSniSslCertSymbolFields.Host].AsString();
56 set => this.Set((int)WixHttpSniSslCertSymbolFields.Host, value);
57 }
58
59 public string Port
60 {
61 get => this.Fields[(int)WixHttpSniSslCertSymbolFields.Port].AsString();
62 set => this.Set((int)WixHttpSniSslCertSymbolFields.Port, value);
63 }
64
65 public string Thumbprint
66 {
67 get => this.Fields[(int)WixHttpSniSslCertSymbolFields.Thumbprint].AsString();
68 set => this.Set((int)WixHttpSniSslCertSymbolFields.Thumbprint, value);
69 }
70
71 public string AppId
72 {
73 get => this.Fields[(int)WixHttpSniSslCertSymbolFields.AppId].AsString();
74 set => this.Set((int)WixHttpSniSslCertSymbolFields.AppId, value);
75 }
76
77 public string Store
78 {
79 get => this.Fields[(int)WixHttpSniSslCertSymbolFields.Store].AsString();
80 set => this.Set((int)WixHttpSniSslCertSymbolFields.Store, value);
81 }
82
83 public HandleExisting HandleExisting
84 {
85 get => (HandleExisting)this.Fields[(int)WixHttpSniSslCertSymbolFields.HandleExisting].AsNumber();
86 set => this.Set((int)WixHttpSniSslCertSymbolFields.HandleExisting, (int)value);
87 }
88
89 public string ComponentRef
90 {
91 get => this.Fields[(int)WixHttpSniSslCertSymbolFields.ComponentRef].AsString();
92 set => this.Set((int)WixHttpSniSslCertSymbolFields.ComponentRef, value);
93 }
94 }
95}
diff --git a/src/ext/Http/wixext/Symbols/WixHttpUrlAceSymbol.cs b/src/ext/Http/wixext/Symbols/WixHttpUrlAceSymbol.cs
new file mode 100644
index 00000000..1d57bd52
--- /dev/null
+++ b/src/ext/Http/wixext/Symbols/WixHttpUrlAceSymbol.cs
@@ -0,0 +1,63 @@
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.Http
4{
5 using WixToolset.Data;
6 using WixToolset.Http.Symbols;
7
8 public static partial class HttpSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixHttpUrlAce = new IntermediateSymbolDefinition(
11 HttpSymbolDefinitionType.WixHttpUrlAce.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixHttpUrlAceSymbolFields.WixHttpUrlReservationRef), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixHttpUrlAceSymbolFields.SecurityPrincipal), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixHttpUrlAceSymbolFields.Rights), IntermediateFieldType.Number),
17 },
18 typeof(WixHttpUrlAceSymbol));
19 }
20}
21
22namespace WixToolset.Http.Symbols
23{
24 using WixToolset.Data;
25
26 public enum WixHttpUrlAceSymbolFields
27 {
28 WixHttpUrlReservationRef,
29 SecurityPrincipal,
30 Rights,
31 }
32
33 public class WixHttpUrlAceSymbol : IntermediateSymbol
34 {
35 public WixHttpUrlAceSymbol() : base(HttpSymbolDefinitions.WixHttpUrlAce, null, null)
36 {
37 }
38
39 public WixHttpUrlAceSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(HttpSymbolDefinitions.WixHttpUrlAce, sourceLineNumber, id)
40 {
41 }
42
43 public IntermediateField this[WixHttpUrlAceSymbolFields index] => this.Fields[(int)index];
44
45 public string WixHttpUrlReservationRef
46 {
47 get => this.Fields[(int)WixHttpUrlAceSymbolFields.WixHttpUrlReservationRef].AsString();
48 set => this.Set((int)WixHttpUrlAceSymbolFields.WixHttpUrlReservationRef, value);
49 }
50
51 public string SecurityPrincipal
52 {
53 get => this.Fields[(int)WixHttpUrlAceSymbolFields.SecurityPrincipal].AsString();
54 set => this.Set((int)WixHttpUrlAceSymbolFields.SecurityPrincipal, value);
55 }
56
57 public int Rights
58 {
59 get => this.Fields[(int)WixHttpUrlAceSymbolFields.Rights].AsNumber();
60 set => this.Set((int)WixHttpUrlAceSymbolFields.Rights, value);
61 }
62 }
63} \ No newline at end of file
diff --git a/src/ext/Http/wixext/Symbols/WixHttpUrlReservationSymbol.cs b/src/ext/Http/wixext/Symbols/WixHttpUrlReservationSymbol.cs
new file mode 100644
index 00000000..4aa4a5da
--- /dev/null
+++ b/src/ext/Http/wixext/Symbols/WixHttpUrlReservationSymbol.cs
@@ -0,0 +1,71 @@
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.Http
4{
5 using WixToolset.Data;
6 using WixToolset.Http.Symbols;
7
8 public static partial class HttpSymbolDefinitions
9 {
10 public static readonly IntermediateSymbolDefinition WixHttpUrlReservation = new IntermediateSymbolDefinition(
11 HttpSymbolDefinitionType.WixHttpUrlReservation.ToString(),
12 new[]
13 {
14 new IntermediateFieldDefinition(nameof(WixHttpUrlReservationSymbolFields.HandleExisting), IntermediateFieldType.Number),
15 new IntermediateFieldDefinition(nameof(WixHttpUrlReservationSymbolFields.Sddl), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixHttpUrlReservationSymbolFields.Url), IntermediateFieldType.String),
17 new IntermediateFieldDefinition(nameof(WixHttpUrlReservationSymbolFields.ComponentRef), IntermediateFieldType.String),
18 },
19 typeof(WixHttpUrlReservationSymbol));
20 }
21}
22
23namespace WixToolset.Http.Symbols
24{
25 using WixToolset.Data;
26
27 public enum WixHttpUrlReservationSymbolFields
28 {
29 HandleExisting,
30 Sddl,
31 Url,
32 ComponentRef,
33 }
34
35 public class WixHttpUrlReservationSymbol : IntermediateSymbol
36 {
37 public WixHttpUrlReservationSymbol() : base(HttpSymbolDefinitions.WixHttpUrlReservation, null, null)
38 {
39 }
40
41 public WixHttpUrlReservationSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(HttpSymbolDefinitions.WixHttpUrlReservation, sourceLineNumber, id)
42 {
43 }
44
45 public IntermediateField this[WixHttpUrlReservationSymbolFields index] => this.Fields[(int)index];
46
47 public HandleExisting HandleExisting
48 {
49 get => (HandleExisting)this.Fields[(int)WixHttpUrlReservationSymbolFields.HandleExisting].AsNumber();
50 set => this.Set((int)WixHttpUrlReservationSymbolFields.HandleExisting, (int)value);
51 }
52
53 public string Sddl
54 {
55 get => this.Fields[(int)WixHttpUrlReservationSymbolFields.Sddl].AsString();
56 set => this.Set((int)WixHttpUrlReservationSymbolFields.Sddl, value);
57 }
58
59 public string Url
60 {
61 get => this.Fields[(int)WixHttpUrlReservationSymbolFields.Url].AsString();
62 set => this.Set((int)WixHttpUrlReservationSymbolFields.Url, value);
63 }
64
65 public string ComponentRef
66 {
67 get => this.Fields[(int)WixHttpUrlReservationSymbolFields.ComponentRef].AsString();
68 set => this.Set((int)WixHttpUrlReservationSymbolFields.ComponentRef, value);
69 }
70 }
71} \ No newline at end of file
diff --git a/src/ext/Http/wixext/WixToolset.Http.wixext.csproj b/src/ext/Http/wixext/WixToolset.Http.wixext.csproj
new file mode 100644
index 00000000..089a51d0
--- /dev/null
+++ b/src/ext/Http/wixext/WixToolset.Http.wixext.csproj
@@ -0,0 +1,31 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project Sdk="Microsoft.NET.Sdk">
5 <PropertyGroup>
6 <TargetFramework>netstandard2.0</TargetFramework>
7 <RootNamespace>WixToolset.Http</RootNamespace>
8 <Description>WiX Toolset Http Extension</Description>
9 <Title>WiX Toolset Http Extension</Title>
10 <IsTool>true</IsTool>
11 <ContentTargetFolders>build</ContentTargetFolders>
12 </PropertyGroup>
13
14 <ItemGroup>
15 <Content Include="$(MSBuildThisFileName).targets" />
16 <EmbeddedResource Include="$(OutputPath)..\http.wixlib" />
17 </ItemGroup>
18
19 <ItemGroup>
20 <PackageReference Include="WixToolset.Data" Version="4.0.*" PrivateAssets="all" />
21 <PackageReference Include="WixToolset.Extensibility" Version="4.0.*" PrivateAssets="all" />
22 </ItemGroup>
23
24 <ItemGroup>
25 <ProjectReference Include="..\wixlib\http.wixproj" ReferenceOutputAssembly="false" Condition=" '$(NCrunch)'=='' " />
26 </ItemGroup>
27
28 <ItemGroup>
29 <PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37" PrivateAssets="all" />
30 </ItemGroup>
31</Project>
diff --git a/src/ext/Http/wixext/WixToolset.Http.wixext.targets b/src/ext/Http/wixext/WixToolset.Http.wixext.targets
new file mode 100644
index 00000000..254b0010
--- /dev/null
+++ b/src/ext/Http/wixext/WixToolset.Http.wixext.targets
@@ -0,0 +1,11 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- 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. -->
3
4<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
5 <PropertyGroup>
6 <WixToolsetHttpWixextPath Condition=" '$(WixToolsetHttpWixextPath)' == '' ">$(MSBuildThisFileDirectory)..\tools\WixToolset.Http.wixext.dll</WixToolsetHttpWixextPath>
7 </PropertyGroup>
8 <ItemGroup>
9 <WixExtension Include="$(WixToolsetHttpWixextPath)" />
10 </ItemGroup>
11</Project>