diff options
| author | Sean Hall <r.sean.hall@gmail.com> | 2018-12-16 21:19:24 -0600 |
|---|---|---|
| committer | Sean Hall <r.sean.hall@gmail.com> | 2018-12-16 21:20:40 -0600 |
| commit | 95a5a8f9efef02ddcec5b3f69be99a00d71a802a (patch) | |
| tree | f0a92b8e8e37e17af6053db11f1b8a7a532cd12c /src/ca/scahttpheader.cpp | |
| parent | aec6e9a4b21accd2e8aeb2cb36ad1cdc8f308f79 (diff) | |
| download | wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.tar.gz wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.tar.bz2 wix-95a5a8f9efef02ddcec5b3f69be99a00d71a802a.zip | |
Import implementation of IisCA from old repo's scasched/scaexec.
Diffstat (limited to 'src/ca/scahttpheader.cpp')
| -rw-r--r-- | src/ca/scahttpheader.cpp | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/src/ca/scahttpheader.cpp b/src/ca/scahttpheader.cpp new file mode 100644 index 00000000..a8fea796 --- /dev/null +++ b/src/ca/scahttpheader.cpp | |||
| @@ -0,0 +1,323 @@ | |||
| 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 | enum eHttpHeaderQuery { hhqName = 1, hhqParentType, hhqParentValue, hhqValue, hhqAttributes}; | ||
| 6 | |||
| 7 | static HRESULT AddHttpHeaderToList( | ||
| 8 | __in SCA_HTTP_HEADER** ppshhList | ||
| 9 | ); | ||
| 10 | |||
| 11 | |||
| 12 | void ScaHttpHeaderFreeList( | ||
| 13 | __in SCA_HTTP_HEADER* pshhList | ||
| 14 | ) | ||
| 15 | { | ||
| 16 | SCA_HTTP_HEADER* pshhDelete = pshhList; | ||
| 17 | while (pshhList) | ||
| 18 | { | ||
| 19 | pshhDelete = pshhList; | ||
| 20 | pshhList = pshhList->pshhNext; | ||
| 21 | |||
| 22 | MemFree(pshhDelete); | ||
| 23 | } | ||
| 24 | } | ||
| 25 | |||
| 26 | |||
| 27 | HRESULT ScaHttpHeaderRead( | ||
| 28 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 29 | __inout LPWSTR *ppwzCustomActionData | ||
| 30 | ) | ||
| 31 | { | ||
| 32 | Assert(ppshhList); | ||
| 33 | |||
| 34 | HRESULT hr = S_OK; | ||
| 35 | MSIHANDLE hRec; | ||
| 36 | LPWSTR pwzData = NULL; | ||
| 37 | SCA_HTTP_HEADER* pshh = NULL; | ||
| 38 | WCA_WRAPQUERY_HANDLE hWrapQuery = NULL; | ||
| 39 | |||
| 40 | hr = WcaBeginUnwrapQuery(&hWrapQuery, ppwzCustomActionData); | ||
| 41 | ExitOnFailure(hr, "Failed to unwrap query for ScaAppPoolRead"); | ||
| 42 | |||
| 43 | if (0 == WcaGetQueryRecords(hWrapQuery)) | ||
| 44 | { | ||
| 45 | WcaLog(LOGMSG_VERBOSE, "Skipping ScaHttpHeaderRead() - required tables not present."); | ||
| 46 | ExitFunction1(hr = S_FALSE); | ||
| 47 | } | ||
| 48 | |||
| 49 | // loop through all the HTTP headers | ||
| 50 | while (S_OK == (hr = WcaFetchWrappedRecord(hWrapQuery, &hRec))) | ||
| 51 | { | ||
| 52 | hr = AddHttpHeaderToList(ppshhList); | ||
| 53 | ExitOnFailure(hr, "failed to add http header to list"); | ||
| 54 | |||
| 55 | pshh = *ppshhList; | ||
| 56 | |||
| 57 | hr = WcaGetRecordInteger(hRec, hhqParentType, &(pshh->iParentType)); | ||
| 58 | ExitOnFailure(hr, "failed to get IIsHttpHeader.ParentType"); | ||
| 59 | |||
| 60 | hr = WcaGetRecordString(hRec, hhqParentValue, &pwzData); | ||
| 61 | ExitOnFailure(hr, "Failed to get IIsHttpHeader.ParentValue"); | ||
| 62 | hr = ::StringCchCopyW(pshh->wzParentValue, countof(pshh->wzParentValue), pwzData); | ||
| 63 | ExitOnFailure(hr, "Failed to copy IIsHttpHeader.ParentValue"); | ||
| 64 | |||
| 65 | hr = WcaGetRecordString(hRec, hhqName, &pwzData); | ||
| 66 | ExitOnFailure(hr, "Failed to get IIsHttpHeader.Name"); | ||
| 67 | hr = ::StringCchCopyW(pshh->wzName, countof(pshh->wzName), pwzData); | ||
| 68 | ExitOnFailure(hr, "Failed to copy IIsHttpHeader.Name"); | ||
| 69 | |||
| 70 | hr = WcaGetRecordString(hRec, hhqValue, &pwzData); | ||
| 71 | ExitOnFailure(hr, "Failed to get IIsHttpHeader.Value"); | ||
| 72 | hr = ::StringCchCopyW(pshh->wzValue, countof(pshh->wzValue), pwzData); | ||
| 73 | ExitOnFailure(hr, "Failed to copy IIsHttpHeader.Value"); | ||
| 74 | |||
| 75 | hr = WcaGetRecordInteger(hRec, hhqAttributes, &(pshh->iAttributes)); | ||
| 76 | ExitOnFailure(hr, "failed to get IIsHttpHeader.Attributes"); | ||
| 77 | } | ||
| 78 | |||
| 79 | if (E_NOMOREITEMS == hr) | ||
| 80 | { | ||
| 81 | hr = S_OK; | ||
| 82 | } | ||
| 83 | ExitOnFailure(hr, "Failure while processing web errors"); | ||
| 84 | |||
| 85 | LExit: | ||
| 86 | WcaFinishUnwrapQuery(hWrapQuery); | ||
| 87 | |||
| 88 | ReleaseStr(pwzData); | ||
| 89 | |||
| 90 | return hr; | ||
| 91 | } | ||
| 92 | |||
| 93 | |||
| 94 | HRESULT ScaGetHttpHeader( | ||
| 95 | __in int iParentType, | ||
| 96 | __in LPCWSTR wzParentValue, | ||
| 97 | __in SCA_HTTP_HEADER** ppshhList, | ||
| 98 | __out SCA_HTTP_HEADER** ppshhOut | ||
| 99 | ) | ||
| 100 | { | ||
| 101 | HRESULT hr = S_OK; | ||
| 102 | SCA_HTTP_HEADER* pshhAdd = NULL; | ||
| 103 | SCA_HTTP_HEADER* pshhLast = NULL; | ||
| 104 | |||
| 105 | *ppshhOut = NULL; | ||
| 106 | |||
| 107 | if (!*ppshhList) | ||
| 108 | { | ||
| 109 | return hr; | ||
| 110 | } | ||
| 111 | |||
| 112 | SCA_HTTP_HEADER* pshh = *ppshhList; | ||
| 113 | while (pshh) | ||
| 114 | { | ||
| 115 | if (iParentType == pshh->iParentType && CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, 0, wzParentValue, -1, pshh->wzParentValue, -1)) | ||
| 116 | { | ||
| 117 | // Found a match, take this one out of the list and add it to the matched out list | ||
| 118 | pshhAdd = pshh; | ||
| 119 | |||
| 120 | if (pshhLast) | ||
| 121 | { | ||
| 122 | // If we're not at the beginning of the list tell the last node about it's new next (since we're taking away it's current next) | ||
| 123 | pshhLast->pshhNext = pshhAdd->pshhNext; | ||
| 124 | } | ||
| 125 | else | ||
| 126 | { | ||
| 127 | // If we are at the beginning (no pshhLast) update the beginning (since we're taking it) | ||
| 128 | *ppshhList = pshh->pshhNext; | ||
| 129 | } | ||
| 130 | pshh = pshh->pshhNext; // move on | ||
| 131 | |||
| 132 | // Add the one we've removed to the beginning of the out list | ||
| 133 | pshhAdd->pshhNext = *ppshhOut; | ||
| 134 | *ppshhOut = pshhAdd; | ||
| 135 | } | ||
| 136 | else | ||
| 137 | { | ||
| 138 | pshhLast = pshh; // remember the last we that didn't match | ||
| 139 | pshh = pshh->pshhNext; // move on | ||
| 140 | } | ||
| 141 | } | ||
| 142 | |||
| 143 | return hr; | ||
| 144 | } | ||
| 145 | |||
| 146 | |||
| 147 | HRESULT ScaWriteHttpHeader( | ||
| 148 | __in IMSAdminBase* piMetabase, | ||
| 149 | __in LPCWSTR wzRoot, | ||
| 150 | __in SCA_HTTP_HEADER* pshhList | ||
| 151 | ) | ||
| 152 | { | ||
| 153 | Assert(piMetabase && pshhList); | ||
| 154 | |||
| 155 | HRESULT hr = S_OK; | ||
| 156 | METADATA_RECORD mr = { 0 }; | ||
| 157 | DWORD cchData = 0; | ||
| 158 | LPWSTR pwzSearchKey = NULL; | ||
| 159 | LPWSTR pwz = NULL; | ||
| 160 | LPWSTR pwzHeaders = NULL; | ||
| 161 | LPWSTR pwzNewHeader = NULL; | ||
| 162 | DWORD dwFoundHeaderIndex = 0; | ||
| 163 | LPCWSTR wzFoundHeader = NULL; | ||
| 164 | BOOL fOldValueFound = FALSE; | ||
| 165 | |||
| 166 | ExitOnNull(wzRoot, hr, E_INVALIDARG, "Failed to write HTTP header, because no root was provided"); | ||
| 167 | |||
| 168 | Assert(*wzRoot); | ||
| 169 | |||
| 170 | // Check if HTTP header already exist here. | ||
| 171 | mr.dwMDIdentifier = MD_HTTP_CUSTOM; | ||
| 172 | mr.dwMDAttributes = METADATA_INHERIT; | ||
| 173 | mr.dwMDUserType = IIS_MD_UT_SERVER; | ||
| 174 | mr.dwMDDataType = ALL_METADATA; | ||
| 175 | mr.dwMDDataLen = cchData = 0; | ||
| 176 | mr.pbMDData = NULL; | ||
| 177 | |||
| 178 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, wzRoot, &mr); | ||
| 179 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr) | ||
| 180 | { | ||
| 181 | // | ||
| 182 | // If we don't have any HTTP Headers already, move up to get the parent headers. | ||
| 183 | // TODO: Make it configurable to not inherit HTTP Headers | ||
| 184 | // | ||
| 185 | hr = StrAllocConcat(&pwzSearchKey, wzRoot, 0); | ||
| 186 | ExitOnFailure(hr, "Failed to copy root string: %ls", wzRoot); | ||
| 187 | |||
| 188 | pwz = pwzSearchKey + lstrlenW(pwzSearchKey); | ||
| 189 | while (NULL == pwzHeaders) | ||
| 190 | { | ||
| 191 | // find the last slash | ||
| 192 | while (*pwz != '/' && pwz != pwzSearchKey) | ||
| 193 | { | ||
| 194 | --pwz; | ||
| 195 | } | ||
| 196 | |||
| 197 | if (pwz == pwzSearchKey) | ||
| 198 | { | ||
| 199 | break; | ||
| 200 | } | ||
| 201 | |||
| 202 | *pwz = L'\0'; | ||
| 203 | |||
| 204 | // Try here. If it's not found, keep walking up the path | ||
| 205 | hr = MetaGetValue(piMetabase, METADATA_MASTER_ROOT_HANDLE, pwzSearchKey, &mr); | ||
| 206 | if (HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND) == hr || MD_ERROR_DATA_NOT_FOUND == hr) | ||
| 207 | { | ||
| 208 | hr = S_FALSE; | ||
| 209 | } | ||
| 210 | ExitOnFailure(hr, "Failed to find search for HTTP headers for web root: %ls while walking up the tree", wzRoot); | ||
| 211 | |||
| 212 | if (S_OK == hr) | ||
| 213 | { | ||
| 214 | hr = StrAllocString(&pwzHeaders, reinterpret_cast<LPWSTR>(mr.pbMDData), 0); | ||
| 215 | ExitOnFailure(hr, "Failed to allocate parent HTTP header string"); | ||
| 216 | break; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | } | ||
| 220 | else | ||
| 221 | { | ||
| 222 | hr = StrAllocString(&pwzHeaders, reinterpret_cast<LPWSTR>(mr.pbMDData), 0); | ||
| 223 | ExitOnFailure(hr, "Failed to allocate HTTP header string"); | ||
| 224 | } | ||
| 225 | ExitOnFailure(hr, "Failed while searching for default HTTP headers to start with for web root: %ls", wzRoot); | ||
| 226 | |||
| 227 | // Loop through the HTTP headers | ||
| 228 | for (SCA_HTTP_HEADER* pshh = pshhList; pshh; pshh = pshh->pshhNext) | ||
| 229 | { | ||
| 230 | fOldValueFound = FALSE; // assume a HTTP Header match will not be found | ||
| 231 | |||
| 232 | hr = StrAllocFormatted(&pwzNewHeader, L"%s: ", pshh->wzName); | ||
| 233 | ExitOnFailure(hr, "Failed to allocate header name"); | ||
| 234 | |||
| 235 | if (NULL != pwzHeaders && *pwzHeaders) | ||
| 236 | { | ||
| 237 | // Try to find a matching header already in the list | ||
| 238 | hr = MultiSzFindSubstring(pwzHeaders, pwzNewHeader, &dwFoundHeaderIndex, &wzFoundHeader); | ||
| 239 | ExitOnFailure(hr, "Failed while searching for existing HTTP header."); | ||
| 240 | |||
| 241 | // If there was a substring HTTP header match, make sure the match was at the beginning | ||
| 242 | // of the string because that is the HTTP header name. | ||
| 243 | if (S_OK == hr) | ||
| 244 | { | ||
| 245 | DWORD cchMatch = lstrlenW(pwzNewHeader); | ||
| 246 | if (CSTR_EQUAL == ::CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, pwzNewHeader, cchMatch, wzFoundHeader, cchMatch)) | ||
| 247 | { | ||
| 248 | fOldValueFound = TRUE; | ||
| 249 | break; | ||
| 250 | } | ||
| 251 | } | ||
| 252 | } | ||
| 253 | |||
| 254 | // Add the value on to the header name now. | ||
| 255 | hr = StrAllocConcat(&pwzNewHeader, pshh->wzValue, 0); | ||
| 256 | ExitOnFailure(hr, "Failed to add value on to HTTP header name."); | ||
| 257 | |||
| 258 | // If we have something to replace, replace it, otherwise, put it at the beginning (order shouldn't matter) | ||
| 259 | if (fOldValueFound) | ||
| 260 | { | ||
| 261 | if (NULL == pwzHeaders) | ||
| 262 | { | ||
| 263 | ExitOnFailure(hr = E_INVALIDARG, "While attempting to replace old HTTP header with new HTTP header, it was discovered that the old HTTP header was NULL!"); | ||
| 264 | } | ||
| 265 | hr = MultiSzReplaceString(&pwzHeaders, dwFoundHeaderIndex, pwzNewHeader); | ||
| 266 | ExitOnFailure(hr, "Failed to replace old HTTP header with new HTTP header"); | ||
| 267 | } | ||
| 268 | else | ||
| 269 | { | ||
| 270 | hr = MultiSzPrepend(&pwzHeaders, NULL, pwzNewHeader); | ||
| 271 | ExitOnFailure(hr, "Failed to prepend new HTTP header"); | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | // now write the HttpCustom to the metabase | ||
| 276 | hr = ScaWriteMetabaseValue(piMetabase, wzRoot, NULL, MD_HTTP_CUSTOM, METADATA_INHERIT, IIS_MD_UT_FILE, MULTISZ_METADATA, pwzHeaders); | ||
| 277 | ExitOnFailure(hr, "Failed to write HTTP Headers to metabase"); | ||
| 278 | |||
| 279 | LExit: | ||
| 280 | MetaFreeValue(&mr); | ||
| 281 | |||
| 282 | ReleaseStr(pwzNewHeader); | ||
| 283 | ReleaseStr(pwzHeaders); | ||
| 284 | ReleaseStr(pwzSearchKey); | ||
| 285 | |||
| 286 | return hr; | ||
| 287 | } | ||
| 288 | |||
| 289 | |||
| 290 | HRESULT ScaHttpHeaderCheckList( | ||
| 291 | __in SCA_HTTP_HEADER* pshhList | ||
| 292 | ) | ||
| 293 | { | ||
| 294 | if (!pshhList) | ||
| 295 | { | ||
| 296 | return S_OK; | ||
| 297 | } | ||
| 298 | |||
| 299 | while (pshhList) | ||
| 300 | { | ||
| 301 | WcaLog(LOGMSG_STANDARD, "Http Header: %ls for parent: %ls not used!", pshhList->wzName, pshhList->wzParentValue); | ||
| 302 | pshhList = pshhList->pshhNext; | ||
| 303 | } | ||
| 304 | |||
| 305 | return E_FAIL; | ||
| 306 | } | ||
| 307 | |||
| 308 | |||
| 309 | static HRESULT AddHttpHeaderToList( | ||
| 310 | __in SCA_HTTP_HEADER** ppshhList | ||
| 311 | ) | ||
| 312 | { | ||
| 313 | HRESULT hr = S_OK; | ||
| 314 | |||
| 315 | SCA_HTTP_HEADER* pshh = static_cast<SCA_HTTP_HEADER*>(MemAlloc(sizeof(SCA_HTTP_HEADER), TRUE)); | ||
| 316 | ExitOnNull(pshh, hr, E_OUTOFMEMORY, "failed to allocate memory for new http header list element"); | ||
| 317 | |||
| 318 | pshh->pshhNext = *ppshhList; | ||
| 319 | *ppshhList = pshh; | ||
| 320 | |||
| 321 | LExit: | ||
| 322 | return hr; | ||
| 323 | } | ||
