aboutsummaryrefslogtreecommitdiff
path: root/src/dutil/uriutil.cpp
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2017-09-03 11:22:38 -0700
committerRob Mensching <rob@firegiant.com>2017-09-03 13:33:33 -0700
commit5d8375007754101ff2889d0e79486c8f9b7cf5ab (patch)
treea76d6fb6a38dd9f04a93ffcfd9d64e76779b3414 /src/dutil/uriutil.cpp
parent8e8da6dbc051ec884b5d439bb4f44dc027d05bbf (diff)
downloadwix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.tar.gz
wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.tar.bz2
wix-5d8375007754101ff2889d0e79486c8f9b7cf5ab.zip
Initial commit
Diffstat (limited to 'src/dutil/uriutil.cpp')
-rw-r--r--src/dutil/uriutil.cpp538
1 files changed, 538 insertions, 0 deletions
diff --git a/src/dutil/uriutil.cpp b/src/dutil/uriutil.cpp
new file mode 100644
index 00000000..fc192b3f
--- /dev/null
+++ b/src/dutil/uriutil.cpp
@@ -0,0 +1,538 @@
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#include "precomp.h"
4
5
6//
7// UriCanonicalize - canonicalizes a URI.
8//
9extern "C" HRESULT DAPI UriCanonicalize(
10 __inout_z LPWSTR* psczUri
11 )
12{
13 HRESULT hr = S_OK;
14 WCHAR wz[INTERNET_MAX_URL_LENGTH] = { };
15 DWORD cch = countof(wz);
16
17 if (!::InternetCanonicalizeUrlW(*psczUri, wz, &cch, ICU_DECODE))
18 {
19 ExitWithLastError(hr, "Failed to canonicalize URI.");
20 }
21
22 hr = StrAllocString(psczUri, wz, cch);
23 ExitOnFailure(hr, "Failed copy canonicalized URI.");
24
25LExit:
26 return hr;
27}
28
29
30//
31// UriCrack - cracks a URI into constituent parts.
32//
33extern "C" HRESULT DAPI UriCrack(
34 __in_z LPCWSTR wzUri,
35 __out_opt INTERNET_SCHEME* pScheme,
36 __deref_opt_out_z LPWSTR* psczHostName,
37 __out_opt INTERNET_PORT* pPort,
38 __deref_opt_out_z LPWSTR* psczUser,
39 __deref_opt_out_z LPWSTR* psczPassword,
40 __deref_opt_out_z LPWSTR* psczPath,
41 __deref_opt_out_z LPWSTR* psczQueryString
42 )
43{
44 HRESULT hr = S_OK;
45 URL_COMPONENTSW components = { };
46 WCHAR wzHostName[INTERNET_MAX_HOST_NAME_LENGTH + 1];
47 WCHAR wzUserName[INTERNET_MAX_USER_NAME_LENGTH + 1];
48 WCHAR wzPassword[INTERNET_MAX_PASSWORD_LENGTH + 1];
49 WCHAR wzPath[INTERNET_MAX_PATH_LENGTH + 1];
50 WCHAR wzQueryString[INTERNET_MAX_PATH_LENGTH + 1];
51
52 components.dwStructSize = sizeof(URL_COMPONENTSW);
53
54 if (psczHostName)
55 {
56 components.lpszHostName = wzHostName;
57 components.dwHostNameLength = countof(wzHostName);
58 }
59
60 if (psczUser)
61 {
62 components.lpszUserName = wzUserName;
63 components.dwUserNameLength = countof(wzUserName);
64 }
65
66 if (psczPassword)
67 {
68 components.lpszPassword = wzPassword;
69 components.dwPasswordLength = countof(wzPassword);
70 }
71
72 if (psczPath)
73 {
74 components.lpszUrlPath = wzPath;
75 components.dwUrlPathLength = countof(wzPath);
76 }
77
78 if (psczQueryString)
79 {
80 components.lpszExtraInfo = wzQueryString;
81 components.dwExtraInfoLength = countof(wzQueryString);
82 }
83
84 if (!::InternetCrackUrlW(wzUri, 0, ICU_DECODE | ICU_ESCAPE, &components))
85 {
86 ExitWithLastError(hr, "Failed to crack URI.");
87 }
88
89 if (pScheme)
90 {
91 *pScheme = components.nScheme;
92 }
93
94 if (psczHostName)
95 {
96 hr = StrAllocString(psczHostName, components.lpszHostName, components.dwHostNameLength);
97 ExitOnFailure(hr, "Failed to copy host name.");
98 }
99
100 if (pPort)
101 {
102 *pPort = components.nPort;
103 }
104
105 if (psczUser)
106 {
107 hr = StrAllocString(psczUser, components.lpszUserName, components.dwUserNameLength);
108 ExitOnFailure(hr, "Failed to copy user name.");
109 }
110
111 if (psczPassword)
112 {
113 hr = StrAllocString(psczPassword, components.lpszPassword, components.dwPasswordLength);
114 ExitOnFailure(hr, "Failed to copy password.");
115 }
116
117 if (psczPath)
118 {
119 hr = StrAllocString(psczPath, components.lpszUrlPath, components.dwUrlPathLength);
120 ExitOnFailure(hr, "Failed to copy path.");
121 }
122
123 if (psczQueryString)
124 {
125 hr = StrAllocString(psczQueryString, components.lpszExtraInfo, components.dwExtraInfoLength);
126 ExitOnFailure(hr, "Failed to copy query string.");
127 }
128
129LExit:
130 return hr;
131}
132
133
134//
135// UriCrackEx - cracks a URI into URI_INFO.
136//
137extern "C" HRESULT DAPI UriCrackEx(
138 __in_z LPCWSTR wzUri,
139 __in URI_INFO* pUriInfo
140 )
141{
142 HRESULT hr = S_OK;
143
144 hr = UriCrack(wzUri, &pUriInfo->scheme, &pUriInfo->sczHostName, &pUriInfo->port, &pUriInfo->sczUser, &pUriInfo->sczPassword, &pUriInfo->sczPath, &pUriInfo->sczQueryString);
145 ExitOnFailure(hr, "Failed to crack URI.");
146
147LExit:
148 return hr;
149}
150
151
152//
153// UriInfoUninitialize - frees the memory in a URI_INFO struct.
154//
155extern "C" void DAPI UriInfoUninitialize(
156 __in URI_INFO* pUriInfo
157 )
158{
159 ReleaseStr(pUriInfo->sczHostName);
160 ReleaseStr(pUriInfo->sczUser);
161 ReleaseStr(pUriInfo->sczPassword);
162 ReleaseStr(pUriInfo->sczPath);
163 ReleaseStr(pUriInfo->sczQueryString);
164 memset(pUriInfo, 0, sizeof(URI_INFO));
165}
166
167
168//
169// UriCreate - creates a URI from constituent parts.
170//
171extern "C" HRESULT DAPI UriCreate(
172 __inout_z LPWSTR* psczUri,
173 __in INTERNET_SCHEME scheme,
174 __in_z_opt LPWSTR wzHostName,
175 __in INTERNET_PORT port,
176 __in_z_opt LPWSTR wzUser,
177 __in_z_opt LPWSTR wzPassword,
178 __in_z_opt LPWSTR wzPath,
179 __in_z_opt LPWSTR wzQueryString
180 )
181{
182 HRESULT hr = S_OK;
183 WCHAR wz[INTERNET_MAX_URL_LENGTH] = { };
184 DWORD cch = countof(wz);
185 URL_COMPONENTSW components = { };
186
187 components.dwStructSize = sizeof(URL_COMPONENTSW);
188 components.nScheme = scheme;
189 components.lpszHostName = wzHostName;
190 components.nPort = port;
191 components.lpszUserName = wzUser;
192 components.lpszPassword = wzPassword;
193 components.lpszUrlPath = wzPath;
194 components.lpszExtraInfo = wzQueryString;
195
196 if (!::InternetCreateUrlW(&components, ICU_ESCAPE, wz, &cch))
197 {
198 ExitWithLastError(hr, "Failed to create URI.");
199 }
200
201 hr = StrAllocString(psczUri, wz, cch);
202 ExitOnFailure(hr, "Failed copy created URI.");
203
204LExit:
205 return hr;
206}
207
208
209//
210// UriGetServerAndResource - gets the server and resource as independent strings from a URI.
211//
212// NOTE: This function is useful for the InternetConnect/HttpRequest APIs.
213//
214extern "C" HRESULT DAPI UriGetServerAndResource(
215 __in_z LPCWSTR wzUri,
216 __out_z LPWSTR* psczServer,
217 __out_z LPWSTR* psczResource
218 )
219{
220 HRESULT hr = S_OK;
221 INTERNET_SCHEME scheme = INTERNET_SCHEME_UNKNOWN;
222 LPWSTR sczHostName = NULL;
223 INTERNET_PORT port = INTERNET_INVALID_PORT_NUMBER;
224 LPWSTR sczUser = NULL;
225 LPWSTR sczPassword = NULL;
226 LPWSTR sczPath = NULL;
227 LPWSTR sczQueryString = NULL;
228
229 hr = UriCrack(wzUri, &scheme, &sczHostName, &port, &sczUser, &sczPassword, &sczPath, &sczQueryString);
230 ExitOnFailure(hr, "Failed to crack URI.");
231
232 hr = UriCreate(psczServer, scheme, sczHostName, port, sczUser, sczPassword, NULL, NULL);
233 ExitOnFailure(hr, "Failed to allocate server URI.");
234
235 hr = UriCreate(psczResource, INTERNET_SCHEME_UNKNOWN, NULL, INTERNET_INVALID_PORT_NUMBER, NULL, NULL, sczPath, sczQueryString);
236 ExitOnFailure(hr, "Failed to allocate resource URI.");
237
238LExit:
239 ReleaseStr(sczQueryString);
240 ReleaseStr(sczPath);
241 ReleaseStr(sczPassword);
242 ReleaseStr(sczUser);
243 ReleaseStr(sczHostName);
244
245 return hr;
246}
247
248
249//
250// UriFile - returns the file part of the URI.
251//
252extern "C" HRESULT DAPI UriFile(
253 __deref_out_z LPWSTR* psczFile,
254 __in_z LPCWSTR wzUri
255 )
256{
257 HRESULT hr = S_OK;
258 WCHAR wz[MAX_PATH + 1];
259 DWORD cch = countof(wz);
260 URL_COMPONENTSW uc = { };
261
262 uc.dwStructSize = sizeof(uc);
263 uc.lpszUrlPath = wz;
264 uc.dwUrlPathLength = cch;
265
266 if (!::InternetCrackUrlW(wzUri, 0, ICU_DECODE | ICU_ESCAPE, &uc))
267 {
268 ExitWithLastError(hr, "Failed to crack URI.");
269 }
270
271 // Copy only the file name. Fortunately, PathFile() understands that
272 // forward slashes can be directory separators like backslashes.
273 hr = StrAllocString(psczFile, PathFile(wz), 0);
274 ExitOnFailure(hr, "Failed to copy file name");
275
276LExit:
277 return hr;
278}
279
280
281/*******************************************************************
282 UriProtocol - determines the protocol of a URI.
283
284********************************************************************/
285extern "C" HRESULT DAPI UriProtocol(
286 __in_z LPCWSTR wzUri,
287 __out URI_PROTOCOL* pProtocol
288 )
289{
290 Assert(wzUri && *wzUri);
291 Assert(pProtocol);
292
293 HRESULT hr = S_OK;
294
295 if ((L'h' == wzUri[0] || L'H' == wzUri[0]) &&
296 (L't' == wzUri[1] || L'T' == wzUri[1]) &&
297 (L't' == wzUri[2] || L'T' == wzUri[2]) &&
298 (L'p' == wzUri[3] || L'P' == wzUri[3]) &&
299 (L's' == wzUri[4] || L'S' == wzUri[4]) &&
300 L':' == wzUri[5] &&
301 L'/' == wzUri[6] &&
302 L'/' == wzUri[7])
303 {
304 *pProtocol = URI_PROTOCOL_HTTPS;
305 }
306 else if ((L'h' == wzUri[0] || L'H' == wzUri[0]) &&
307 (L't' == wzUri[1] || L'T' == wzUri[1]) &&
308 (L't' == wzUri[2] || L'T' == wzUri[2]) &&
309 (L'p' == wzUri[3] || L'P' == wzUri[3]) &&
310 L':' == wzUri[4] &&
311 L'/' == wzUri[5] &&
312 L'/' == wzUri[6])
313 {
314 *pProtocol = URI_PROTOCOL_HTTP;
315 }
316 else if ((L'f' == wzUri[0] || L'F' == wzUri[0]) &&
317 (L't' == wzUri[1] || L'T' == wzUri[1]) &&
318 (L'p' == wzUri[2] || L'P' == wzUri[2]) &&
319 L':' == wzUri[3] &&
320 L'/' == wzUri[4] &&
321 L'/' == wzUri[5])
322 {
323 *pProtocol = URI_PROTOCOL_FTP;
324 }
325 else if ((L'f' == wzUri[0] || L'F' == wzUri[0]) &&
326 (L'i' == wzUri[1] || L'I' == wzUri[1]) &&
327 (L'l' == wzUri[2] || L'L' == wzUri[2]) &&
328 (L'e' == wzUri[3] || L'E' == wzUri[3]) &&
329 L':' == wzUri[4] &&
330 L'/' == wzUri[5] &&
331 L'/' == wzUri[6])
332 {
333 *pProtocol = URI_PROTOCOL_FILE;
334 }
335 else
336 {
337 *pProtocol = URI_PROTOCOL_UNKNOWN;
338 }
339
340 return hr;
341}
342
343
344/*******************************************************************
345 UriRoot - returns the root of the path specified in the URI.
346
347 examples:
348 file:///C:\path\path -> C:\
349 file://server/share/path/path -> \\server\share
350 http://www.example.com/path/path -> http://www.example.com/
351 ftp://ftp.example.com/path/path -> ftp://www.example.com/
352
353 NOTE: This function should only be used on cannonicalized URIs.
354 It does not cannonicalize itself.
355********************************************************************/
356extern "C" HRESULT DAPI UriRoot(
357 __in_z LPCWSTR wzUri,
358 __out LPWSTR* ppwzRoot,
359 __out_opt URI_PROTOCOL* pProtocol
360 )
361{
362 Assert(wzUri && *wzUri);
363 Assert(ppwzRoot);
364
365 HRESULT hr = S_OK;
366 URI_PROTOCOL protocol = URI_PROTOCOL_UNKNOWN;
367 LPCWSTR pwcSlash = NULL;
368
369 hr = UriProtocol(wzUri, &protocol);
370 ExitOnFailure(hr, "Invalid URI.");
371
372 switch (protocol)
373 {
374 case URI_PROTOCOL_FILE:
375 if (L'/' == wzUri[7]) // file path
376 {
377 if (((L'a' <= wzUri[8] && L'z' >= wzUri[8]) || (L'A' <= wzUri[8] && L'Z' >= wzUri[8])) && L':' == wzUri[9])
378 {
379 hr = StrAlloc(ppwzRoot, 4);
380 ExitOnFailure(hr, "Failed to allocate string for root of URI.");
381 *ppwzRoot[0] = wzUri[8];
382 *ppwzRoot[1] = L':';
383 *ppwzRoot[2] = L'\\';
384 *ppwzRoot[3] = L'\0';
385 }
386 else
387 {
388 hr = E_INVALIDARG;
389 ExitOnFailure(hr, "Invalid file path in URI.");
390 }
391 }
392 else // UNC share
393 {
394 pwcSlash = wcschr(wzUri + 8, L'/');
395 if (!pwcSlash)
396 {
397 hr = E_INVALIDARG;
398 ExitOnFailure(hr, "Invalid server name in URI.");
399 }
400 else
401 {
402 hr = StrAllocString(ppwzRoot, L"\\\\", 64);
403 ExitOnFailure(hr, "Failed to allocate string for root of URI.");
404
405 pwcSlash = wcschr(pwcSlash + 1, L'/');
406 if (pwcSlash)
407 {
408 hr = StrAllocConcat(ppwzRoot, wzUri + 8, pwcSlash - wzUri - 8);
409 ExitOnFailure(hr, "Failed to add server/share to root of URI.");
410 }
411 else
412 {
413 hr = StrAllocConcat(ppwzRoot, wzUri + 8, 0);
414 ExitOnFailure(hr, "Failed to add server/share to root of URI.");
415 }
416
417 // replace all slashes with backslashes to be truly UNC.
418 for (LPWSTR pwc = *ppwzRoot; pwc && *pwc; ++pwc)
419 {
420 if (L'/' == *pwc)
421 {
422 *pwc = L'\\';
423 }
424 }
425 }
426 }
427 break;
428
429 case URI_PROTOCOL_FTP:
430 pwcSlash = wcschr(wzUri + 6, L'/');
431 if (pwcSlash)
432 {
433 hr = StrAllocString(ppwzRoot, wzUri, pwcSlash - wzUri);
434 ExitOnFailure(hr, "Failed allocate root from URI.");
435 }
436 else
437 {
438 hr = StrAllocString(ppwzRoot, wzUri, 0);
439 ExitOnFailure(hr, "Failed allocate root from URI.");
440 }
441 break;
442
443 case URI_PROTOCOL_HTTP:
444 pwcSlash = wcschr(wzUri + 7, L'/');
445 if (pwcSlash)
446 {
447 hr = StrAllocString(ppwzRoot, wzUri, pwcSlash - wzUri);
448 ExitOnFailure(hr, "Failed allocate root from URI.");
449 }
450 else
451 {
452 hr = StrAllocString(ppwzRoot, wzUri, 0);
453 ExitOnFailure(hr, "Failed allocate root from URI.");
454 }
455 break;
456
457 default:
458 hr = E_INVALIDARG;
459 ExitOnFailure(hr, "Unknown URI protocol.");
460 }
461
462 if (pProtocol)
463 {
464 *pProtocol = protocol;
465 }
466
467LExit:
468 return hr;
469}
470
471
472extern "C" HRESULT DAPI UriResolve(
473 __in_z LPCWSTR wzUri,
474 __in_opt LPCWSTR wzBaseUri,
475 __out LPWSTR* ppwzResolvedUri,
476 __out_opt const URI_PROTOCOL* pResolvedProtocol
477 )
478{
479 UNREFERENCED_PARAMETER(wzUri);
480 UNREFERENCED_PARAMETER(wzBaseUri);
481 UNREFERENCED_PARAMETER(ppwzResolvedUri);
482 UNREFERENCED_PARAMETER(pResolvedProtocol);
483
484 HRESULT hr = E_NOTIMPL;
485#if 0
486 URI_PROTOCOL protocol = URI_PROTOCOL_UNKNOWN;
487
488 hr = UriProtocol(wzUri, &protocol);
489 ExitOnFailure(hr, "Failed to determine protocol for URL: %ls", wzUri);
490
491 ExitOnNull(ppwzResolvedUri, hr, E_INVALIDARG, "Failed to resolve URI, because no method of output was provided");
492
493 if (URI_PROTOCOL_UNKNOWN == protocol)
494 {
495 ExitOnNull(wzBaseUri, hr, E_INVALIDARG, "Failed to resolve URI - base URI provided was NULL");
496
497 if (L'/' == *wzUri || L'\\' == *wzUri)
498 {
499 hr = UriRoot(wzBaseUri, ppwzResolvedUri, &protocol);
500 ExitOnFailure(hr, "Failed to get root from URI: %ls", wzBaseUri);
501
502 hr = StrAllocConcat(ppwzResolvedUri, wzUri, 0);
503 ExitOnFailure(hr, "Failed to concat file to base URI.");
504 }
505 else
506 {
507 hr = UriProtocol(wzBaseUri, &protocol);
508 ExitOnFailure(hr, "Failed to get protocol of base URI: %ls", wzBaseUri);
509
510 LPCWSTR pwcFile = const_cast<LPCWSTR> (UriFile(wzBaseUri));
511 if (!pwcFile)
512 {
513 hr = E_INVALIDARG;
514 ExitOnFailure(hr, "Failed to get file from base URI: %ls", wzBaseUri);
515 }
516
517 hr = StrAllocString(ppwzResolvedUri, wzBaseUri, pwcFile - wzBaseUri);
518 ExitOnFailure(hr, "Failed to allocate string for resolved URI.");
519
520 hr = StrAllocConcat(ppwzResolvedUri, wzUri, 0);
521 ExitOnFailure(hr, "Failed to concat file to resolved URI.");
522 }
523 }
524 else
525 {
526 hr = StrAllocString(ppwzResolvedUri, wzUri, 0);
527 ExitOnFailure(hr, "Failed to copy resolved URI.");
528 }
529
530 if (pResolvedProtocol)
531 {
532 *pResolvedProtocol = protocol;
533 }
534
535LExit:
536#endif
537 return hr;
538}