From 7f642e51670bc38a4ef782a363936850bc2b0ba9 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 22 Apr 2021 06:38:23 -0700 Subject: Move dutil into libs/dutil --- src/libs/dutil/WixToolset.DUtil/uriutil.cpp | 553 ++++++++++++++++++++++++++++ 1 file changed, 553 insertions(+) create mode 100644 src/libs/dutil/WixToolset.DUtil/uriutil.cpp (limited to 'src/libs/dutil/WixToolset.DUtil/uriutil.cpp') diff --git a/src/libs/dutil/WixToolset.DUtil/uriutil.cpp b/src/libs/dutil/WixToolset.DUtil/uriutil.cpp new file mode 100644 index 00000000..7913c22e --- /dev/null +++ b/src/libs/dutil/WixToolset.DUtil/uriutil.cpp @@ -0,0 +1,553 @@ +// 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. + +#include "precomp.h" + + +// Exit macros +#define UriExitOnLastError(x, s, ...) ExitOnLastErrorSource(DUTIL_SOURCE_URIUTIL, x, s, __VA_ARGS__) +#define UriExitOnLastErrorDebugTrace(x, s, ...) ExitOnLastErrorDebugTraceSource(DUTIL_SOURCE_URIUTIL, x, s, __VA_ARGS__) +#define UriExitWithLastError(x, s, ...) ExitWithLastErrorSource(DUTIL_SOURCE_URIUTIL, x, s, __VA_ARGS__) +#define UriExitOnFailure(x, s, ...) ExitOnFailureSource(DUTIL_SOURCE_URIUTIL, x, s, __VA_ARGS__) +#define UriExitOnRootFailure(x, s, ...) ExitOnRootFailureSource(DUTIL_SOURCE_URIUTIL, x, s, __VA_ARGS__) +#define UriExitOnFailureDebugTrace(x, s, ...) ExitOnFailureDebugTraceSource(DUTIL_SOURCE_URIUTIL, x, s, __VA_ARGS__) +#define UriExitOnNull(p, x, e, s, ...) ExitOnNullSource(DUTIL_SOURCE_URIUTIL, p, x, e, s, __VA_ARGS__) +#define UriExitOnNullWithLastError(p, x, s, ...) ExitOnNullWithLastErrorSource(DUTIL_SOURCE_URIUTIL, p, x, s, __VA_ARGS__) +#define UriExitOnNullDebugTrace(p, x, e, s, ...) ExitOnNullDebugTraceSource(DUTIL_SOURCE_URIUTIL, p, x, e, s, __VA_ARGS__) +#define UriExitOnInvalidHandleWithLastError(p, x, s, ...) ExitOnInvalidHandleWithLastErrorSource(DUTIL_SOURCE_URIUTIL, p, x, s, __VA_ARGS__) +#define UriExitOnWin32Error(e, x, s, ...) ExitOnWin32ErrorSource(DUTIL_SOURCE_URIUTIL, e, x, s, __VA_ARGS__) +#define UriExitOnGdipFailure(g, x, s, ...) ExitOnGdipFailureSource(DUTIL_SOURCE_URIUTIL, g, x, s, __VA_ARGS__) + + +// +// UriCanonicalize - canonicalizes a URI. +// +extern "C" HRESULT DAPI UriCanonicalize( + __inout_z LPWSTR* psczUri + ) +{ + HRESULT hr = S_OK; + WCHAR wz[INTERNET_MAX_URL_LENGTH] = { }; + DWORD cch = countof(wz); + + if (!::InternetCanonicalizeUrlW(*psczUri, wz, &cch, ICU_DECODE)) + { + UriExitWithLastError(hr, "Failed to canonicalize URI."); + } + + hr = StrAllocString(psczUri, wz, cch); + UriExitOnFailure(hr, "Failed copy canonicalized URI."); + +LExit: + return hr; +} + + +// +// UriCrack - cracks a URI into constituent parts. +// +extern "C" HRESULT DAPI UriCrack( + __in_z LPCWSTR wzUri, + __out_opt INTERNET_SCHEME* pScheme, + __deref_opt_out_z LPWSTR* psczHostName, + __out_opt INTERNET_PORT* pPort, + __deref_opt_out_z LPWSTR* psczUser, + __deref_opt_out_z LPWSTR* psczPassword, + __deref_opt_out_z LPWSTR* psczPath, + __deref_opt_out_z LPWSTR* psczQueryString + ) +{ + HRESULT hr = S_OK; + URL_COMPONENTSW components = { }; + WCHAR wzHostName[INTERNET_MAX_HOST_NAME_LENGTH + 1]; + WCHAR wzUserName[INTERNET_MAX_USER_NAME_LENGTH + 1]; + WCHAR wzPassword[INTERNET_MAX_PASSWORD_LENGTH + 1]; + WCHAR wzPath[INTERNET_MAX_PATH_LENGTH + 1]; + WCHAR wzQueryString[INTERNET_MAX_PATH_LENGTH + 1]; + + components.dwStructSize = sizeof(URL_COMPONENTSW); + + if (psczHostName) + { + components.lpszHostName = wzHostName; + components.dwHostNameLength = countof(wzHostName); + } + + if (psczUser) + { + components.lpszUserName = wzUserName; + components.dwUserNameLength = countof(wzUserName); + } + + if (psczPassword) + { + components.lpszPassword = wzPassword; + components.dwPasswordLength = countof(wzPassword); + } + + if (psczPath) + { + components.lpszUrlPath = wzPath; + components.dwUrlPathLength = countof(wzPath); + } + + if (psczQueryString) + { + components.lpszExtraInfo = wzQueryString; + components.dwExtraInfoLength = countof(wzQueryString); + } + + if (!::InternetCrackUrlW(wzUri, 0, ICU_DECODE | ICU_ESCAPE, &components)) + { + UriExitWithLastError(hr, "Failed to crack URI."); + } + + if (pScheme) + { + *pScheme = components.nScheme; + } + + if (psczHostName) + { + hr = StrAllocString(psczHostName, components.lpszHostName, components.dwHostNameLength); + UriExitOnFailure(hr, "Failed to copy host name."); + } + + if (pPort) + { + *pPort = components.nPort; + } + + if (psczUser) + { + hr = StrAllocString(psczUser, components.lpszUserName, components.dwUserNameLength); + UriExitOnFailure(hr, "Failed to copy user name."); + } + + if (psczPassword) + { + hr = StrAllocString(psczPassword, components.lpszPassword, components.dwPasswordLength); + UriExitOnFailure(hr, "Failed to copy password."); + } + + if (psczPath) + { + hr = StrAllocString(psczPath, components.lpszUrlPath, components.dwUrlPathLength); + UriExitOnFailure(hr, "Failed to copy path."); + } + + if (psczQueryString) + { + hr = StrAllocString(psczQueryString, components.lpszExtraInfo, components.dwExtraInfoLength); + UriExitOnFailure(hr, "Failed to copy query string."); + } + +LExit: + return hr; +} + + +// +// UriCrackEx - cracks a URI into URI_INFO. +// +extern "C" HRESULT DAPI UriCrackEx( + __in_z LPCWSTR wzUri, + __in URI_INFO* pUriInfo + ) +{ + HRESULT hr = S_OK; + + hr = UriCrack(wzUri, &pUriInfo->scheme, &pUriInfo->sczHostName, &pUriInfo->port, &pUriInfo->sczUser, &pUriInfo->sczPassword, &pUriInfo->sczPath, &pUriInfo->sczQueryString); + UriExitOnFailure(hr, "Failed to crack URI."); + +LExit: + return hr; +} + + +// +// UriInfoUninitialize - frees the memory in a URI_INFO struct. +// +extern "C" void DAPI UriInfoUninitialize( + __in URI_INFO* pUriInfo + ) +{ + ReleaseStr(pUriInfo->sczHostName); + ReleaseStr(pUriInfo->sczUser); + ReleaseStr(pUriInfo->sczPassword); + ReleaseStr(pUriInfo->sczPath); + ReleaseStr(pUriInfo->sczQueryString); + memset(pUriInfo, 0, sizeof(URI_INFO)); +} + + +// +// UriCreate - creates a URI from constituent parts. +// +extern "C" HRESULT DAPI UriCreate( + __inout_z LPWSTR* psczUri, + __in INTERNET_SCHEME scheme, + __in_z_opt LPWSTR wzHostName, + __in INTERNET_PORT port, + __in_z_opt LPWSTR wzUser, + __in_z_opt LPWSTR wzPassword, + __in_z_opt LPWSTR wzPath, + __in_z_opt LPWSTR wzQueryString + ) +{ + HRESULT hr = S_OK; + WCHAR wz[INTERNET_MAX_URL_LENGTH] = { }; + DWORD cch = countof(wz); + URL_COMPONENTSW components = { }; + + components.dwStructSize = sizeof(URL_COMPONENTSW); + components.nScheme = scheme; + components.lpszHostName = wzHostName; + components.nPort = port; + components.lpszUserName = wzUser; + components.lpszPassword = wzPassword; + components.lpszUrlPath = wzPath; + components.lpszExtraInfo = wzQueryString; + + if (!::InternetCreateUrlW(&components, ICU_ESCAPE, wz, &cch)) + { + UriExitWithLastError(hr, "Failed to create URI."); + } + + hr = StrAllocString(psczUri, wz, cch); + UriExitOnFailure(hr, "Failed copy created URI."); + +LExit: + return hr; +} + + +// +// UriGetServerAndResource - gets the server and resource as independent strings from a URI. +// +// NOTE: This function is useful for the InternetConnect/HttpRequest APIs. +// +extern "C" HRESULT DAPI UriGetServerAndResource( + __in_z LPCWSTR wzUri, + __out_z LPWSTR* psczServer, + __out_z LPWSTR* psczResource + ) +{ + HRESULT hr = S_OK; + INTERNET_SCHEME scheme = INTERNET_SCHEME_UNKNOWN; + LPWSTR sczHostName = NULL; + INTERNET_PORT port = INTERNET_INVALID_PORT_NUMBER; + LPWSTR sczUser = NULL; + LPWSTR sczPassword = NULL; + LPWSTR sczPath = NULL; + LPWSTR sczQueryString = NULL; + + hr = UriCrack(wzUri, &scheme, &sczHostName, &port, &sczUser, &sczPassword, &sczPath, &sczQueryString); + UriExitOnFailure(hr, "Failed to crack URI."); + + hr = UriCreate(psczServer, scheme, sczHostName, port, sczUser, sczPassword, NULL, NULL); + UriExitOnFailure(hr, "Failed to allocate server URI."); + + hr = UriCreate(psczResource, INTERNET_SCHEME_UNKNOWN, NULL, INTERNET_INVALID_PORT_NUMBER, NULL, NULL, sczPath, sczQueryString); + UriExitOnFailure(hr, "Failed to allocate resource URI."); + +LExit: + ReleaseStr(sczQueryString); + ReleaseStr(sczPath); + ReleaseStr(sczPassword); + ReleaseStr(sczUser); + ReleaseStr(sczHostName); + + return hr; +} + + +// +// UriFile - returns the file part of the URI. +// +extern "C" HRESULT DAPI UriFile( + __deref_out_z LPWSTR* psczFile, + __in_z LPCWSTR wzUri + ) +{ + HRESULT hr = S_OK; + WCHAR wz[MAX_PATH + 1]; + DWORD cch = countof(wz); + URL_COMPONENTSW uc = { }; + + uc.dwStructSize = sizeof(uc); + uc.lpszUrlPath = wz; + uc.dwUrlPathLength = cch; + + if (!::InternetCrackUrlW(wzUri, 0, ICU_DECODE | ICU_ESCAPE, &uc)) + { + UriExitWithLastError(hr, "Failed to crack URI."); + } + + // Copy only the file name. Fortunately, PathFile() understands that + // forward slashes can be directory separators like backslashes. + hr = StrAllocString(psczFile, PathFile(wz), 0); + UriExitOnFailure(hr, "Failed to copy file name"); + +LExit: + return hr; +} + + +/******************************************************************* + UriProtocol - determines the protocol of a URI. + +********************************************************************/ +extern "C" HRESULT DAPI UriProtocol( + __in_z LPCWSTR wzUri, + __out URI_PROTOCOL* pProtocol + ) +{ + Assert(wzUri && *wzUri); + Assert(pProtocol); + + HRESULT hr = S_OK; + + if ((L'h' == wzUri[0] || L'H' == wzUri[0]) && + (L't' == wzUri[1] || L'T' == wzUri[1]) && + (L't' == wzUri[2] || L'T' == wzUri[2]) && + (L'p' == wzUri[3] || L'P' == wzUri[3]) && + (L's' == wzUri[4] || L'S' == wzUri[4]) && + L':' == wzUri[5] && + L'/' == wzUri[6] && + L'/' == wzUri[7]) + { + *pProtocol = URI_PROTOCOL_HTTPS; + } + else if ((L'h' == wzUri[0] || L'H' == wzUri[0]) && + (L't' == wzUri[1] || L'T' == wzUri[1]) && + (L't' == wzUri[2] || L'T' == wzUri[2]) && + (L'p' == wzUri[3] || L'P' == wzUri[3]) && + L':' == wzUri[4] && + L'/' == wzUri[5] && + L'/' == wzUri[6]) + { + *pProtocol = URI_PROTOCOL_HTTP; + } + else if ((L'f' == wzUri[0] || L'F' == wzUri[0]) && + (L't' == wzUri[1] || L'T' == wzUri[1]) && + (L'p' == wzUri[2] || L'P' == wzUri[2]) && + L':' == wzUri[3] && + L'/' == wzUri[4] && + L'/' == wzUri[5]) + { + *pProtocol = URI_PROTOCOL_FTP; + } + else if ((L'f' == wzUri[0] || L'F' == wzUri[0]) && + (L'i' == wzUri[1] || L'I' == wzUri[1]) && + (L'l' == wzUri[2] || L'L' == wzUri[2]) && + (L'e' == wzUri[3] || L'E' == wzUri[3]) && + L':' == wzUri[4] && + L'/' == wzUri[5] && + L'/' == wzUri[6]) + { + *pProtocol = URI_PROTOCOL_FILE; + } + else + { + *pProtocol = URI_PROTOCOL_UNKNOWN; + } + + return hr; +} + + +/******************************************************************* + UriRoot - returns the root of the path specified in the URI. + + examples: + file:///C:\path\path -> C:\ + file://server/share/path/path -> \\server\share + http://www.example.com/path/path -> http://www.example.com/ + ftp://ftp.example.com/path/path -> ftp://www.example.com/ + + NOTE: This function should only be used on cannonicalized URIs. + It does not cannonicalize itself. +********************************************************************/ +extern "C" HRESULT DAPI UriRoot( + __in_z LPCWSTR wzUri, + __out LPWSTR* ppwzRoot, + __out_opt URI_PROTOCOL* pProtocol + ) +{ + Assert(wzUri && *wzUri); + Assert(ppwzRoot); + + HRESULT hr = S_OK; + URI_PROTOCOL protocol = URI_PROTOCOL_UNKNOWN; + LPCWSTR pwcSlash = NULL; + + hr = UriProtocol(wzUri, &protocol); + UriExitOnFailure(hr, "Invalid URI."); + + switch (protocol) + { + case URI_PROTOCOL_FILE: + if (L'/' == wzUri[7]) // file path + { + if (((L'a' <= wzUri[8] && L'z' >= wzUri[8]) || (L'A' <= wzUri[8] && L'Z' >= wzUri[8])) && L':' == wzUri[9]) + { + hr = StrAlloc(ppwzRoot, 4); + UriExitOnFailure(hr, "Failed to allocate string for root of URI."); + *ppwzRoot[0] = wzUri[8]; + *ppwzRoot[1] = L':'; + *ppwzRoot[2] = L'\\'; + *ppwzRoot[3] = L'\0'; + } + else + { + hr = E_INVALIDARG; + UriExitOnFailure(hr, "Invalid file path in URI."); + } + } + else // UNC share + { + pwcSlash = wcschr(wzUri + 8, L'/'); + if (!pwcSlash) + { + hr = E_INVALIDARG; + UriExitOnFailure(hr, "Invalid server name in URI."); + } + else + { + hr = StrAllocString(ppwzRoot, L"\\\\", 64); + UriExitOnFailure(hr, "Failed to allocate string for root of URI."); + + pwcSlash = wcschr(pwcSlash + 1, L'/'); + if (pwcSlash) + { + hr = StrAllocConcat(ppwzRoot, wzUri + 8, pwcSlash - wzUri - 8); + UriExitOnFailure(hr, "Failed to add server/share to root of URI."); + } + else + { + hr = StrAllocConcat(ppwzRoot, wzUri + 8, 0); + UriExitOnFailure(hr, "Failed to add server/share to root of URI."); + } + + // replace all slashes with backslashes to be truly UNC. + for (LPWSTR pwc = *ppwzRoot; pwc && *pwc; ++pwc) + { + if (L'/' == *pwc) + { + *pwc = L'\\'; + } + } + } + } + break; + + case URI_PROTOCOL_FTP: + pwcSlash = wcschr(wzUri + 6, L'/'); + if (pwcSlash) + { + hr = StrAllocString(ppwzRoot, wzUri, pwcSlash - wzUri); + UriExitOnFailure(hr, "Failed allocate root from URI."); + } + else + { + hr = StrAllocString(ppwzRoot, wzUri, 0); + UriExitOnFailure(hr, "Failed allocate root from URI."); + } + break; + + case URI_PROTOCOL_HTTP: + pwcSlash = wcschr(wzUri + 7, L'/'); + if (pwcSlash) + { + hr = StrAllocString(ppwzRoot, wzUri, pwcSlash - wzUri); + UriExitOnFailure(hr, "Failed allocate root from URI."); + } + else + { + hr = StrAllocString(ppwzRoot, wzUri, 0); + UriExitOnFailure(hr, "Failed allocate root from URI."); + } + break; + + default: + hr = E_INVALIDARG; + UriExitOnFailure(hr, "Unknown URI protocol."); + } + + if (pProtocol) + { + *pProtocol = protocol; + } + +LExit: + return hr; +} + + +extern "C" HRESULT DAPI UriResolve( + __in_z LPCWSTR wzUri, + __in_opt LPCWSTR wzBaseUri, + __out LPWSTR* ppwzResolvedUri, + __out_opt URI_PROTOCOL* pResolvedProtocol + ) +{ + UNREFERENCED_PARAMETER(wzUri); + UNREFERENCED_PARAMETER(wzBaseUri); + UNREFERENCED_PARAMETER(ppwzResolvedUri); + UNREFERENCED_PARAMETER(pResolvedProtocol); + + HRESULT hr = E_NOTIMPL; +#if 0 + URI_PROTOCOL protocol = URI_PROTOCOL_UNKNOWN; + + hr = UriProtocol(wzUri, &protocol); + UriExitOnFailure(hr, "Failed to determine protocol for URL: %ls", wzUri); + + UriExitOnNull(ppwzResolvedUri, hr, E_INVALIDARG, "Failed to resolve URI, because no method of output was provided"); + + if (URI_PROTOCOL_UNKNOWN == protocol) + { + UriExitOnNull(wzBaseUri, hr, E_INVALIDARG, "Failed to resolve URI - base URI provided was NULL"); + + if (L'/' == *wzUri || L'\\' == *wzUri) + { + hr = UriRoot(wzBaseUri, ppwzResolvedUri, &protocol); + UriExitOnFailure(hr, "Failed to get root from URI: %ls", wzBaseUri); + + hr = StrAllocConcat(ppwzResolvedUri, wzUri, 0); + UriExitOnFailure(hr, "Failed to concat file to base URI."); + } + else + { + hr = UriProtocol(wzBaseUri, &protocol); + UriExitOnFailure(hr, "Failed to get protocol of base URI: %ls", wzBaseUri); + + LPCWSTR pwcFile = const_cast (UriFile(wzBaseUri)); + if (!pwcFile) + { + hr = E_INVALIDARG; + UriExitOnFailure(hr, "Failed to get file from base URI: %ls", wzBaseUri); + } + + hr = StrAllocString(ppwzResolvedUri, wzBaseUri, pwcFile - wzBaseUri); + UriExitOnFailure(hr, "Failed to allocate string for resolved URI."); + + hr = StrAllocConcat(ppwzResolvedUri, wzUri, 0); + UriExitOnFailure(hr, "Failed to concat file to resolved URI."); + } + } + else + { + hr = StrAllocString(ppwzResolvedUri, wzUri, 0); + UriExitOnFailure(hr, "Failed to copy resolved URI."); + } + + if (pResolvedProtocol) + { + *pResolvedProtocol = protocol; + } + +LExit: +#endif + return hr; +} -- cgit v1.2.3-55-g6feb