Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1839 lines
50 KiB

  1. /*++
  2. Copyright (c) 1995-1997 Microsoft Corporation
  3. Module Name :
  4. w3meta.cxx
  5. Abstract:
  6. Defines the functions for W3_METADATA
  7. Author:
  8. IIS Core Team 1997
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. W3 Service DLL
  13. Revision History:
  14. --*/
  15. /************************************************************
  16. * Include Headers
  17. ************************************************************/
  18. #include "w3p.hxx"
  19. #include <inetinfo.h>
  20. #include "basereq.hxx"
  21. #include <lonsi.hxx>
  22. #define SET_WIN32_ERR(p,x) { (p)->IsValid = TRUE; \
  23. (p)->ErrorReason = METADATA_ERROR_WIN32;\
  24. (p)->Win32Error = (x); \
  25. }
  26. #define SET_VALUE_ERR(x) { (x)->IsValid = TRUE; \
  27. (x)->ErrorReason = METADATA_ERROR_VALUE;\
  28. }
  29. /************************************************************
  30. * Functions
  31. ************************************************************/
  32. BOOL
  33. W3_METADATA::BuildCustomErrorTable(
  34. CHAR *pszErrorList,
  35. PMETADATA_ERROR_INFO pMDErrorInfo
  36. )
  37. /*++
  38. Description:
  39. Take an input string and build a custom error table out of it. The
  40. input string is a multi-sz, where each string is of the form error,
  41. suberror, {FILE | URL}, path.
  42. Arguments:
  43. pszErrorList - Pointer to the error list.
  44. Returns:
  45. TRUE if we built the table successfully, FALSE otherwise.
  46. --*/
  47. {
  48. CHAR *pszType;
  49. CHAR *pszSubError;
  50. CHAR *pszPath;
  51. CHAR *pszNewPath;
  52. CHAR cTemp;
  53. DWORD dwError;
  54. DWORD dwSubError;
  55. BOOL bWildcardSubError;
  56. BOOL bIsFile;
  57. PCUSTOM_ERROR_ENTRY pNewEntry;
  58. DWORD dwPathLength;
  59. for (;;)
  60. {
  61. // Convert the first parameter to a number.
  62. dwError = atoi(pszErrorList);
  63. if (dwError < 300)
  64. {
  65. SET_VALUE_ERR(pMDErrorInfo);
  66. SetLastError( ERROR_INVALID_DATA );
  67. return FALSE;
  68. }
  69. // Now convert the second parameter (the suberror) to a number.
  70. pszSubError = strchr(pszErrorList, ',');
  71. if (pszSubError == NULL)
  72. {
  73. SET_VALUE_ERR(pMDErrorInfo);
  74. SetLastError( ERROR_INVALID_DATA );
  75. return FALSE;
  76. }
  77. pszSubError++;
  78. while (isspace((UCHAR)(*pszSubError)))
  79. {
  80. pszSubError++;
  81. }
  82. if (*pszSubError == '*')
  83. {
  84. bWildcardSubError = TRUE;
  85. dwSubError = 0;
  86. }
  87. else
  88. {
  89. if (!isdigit((UCHAR)(*pszSubError)))
  90. {
  91. SET_VALUE_ERR(pMDErrorInfo);
  92. return FALSE;
  93. }
  94. dwSubError = atoi(pszSubError);
  95. bWildcardSubError = FALSE;
  96. }
  97. // Now find the comma that seperates the number and the type.
  98. pszType = strchr(pszSubError, ',');
  99. if (pszType == NULL)
  100. {
  101. // Didn't find it.
  102. SET_VALUE_ERR(pMDErrorInfo);
  103. SetLastError( ERROR_INVALID_DATA );
  104. return FALSE;
  105. }
  106. pszType++;
  107. // Skip any preceding ws.
  108. while (isspace((UCHAR)(*pszType)))
  109. {
  110. pszType++;
  111. }
  112. // We found the end of ws. If this isn't an alphabetic character, it's
  113. // an error. If it is, find the end of the alpha. chars.
  114. if (!isalpha((UCHAR)(*pszType)))
  115. {
  116. SET_VALUE_ERR(pMDErrorInfo);
  117. SetLastError( ERROR_INVALID_DATA );
  118. return FALSE;
  119. }
  120. pszPath = pszType;
  121. while (isalpha((UCHAR)(*pszPath)))
  122. {
  123. pszPath++;
  124. }
  125. cTemp = *pszPath;
  126. *pszPath = '\0';
  127. // Now see what the parameter is.
  128. if (!_stricmp(pszType, "FILE"))
  129. {
  130. bIsFile = TRUE;
  131. }
  132. else
  133. {
  134. if (!_stricmp(pszType, "URL"))
  135. {
  136. bIsFile = FALSE;
  137. }
  138. else
  139. {
  140. *pszPath = cTemp;
  141. SET_VALUE_ERR(pMDErrorInfo);
  142. SetLastError( ERROR_INVALID_DATA );
  143. return FALSE;
  144. }
  145. }
  146. *pszPath = cTemp;
  147. // Now find the comma that seperates the type from the URL/path.
  148. pszPath = strchr(pszPath, ',');
  149. if (pszPath == NULL)
  150. {
  151. SET_VALUE_ERR(pMDErrorInfo);
  152. SetLastError( ERROR_INVALID_DATA );
  153. return FALSE;
  154. }
  155. // Found the comma. Go one past and find the path or URL.
  156. pszPath++;
  157. while (isspace((UCHAR)(*pszPath)))
  158. {
  159. pszPath++;
  160. }
  161. if (*pszPath == '\0')
  162. {
  163. SET_VALUE_ERR(pMDErrorInfo);
  164. SetLastError( ERROR_INVALID_DATA );
  165. return FALSE;
  166. }
  167. dwPathLength = strlen(pszPath) + 1;
  168. pszNewPath = (CHAR *)TCP_ALLOC(dwPathLength);
  169. if (pszNewPath == NULL)
  170. {
  171. SET_VALUE_ERR(pMDErrorInfo);
  172. SetLastError( ERROR_INVALID_DATA );
  173. return FALSE;
  174. }
  175. memcpy(pszNewPath, pszPath, dwPathLength);
  176. pNewEntry = new CUSTOM_ERROR_ENTRY(dwError, dwSubError,
  177. bWildcardSubError, pszNewPath, bIsFile);
  178. if (pNewEntry == NULL)
  179. {
  180. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  181. TCP_FREE(pszNewPath);
  182. return FALSE;
  183. }
  184. // Insert wildcard errors at the end, and specific errors at the
  185. // begining, so that specific errors have priority.
  186. if (bWildcardSubError)
  187. {
  188. InsertTailList(&m_CustomErrorHead, &pNewEntry->_ListEntry );
  189. }
  190. else
  191. {
  192. InsertHeadList(&m_CustomErrorHead, &pNewEntry->_ListEntry );
  193. }
  194. pszErrorList = pszPath + dwPathLength;
  195. if (*pszErrorList == '\0')
  196. {
  197. return TRUE;
  198. }
  199. }
  200. }
  201. VOID
  202. W3_METADATA::DestroyCustomErrorTable(
  203. VOID
  204. )
  205. /*++
  206. Description:
  207. Destroy the custom error table for this metadata.
  208. Arguments:
  209. Returns:
  210. --*/
  211. {
  212. LIST_ENTRY *pEntry;
  213. PCUSTOM_ERROR_ENTRY pErrorEntry;
  214. while ( !IsListEmpty( &m_CustomErrorHead ))
  215. {
  216. pErrorEntry = CONTAINING_RECORD( m_CustomErrorHead.Flink,
  217. CUSTOM_ERROR_ENTRY,
  218. _ListEntry );
  219. RemoveEntryList( &pErrorEntry->_ListEntry );
  220. delete pErrorEntry;
  221. }
  222. }
  223. /*******************************************************************
  224. NAME: CompactParameters
  225. SYNOPSIS: Reads a metadata multisz set of comma seperated
  226. strings, and copies this into a BUFFER while stripping
  227. whitespace. There can be multiple lines.
  228. ENTRY: bufDest - Pointer to BUFFER to copy into.
  229. pszSrc - Source string.
  230. dwNumParam - Number of paramters to retrieve.
  231. fFlags - Bit field, indicating which parameters
  232. are to have white space stripped.
  233. RETURNS: TRUE if successful, FALSE if an error occurred.
  234. NOTES:
  235. ********************************************************************/
  236. BOOL
  237. CompactParameters(
  238. BUFFER *bufDest,
  239. CHAR *pszSrc,
  240. DWORD dwNumParam,
  241. DWORD fFlags,
  242. PMETADATA_ERROR_INFO pMDErrorInfo
  243. )
  244. {
  245. DWORD dwParamFound;
  246. CHAR *pszCurrent;
  247. BOOL bFirst;
  248. DWORD dwBytesCopied;
  249. DWORD dwBufferSize;
  250. CHAR *pszBuffer;
  251. DWORD fWSFlags;
  252. DBG_ASSERT(pszSrc != NULL);
  253. // Go through each line, looking for dwNumParam parameters. When we find
  254. // that many, go to end of line, and start again. If we don't find
  255. // enough parameters in a line, fail.
  256. dwParamFound = 0;
  257. dwBytesCopied = 0;
  258. bFirst = TRUE;
  259. fWSFlags = fFlags;
  260. dwBufferSize = bufDest->QuerySize();
  261. pszBuffer = (CHAR *)bufDest->QueryPtr();
  262. for (;;)
  263. {
  264. DWORD dwBytesNeeded;
  265. while (isspace((UCHAR)(*pszSrc)))
  266. {
  267. pszSrc++;
  268. }
  269. if (*pszSrc == '\0')
  270. {
  271. // Didn't find enough.
  272. SET_VALUE_ERR(pMDErrorInfo);
  273. return FALSE;
  274. }
  275. // Now scan this parameter, looking for either WS or a comma,
  276. // depending on fWSFlags.
  277. pszCurrent = pszSrc;
  278. while (*pszSrc != ',' && ( (fWSFlags & 1) ? TRUE : !isspace((UCHAR)(*pszSrc))) &&
  279. *pszSrc != '\0')
  280. {
  281. pszSrc++;
  282. }
  283. dwParamFound++;
  284. // Now pszSrc points at the character that terminated our parameter.
  285. // Make sure we have enough room to copy this.
  286. dwBytesNeeded = DIFF(pszSrc - pszCurrent) + (bFirst ? 0 : sizeof(CHAR)) +
  287. ((dwParamFound != dwNumParam) ? 0 : sizeof(CHAR));
  288. if ((dwBufferSize - dwBytesCopied) < dwBytesNeeded)
  289. {
  290. if (!bufDest->Resize(dwBytesCopied + dwBytesNeeded + 32))
  291. {
  292. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  293. return FALSE;
  294. }
  295. dwBufferSize = bufDest->QuerySize();
  296. pszBuffer = (CHAR *)bufDest->QueryPtr();
  297. }
  298. if (!bFirst)
  299. {
  300. *(pszBuffer + dwBytesCopied) = ',';
  301. dwBytesCopied++;
  302. }
  303. memcpy(pszBuffer + dwBytesCopied, pszCurrent, DIFF(pszSrc - pszCurrent));
  304. dwBytesCopied += DIFF(pszSrc - pszCurrent);
  305. bFirst = FALSE;
  306. fWSFlags >>= 1;
  307. if (dwParamFound == dwNumParam)
  308. {
  309. // Found all we need on this line, look for the next.
  310. *(pszBuffer + dwBytesCopied) = '\0';
  311. dwBytesCopied++;
  312. bFirst = TRUE;
  313. fWSFlags = fFlags;
  314. dwParamFound = 0;
  315. while (*pszSrc != '\0')
  316. {
  317. pszSrc++;
  318. }
  319. // Move to start of next line.
  320. pszSrc++;
  321. if (*pszSrc == '\0')
  322. {
  323. // Found end of multisz. Terminate buffer and return.
  324. break;
  325. }
  326. }
  327. else
  328. {
  329. // Otherwise, still have more parameters to find on this line.
  330. while (*pszSrc != ',')
  331. {
  332. if (*pszSrc == '\0')
  333. {
  334. if (dwNumParam != 0xffffffff)
  335. {
  336. SET_VALUE_ERR(pMDErrorInfo);
  337. SetLastError( ERROR_INVALID_DATA );
  338. return FALSE;
  339. }
  340. // Copying an unknown number, so terminate the line now.
  341. if ((dwBufferSize - dwBytesCopied) == 0)
  342. {
  343. if (!bufDest->Resize(dwBytesCopied + 32))
  344. {
  345. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  346. return FALSE;
  347. }
  348. dwBufferSize = bufDest->QuerySize();
  349. pszBuffer = (CHAR *)bufDest->QueryPtr();
  350. }
  351. *(pszBuffer + dwBytesCopied) = '\0';
  352. dwBytesCopied++;
  353. bFirst = TRUE;
  354. fWSFlags = fFlags;
  355. dwParamFound = 0;
  356. break;
  357. }
  358. else
  359. {
  360. pszSrc++;
  361. }
  362. }
  363. if (*pszSrc == '\0')
  364. {
  365. // We broke out of the loop because we hit the end of the
  366. // line on a 'read all' string.
  367. if (*(pszSrc + 1) == '\0')
  368. {
  369. // Hit the end of a multisz.
  370. break;
  371. }
  372. }
  373. pszSrc++;
  374. }
  375. }
  376. // We get here when we've copied all of the buffer. Terminate the multisz
  377. // and we're done.
  378. if ((dwBufferSize - dwBytesCopied) == 0)
  379. {
  380. if (!bufDest->Resize(dwBytesCopied + 1))
  381. {
  382. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  383. return FALSE;
  384. }
  385. pszBuffer = (CHAR *)bufDest->QueryPtr();
  386. }
  387. *(pszBuffer + dwBytesCopied) = '\0';
  388. return TRUE;
  389. }
  390. BOOL
  391. W3_METADATA::ReadCustomFooter(
  392. CHAR *pszFooter,
  393. TSVC_CACHE &Cache,
  394. HANDLE User,
  395. PMETADATA_ERROR_INFO pMDErrorInfo
  396. )
  397. /*++
  398. Routine Description:
  399. Process a footer string, either reading the file or copying the string
  400. to the buffer.
  401. Arguments:
  402. pszFooter - The footer string, which may be a string or a file name.
  403. Cache - Cache info for opening file
  404. User - Token for opening user
  405. Returns:
  406. TRUE if we succeed, FALSE if we don't.
  407. --*/
  408. {
  409. BOOL bIsString;
  410. DWORD dwLength;
  411. STACK_STR(strError, 128);
  412. if (!FooterEnabled())
  413. {
  414. return TRUE;
  415. }
  416. // First thing to do is to determine if this is a string or a file name.
  417. // Skip preceding whitespace and then strcmp.
  418. while (isspace((UCHAR)(*pszFooter)))
  419. {
  420. pszFooter++;
  421. }
  422. if (!_strnicmp(pszFooter, "STRING", sizeof("STRING") - 1))
  423. {
  424. bIsString = TRUE;
  425. pszFooter += sizeof("STRING") - 1;
  426. }
  427. else
  428. {
  429. if (!_strnicmp(pszFooter, "FILE", sizeof("FILE") - 1))
  430. {
  431. bIsString = FALSE;
  432. pszFooter += sizeof("FILE") - 1;
  433. }
  434. else
  435. {
  436. SET_VALUE_ERR(pMDErrorInfo);
  437. SetLastError( ERROR_INVALID_DATA );
  438. return FALSE;
  439. }
  440. }
  441. // Now we look for 0 or more white space, followed by a colon, followed by
  442. // more white space.
  443. while (isspace((UCHAR)(*pszFooter)))
  444. {
  445. pszFooter++;
  446. }
  447. if (*pszFooter != ':')
  448. {
  449. // No colon seperator, error.
  450. SET_VALUE_ERR(pMDErrorInfo);
  451. SetLastError( ERROR_INVALID_DATA );
  452. return FALSE;
  453. }
  454. pszFooter++;
  455. //
  456. // OK, now if this is a string we take everything after the colon to the
  457. // end for the string. If this is a file name then we'll open and read the
  458. // file.
  459. //
  460. if (bIsString)
  461. {
  462. dwLength = strlen(pszFooter);
  463. if (!m_bufFooter.Resize(dwLength))
  464. {
  465. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  466. return FALSE;
  467. }
  468. memcpy(m_bufFooter.QueryPtr(), pszFooter, dwLength);
  469. }
  470. else
  471. {
  472. //
  473. // For files, we'll skip any more white space before the name.
  474. //
  475. while (isspace((UCHAR)(*pszFooter)))
  476. {
  477. pszFooter++;
  478. }
  479. if (!ReadEntireFile(pszFooter, Cache, User ,&m_bufFooter, &dwLength))
  480. {
  481. // Couldn't read the file, so instead we'll read the error
  482. // string and use that.
  483. if ( g_pInetSvc->LoadStr( strError, IDS_ERROR_FOOTER ))
  484. {
  485. dwLength = strError.QueryCB();
  486. if (!m_bufFooter.Resize(dwLength))
  487. {
  488. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  489. return FALSE;
  490. }
  491. memcpy(m_bufFooter.QueryPtr(), strError.QueryStr(), dwLength);
  492. }
  493. else
  494. {
  495. // Couldn't read the error string, so fail.
  496. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  497. return FALSE;
  498. }
  499. }
  500. }
  501. SetFooter(dwLength, (CHAR *)m_bufFooter.QueryPtr());
  502. return TRUE;
  503. }
  504. #define SIZEOF_EXPIRE_HEADER sizeof("Expires: \r\n")
  505. #define SIZEOF_GMT_DATETIME 64
  506. #define SIZEOF_CACHE_CONTROL (sizeof("Cache-Control: max-age=4294967295\r\n") - 1)
  507. BOOL
  508. W3_METADATA::SetExpire(
  509. CHAR* pszExpire,
  510. PMETADATA_ERROR_INFO pMDErrorInfo
  511. )
  512. /*++
  513. Routine Description:
  514. Set metadata based on MD_HTTP_EXPIRES entry
  515. Arguments:
  516. pszExpire - expire configuration
  517. Return value:
  518. TRUE if success, otherwise FALSE
  519. --*/
  520. {
  521. DWORD dwExpires;
  522. LPSTR pszParam;
  523. CHAR *EndPtr;
  524. while (isspace((UCHAR)(*pszExpire)))
  525. {
  526. pszExpire++;
  527. }
  528. if ( !(pszParam = strchr( pszExpire, ',' )) )
  529. {
  530. if (*pszExpire == '\0' || toupper(*pszExpire) == 'N')
  531. {
  532. m_dwExpireMode = EXPIRE_MODE_OFF;
  533. return TRUE;
  534. }
  535. SET_VALUE_ERR(pMDErrorInfo);
  536. SetLastError( ERROR_INVALID_DATA );
  537. return FALSE;
  538. }
  539. ++pszParam;
  540. while (isspace((UCHAR)(*pszParam)))
  541. {
  542. pszParam++;
  543. }
  544. switch ( *(CHAR*)pszExpire )
  545. {
  546. case 's': case 'S':
  547. if ( !m_strExpireHeader.Copy( "Expires: " ) ||
  548. !m_strExpireHeader.Append( pszParam ) ||
  549. !m_strExpireHeader.Append( "\r\n" ) )
  550. {
  551. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  552. return FALSE;
  553. }
  554. m_dwExpireMaxLength = m_strExpireHeader.QueryCCH() +
  555. SIZEOF_CACHE_CONTROL;
  556. m_dwExpireMode = EXPIRE_MODE_STATIC;
  557. if ( !StringTimeToFileTime( pszParam,
  558. &m_liExpireTime ))
  559. {
  560. m_liExpireTime.QuadPart = 0;
  561. }
  562. break;
  563. case 'd': case 'D':
  564. dwExpires = strtoul(pszParam,&EndPtr,0);
  565. if (!isspace((UCHAR)(*EndPtr)) && *EndPtr != '\0')
  566. {
  567. SET_VALUE_ERR(pMDErrorInfo);
  568. return FALSE;
  569. }
  570. if ( dwExpires != NO_GLOBAL_EXPIRE )
  571. {
  572. if (dwExpires > MAX_GLOBAL_EXPIRE )
  573. {
  574. dwExpires = MAX_GLOBAL_EXPIRE;
  575. }
  576. m_dwExpireMode = EXPIRE_MODE_DYNAMIC;
  577. m_dwExpireDelta = dwExpires;
  578. m_dwExpireMaxLength = SIZEOF_EXPIRE_HEADER + SIZEOF_GMT_DATETIME;
  579. }
  580. break;
  581. case 'n': case 'N':
  582. m_dwExpireMode = EXPIRE_MODE_OFF;
  583. break;
  584. default:
  585. SET_VALUE_ERR(pMDErrorInfo);
  586. SetLastError( ERROR_INVALID_DATA );
  587. return FALSE;
  588. }
  589. return TRUE;
  590. }
  591. #define RMD_ASSERT(x) if (!(x)) { pMDErrorInfo->IsValid = TRUE; \
  592. pMDErrorInfo->ErrorParameter = pMDRecord->dwMDIdentifier; \
  593. pMDErrorInfo->ErrorReason = METADATA_ERROR_TYPE;\
  594. SetLastError(ERROR_INVALID_PARAMETER);\
  595. return FALSE; \
  596. }
  597. BOOL
  598. W3_METADATA::HandlePrivateProperty(
  599. LPSTR pszURL,
  600. PIIS_SERVER_INSTANCE pInstance,
  601. METADATA_GETALL_INTERNAL_RECORD *pMDRecord,
  602. PVOID pDataPointer,
  603. BUFFER *pBuffer,
  604. DWORD *pdwBytesUsed,
  605. PMETADATA_ERROR_INFO pMDErrorInfo
  606. )
  607. /*++
  608. Routine Description:
  609. Handle metadata properties specific to W3
  610. Arguments:
  611. pszURL - URL for which we are reading metadata
  612. pInstance - current w3 instance
  613. pMDRecord - metadata record to process
  614. pDataPointer - data associated with pMDRecord
  615. Return value:
  616. TRUE if success, otherwise FALSE
  617. --*/
  618. {
  619. BUFFER bufTemp1;
  620. PW3_METADATA_INFO pMDInfo;
  621. CHAR *pszStart;
  622. pMDErrorInfo->ErrorParameter = pMDRecord->dwMDIdentifier;
  623. if (*pdwBytesUsed == 0)
  624. {
  625. if (!pBuffer->Resize(sizeof(W3_METADATA_INFO)))
  626. {
  627. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  628. return FALSE;
  629. }
  630. *pdwBytesUsed = sizeof(W3_METADATA_INFO);
  631. }
  632. switch( pMDRecord->dwMDIdentifier )
  633. {
  634. CHAR *pszTemp;
  635. DWORD dwTemp;
  636. case MD_ANONYMOUS_USER_NAME:
  637. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  638. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  639. if ( *(CHAR*)pDataPointer == '\0' )
  640. {
  641. SET_VALUE_ERR(pMDErrorInfo);
  642. return FALSE;
  643. }
  644. if ( !SetAnonUserName( (CHAR *) pDataPointer ) ||
  645. !BuildAnonymousAcctDesc( QueryAuthentInfo() ))
  646. {
  647. return FALSE;
  648. }
  649. #if defined(CAL_ENABLED)
  650. CalExemptAddRef( (CHAR *) pDataPointer, &m_dwCalHnd );
  651. #endif
  652. break;
  653. case MD_ANONYMOUS_PWD:
  654. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  655. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  656. if ( !SetAnonUserPassword( (CHAR *) pDataPointer ) ||
  657. !BuildAnonymousAcctDesc( QueryAuthentInfo() ))
  658. {
  659. return FALSE;
  660. }
  661. break;
  662. case MD_ANONYMOUS_USE_SUBAUTH:
  663. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  664. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  665. // Win64 UNALIGNED pointer fix
  666. SetUseAnonSubAuth( *((UNALIGNED DWORD *) pDataPointer ));
  667. break;
  668. case MD_DEFAULT_LOGON_DOMAIN:
  669. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  670. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  671. if ( !SetDefaultLogonDomain( (CHAR *) pDataPointer ))
  672. {
  673. return FALSE;
  674. }
  675. break;
  676. case MD_LOGON_METHOD:
  677. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  678. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  679. //
  680. // The MD_LOGON_METHOD values in the metabase don't match the NT logon
  681. // values, so we'll convert them
  682. //
  683. // Win64 UNALIGNED pointer fix
  684. switch ( *((UNALIGNED DWORD *) pDataPointer ) )
  685. {
  686. case MD_LOGON_BATCH:
  687. SetLogonMethod( LOGON32_LOGON_BATCH );
  688. break;
  689. case MD_LOGON_INTERACTIVE:
  690. SetLogonMethod( LOGON32_LOGON_INTERACTIVE );
  691. break;
  692. case MD_LOGON_NETWORK:
  693. SetLogonMethod( LOGON32_LOGON_NETWORK );
  694. break;
  695. case MD_LOGON_NETWORK_CLEARTEXT:
  696. SetLogonMethod( LOGON32_LOGON_NETWORK_CLEARTEXT );
  697. break;
  698. default:
  699. return FALSE;
  700. }
  701. break;
  702. case MD_AUTHORIZATION:
  703. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  704. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  705. if ( QuerySingleAccessToken() )
  706. {
  707. // Win64 UNALIGNED pointer fix
  708. SetAuthentication( (*((UNALIGNED DWORD *) pDataPointer)&~MD_AUTH_BASIC ));
  709. }
  710. else
  711. {
  712. // Win64 UNALIGNED pointer fix
  713. SetAuthentication( *((UNALIGNED DWORD *) pDataPointer ));
  714. }
  715. break;
  716. case MD_AUTHORIZATION_PERSISTENCE:
  717. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  718. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  719. // Win64 UNALIGNED pointer fix
  720. SetAuthenticationPersistence( *((UNALIGNED DWORD *) pDataPointer ));
  721. break;
  722. case MD_REALM:
  723. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  724. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  725. if ( !SetRealm( (CHAR *)pDataPointer ))
  726. {
  727. return FALSE;
  728. }
  729. break;
  730. case MD_DEFAULT_LOAD_FILE:
  731. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  732. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  733. if (!QueryDefaultDocs()->Copy((const CHAR *)pDataPointer))
  734. {
  735. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  736. return FALSE;
  737. }
  738. break;
  739. case MD_DIRECTORY_BROWSING:
  740. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  741. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  742. // Win64 UNALIGNED pointer fix
  743. SetDirBrowseFlags( *((UNALIGNED DWORD *) pDataPointer ));
  744. break;
  745. case MD_MIME_MAP:
  746. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  747. RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
  748. if ( *((CHAR *)pDataPointer) )
  749. {
  750. if (!CompactParameters(QueryMimeMap(), (CHAR *)pDataPointer,
  751. 2, 0x2, pMDErrorInfo))
  752. {
  753. return FALSE;
  754. }
  755. }
  756. break;
  757. case MD_SCRIPT_MAPS:
  758. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  759. RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
  760. if ( *((CHAR *)pDataPointer) )
  761. {
  762. if (!CompactParameters(&bufTemp1, (CHAR *)pDataPointer, 0xffffffff,
  763. 0x02, pMDErrorInfo))
  764. {
  765. return FALSE;
  766. }
  767. if (!BuildExtMap((CHAR *)bufTemp1.QueryPtr()))
  768. {
  769. if (GetLastError() == ERROR_INVALID_DATA)
  770. {
  771. // Return the specific error that the script map is bad
  772. SET_VALUE_ERR(pMDErrorInfo);
  773. }
  774. else
  775. {
  776. // Handle other errors
  777. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  778. }
  779. return FALSE;
  780. }
  781. }
  782. break;
  783. case MD_HTTP_EXPIRES:
  784. // An Expires value. Range check it, and then format it and
  785. // save it in the metadata.
  786. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  787. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  788. return SetExpire( (CHAR*)pDataPointer, pMDErrorInfo );
  789. case MD_HTTP_PICS:
  790. case MD_HTTP_CUSTOM:
  791. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  792. RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
  793. // Copies these headers into our header structure. If it fails,
  794. // free our metadata and give up.
  795. pszStart = (CHAR *)pDataPointer;
  796. while ( *pszStart != '\0' )
  797. {
  798. DWORD dwLength;
  799. dwLength = strlen(pszStart);
  800. if ( !QueryHeaders()->Append( pszStart,
  801. dwLength ) ||
  802. !QueryHeaders()->Append( "\r\n",
  803. sizeof("\r\n") - 1) )
  804. {
  805. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  806. return FALSE;
  807. }
  808. pszStart += (dwLength + 1);
  809. }
  810. break;
  811. case MD_CREATE_PROCESS_AS_USER:
  812. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  813. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  814. // Win64 UNALIGNED pointer fix
  815. SetCreateProcessAsUser( *((UNALIGNED DWORD *) pDataPointer ));
  816. break;
  817. case MD_CREATE_PROC_NEW_CONSOLE:
  818. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  819. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  820. // Win64 UNALIGNED pointer fix
  821. SetCreateProcessNewConsole( *((UNALIGNED DWORD *) pDataPointer ));
  822. break;
  823. case MD_HTTP_REDIRECT:
  824. {
  825. STACK_STR( strRealSource, MAX_PATH );
  826. STACK_STR( strDestination, MAX_PATH );
  827. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  828. RMD_ASSERT( (pMDRecord->dwMDDataType == STRING_METADATA) ||
  829. (pMDRecord->dwMDDataType == MULTISZ_METADATA) );
  830. if ( !strDestination.Copy( (CHAR*) pDataPointer ) ||
  831. !GetTrueRedirectionSource( pszURL,
  832. pInstance,
  833. (CHAR*) pDataPointer,
  834. pMDRecord->dwMDDataType == STRING_METADATA,
  835. &strRealSource ) ||
  836. !SetRedirectionBlob( strRealSource,
  837. strDestination ) )
  838. {
  839. return FALSE;
  840. }
  841. if (pMDRecord->dwMDDataType == MULTISZ_METADATA)
  842. {
  843. // Have some conditional headers, add them now.
  844. //
  845. DBG_ASSERT(QueryRedirectionBlob() != NULL);
  846. if (!QueryRedirectionBlob()->SetConditionalHeaders(
  847. (CHAR *)pDataPointer + strlen((CHAR *)pDataPointer) + 1)
  848. )
  849. {
  850. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  851. return FALSE;
  852. }
  853. }
  854. break;
  855. }
  856. case MD_CUSTOM_ERROR:
  857. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  858. RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
  859. // Treat a NULL custom error string as not being present.
  860. if (*(CHAR *)pDataPointer == '\0')
  861. {
  862. break;
  863. }
  864. if (!BuildCustomErrorTable( (CHAR *) pDataPointer,pMDErrorInfo ))
  865. {
  866. return FALSE;
  867. }
  868. break;
  869. case MD_FOOTER_DOCUMENT:
  870. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  871. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  872. if (!ReadCustomFooter((CHAR *)pDataPointer,
  873. pInstance->GetTsvcCache(),
  874. g_hSysAccToken,
  875. pMDErrorInfo
  876. ))
  877. {
  878. return FALSE;
  879. }
  880. break;
  881. case MD_FOOTER_ENABLED:
  882. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  883. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  884. // Win64 UNALIGNED pointer fix
  885. if (*(UNALIGNED DWORD *)pDataPointer == 0)
  886. {
  887. SetFooterEnabled(FALSE);
  888. SetFooter(0, NULL);
  889. }
  890. break;
  891. case MD_SSI_EXEC_DISABLED:
  892. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  893. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  894. // Win64 UNALIGNED pointer fix
  895. SetSSIExecDisabled( !!*((UNALIGNED DWORD *) pDataPointer) );
  896. break;
  897. case MD_SCRIPT_TIMEOUT:
  898. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  899. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  900. // Win64 UNALIGNED pointer fix
  901. SetCGIScriptTimeout( *((UNALIGNED DWORD *) pDataPointer ) );
  902. break;
  903. case MD_POOL_IDC_TIMEOUT:
  904. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  905. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  906. // Win64 UNALIGNED pointer fix
  907. SetPoolIDCTimeout( *((UNALIGNED DWORD *) pDataPointer ) );
  908. break;
  909. case MD_NTAUTHENTICATION_PROVIDERS:
  910. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  911. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  912. // Win64 UNALIGNED pointer fix
  913. if ( !BuildProviderList( (CHAR *) pDataPointer ))
  914. {
  915. return FALSE;
  916. }
  917. break;
  918. case MD_ALLOW_KEEPALIVES:
  919. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  920. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  921. // Win64 UNALIGNED pointer fix
  922. SetAllowKeepAlives( *((UNALIGNED DWORD *) pDataPointer ) );
  923. break;
  924. case MD_CACHE_EXTENSIONS:
  925. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  926. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  927. // Win64 UNALIGNED pointer fix
  928. SetCacheISAPIApps( *((UNALIGNED DWORD *) pDataPointer ) );
  929. break;
  930. case MD_DO_REVERSE_DNS:
  931. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  932. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  933. // Win64 UNALIGNED pointer fix
  934. m_fDoReverseDns = !!*((UNALIGNED DWORD *) pDataPointer);
  935. break;
  936. case MD_NOTIFY_EXAUTH:
  937. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  938. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  939. // Win64 UNALIGNED pointer fix
  940. m_dwNotifyExAuth = *((UNALIGNED DWORD *) pDataPointer);
  941. break;
  942. case MD_CC_NO_CACHE:
  943. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  944. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  945. // Win64 UNALIGNED pointer fix
  946. if (*(UNALIGNED DWORD *)pDataPointer != 0)
  947. {
  948. SetConfigNoCache();
  949. if (QueryExpireMode() == EXPIRE_MODE_NONE)
  950. {
  951. return SetExpire("d, 0", pMDErrorInfo);
  952. }
  953. }
  954. break;
  955. case MD_CC_MAX_AGE:
  956. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  957. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  958. pMDInfo = (PW3_METADATA_INFO)pBuffer->QueryPtr();
  959. // Win64 UNALIGNED pointer fix
  960. pMDInfo->dwMaxAge = *(UNALIGNED DWORD *)pDataPointer;
  961. SetHaveMaxAge();
  962. break;
  963. case MD_CC_OTHER:
  964. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  965. RMD_ASSERT( pMDRecord->dwMDDataType == STRING_METADATA );
  966. if (*(CHAR *)pDataPointer != '\0')
  967. {
  968. if (!m_strCacheControlHeader.Copy("Cache-Control: ",
  969. sizeof("Cache-Control: ") - 1) ||
  970. !m_strCacheControlHeader.Append((CHAR *)pDataPointer))
  971. {
  972. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  973. return FALSE;
  974. }
  975. }
  976. break;
  977. case MD_REDIRECT_HEADERS:
  978. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  979. RMD_ASSERT( pMDRecord->dwMDDataType == MULTISZ_METADATA );
  980. // Copies these headers into our redirect header structure.
  981. pszStart = (CHAR *)pDataPointer;
  982. while ( *pszStart != '\0' )
  983. {
  984. DWORD dwLength;
  985. dwLength = strlen(pszStart);
  986. if ( !QueryRedirectHeaders()->Append( pszStart,
  987. dwLength ) ||
  988. !QueryRedirectHeaders()->Append( "\r\n",
  989. sizeof("\r\n") - 1) )
  990. {
  991. SET_WIN32_ERR(pMDErrorInfo, GetLastError());
  992. return FALSE;
  993. }
  994. pszStart += (dwLength + 1);
  995. }
  996. break;
  997. case MD_UPLOAD_READAHEAD_SIZE:
  998. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  999. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  1000. // Win64 UNALIGNED pointer fix
  1001. SetUploadReadAhead( *((UNALIGNED DWORD *) pDataPointer ) );
  1002. break;
  1003. case MD_PUT_READ_SIZE:
  1004. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  1005. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  1006. // Win64 UNALIGNED pointer fix
  1007. SetPutReadSize( *((UNALIGNED DWORD *) pDataPointer ) );
  1008. break;
  1009. case MD_CPU_CGI_ENABLED:
  1010. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  1011. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  1012. #ifdef _WIN64
  1013. // SetJobCGIEnabled( *((CHAR *) pDataPointer ));
  1014. // Win64 UNALIGNED pointer fix
  1015. SetJobCGIEnabled( *((UNALIGNED DWORD *) pDataPointer ));
  1016. #else
  1017. SetJobCGIEnabled( *((DWORD *) pDataPointer ));
  1018. #endif
  1019. break;
  1020. case MD_VR_IGNORE_TRANSLATE:
  1021. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  1022. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  1023. // Win64 UNALIGNED pointer fix
  1024. SetIgnoreTranslate( *((UNALIGNED DWORD *) pDataPointer) );
  1025. break;
  1026. case MD_USE_DIGEST_SSP:
  1027. DBG_ASSERT( pMDRecord->dwMDDataTag == NULL );
  1028. RMD_ASSERT( pMDRecord->dwMDDataType == DWORD_METADATA );
  1029. SetUseDigestSSP( *((UNALIGNED DWORD *) pDataPointer) );
  1030. break;
  1031. }
  1032. return TRUE;
  1033. }
  1034. BOOL
  1035. W3_METADATA::SetCCHeader(
  1036. BOOL bNoCache,
  1037. BOOL bMaxAge,
  1038. DWORD dwMaxAge
  1039. )
  1040. /*++
  1041. Routine Description:
  1042. Build a Cache-Control header with no-cache or max-age=.
  1043. Arguments:
  1044. bNoCache - True if we're to build a no-cache header.
  1045. bMaxAge - True if we're to build a max-age= header.
  1046. dwMaxAge - Max-Age to use.
  1047. Return value:
  1048. TRUE if success, otherwise FALSE
  1049. --*/
  1050. {
  1051. CHAR cMaxAgeBuffer[34];
  1052. BOOL bHaveCCHeader;
  1053. METADATA_ERROR_INFO DummyError;
  1054. bHaveCCHeader = !m_strCacheControlHeader.IsEmpty();
  1055. //
  1056. // If we don't already have the basic Cache-Control: header, add it.
  1057. //
  1058. if (!bHaveCCHeader)
  1059. {
  1060. if (!m_strCacheControlHeader.Copy("Cache-Control: ",
  1061. sizeof("Cache-Control: ") - 1) )
  1062. {
  1063. return FALSE;
  1064. }
  1065. }
  1066. //
  1067. // Now see if we're to add a no-cache or max-age= header.
  1068. //
  1069. if (bNoCache)
  1070. {
  1071. // It's a no-cache, this is straightforward.
  1072. //
  1073. if (!m_strCacheControlHeader.Append(bHaveCCHeader ?
  1074. ",no-cache" : "no-cache",
  1075. sizeof("no-cache") - (bHaveCCHeader ? 0 : 1) ))
  1076. {
  1077. return FALSE;
  1078. }
  1079. }
  1080. else
  1081. {
  1082. if (bMaxAge)
  1083. {
  1084. // Add a max-age header. First convert it to a string.
  1085. // We build the string at an offset into the MaxAge buffer
  1086. // so later we can convert the MaxAge buffer into a string
  1087. // suitable for SetExpire if we need to.
  1088. _itoa(dwMaxAge, &cMaxAgeBuffer[2], 10);
  1089. if (!m_strCacheControlHeader.Append(bHaveCCHeader ?
  1090. ",max-age=" : "max-age=",
  1091. sizeof("max-age=") - (bHaveCCHeader ? 0 : 1) ))
  1092. {
  1093. return FALSE;
  1094. }
  1095. if (!m_strCacheControlHeader.Append(&cMaxAgeBuffer[2]))
  1096. {
  1097. return FALSE;
  1098. }
  1099. // Now, if we don't already have an expiration time, set one.
  1100. if (QueryExpireMode() == EXPIRE_MODE_NONE)
  1101. {
  1102. cMaxAgeBuffer[0] = 'd';
  1103. cMaxAgeBuffer[1] = ',';
  1104. if (!SetExpire(cMaxAgeBuffer, &DummyError))
  1105. {
  1106. return FALSE;
  1107. }
  1108. }
  1109. }
  1110. }
  1111. return TRUE;
  1112. }
  1113. BOOL
  1114. W3_METADATA::FinishPrivateProperties(
  1115. BUFFER *pBuffer,
  1116. DWORD dwBytesUsed,
  1117. BOOL bSucceeded
  1118. )
  1119. /*++
  1120. Routine Description:
  1121. Finish processing of private W3 metadata properties.
  1122. Arguments:
  1123. pBuffer - Pointer to BUFFER containing info gathered during
  1124. calls to HandlePrivateProperty.
  1125. dwBytesUsed - Size in bytes of buffer pointed to by pBuffer
  1126. bSucceede - TRUE iff we read all private properties successfully.
  1127. Return value:
  1128. TRUE if success, otherwise FALSE
  1129. --*/
  1130. {
  1131. PW3_METADATA_INFO pMDInfo;
  1132. BOOL bHaveCCHeader;
  1133. if (dwBytesUsed != 0 && dwBytesUsed != sizeof(W3_METADATA_INFO))
  1134. {
  1135. return FALSE;
  1136. }
  1137. pMDInfo = (PW3_METADATA_INFO)pBuffer->QueryPtr();
  1138. if (bSucceeded)
  1139. {
  1140. bHaveCCHeader = !m_strCacheControlHeader.IsEmpty();
  1141. if (QueryExpireMode() == EXPIRE_MODE_OFF)
  1142. {
  1143. ClearConfigNoCache();
  1144. ClearHaveMaxAge();
  1145. }
  1146. else
  1147. {
  1148. if (QueryConfigNoCache() || QueryHaveMaxAge())
  1149. {
  1150. // We have some sort of cache-control header to add here.
  1151. if (!SetCCHeader(QueryConfigNoCache(), QueryHaveMaxAge(),
  1152. QueryHaveMaxAge() ? pMDInfo->dwMaxAge : 0))
  1153. {
  1154. return FALSE;
  1155. }
  1156. bHaveCCHeader = TRUE;
  1157. }
  1158. else
  1159. {
  1160. //
  1161. // We don't have either a max-age or no-cache header. If we have
  1162. // a dynamic Expires header, create a max-age header now.
  1163. //
  1164. if (QueryExpireMode() == EXPIRE_MODE_DYNAMIC)
  1165. {
  1166. DWORD dwDelta = QueryExpireDelta();
  1167. BOOL SetCCRetVal;
  1168. if (dwDelta != 0)
  1169. {
  1170. SetCCRetVal = SetCCHeader(FALSE, TRUE, dwDelta);
  1171. }
  1172. else
  1173. {
  1174. SetCCRetVal = SetCCHeader(TRUE, FALSE, 0);
  1175. }
  1176. if (!SetCCRetVal)
  1177. {
  1178. return FALSE;
  1179. }
  1180. bHaveCCHeader = TRUE;
  1181. }
  1182. else
  1183. {
  1184. if (QueryExpireMode() == EXPIRE_MODE_STATIC)
  1185. {
  1186. // We have a static expiration data and no configured
  1187. // max-age or no-cache controls. If we don't have a
  1188. // cache-control header built, build one, and leave off
  1189. // the trailing CRLF, that'll be added later when we build
  1190. // the whole header.
  1191. if (!bHaveCCHeader)
  1192. {
  1193. if (!m_strCacheControlHeader.Copy("Cache-Control: ",
  1194. sizeof("Cache-Control: ") - 1) )
  1195. {
  1196. return FALSE;
  1197. }
  1198. }
  1199. else
  1200. {
  1201. // Already have a header, append a comma.
  1202. if (!m_strCacheControlHeader.Append(",",
  1203. sizeof(",") - 1) )
  1204. {
  1205. return FALSE;
  1206. }
  1207. }
  1208. bHaveCCHeader = FALSE;
  1209. }
  1210. }
  1211. }
  1212. }
  1213. if (bHaveCCHeader)
  1214. {
  1215. if ( !m_strCacheControlHeader.Append("\r\n", sizeof("\r\n") - 1))
  1216. {
  1217. return FALSE;
  1218. }
  1219. }
  1220. }
  1221. return TRUE;
  1222. }
  1223. #define DEFINE_MD_MAP(x) {x, #x }
  1224. struct MDIDMap
  1225. {
  1226. DWORD MDID;
  1227. CHAR *IDName;
  1228. } MDIDMappingTable[] =
  1229. {
  1230. DEFINE_MD_MAP(MD_AUTHORIZATION),
  1231. DEFINE_MD_MAP(MD_REALM),
  1232. DEFINE_MD_MAP(MD_HTTP_EXPIRES),
  1233. DEFINE_MD_MAP(MD_HTTP_PICS),
  1234. DEFINE_MD_MAP(MD_HTTP_CUSTOM),
  1235. DEFINE_MD_MAP(MD_DIRECTORY_BROWSING),
  1236. DEFINE_MD_MAP(MD_DEFAULT_LOAD_FILE),
  1237. DEFINE_MD_MAP(MD_CONTENT_NEGOTIATION),
  1238. DEFINE_MD_MAP(MD_CUSTOM_ERROR),
  1239. DEFINE_MD_MAP(MD_FOOTER_DOCUMENT),
  1240. DEFINE_MD_MAP(MD_FOOTER_ENABLED),
  1241. DEFINE_MD_MAP(MD_HTTP_REDIRECT),
  1242. DEFINE_MD_MAP(MD_DEFAULT_LOGON_DOMAIN),
  1243. DEFINE_MD_MAP(MD_LOGON_METHOD),
  1244. DEFINE_MD_MAP(MD_SCRIPT_MAPS),
  1245. DEFINE_MD_MAP(MD_MIME_MAP),
  1246. DEFINE_MD_MAP(MD_ACCESS_PERM),
  1247. #if 0
  1248. DEFINE_MD_MAP(MD_HEADER_DOCUMENT),
  1249. DEFINE_MD_MAP(MD_HEADER_ENABLED),
  1250. #endif
  1251. DEFINE_MD_MAP(MD_IP_SEC),
  1252. DEFINE_MD_MAP(MD_ANONYMOUS_USER_NAME),
  1253. DEFINE_MD_MAP(MD_ANONYMOUS_PWD),
  1254. DEFINE_MD_MAP(MD_ANONYMOUS_USE_SUBAUTH),
  1255. DEFINE_MD_MAP(MD_DONT_LOG),
  1256. DEFINE_MD_MAP(MD_ADMIN_ACL),
  1257. DEFINE_MD_MAP(MD_SSI_EXEC_DISABLED),
  1258. DEFINE_MD_MAP(MD_DO_REVERSE_DNS),
  1259. DEFINE_MD_MAP(MD_SSL_ACCESS_PERM),
  1260. DEFINE_MD_MAP(MD_AUTHORIZATION_PERSISTENCE),
  1261. DEFINE_MD_MAP(MD_NTAUTHENTICATION_PROVIDERS),
  1262. DEFINE_MD_MAP(MD_SCRIPT_TIMEOUT),
  1263. DEFINE_MD_MAP(MD_CACHE_EXTENSIONS),
  1264. DEFINE_MD_MAP(MD_CREATE_PROCESS_AS_USER),
  1265. DEFINE_MD_MAP(MD_CREATE_PROC_NEW_CONSOLE),
  1266. DEFINE_MD_MAP(MD_POOL_IDC_TIMEOUT),
  1267. DEFINE_MD_MAP(MD_ALLOW_KEEPALIVES),
  1268. DEFINE_MD_MAP(MD_IS_CONTENT_INDEXED),
  1269. DEFINE_MD_MAP(MD_NOTIFY_EXAUTH),
  1270. DEFINE_MD_MAP(MD_CC_NO_CACHE),
  1271. DEFINE_MD_MAP(MD_CC_MAX_AGE),
  1272. DEFINE_MD_MAP(MD_CC_OTHER),
  1273. DEFINE_MD_MAP(MD_REDIRECT_HEADERS),
  1274. DEFINE_MD_MAP(MD_UPLOAD_READAHEAD_SIZE),
  1275. DEFINE_MD_MAP(MD_PUT_READ_SIZE)
  1276. };
  1277. CHAR *
  1278. MapMetaDataID(
  1279. DWORD dwMDID
  1280. )
  1281. /*++
  1282. Routine Description:
  1283. Map a DWORD metadata identifier to it's name as an ASCII string.
  1284. Arguments:
  1285. dwMDID - Identifier to be mapped.
  1286. Return value:
  1287. String describing identifier
  1288. --*/
  1289. {
  1290. DWORD i;
  1291. for (i = 0; i < (sizeof(MDIDMappingTable)/sizeof(struct MDIDMap)); i++)
  1292. {
  1293. if (MDIDMappingTable[i].MDID == dwMDID)
  1294. {
  1295. return MDIDMappingTable[i].IDName;
  1296. }
  1297. }
  1298. return "an unknown metabase property";
  1299. }
  1300. BOOL
  1301. HTTP_REQUEST::SendMetaDataError(
  1302. PMETADATA_ERROR_INFO pErrorInfo
  1303. )
  1304. /*++
  1305. Routine Description:
  1306. Look at the error information returned from a previous call to
  1307. ReadMetaData(), and format and send an appropriate error message.
  1308. Arguments:
  1309. pErrorInfo - Pointer to the returned error information.
  1310. Return value:
  1311. TRUE if success, otherwise FALSE
  1312. --*/
  1313. {
  1314. STACK_STR(strBody, 80);
  1315. STACK_STR(strResp, 80);
  1316. STACK_STR(strWin32Error, 80);
  1317. DWORD dwContentLength;
  1318. BOOL fDone;
  1319. BOOL bHaveCustomError = FALSE;
  1320. BOOL fRet;
  1321. CHAR *IDName;
  1322. CHAR szMDID[17];
  1323. CHAR szCL[17];
  1324. CHAR szWin32Error[17];
  1325. DWORD dwCurrentSize;
  1326. DWORD dwBytesNeeded;
  1327. DWORD dwCLLength;
  1328. CHAR *pszTail;
  1329. if (!pErrorInfo->IsValid)
  1330. {
  1331. return FALSE;
  1332. }
  1333. //
  1334. // First check to see if we've got a custom error handler set up for this.
  1335. //
  1336. if (CheckCustomError(&strBody, HT_SERVER_ERROR, 0, &fDone, &dwContentLength))
  1337. {
  1338. // Had at least some custom error processing. If we're done, we can
  1339. // return, but set a flag telling our callers not to disconnect, since
  1340. // we're still processing.
  1341. if (fDone)
  1342. {
  1343. _fNoDisconnectOnError = TRUE;
  1344. return TRUE;
  1345. }
  1346. bHaveCustomError = TRUE;
  1347. }
  1348. //
  1349. // Build the error string and header fields. If we didn't have a custom
  1350. // error, load an error body string from.
  1351. if (!bHaveCustomError)
  1352. {
  1353. fRet = BuildStatusLine( &strResp, HT_SERVER_ERROR,
  1354. IDS_METADATA_CONFIG_ERROR + pErrorInfo->ErrorReason,
  1355. QueryURL(),
  1356. &strBody);
  1357. dwContentLength = strBody.QueryCB();
  1358. }
  1359. else
  1360. {
  1361. fRet = BuildStatusLine( &strResp, HT_SERVER_ERROR, 0, QueryURL(), NULL );
  1362. }
  1363. if (!fRet)
  1364. {
  1365. // Trouble building the status line.
  1366. return FALSE;
  1367. }
  1368. // Now build the various header fields.
  1369. strResp.SetLen(strlen((CHAR *)strResp.QueryPtr()));
  1370. SetKeepConn(FALSE);
  1371. SetAuthenticationRequested(FALSE);
  1372. fDone = FALSE;
  1373. if ( !BuildBaseResponseHeader( QueryRespBuf(), &fDone, &strResp,
  1374. HTTPH_NO_CUSTOM)
  1375. )
  1376. {
  1377. // Couldn't build the headers, so return.
  1378. return FALSE;
  1379. }
  1380. //
  1381. // If it failed because of a Win32 error, load a descriptive string.
  1382. //
  1383. if (pErrorInfo->ErrorReason == METADATA_ERROR_WIN32)
  1384. {
  1385. if ( !g_pInetSvc->LoadStr( strWin32Error, pErrorInfo->Win32Error ))
  1386. {
  1387. // Couldn't load the string, convert the error number and
  1388. // use that.
  1389. _itoa(pErrorInfo->Win32Error, szWin32Error, 10);
  1390. if (!strWin32Error.Copy(szWin32Error))
  1391. {
  1392. return FALSE;
  1393. }
  1394. }
  1395. // Adjust content length for extra %s.
  1396. dwContentLength -= sizeof("%s") - 1;
  1397. }
  1398. // OK, we've built everything. Map the metabase ID to a string, and
  1399. // format the message.
  1400. IDName = MapMetaDataID(pErrorInfo->ErrorParameter);
  1401. _itoa( pErrorInfo->ErrorParameter, szMDID, 10 );
  1402. // Adjust content length for size of strings we're adding in, and for
  1403. // the formatting characters.
  1404. dwContentLength += strlen(szMDID) + strlen(IDName) + strWin32Error.QueryCB();
  1405. dwContentLength -= (sizeof("%s") - 1) * 2;
  1406. _itoa( dwContentLength, szCL, 10 );
  1407. dwCLLength = strlen(szCL);
  1408. // Make sure we have enough room in the response buffer.
  1409. dwCurrentSize = strlen(QueryRespBufPtr());
  1410. dwBytesNeeded = dwCurrentSize + dwContentLength + dwCLLength +
  1411. sizeof("Content-Length: \r\n") - 1 +
  1412. sizeof("Content-Type: text/html\r\n") - 1;
  1413. if (!QueryRespBuf()->Resize(dwBytesNeeded))
  1414. {
  1415. return FALSE;
  1416. }
  1417. // Everything's set up, go ahead and copy it into the buffer.
  1418. pszTail = QueryRespBufPtr() + dwCurrentSize;
  1419. APPEND_STRING(pszTail, "Content-Length: ");
  1420. memcpy(pszTail, szCL, dwCLLength + 1);
  1421. pszTail += dwCLLength;
  1422. APPEND_STRING(pszTail, "\r\n");
  1423. if (!bHaveCustomError)
  1424. {
  1425. APPEND_STRING(pszTail, "Content-Type: text/html\r\n\r\n");
  1426. }
  1427. pszTail += wsprintf(pszTail, strBody.QueryStr(), IDName, szMDID,
  1428. strWin32Error.QueryStr());
  1429. // Now send the header.
  1430. if ( !SendHeader( QueryRespBufPtr(), (DWORD) (pszTail - QueryRespBufPtr()),
  1431. IO_FLAG_SYNC, &fDone ))
  1432. {
  1433. return FALSE;
  1434. }
  1435. _fDiscNoError = TRUE;
  1436. return TRUE;
  1437. }
  1438. /************************ End of File ***********************/