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.

2579 lines
61 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. w3metadata.cxx
  5. Abstract:
  6. Code to read metadata and generate W3_METADATA objects
  7. Author:
  8. Bilal Alam (balam) 23-Jan-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. #include "redirect.hxx"
  16. ALLOC_CACHE_HANDLER * W3_METADATA::sm_pachW3MetaData;
  17. W3_METADATA::W3_METADATA( OBJECT_CACHE * pObjectCache )
  18. : CACHE_ENTRY ( pObjectCache ),
  19. _dwAccessPerm ( MD_ACCESS_READ ),
  20. _dwSslAccessPerm ( 0 ),
  21. _cbIpAccessCheck ( 0 ),
  22. _dwLogonMethod ( LOGON32_LOGON_INTERACTIVE ),
  23. _dwVrLevel ( 0 ),
  24. _dwVrLen ( 0 ),
  25. _pRedirectBlob ( NULL ),
  26. _dwDirBrowseFlags ( MD_DIRBROW_LOADDEFAULT ),
  27. _dwAuthentication ( 0 ),
  28. _dwAuthPersistence ( 0 ),
  29. _strUserName ( _rgUserName, sizeof( _rgUserName ) ),
  30. _strPasswd ( _rgPasswd, sizeof( _rgPasswd ) ),
  31. _strDomainName ( _rgDomainName, sizeof( _rgDomainName ) ),
  32. _strRealm ( _rgRealm, sizeof( _rgRealm ) ),
  33. _pctVrToken ( NULL ),
  34. _pctAnonymousToken ( NULL ),
  35. _fCreateProcessAsUser ( TRUE ),
  36. _fCreateProcessNewConsole ( FALSE ),
  37. _fDoStaticCompression ( HTTP_COMPRESSION::QueryDoStaticCompression() ),
  38. _fDoDynamicCompression ( HTTP_COMPRESSION::QueryDoDynamicCompression() ),
  39. _dwCGIScriptTimeout ( DEFAULT_SCRIPT_TIMEOUT ),
  40. _ScriptMap (),
  41. _pMimeMap ( NULL ),
  42. _fIgnoreTranslate ( FALSE ),
  43. _fSSIExecDisabled ( FALSE ),
  44. _fVrPassThrough ( FALSE ),
  45. _fDontLog ( FALSE ),
  46. _fFooterEnabled ( FALSE ),
  47. _dwExpireMode ( EXPIRE_MODE_NONE ),
  48. _fHaveNoCache ( FALSE ),
  49. _fHaveMaxAge ( FALSE ),
  50. _fDoReverseDNS ( FALSE ),
  51. _cbEntityReadAhead ( DEFAULT_ENTITY_READ_AHEAD ),
  52. _fNoCache ( FALSE ),
  53. _fDisableDav ( FALSE ),
  54. _dwAppIsolated ( 0 ),
  55. _dwAppOopRecoverLimit ( 0 )
  56. {
  57. //
  58. // Hmmm, since most of these values aren't getting initialized, if
  59. // somebody went and deleted all the metadata items from the tree,
  60. // then bad things could happen. We should initialize with defaults
  61. // things that might screw us
  62. //
  63. _dirmonConfig.hToken = NULL;
  64. _dirmonConfig.pszDirPath = NULL;
  65. }
  66. W3_METADATA::~W3_METADATA()
  67. {
  68. if ( _pctVrToken != NULL )
  69. {
  70. _pctVrToken->DereferenceCacheEntry();
  71. _pctVrToken = NULL;
  72. }
  73. if ( _pctAnonymousToken != NULL )
  74. {
  75. _pctAnonymousToken->DereferenceCacheEntry();
  76. _pctAnonymousToken = NULL;
  77. }
  78. if ( _pMimeMap )
  79. {
  80. delete _pMimeMap;
  81. _pMimeMap = NULL;
  82. }
  83. if (_pRedirectBlob)
  84. {
  85. delete _pRedirectBlob;
  86. _pRedirectBlob = NULL;
  87. }
  88. DBG_ASSERT(CheckSignature());
  89. }
  90. //static
  91. HRESULT
  92. W3_METADATA::Initialize(
  93. VOID
  94. )
  95. /*++
  96. Routine Description:
  97. Initialize metadata lookaside
  98. Arguments:
  99. None
  100. Return Value:
  101. HRESULT
  102. --*/
  103. {
  104. ALLOC_CACHE_CONFIGURATION acConfig;
  105. HRESULT hr;
  106. //
  107. // Initialize allocation lookaside
  108. //
  109. acConfig.nConcurrency = 1;
  110. acConfig.nThreshold = 100;
  111. acConfig.cbSize = sizeof( W3_METADATA );
  112. DBG_ASSERT( sm_pachW3MetaData == NULL );
  113. sm_pachW3MetaData = new ALLOC_CACHE_HANDLER( "W3_METADATA",
  114. &acConfig );
  115. if ( sm_pachW3MetaData == NULL )
  116. {
  117. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  118. DBGPRINTF(( DBG_CONTEXT,
  119. "Error initializing sm_pachW3MetaData. hr = 0x%x\n",
  120. hr ));
  121. return hr;
  122. }
  123. return NO_ERROR;
  124. }
  125. //static
  126. VOID
  127. W3_METADATA::Terminate(
  128. VOID
  129. )
  130. {
  131. if ( sm_pachW3MetaData != NULL )
  132. {
  133. delete sm_pachW3MetaData;
  134. sm_pachW3MetaData = NULL;
  135. }
  136. }
  137. //
  138. // Private constants.
  139. //
  140. #define DEFAULT_MD_RECORDS 40
  141. #define DEFAULT_RECORD_SIZE 50
  142. # define DEF_MD_REC_SIZE ((1 + DEFAULT_MD_RECORDS) * \
  143. (sizeof(METADATA_GETALL_RECORD) + DEFAULT_RECORD_SIZE))
  144. HRESULT
  145. W3_METADATA::ReadMetaData(
  146. const STRU & strMetabasePath,
  147. const STRU & strURL
  148. )
  149. /*++
  150. Routine Description:
  151. Reads the metabase (directly) to get the metadata for the given URL
  152. Arguments:
  153. strMetabasePath - The preceding service/instance goo (like "LM/W3SVC/1/ROOT" )
  154. strURL - URL in question
  155. Return Value:
  156. HRESULT
  157. --*/
  158. {
  159. PMETADATA_GETALL_RECORD pMDRecord;
  160. DWORD dwNumMDRecords;
  161. DWORD dwNumWamRecords;
  162. BYTE tmpBuffer[ DEF_MD_REC_SIZE];
  163. BYTE tmpWamBuffer[ DEF_MD_REC_SIZE];
  164. BUFFER TempBuff( tmpBuffer, DEF_MD_REC_SIZE);
  165. BUFFER WamBuff( tmpWamBuffer, DEF_MD_REC_SIZE);
  166. DWORD i;
  167. DWORD dwDataSetNumber;
  168. DWORD dwWamDataSetNumber;
  169. WCHAR ch;
  170. LPWSTR pszInVr;
  171. LPWSTR pszMinInVr;
  172. LPWSTR pszURL;
  173. DWORD dwNeed;
  174. DWORD dwL;
  175. DWORD dwVRLen;
  176. BYTE tmpPrivateBuffer[ 20 ];
  177. BUFFER PrivateBuffer( tmpPrivateBuffer, 20 );
  178. DWORD dwPrivateBufferUsed;
  179. MB mb( g_pW3Server->QueryMDObject() );
  180. MB * pmb = &mb;
  181. HRESULT hr = NO_ERROR;
  182. WCHAR * pszVrUserName = NULL;
  183. WCHAR * pszVrPasswd = NULL;
  184. HANDLE hVrToken = NULL;
  185. WCHAR * pszStart = NULL;
  186. DWORD cchLength = 0;
  187. //
  188. // We lie about modifying the input path
  189. //
  190. pszURL = (LPWSTR)strURL.QueryStr();
  191. DBG_ASSERT( pszURL != NULL );
  192. DBG_ASSERT( TempBuff.QuerySize() >=
  193. (DEFAULT_MD_RECORDS *
  194. (sizeof(METADATA_GETALL_RECORD) + DEFAULT_RECORD_SIZE))
  195. );
  196. DBG_ASSERT( WamBuff.QuerySize() >=
  197. (DEFAULT_MD_RECORDS *
  198. (sizeof(METADATA_GETALL_RECORD) + DEFAULT_RECORD_SIZE))
  199. );
  200. //
  201. // Read the metabase
  202. //
  203. if ( !pmb->Open( strMetabasePath.QueryStr() ))
  204. {
  205. hr = HRESULT_FROM_WIN32( GetLastError() );
  206. goto Failure;
  207. }
  208. //
  209. // Get the UT_FILE info
  210. //
  211. if ( !pmb->GetAll( pszURL,
  212. METADATA_INHERIT | METADATA_PARTIAL_PATH,
  213. IIS_MD_UT_FILE,
  214. &TempBuff,
  215. &dwNumMDRecords,
  216. &dwDataSetNumber ))
  217. {
  218. hr = HRESULT_FROM_WIN32( GetLastError() );
  219. goto Failure;
  220. }
  221. //
  222. // Get the UT_WAM info
  223. //
  224. if ( !pmb->GetAll( pszURL,
  225. METADATA_INHERIT | METADATA_PARTIAL_PATH,
  226. IIS_MD_UT_WAM,
  227. &WamBuff,
  228. &dwNumWamRecords,
  229. &dwWamDataSetNumber ))
  230. {
  231. hr = HRESULT_FROM_WIN32( GetLastError() );
  232. goto Failure;
  233. }
  234. //
  235. // Both sets of data better have the same data set number
  236. //
  237. DBG_ASSERT( dwDataSetNumber == dwWamDataSetNumber );
  238. //
  239. // Set the data set number, so that this object is metadata cachable
  240. //
  241. _cacheKey.SetDataSetNumber( dwDataSetNumber );
  242. //
  243. // Grok the buffer containing all the records
  244. //
  245. pMDRecord = (PMETADATA_GETALL_RECORD)TempBuff.QueryPtr();
  246. i = 0;
  247. //
  248. // Check from where we got VR_PATH
  249. //
  250. pszMinInVr = pszURL ;
  251. if ( *pszURL )
  252. {
  253. for ( pszInVr = pszMinInVr + wcslen(pszMinInVr) ;; )
  254. {
  255. ch = *pszInVr;
  256. *pszInVr = L'\0';
  257. dwNeed = 0;
  258. if ( !pmb->GetString( pszURL,
  259. MD_VR_PATH,
  260. IIS_MD_UT_FILE,
  261. NULL,
  262. &dwNeed,
  263. 0 ) &&
  264. GetLastError() == ERROR_INSUFFICIENT_BUFFER )
  265. {
  266. *pszInVr = ch;
  267. // VR_PATH was defined at this level !
  268. break;
  269. }
  270. *pszInVr = ch;
  271. if ( ch )
  272. {
  273. if ( pszInVr > pszMinInVr )
  274. {
  275. pszInVr--;
  276. }
  277. else
  278. {
  279. //
  280. // VR_PATH was defined above Instance vroot
  281. // or not at all. If defined above, then the reference
  282. // path is empty, so we can claim we found it.
  283. // if not defined, then this will be catch later.
  284. //
  285. break;
  286. }
  287. }
  288. // scan for previous delimiter
  289. while ( *pszInVr != L'/' && *pszInVr != L'\\' )
  290. {
  291. if ( pszInVr > pszMinInVr )
  292. {
  293. pszInVr--;
  294. }
  295. else
  296. {
  297. //
  298. // VR_PATH was defined above Instance vroot
  299. // or not at all. If defined above, then the reference
  300. // path is empty, so we can claim we found it.
  301. // if not defined, then this will be catch later.
  302. //
  303. break;
  304. }
  305. }
  306. }
  307. dwVRLen = DIFF(pszInVr - pszMinInVr);
  308. }
  309. else
  310. {
  311. dwVRLen = 0;
  312. pszInVr = pszMinInVr;
  313. }
  314. // Close this now to minimize lock contention.
  315. DBG_REQUIRE(pmb->Close());
  316. for ( dwL = 0 ; pszMinInVr < pszInVr - 1 ; pszMinInVr++ )
  317. {
  318. if ( *pszMinInVr == L'/' || *pszMinInVr == L'\\' )
  319. {
  320. ++dwL;
  321. }
  322. }
  323. //
  324. // Now walk through the array of returned metadata objects and format
  325. // each one into our predigested form.
  326. //
  327. _dwVrLevel = dwL;
  328. _dwVrLen = dwVRLen;
  329. dwPrivateBufferUsed = 0;
  330. for ( ; i < dwNumMDRecords; i++, pMDRecord++ ) {
  331. PVOID pDataPointer;
  332. pDataPointer = (PVOID) ((PCHAR)TempBuff.QueryPtr() +
  333. pMDRecord->dwMDDataOffset);
  334. DBG_ASSERT(pMDRecord->dwMDDataTag == 0);
  335. switch ( pMDRecord->dwMDIdentifier )
  336. {
  337. case MD_DAV_ENABLED:
  338. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  339. {
  340. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  341. goto Failure;
  342. }
  343. _fDisableDav = !*((DWORD *) pDataPointer );
  344. break;
  345. case MD_FOOTER_DOCUMENT:
  346. if (pMDRecord->dwMDDataType != STRING_METADATA)
  347. {
  348. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  349. goto Failure;
  350. }
  351. if (FAILED(hr = ReadCustomFooter((WCHAR *)pDataPointer)))
  352. {
  353. goto Failure;
  354. }
  355. break;
  356. case MD_FOOTER_ENABLED:
  357. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  358. {
  359. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  360. goto Failure;
  361. }
  362. _fFooterEnabled = !!*((DWORD *) pDataPointer );
  363. if ( _fFooterEnabled )
  364. {
  365. //
  366. // If we have footers for a static file, we cannot do static
  367. // compression on it
  368. //
  369. _fDoStaticCompression = FALSE;
  370. }
  371. break;
  372. case MD_HTTP_EXPIRES:
  373. if (pMDRecord->dwMDDataType != STRING_METADATA)
  374. {
  375. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  376. goto Failure;
  377. }
  378. if (FAILED(hr = SetExpire((WCHAR *)pDataPointer)))
  379. {
  380. goto Failure;
  381. }
  382. break;
  383. case MD_CC_NO_CACHE:
  384. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  385. {
  386. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  387. goto Failure;
  388. }
  389. if (*(BOOL *)pDataPointer)
  390. {
  391. _fHaveNoCache = TRUE;
  392. }
  393. break;
  394. case MD_CC_MAX_AGE:
  395. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  396. {
  397. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  398. goto Failure;
  399. }
  400. _dwMaxAge = *(DWORD *)pDataPointer;
  401. _fHaveMaxAge = TRUE;
  402. break;
  403. case MD_CC_OTHER:
  404. if (pMDRecord->dwMDDataType != STRING_METADATA)
  405. {
  406. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  407. goto Failure;
  408. }
  409. if (FAILED(hr = _strCacheControlHeader.CopyWTruncate((WCHAR *)pDataPointer)))
  410. {
  411. goto Failure;
  412. }
  413. break;
  414. case MD_HTTP_REDIRECT:
  415. {
  416. if (pMDRecord->dwMDDataType != STRING_METADATA &&
  417. pMDRecord->dwMDDataType != MULTISZ_METADATA)
  418. {
  419. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  420. goto Failure;
  421. }
  422. STACK_STRU( strRealSource, MAX_PATH );
  423. STACK_STRU( strDestination, MAX_PATH );
  424. if (FAILED(hr = strDestination.Copy((WCHAR *)pDataPointer)) ||
  425. FAILED(hr = GetTrueRedirectionSource(
  426. pszURL,
  427. strMetabasePath.QueryStr(),
  428. (WCHAR *)pDataPointer,
  429. pMDRecord->dwMDDataType == STRING_METADATA,
  430. &strRealSource)) ||
  431. FAILED(hr = SetRedirectionBlob(strRealSource,
  432. strDestination)))
  433. {
  434. goto Failure;
  435. }
  436. if (pMDRecord->dwMDDataType == MULTISZ_METADATA)
  437. {
  438. //
  439. // Have some conditional headers, add them now.
  440. //
  441. if (FAILED(hr = QueryRedirectionBlob()->SetConditionalHeaders(
  442. (WCHAR *)pDataPointer + wcslen((WCHAR *)pDataPointer) + 1)
  443. ))
  444. {
  445. goto Failure;
  446. }
  447. }
  448. break;
  449. }
  450. case MD_DONT_LOG:
  451. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  452. {
  453. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  454. goto Failure;
  455. }
  456. _fDontLog = *(BOOL *)pDataPointer;
  457. break;
  458. case MD_CREATE_PROCESS_AS_USER:
  459. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  460. {
  461. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  462. goto Failure;
  463. }
  464. _fCreateProcessAsUser = *(BOOL *)pDataPointer;
  465. break;
  466. case MD_CREATE_PROC_NEW_CONSOLE:
  467. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  468. {
  469. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  470. goto Failure;
  471. }
  472. _fCreateProcessNewConsole = *(BOOL *)pDataPointer;
  473. break;
  474. case MD_SCRIPT_TIMEOUT:
  475. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  476. {
  477. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  478. goto Failure;
  479. }
  480. _dwCGIScriptTimeout = *(DWORD *)pDataPointer;
  481. break;
  482. case MD_MIME_MAP:
  483. if (pMDRecord->dwMDDataType != MULTISZ_METADATA)
  484. {
  485. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  486. goto Failure;
  487. }
  488. if (*(WCHAR *)pDataPointer)
  489. {
  490. _pMimeMap = new MIME_MAP((WCHAR *)pDataPointer);
  491. if (_pMimeMap == NULL)
  492. {
  493. hr = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  494. goto Failure;
  495. }
  496. }
  497. break;
  498. case MD_HC_DO_NAMESPACE_DYNAMIC_COMPRESSION:
  499. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  500. {
  501. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  502. goto Failure;
  503. }
  504. _fDoDynamicCompression = *(BOOL *)pDataPointer;
  505. break;
  506. case MD_HC_DO_NAMESPACE_STATIC_COMPRESSION:
  507. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  508. {
  509. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  510. goto Failure;
  511. }
  512. _fDoStaticCompression = *(BOOL *)pDataPointer;
  513. break;
  514. case MD_VR_IGNORE_TRANSLATE:
  515. if (pMDRecord->dwMDDataType != DWORD_METADATA)
  516. {
  517. hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  518. goto Failure;
  519. }
  520. _fIgnoreTranslate = *(DWORD*) pDataPointer;
  521. break;
  522. case MD_ANONYMOUS_USER_NAME:
  523. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  524. {
  525. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  526. goto Failure;
  527. }
  528. if ( FAILED( hr = _strUserName.Copy(
  529. (WCHAR *)pDataPointer) ) )
  530. {
  531. goto Failure;
  532. }
  533. break;
  534. case MD_ANONYMOUS_PWD:
  535. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  536. {
  537. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  538. goto Failure;
  539. }
  540. if ( FAILED( hr = _strPasswd.Copy(
  541. (WCHAR *)pDataPointer) ) )
  542. {
  543. goto Failure;
  544. }
  545. break;
  546. case MD_DEFAULT_LOGON_DOMAIN:
  547. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  548. {
  549. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  550. goto Failure;
  551. }
  552. if ( FAILED( hr = _strDomainName.Copy(
  553. (WCHAR *)pDataPointer) ) )
  554. {
  555. goto Failure;
  556. }
  557. break;
  558. case MD_HTTP_PICS:
  559. case MD_HTTP_CUSTOM:
  560. if ( pMDRecord->dwMDDataType != MULTISZ_METADATA )
  561. {
  562. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  563. goto Failure;
  564. }
  565. //
  566. // Copy all the specified headers into our header buffer
  567. //
  568. pszStart = (WCHAR*) pDataPointer;
  569. while ( *pszStart != L'\0' )
  570. {
  571. cchLength = wcslen( pszStart );
  572. hr = _strCustomHeaders.AppendW( pszStart );
  573. if ( FAILED( hr ) )
  574. {
  575. goto Failure;
  576. }
  577. hr = _strCustomHeaders.Append( "\r\n", 2 );
  578. if ( FAILED( hr ) )
  579. {
  580. goto Failure;
  581. }
  582. pszStart += ( cchLength + 1 );
  583. }
  584. break;
  585. case MD_LOGON_METHOD:
  586. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  587. {
  588. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  589. goto Failure;
  590. }
  591. //
  592. // The MD_LOGON_METHOD values in the metabase don't match
  593. // the NT logon values, so we'll convert them
  594. //
  595. switch ( *((DWORD *) pDataPointer ) )
  596. {
  597. case MD_LOGON_BATCH:
  598. _dwLogonMethod = LOGON32_LOGON_BATCH;
  599. break;
  600. case MD_LOGON_INTERACTIVE:
  601. _dwLogonMethod = LOGON32_LOGON_INTERACTIVE;
  602. break;
  603. case MD_LOGON_NETWORK:
  604. _dwLogonMethod = LOGON32_LOGON_NETWORK;
  605. break;
  606. case MD_LOGON_NETWORK_CLEARTEXT:
  607. _dwLogonMethod = LOGON32_LOGON_NETWORK_CLEARTEXT;
  608. break;
  609. default:
  610. break;
  611. }
  612. break;
  613. case MD_AUTHORIZATION:
  614. if( pMDRecord->dwMDDataType != DWORD_METADATA )
  615. {
  616. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  617. goto Failure;
  618. }
  619. _dwAuthentication = *((DWORD *) pDataPointer );
  620. break;
  621. case MD_REALM:
  622. if( pMDRecord->dwMDDataType != STRING_METADATA )
  623. {
  624. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  625. goto Failure;
  626. }
  627. if( FAILED( hr = _strRealm.Copy( ( WCHAR* )pDataPointer ) ) )
  628. {
  629. goto Failure;
  630. }
  631. break;
  632. case MD_NTAUTHENTICATION_PROVIDERS:
  633. if( pMDRecord->dwMDDataType != STRING_METADATA )
  634. {
  635. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  636. goto Failure;
  637. }
  638. hr = BuildProviderList( ( WCHAR* )pDataPointer );
  639. if ( FAILED( hr ) )
  640. {
  641. goto Failure;
  642. }
  643. break;
  644. case MD_AUTHORIZATION_PERSISTENCE:
  645. if( pMDRecord->dwMDDataType != DWORD_METADATA )
  646. {
  647. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  648. goto Failure;
  649. }
  650. _dwAuthPersistence = *((DWORD *) pDataPointer );
  651. break;
  652. case MD_IP_SEC:
  653. if( pMDRecord->dwMDDataType != BINARY_METADATA )
  654. {
  655. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  656. goto Failure;
  657. }
  658. if ( pMDRecord->dwMDDataLen )
  659. {
  660. hr = SetIpAccessCheck( pDataPointer,
  661. pMDRecord->dwMDDataLen );
  662. if ( FAILED( hr ) )
  663. {
  664. goto Failure;
  665. }
  666. }
  667. break;
  668. case MD_ACCESS_PERM:
  669. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  670. {
  671. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  672. goto Failure;
  673. }
  674. _dwAccessPerm = *((DWORD*) pDataPointer);
  675. break;
  676. case MD_SSL_ACCESS_PERM:
  677. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  678. {
  679. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  680. goto Failure;
  681. }
  682. _dwSslAccessPerm = *((DWORD*)pDataPointer) & MD_SSL_ACCESS_MASK;
  683. break;
  684. case MD_VR_PATH:
  685. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  686. {
  687. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  688. goto Failure;
  689. }
  690. if ( FAILED( hr = _strVrPath.Copy((WCHAR *)pDataPointer) ) )
  691. {
  692. goto Failure;
  693. }
  694. break;
  695. case MD_APP_ROOT:
  696. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  697. {
  698. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  699. goto Failure;
  700. }
  701. if ( FAILED( hr = _strAppMetaPath.Copy((WCHAR *)pDataPointer) ) )
  702. {
  703. goto Failure;
  704. }
  705. break;
  706. case MD_VR_USERNAME:
  707. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  708. {
  709. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  710. goto Failure;
  711. }
  712. pszVrUserName = ( WCHAR * )pDataPointer;
  713. break;
  714. case MD_VR_PASSWORD:
  715. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  716. {
  717. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  718. goto Failure;
  719. }
  720. pszVrPasswd = ( WCHAR * )pDataPointer;
  721. break;
  722. case MD_VR_PASSTHROUGH:
  723. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  724. {
  725. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  726. goto Failure;
  727. }
  728. _fVrPassThrough = !!*((DWORD *) pDataPointer );
  729. break;
  730. case MD_REDIRECT_HEADERS:
  731. if ( pMDRecord->dwMDDataType != MULTISZ_METADATA )
  732. {
  733. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  734. goto Failure;
  735. }
  736. //
  737. // Copy all the specified headers into our header buffer
  738. //
  739. pszStart = (WCHAR*) pDataPointer;
  740. while ( *pszStart != L'\0' )
  741. {
  742. cchLength = wcslen( pszStart );
  743. hr = _strRedirectHeaders.AppendW( pszStart );
  744. if ( FAILED( hr ) )
  745. {
  746. goto Failure;
  747. }
  748. hr = _strRedirectHeaders.Append( "\r\n", 2 );
  749. if ( FAILED( hr ) )
  750. {
  751. goto Failure;
  752. }
  753. pszStart += ( cchLength + 1 );
  754. }
  755. break;
  756. case MD_DIRECTORY_BROWSING:
  757. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  758. {
  759. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  760. goto Failure;
  761. }
  762. _dwDirBrowseFlags = *((DWORD *) pDataPointer );
  763. break;
  764. case MD_DEFAULT_LOAD_FILE:
  765. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  766. {
  767. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  768. goto Failure;
  769. }
  770. hr = _strDefaultLoad.Copy( (WCHAR*) pDataPointer );
  771. if ( FAILED( hr ) )
  772. {
  773. goto Failure;
  774. }
  775. break;
  776. case MD_SCRIPT_MAPS:
  777. if ( pMDRecord->dwMDDataType != MULTISZ_METADATA )
  778. {
  779. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  780. goto Failure;
  781. }
  782. hr = _ScriptMap.Initialize( (WCHAR *)pDataPointer );
  783. if( FAILED(hr) )
  784. {
  785. goto Failure;
  786. }
  787. break;
  788. case MD_CUSTOM_ERROR:
  789. if ( pMDRecord->dwMDDataType != MULTISZ_METADATA )
  790. {
  791. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  792. goto Failure;
  793. }
  794. //
  795. // An empty string means use hard-coded errors
  796. //
  797. if ( *((WCHAR*)pDataPointer) == L'\0' )
  798. {
  799. break;
  800. }
  801. hr = _customErrorTable.BuildTable( (WCHAR*) pDataPointer );
  802. if ( FAILED( hr ) )
  803. {
  804. goto Failure;
  805. }
  806. break;
  807. case MD_SSI_EXEC_DISABLED:
  808. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  809. {
  810. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  811. goto Failure;
  812. }
  813. _fSSIExecDisabled = !!*( ( DWORD * ) pDataPointer );
  814. break;
  815. case MD_DO_REVERSE_DNS:
  816. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  817. {
  818. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  819. goto Failure;
  820. }
  821. _fDoReverseDNS = !!*((DWORD*)pDataPointer);
  822. break;
  823. case MD_UPLOAD_READAHEAD_SIZE:
  824. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  825. {
  826. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  827. goto Failure;
  828. }
  829. _cbEntityReadAhead = *(DWORD*)pDataPointer;
  830. break;
  831. case MD_APPPOOL_APPPOOL_ID:
  832. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  833. {
  834. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  835. goto Failure;
  836. }
  837. hr = _strAppPoolId.Copy( (WCHAR*) pDataPointer );
  838. if ( FAILED( hr ) )
  839. {
  840. goto Failure;
  841. }
  842. break;
  843. case MD_VR_NO_CACHE:
  844. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  845. {
  846. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  847. goto Failure;
  848. }
  849. _fNoCache = !!*((DWORD*)pDataPointer);
  850. break;
  851. default:
  852. // BUGBUGBUG
  853. DBG_ASSERT(CheckSignature());
  854. break;
  855. }
  856. }
  857. //
  858. // Walk through the WAM data
  859. //
  860. pMDRecord = (PMETADATA_GETALL_RECORD)WamBuff.QueryPtr();
  861. i = 0;
  862. for ( ; i < dwNumWamRecords; i++, pMDRecord++ ) {
  863. PVOID pDataPointer;
  864. pDataPointer = (PVOID) ((PCHAR)WamBuff.QueryPtr() +
  865. pMDRecord->dwMDDataOffset);
  866. DBG_ASSERT(pMDRecord->dwMDDataTag == 0);
  867. switch ( pMDRecord->dwMDIdentifier )
  868. {
  869. case MD_APP_ISOLATED:
  870. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  871. {
  872. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  873. goto Failure;
  874. }
  875. _dwAppIsolated = *(DWORD*)pDataPointer;
  876. break;
  877. case MD_APP_WAM_CLSID:
  878. if ( pMDRecord->dwMDDataType != STRING_METADATA )
  879. {
  880. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  881. goto Failure;
  882. }
  883. hr = _strWamClsId.Copy( (WCHAR*)pDataPointer );
  884. break;
  885. case MD_APP_OOP_RECOVER_LIMIT:
  886. if ( pMDRecord->dwMDDataType != DWORD_METADATA )
  887. {
  888. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  889. goto Failure;
  890. }
  891. _dwAppOopRecoverLimit = *(DWORD*)pDataPointer;
  892. break;
  893. default:
  894. break;
  895. }
  896. }
  897. //
  898. // If no-cache, max-age or a dynamic expires directive is present, add
  899. // it to Cache-Control header
  900. //
  901. if (FAILED(hr = SetCacheControlHeader()))
  902. {
  903. goto Failure;
  904. }
  905. if ( _strVrPath.IsEmpty() )
  906. {
  907. DBGPRINTF(( DBG_CONTEXT,
  908. "[ReadMetaData] Virtual Dir Path mapping not found\n" ));
  909. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  910. goto Failure;
  911. }
  912. //
  913. // If this is an UNC share, logon using associated credentials
  914. // keep a reference to this access token in the cache
  915. //
  916. if ( _strVrPath.QueryStr()[0] == L'\\' &&
  917. _strVrPath.QueryStr()[1] == L'\\' )
  918. {
  919. if ( pszVrUserName != NULL && pszVrPasswd != NULL &&
  920. pszVrUserName[0] )
  921. {
  922. hr = CreateUNCVrToken( pszVrUserName, pszVrPasswd );
  923. if( FAILED( hr ) )
  924. {
  925. DBGPRINTF((DBG_CONTEXT,
  926. "Error logging on the UNC account. hr = 0x%x.\n",
  927. hr ));
  928. goto Failure;
  929. }
  930. }
  931. }
  932. //
  933. // Setup the dirmon configuration
  934. //
  935. if ( _pctVrToken != NULL )
  936. {
  937. _dirmonConfig.hToken = _pctVrToken->QueryImpersonationToken();
  938. }
  939. else
  940. {
  941. _dirmonConfig.hToken = NULL;
  942. }
  943. _dirmonConfig.pszDirPath = _strVrPath.QueryStr();
  944. //
  945. // Get anonymous user token
  946. //
  947. hr = CreateAnonymousToken( _strUserName.QueryStr(),
  948. _strPasswd.QueryStr() );
  949. if ( FAILED( hr ) )
  950. {
  951. goto Failure;
  952. }
  953. DBG_ASSERT( CheckSignature() );
  954. return S_OK;
  955. Failure:
  956. return hr;
  957. }
  958. HRESULT
  959. W3_METADATA::BuildPhysicalPath(
  960. STRU & strUrl,
  961. STRU * pstrPhysicalPath
  962. )
  963. /*++
  964. Routine Description:
  965. From the current metadata, convert a URL to a physical path
  966. (using the MD_VR_ROOT property and inheritance level calculated on read)
  967. Arguments:
  968. strUrl - Virtual path
  969. pstrPhysicalPath - String filled with physical path of strURL
  970. Return Value:
  971. BOOL
  972. --*/
  973. {
  974. LPWSTR pszInVr;
  975. DWORD dwL;
  976. WCHAR ch;
  977. HRESULT hr = S_OK;
  978. DBG_ASSERT(CheckSignature());
  979. //
  980. // Build physical path from VR_PATH & portion of URI not used to define VR_PATH
  981. //
  982. //
  983. // skip the URI components used to locate the virtual root
  984. //
  985. pszInVr = strUrl.QueryStr();
  986. dwL = _dwVrLevel;
  987. while ( dwL-- )
  988. {
  989. if ( *pszInVr )
  990. {
  991. DBG_ASSERT( *pszInVr == L'/' || *pszInVr == L'\\' );
  992. ++pszInVr;
  993. while ( (ch = *pszInVr) && ch != L'/' && ch !=L'\\' )
  994. {
  995. pszInVr++;
  996. }
  997. }
  998. }
  999. DBG_ASSERT( dwL == (DWORD)-1 );
  1000. if ( FAILED(hr = pstrPhysicalPath->Copy( _strVrPath ) ) )
  1001. {
  1002. return hr;
  1003. }
  1004. //
  1005. // Add a path delimiter char between virtual root mount point & significant part of URI
  1006. //
  1007. if ( pstrPhysicalPath->QueryCCH() )
  1008. {
  1009. ch = pstrPhysicalPath->QueryStr()[ pstrPhysicalPath->QueryCCH() - 1 ];
  1010. if ( (ch == L'/' || ch == L'\\') && *pszInVr )
  1011. {
  1012. ++pszInVr;
  1013. }
  1014. }
  1015. if ( FAILED(hr = pstrPhysicalPath->Append( pszInVr ) ) )
  1016. {
  1017. return hr;
  1018. }
  1019. //
  1020. // insure physical path last char uses standard directory delimiter
  1021. //
  1022. FlipSlashes( pstrPhysicalPath->QueryStr() );
  1023. return NO_ERROR;
  1024. }
  1025. HRESULT
  1026. W3_METADATA::BuildProviderList(
  1027. IN WCHAR * pszProviders
  1028. )
  1029. /*++
  1030. Description:
  1031. Builds a name array of SSPI Authentication providers
  1032. Arguments:
  1033. pszProviders - Comma separated list of providers
  1034. Returns:
  1035. HRESULT
  1036. --*/
  1037. {
  1038. WCHAR * pszCursor;
  1039. WCHAR * pszEnd;
  1040. HRESULT hr;
  1041. BOOL fFinished = FALSE;
  1042. DBG_ASSERT(CheckSignature());
  1043. if ( pszProviders == NULL )
  1044. {
  1045. DBG_ASSERT( FALSE );
  1046. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1047. }
  1048. //
  1049. // Parse comma delimited list of providers, removing white space
  1050. //
  1051. pszCursor = SkipWhite( pszProviders );
  1052. for( ; ; )
  1053. {
  1054. pszEnd = wcschr( pszCursor, L',' );
  1055. if ( pszEnd == NULL )
  1056. {
  1057. fFinished = TRUE;
  1058. pszEnd = pszCursor + wcslen( pszCursor );
  1059. }
  1060. while ( pszEnd > pszCursor )
  1061. {
  1062. if ( !ISWHITEW( *pszEnd ) )
  1063. {
  1064. break;
  1065. }
  1066. pszEnd--;
  1067. }
  1068. *pszEnd = L'\0';
  1069. if ( !_mstrAuthProviders.AppendW( pszCursor ) )
  1070. {
  1071. return HRESULT_FROM_WIN32( GetLastError() );
  1072. }
  1073. if ( fFinished )
  1074. {
  1075. break;
  1076. }
  1077. //
  1078. // Advance to next provider
  1079. //
  1080. pszCursor = SkipWhite( pszEnd + 1 );
  1081. }
  1082. return NO_ERROR;
  1083. }
  1084. BOOL
  1085. W3_METADATA::CheckAuthProvider(
  1086. IN CHAR * pszPkgName
  1087. )
  1088. /*++
  1089. Description:
  1090. Check if we support the SSP package of name pszPkgName
  1091. Arguments:
  1092. pszPkgName - Name of the package we check against
  1093. Returns:
  1094. TRUE if we support the package, FALSE if we don't.
  1095. --*/
  1096. {
  1097. const CHAR * pszProvider;
  1098. DBG_ASSERT( CheckSignature() );
  1099. if ( pszPkgName == NULL )
  1100. {
  1101. DBG_ASSERT( FALSE );
  1102. return FALSE;
  1103. }
  1104. pszProvider = _mstrAuthProviders.First();
  1105. while ( pszProvider != NULL )
  1106. {
  1107. if ( _stricmp( pszPkgName, pszProvider ) == 0 )
  1108. {
  1109. return TRUE;
  1110. }
  1111. pszProvider = _mstrAuthProviders.Next( pszProvider );
  1112. }
  1113. return FALSE;
  1114. }
  1115. HRESULT
  1116. W3_METADATA::CreateUNCVrToken(
  1117. IN LPWSTR pszUserName,
  1118. IN LPWSTR pszPasswd
  1119. )
  1120. /*++
  1121. Description:
  1122. Logon the user account for the UNC virtual path
  1123. Arguments:
  1124. pszUserName - User name of the account in format domain\username
  1125. pszPasswd - Passwd of the account
  1126. Returns:
  1127. HRESULT
  1128. --*/
  1129. {
  1130. STACK_STRU( strUserName, UNLEN + 1 );
  1131. STACK_STRU( strDomainName, IIS_DNLEN + 1 );
  1132. // add 1 to strUserDomain for separator "\"
  1133. STACK_STRU( strUserDomain, UNLEN + IIS_DNLEN + 1 + 1);
  1134. HRESULT hr;
  1135. DWORD dwError;
  1136. BOOL fPossibleUPNLogon = FALSE;
  1137. hr = strUserDomain.Copy( pszUserName );
  1138. if ( FAILED( hr ) )
  1139. {
  1140. return hr;
  1141. }
  1142. hr = W3_STATE_AUTHENTICATION::SplitUserDomain( strUserDomain,
  1143. &strUserName,
  1144. &strDomainName,
  1145. QueryDomainName(),
  1146. &fPossibleUPNLogon );
  1147. if ( FAILED( hr ) )
  1148. {
  1149. return hr;
  1150. }
  1151. DBG_ASSERT( g_pW3Server->QueryTokenCache() != NULL );
  1152. hr = g_pW3Server->QueryTokenCache()->GetCachedToken(
  1153. strUserName.QueryStr(),
  1154. strDomainName.QueryStr(),
  1155. pszPasswd,
  1156. QueryLogonMethod(),
  1157. fPossibleUPNLogon,
  1158. &_pctVrToken,
  1159. &dwError );
  1160. if ( FAILED( hr ) )
  1161. {
  1162. return hr;
  1163. }
  1164. return NO_ERROR;
  1165. }
  1166. HRESULT
  1167. W3_METADATA::CreateAnonymousToken(
  1168. IN LPWSTR pszUserName,
  1169. IN LPWSTR pszPasswd
  1170. )
  1171. /*++
  1172. Description:
  1173. Logon the user account for the UNC virtual path
  1174. Arguments:
  1175. pszUserName - User name of the account in format domain\username
  1176. pszPasswd - Passwd of the account
  1177. Returns:
  1178. HRESULT
  1179. --*/
  1180. {
  1181. STACK_STRU( strUserName, UNLEN );
  1182. STACK_STRU( strDomainName, IIS_DNLEN );
  1183. // add 1 to strUserDomain for separator "\"
  1184. STACK_STRU( strUserDomain, UNLEN + IIS_DNLEN + 1 );
  1185. HRESULT hr;
  1186. DWORD dwLogonError;
  1187. BOOL fPossibleUPNLogon = FALSE;
  1188. hr = strUserDomain.Copy( pszUserName );
  1189. if ( FAILED( hr ) )
  1190. {
  1191. return hr;
  1192. }
  1193. hr = W3_STATE_AUTHENTICATION::SplitUserDomain( strUserDomain,
  1194. &strUserName,
  1195. &strDomainName,
  1196. QueryDomainName(),
  1197. &fPossibleUPNLogon );
  1198. if ( FAILED( hr ) )
  1199. {
  1200. return hr;
  1201. }
  1202. DBG_ASSERT( g_pW3Server->QueryTokenCache() != NULL );
  1203. hr = g_pW3Server->QueryTokenCache()->GetCachedToken(
  1204. strUserName.QueryStr(),
  1205. strDomainName.QueryStr(),
  1206. pszPasswd,
  1207. QueryLogonMethod(),
  1208. fPossibleUPNLogon,
  1209. &_pctAnonymousToken,
  1210. &dwLogonError );
  1211. if ( FAILED( hr ) )
  1212. {
  1213. return hr;
  1214. }
  1215. return NO_ERROR;
  1216. }
  1217. HRESULT
  1218. W3_METADATA::SetIpAccessCheck(
  1219. LPVOID pMDData,
  1220. DWORD dwDataLen
  1221. )
  1222. /*++
  1223. Description:
  1224. Store away the IP DNS list
  1225. Arguments:
  1226. pMDData - Beginning of binary blob to store
  1227. dwDataLen - Length of binary data
  1228. Returns:
  1229. HRESULT
  1230. --*/
  1231. {
  1232. if ( !_buffIpAccessCheck.Resize( dwDataLen ) )
  1233. {
  1234. return HRESULT_FROM_WIN32( GetLastError() );
  1235. }
  1236. memcpy( _buffIpAccessCheck.QueryPtr(),
  1237. pMDData,
  1238. dwDataLen );
  1239. _cbIpAccessCheck = dwDataLen;
  1240. return NO_ERROR;
  1241. }
  1242. HRESULT
  1243. W3_METADATA::ReadCustomFooter(
  1244. WCHAR * pszFooter
  1245. )
  1246. /*++
  1247. Routine Description:
  1248. Process a footer string, either reading the file or copying the string
  1249. to the buffer.
  1250. Arguments:
  1251. pszFooter - The footer string, which may be a string or a file name.
  1252. It looks like "STRING : some-string" or "FILE : file-name"
  1253. Returns:
  1254. HRESULT
  1255. --*/
  1256. {
  1257. HRESULT hr;
  1258. STACK_STRU( strFooter, MAX_PATH );
  1259. BOOL fFooterIsString = FALSE;
  1260. // First thing to do is to determine if this is a string or a file name.
  1261. // Skip preceding whitespace and then strcmp.
  1262. while (iswspace(*pszFooter))
  1263. {
  1264. pszFooter++;
  1265. }
  1266. if (!_wcsnicmp(pszFooter, L"STRING", 6))
  1267. {
  1268. fFooterIsString = TRUE;
  1269. pszFooter += 6;
  1270. }
  1271. else if (!_wcsnicmp(pszFooter, L"FILE", 4))
  1272. {
  1273. fFooterIsString = FALSE;
  1274. pszFooter += 4;
  1275. }
  1276. else
  1277. {
  1278. return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1279. }
  1280. // Now we look for 0 or more white space, followed by a colon, followed by
  1281. // more white space.
  1282. while (iswspace(*pszFooter))
  1283. {
  1284. pszFooter++;
  1285. }
  1286. if (*pszFooter != L':')
  1287. {
  1288. // No colon seperator, error.
  1289. return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1290. }
  1291. pszFooter++;
  1292. //
  1293. // OK, now if this is a string we take everything after the colon to the
  1294. // end for the string. If this is a file name then we'll open and read the
  1295. // file.
  1296. //
  1297. if (fFooterIsString)
  1298. {
  1299. return _strFooterString.CopyW(pszFooter);
  1300. }
  1301. else
  1302. {
  1303. //
  1304. // For files, we'll skip any more white space before the name.
  1305. //
  1306. while (iswspace(*pszFooter))
  1307. {
  1308. pszFooter++;
  1309. }
  1310. hr = _strFooterDocument.Copy( pszFooter );
  1311. if ( FAILED( hr ) )
  1312. {
  1313. return hr;
  1314. }
  1315. }
  1316. return S_OK;
  1317. }
  1318. HRESULT W3_METADATA::SetExpire(WCHAR *pszExpire)
  1319. /*++
  1320. Routine Description:
  1321. Set the expire header to be used on all responses
  1322. Arguments:
  1323. pszExpire: the string containing the description. It could have the form
  1324. "n" : no expire
  1325. "s, some-date" : expire on this date"
  1326. "d, some-number" : expire after this many seconds
  1327. Returns:
  1328. HRESULT
  1329. --*/
  1330. {
  1331. while (iswspace(*pszExpire))
  1332. {
  1333. pszExpire++;
  1334. }
  1335. LPWSTR pszParam;
  1336. if ((pszParam = wcschr(pszExpire, L',')) == NULL)
  1337. {
  1338. if (*pszExpire == L'\0' ||
  1339. *pszExpire == L'n' ||
  1340. *pszExpire == L'N')
  1341. {
  1342. _dwExpireMode = EXPIRE_MODE_OFF;
  1343. return S_OK;
  1344. }
  1345. return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1346. }
  1347. pszParam++;
  1348. while (iswspace(*pszParam))
  1349. {
  1350. pszParam++;
  1351. }
  1352. HRESULT hr;
  1353. switch (*pszExpire)
  1354. {
  1355. case L's':
  1356. case L'S':
  1357. if (FAILED(hr = _strExpireHeader.CopyWTruncate(pszParam)))
  1358. {
  1359. return hr;
  1360. }
  1361. _dwExpireMode = EXPIRE_MODE_STATIC;
  1362. break;
  1363. case L'd':
  1364. case L'D':
  1365. LPWSTR endPtr;
  1366. DWORD dwExpire;
  1367. if (pszParam[0] == L'0' && pszParam[1] == L'x')
  1368. {
  1369. dwExpire = wcstoul(pszParam + 2, &endPtr, 16);
  1370. }
  1371. else
  1372. {
  1373. dwExpire = wcstoul(pszParam, &endPtr, 10);
  1374. }
  1375. if (!iswspace(*endPtr) &&
  1376. *endPtr != L'\0')
  1377. {
  1378. return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1379. }
  1380. if (dwExpire != ULONG_MAX)
  1381. {
  1382. if (dwExpire > MAX_GLOBAL_EXPIRE)
  1383. {
  1384. dwExpire = MAX_GLOBAL_EXPIRE;
  1385. }
  1386. _dwExpireMode = EXPIRE_MODE_DYNAMIC;
  1387. _dwExpireDelta = dwExpire;
  1388. }
  1389. break;
  1390. case L'n':
  1391. case L'N':
  1392. _dwExpireMode = EXPIRE_MODE_OFF;
  1393. break;
  1394. default:
  1395. return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1396. }
  1397. return S_OK;
  1398. }
  1399. HRESULT W3_METADATA::SetCacheControlHeader()
  1400. /*++
  1401. Routine Description:
  1402. If no-cache, max-age or a dynamic expires directive is present, add
  1403. it to Cache-Control header
  1404. Arguments:
  1405. None
  1406. Returns:
  1407. HRESULT
  1408. --*/
  1409. {
  1410. switch (QueryExpireMode())
  1411. {
  1412. case EXPIRE_MODE_NONE:
  1413. _fHaveNoCache = FALSE;
  1414. _fHaveMaxAge = FALSE;
  1415. break;
  1416. case EXPIRE_MODE_DYNAMIC:
  1417. // If we have a dynamic Expires header, create a max-age directive
  1418. if (_dwExpireDelta != 0)
  1419. {
  1420. _fHaveNoCache = FALSE;
  1421. if (!_fHaveMaxAge)
  1422. {
  1423. _fHaveMaxAge = TRUE;
  1424. _dwMaxAge = _dwExpireDelta;
  1425. }
  1426. }
  1427. else
  1428. {
  1429. _fHaveNoCache = TRUE;
  1430. _fHaveMaxAge = FALSE;
  1431. }
  1432. break;
  1433. default:
  1434. break;
  1435. }
  1436. BOOL fHaveCCHeader = !_strCacheControlHeader.IsEmpty();
  1437. HRESULT hr;
  1438. if (_fHaveNoCache)
  1439. {
  1440. if (FAILED(hr = _strCacheControlHeader.Append(
  1441. fHaveCCHeader ? ",no-cache" : "no-cache")))
  1442. {
  1443. return hr;
  1444. }
  1445. }
  1446. else if (_fHaveMaxAge)
  1447. {
  1448. CHAR pszMaxAgeBuffer[16];
  1449. _itoa(_dwMaxAge, pszMaxAgeBuffer, 10);
  1450. if (FAILED(hr = _strCacheControlHeader.Append(
  1451. fHaveCCHeader ? ",max-age=" : "max-age=")) ||
  1452. FAILED(hr = _strCacheControlHeader.Append(pszMaxAgeBuffer)))
  1453. {
  1454. return hr;
  1455. }
  1456. }
  1457. return S_OK;
  1458. }
  1459. HRESULT
  1460. META_SCRIPT_MAP::Initialize(
  1461. IN WCHAR * szScriptMapData
  1462. )
  1463. /*++
  1464. Routine Description:
  1465. Initialize the collection of META_SCRIPT_MAP_ENTRIES from the
  1466. metadata.
  1467. This routine will modify the multisz it works with (by replacing
  1468. some ',' with '\0' ).
  1469. Currently it modifies the in parameter, which is kindof icky.
  1470. We could avoid this by copying the buffer.
  1471. Arguments:
  1472. szScriptMapData - A multi-sz of script map entries.
  1473. Return Value:
  1474. Notes:
  1475. Script map is a multi-sz with each string being a comma separated list
  1476. <extension>,<executable>,<flags>,<verb list>
  1477. <extension>:
  1478. .xyz - Maximum of 128 characters
  1479. * - Star script map - routes all requests though the executable
  1480. <executable>
  1481. - Extension to invoke
  1482. <flags>:
  1483. 1 - Allow run in script access directory ( MD_SCRIPTMAPFLAG_SCRIPT )
  1484. 4 - Check for pathinfo file ( MD_SCRIPTMAPFLAG_CHECK_PATH_INFO )
  1485. <verb list>:
  1486. <verb>,<verb>,<verb>
  1487. - Allowed verbs
  1488. - If no verbs are listed, a value of "all verbs" is assumed.
  1489. --*/
  1490. {
  1491. DBG_ASSERT( szScriptMapData );
  1492. HRESULT hr = NOERROR;
  1493. // Iterate over multisz
  1494. WCHAR * pszEntryIterator;
  1495. // Current mapping
  1496. WCHAR * pszExtension;
  1497. WCHAR * pszExecutable;
  1498. WCHAR * pszFlags;
  1499. DWORD Flags;
  1500. WCHAR * pszVerbs;
  1501. DWORD cchVerbs;
  1502. //
  1503. // Iterate over each mapping
  1504. //
  1505. pszEntryIterator = szScriptMapData;
  1506. while( *pszEntryIterator != L'\0' )
  1507. {
  1508. //
  1509. // Get the extension
  1510. //
  1511. pszExtension = pszEntryIterator;
  1512. //
  1513. // Get the executable
  1514. //
  1515. pszEntryIterator = wcschr( pszEntryIterator, L',' );
  1516. if( pszEntryIterator == NULL )
  1517. {
  1518. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  1519. return hr;
  1520. }
  1521. *pszEntryIterator++ = L'\0';
  1522. pszExecutable = pszEntryIterator;
  1523. if( pszExecutable == L'\0' )
  1524. {
  1525. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  1526. return hr;
  1527. }
  1528. //
  1529. // Get the flags
  1530. //
  1531. pszEntryIterator = wcschr( pszEntryIterator, L',' );
  1532. if( pszEntryIterator == NULL )
  1533. {
  1534. hr = HRESULT_FROM_WIN32( ERROR_INVALID_DATA );
  1535. return hr;
  1536. }
  1537. *pszEntryIterator++ = L'\0';
  1538. //
  1539. // We don't need pszFlags here, but we will need it if
  1540. // there is an empty verb list, to reset our iterator.
  1541. //
  1542. pszFlags = pszEntryIterator;
  1543. Flags = wcstoul( pszFlags, NULL, 10 );
  1544. //
  1545. // Get the verbs
  1546. //
  1547. pszEntryIterator = wcschr( pszEntryIterator, L',' );
  1548. if( pszEntryIterator != NULL )
  1549. {
  1550. //
  1551. // There is a list of verbs
  1552. //
  1553. *pszEntryIterator++ = L'\0';
  1554. pszVerbs = pszEntryIterator;
  1555. //
  1556. // Format verb list as a multi-sz for each entry
  1557. //
  1558. cchVerbs = 1;
  1559. while( *pszEntryIterator != L'\0')
  1560. {
  1561. if( *pszEntryIterator == L',' )
  1562. {
  1563. *pszEntryIterator = L'\0';
  1564. }
  1565. cchVerbs++;
  1566. pszEntryIterator++;
  1567. }
  1568. }
  1569. else
  1570. {
  1571. //
  1572. // Empty Verb List
  1573. //
  1574. //
  1575. // We've lost our iterator so we need to get it back.
  1576. // Point to the terminator.
  1577. //
  1578. pszEntryIterator = pszFlags + wcslen( pszFlags );
  1579. pszVerbs = pszEntryIterator;
  1580. cchVerbs = 1;
  1581. }
  1582. //
  1583. // Create and add the entry object to our list
  1584. //
  1585. META_SCRIPT_MAP_ENTRY *
  1586. pNewEntry = new META_SCRIPT_MAP_ENTRY();
  1587. if( pNewEntry == NULL )
  1588. {
  1589. hr = E_OUTOFMEMORY;
  1590. return hr;
  1591. }
  1592. hr = pNewEntry->Create( pszExtension,
  1593. pszExecutable,
  1594. Flags,
  1595. pszVerbs,
  1596. cchVerbs
  1597. );
  1598. if( FAILED(hr) )
  1599. {
  1600. delete pNewEntry;
  1601. return hr;
  1602. }
  1603. if (pNewEntry->QueryIsStarScriptMap())
  1604. {
  1605. if (m_StarScriptMapEntry != NULL)
  1606. {
  1607. delete m_StarScriptMapEntry;
  1608. }
  1609. m_StarScriptMapEntry = pNewEntry;
  1610. }
  1611. else
  1612. {
  1613. InsertTailList( &m_ListHead, &pNewEntry->m_ListEntry );
  1614. }
  1615. //
  1616. // Move to the next entry.
  1617. //
  1618. pszEntryIterator++;
  1619. }
  1620. return hr;
  1621. }
  1622. BOOL
  1623. META_SCRIPT_MAP::FindEntry(
  1624. IN const STRU & strExtension,
  1625. OUT META_SCRIPT_MAP_ENTRY * * ppScriptMapEntry
  1626. )
  1627. /*++
  1628. Routine Description:
  1629. Arguments:
  1630. Return Value:
  1631. --*/
  1632. {
  1633. *ppScriptMapEntry = NULL;
  1634. PLIST_ENTRY pEntry;
  1635. META_SCRIPT_MAP_ENTRY * pScriptMapEntry = NULL;
  1636. for( pEntry = m_ListHead.Flink;
  1637. pEntry != &m_ListHead;
  1638. pEntry = pEntry->Flink )
  1639. {
  1640. pScriptMapEntry = CONTAINING_RECORD( pEntry,
  1641. META_SCRIPT_MAP_ENTRY,
  1642. m_ListEntry
  1643. );
  1644. if( strExtension.Equals( pScriptMapEntry->m_strExtension ) )
  1645. {
  1646. *ppScriptMapEntry = pScriptMapEntry;
  1647. return TRUE;
  1648. }
  1649. }
  1650. return FALSE;
  1651. }
  1652. VOID
  1653. META_SCRIPT_MAP::Terminate( VOID )
  1654. /*++
  1655. Routine Description:
  1656. Arguments:
  1657. Return Value:
  1658. --*/
  1659. {
  1660. if (m_StarScriptMapEntry != NULL)
  1661. {
  1662. delete m_StarScriptMapEntry;
  1663. m_StarScriptMapEntry = NULL;
  1664. }
  1665. META_SCRIPT_MAP_ENTRY * pScriptMapEntry;
  1666. while( !IsListEmpty( &m_ListHead ) )
  1667. {
  1668. pScriptMapEntry = CONTAINING_RECORD( m_ListHead.Flink,
  1669. META_SCRIPT_MAP_ENTRY,
  1670. m_ListEntry );
  1671. RemoveEntryList( &pScriptMapEntry->m_ListEntry );
  1672. delete pScriptMapEntry;
  1673. }
  1674. }
  1675. HRESULT
  1676. META_SCRIPT_MAP_ENTRY::Create(
  1677. IN const WCHAR * szExtension,
  1678. IN const WCHAR * szExecutable,
  1679. IN DWORD Flags,
  1680. IN const WCHAR * szVerbs,
  1681. IN DWORD cchVerbs
  1682. )
  1683. /*++
  1684. Routine Description:
  1685. Arguments:
  1686. Return Value:
  1687. --*/
  1688. {
  1689. HRESULT hr = NOERROR;
  1690. DWORD cchExecutable;
  1691. //
  1692. // Capture initialization parameters
  1693. //
  1694. m_Flags = Flags;
  1695. hr = m_strExtension.Copy( szExtension );
  1696. if( FAILED(hr) )
  1697. {
  1698. return hr;
  1699. }
  1700. //
  1701. // Lower-case to allow for case insensitive comparisons
  1702. //
  1703. _wcslwr( m_strExtension.QueryStr() );
  1704. if (szExtension[0] == L'*' && szExtension[1] == L'\0')
  1705. {
  1706. m_fIsStarScriptMapEntry = TRUE;
  1707. }
  1708. //
  1709. // We treat the executable name as an ExpandSz, so expand it
  1710. //
  1711. WCHAR szExpand[MAX_PATH + 1];
  1712. if (!ExpandEnvironmentStrings(szExecutable,
  1713. szExpand,
  1714. sizeof szExpand/sizeof WCHAR))
  1715. {
  1716. return HRESULT_FROM_WIN32(GetLastError());
  1717. }
  1718. if (FAILED(hr = m_strExecutable.Copy( szExpand )))
  1719. {
  1720. return hr;
  1721. }
  1722. //
  1723. // If the executable is quoted, remove the quotes now
  1724. //
  1725. if ( m_strExecutable.QueryStr()[ 0 ] == L'"' &&
  1726. m_strExecutable.QueryStr()[ m_strExecutable.QueryCCH() - 1 ] == L'"' )
  1727. {
  1728. cchExecutable = m_strExecutable.QueryCCH();
  1729. memmove( m_strExecutable.QueryStr(),
  1730. m_strExecutable.QueryStr() + 1,
  1731. cchExecutable * sizeof( WCHAR ) );
  1732. m_strExecutable.SetLen( cchExecutable - 2 );
  1733. }
  1734. if (m_strExecutable.QueryCCH() > 4)
  1735. {
  1736. if (!_wcsicmp(
  1737. m_strExecutable.QueryStr() + m_strExecutable.QueryCCH() - 4,
  1738. L".dll"))
  1739. {
  1740. m_Gateway = GATEWAY_ISAPI;
  1741. }
  1742. else
  1743. {
  1744. m_Gateway = GATEWAY_CGI;
  1745. }
  1746. }
  1747. else
  1748. {
  1749. return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  1750. }
  1751. if (!m_Verbs.AppendW( szVerbs, cchVerbs ))
  1752. {
  1753. hr = HRESULT_FROM_WIN32(GetLastError());
  1754. return hr;
  1755. }
  1756. return S_OK;
  1757. }
  1758. HRESULT
  1759. W3_METADATA_CACHE::Initialize(
  1760. VOID
  1761. )
  1762. /*++
  1763. Description:
  1764. Initialize metadata cache
  1765. Arguments:
  1766. None
  1767. Return:
  1768. HRESULT
  1769. --*/
  1770. {
  1771. HRESULT hr;
  1772. DWORD dwData;
  1773. DWORD dwType;
  1774. DWORD cbData = sizeof( DWORD );
  1775. DWORD csecTTL = DEFAULT_W3_METADATA_CACHE_TTL;
  1776. HKEY hKey;
  1777. //
  1778. // What is the TTL for the URI cache
  1779. //
  1780. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1781. L"System\\CurrentControlSet\\Services\\w3svc\\Parameters",
  1782. 0,
  1783. KEY_READ,
  1784. &hKey ) == ERROR_SUCCESS )
  1785. {
  1786. DBG_ASSERT( hKey != NULL );
  1787. if ( RegQueryValueEx( hKey,
  1788. L"MetadataCacheTTL",
  1789. NULL,
  1790. &dwType,
  1791. (LPBYTE) &dwData,
  1792. &cbData ) == ERROR_SUCCESS &&
  1793. dwType == REG_DWORD )
  1794. {
  1795. csecTTL = dwData;
  1796. }
  1797. RegCloseKey( hKey );
  1798. }
  1799. //
  1800. // We'll use TTL for scavenge period, and expect two inactive periods to
  1801. // flush
  1802. //
  1803. hr = SetCacheConfiguration( csecTTL * 1000,
  1804. csecTTL * 1000,
  1805. CACHE_INVALIDATION_METADATA,
  1806. NULL );
  1807. if ( FAILED( hr ) )
  1808. {
  1809. return hr;
  1810. }
  1811. return W3_METADATA::Initialize();
  1812. }
  1813. HRESULT
  1814. W3_METADATA_CACHE::GetMetaData(
  1815. W3_CONTEXT * pW3Context,
  1816. STRU & strUrl,
  1817. W3_METADATA ** ppMetaData
  1818. )
  1819. /*++
  1820. Routine Description:
  1821. Retrieve a W3_METADATA, creating if necessary
  1822. Arguments:
  1823. pW3Context - W3 context
  1824. strUrl - Url
  1825. ppMetaData - Set to point to metadata on success
  1826. Return Value:
  1827. HRESULT
  1828. --*/
  1829. {
  1830. W3_METADATA_KEY metaKey;
  1831. W3_METADATA * pMetaData;
  1832. DWORD dwDataSetNumber;
  1833. HRESULT hr;
  1834. STACK_STRU( strFullPath, 128 );
  1835. MB mb( g_pW3Server->QueryMDObject() );
  1836. HANDLE hToken = NULL;
  1837. if ( pW3Context == NULL ||
  1838. ppMetaData == NULL )
  1839. {
  1840. DBG_ASSERT( FALSE );
  1841. hr = HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1842. goto Failed;
  1843. }
  1844. *ppMetaData = NULL;
  1845. //
  1846. // Setup a key to lookup by determining data set number
  1847. //
  1848. hr = GetFullMetadataPath( pW3Context,
  1849. strUrl,
  1850. &strFullPath );
  1851. if ( FAILED( hr ) )
  1852. {
  1853. goto Failed;
  1854. }
  1855. //
  1856. // If the caller is coming from an ISAPI, then the thread may
  1857. // be impersonating. Temporarily discard the impersonation
  1858. // token until we get the metadata.
  1859. //
  1860. if ( OpenThreadToken( GetCurrentThread(),
  1861. TOKEN_IMPERSONATE,
  1862. TRUE,
  1863. &hToken ) )
  1864. {
  1865. DBG_ASSERT( hToken != NULL );
  1866. DBG_REQUIRE( RevertToSelf() );
  1867. }
  1868. if ( !mb.GetDataSetNumber( strFullPath.QueryStr(),
  1869. &dwDataSetNumber ) )
  1870. {
  1871. hr = HRESULT_FROM_WIN32( GetLastError() );
  1872. goto Failed;
  1873. }
  1874. metaKey.SetDataSetNumber( dwDataSetNumber );
  1875. //
  1876. // Look it up
  1877. //
  1878. hr = FindCacheEntry( &metaKey, (CACHE_ENTRY**) &pMetaData );
  1879. if ( SUCCEEDED( hr ) )
  1880. {
  1881. DBG_ASSERT( pMetaData != NULL );
  1882. *ppMetaData = pMetaData;
  1883. goto Succeeded;
  1884. }
  1885. //
  1886. // We need to create a metadata entry and add it
  1887. //
  1888. hr = CreateNewMetaData( pW3Context,
  1889. strUrl,
  1890. strFullPath,
  1891. &pMetaData );
  1892. if ( FAILED( hr ) )
  1893. {
  1894. goto Failed;
  1895. }
  1896. DBG_ASSERT( pMetaData != NULL );
  1897. //
  1898. // Add to the cache
  1899. //
  1900. AddCacheEntry( pMetaData );
  1901. *ppMetaData = pMetaData;
  1902. Succeeded:
  1903. DBG_ASSERT( SUCCEEDED( hr ) );
  1904. if ( hToken != NULL )
  1905. {
  1906. DBG_REQUIRE( SetThreadToken( NULL, hToken ) );
  1907. DBG_REQUIRE( CloseHandle( hToken ) );
  1908. hToken = NULL;
  1909. }
  1910. return NO_ERROR;
  1911. Failed:
  1912. DBG_ASSERT( FAILED( hr ) );
  1913. if ( hToken != NULL )
  1914. {
  1915. DBG_REQUIRE( SetThreadToken( NULL, hToken ) );
  1916. DBG_REQUIRE( CloseHandle( hToken ) );
  1917. hToken = NULL;
  1918. }
  1919. return hr;
  1920. }
  1921. HRESULT
  1922. W3_METADATA_CACHE::CreateNewMetaData(
  1923. W3_CONTEXT * pW3Context,
  1924. STRU & strUrl,
  1925. STRU & strFullMetadataPath,
  1926. W3_METADATA ** ppMetaData
  1927. )
  1928. /*++
  1929. Routine Description:
  1930. Create a new W3_METADATA and initializes it
  1931. Arguments:
  1932. pW3Context - context
  1933. strUrl - URL
  1934. strFullMetadataPath - Full metabase path to open
  1935. ppMetaData - Set to new metadata entry on success
  1936. Return Value:
  1937. HRESULT
  1938. --*/
  1939. {
  1940. HRESULT hr;
  1941. W3_METADATA * pMetaData = NULL;
  1942. if ( pW3Context == NULL ||
  1943. ppMetaData == NULL )
  1944. {
  1945. DBG_ASSERT( FALSE );
  1946. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1947. }
  1948. *ppMetaData = NULL;
  1949. //
  1950. // Create the metadata object
  1951. //
  1952. pMetaData = new W3_METADATA( this );
  1953. if ( pMetaData == NULL )
  1954. {
  1955. return HRESULT_FROM_WIN32( GetLastError() );
  1956. }
  1957. //
  1958. // Set full URL for flushing purposes
  1959. //
  1960. hr = pMetaData->QueryMetadataPath()->Copy( strFullMetadataPath );
  1961. if ( FAILED( hr ) )
  1962. {
  1963. pMetaData->DereferenceCacheEntry();
  1964. return hr;
  1965. }
  1966. //
  1967. // Initialize it
  1968. //
  1969. hr = pMetaData->ReadMetaData( *(pW3Context->QuerySite()->QueryMBRoot()),
  1970. strUrl );
  1971. if( FAILED(hr) )
  1972. {
  1973. pMetaData->DereferenceCacheEntry();
  1974. return hr;
  1975. }
  1976. *ppMetaData = pMetaData;
  1977. return NO_ERROR;
  1978. }
  1979. HRESULT
  1980. W3_METADATA_CACHE::GetFullMetadataPath(
  1981. W3_CONTEXT * pW3Context,
  1982. STRU & strUrl,
  1983. STRU * pstrFullPath
  1984. )
  1985. /*++
  1986. Routine Description:
  1987. Get the full metadata given the URL and site
  1988. Arguments:
  1989. pW3Context - Used to get the site
  1990. strUrl - Url
  1991. pstrFullPath - Filled with full path on success
  1992. Return Value:
  1993. HRESULT
  1994. --*/
  1995. {
  1996. HRESULT hr;
  1997. WCHAR * pszSource;
  1998. DWORD cchSource;
  1999. if ( pW3Context == NULL ||
  2000. pstrFullPath == NULL )
  2001. {
  2002. DBG_ASSERT( FALSE );
  2003. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  2004. }
  2005. //
  2006. // Build up full metabase path (including instance)
  2007. //
  2008. hr = pstrFullPath->Copy( *(pW3Context->QuerySite()->QueryMBRoot()) );
  2009. if ( FAILED( hr ) )
  2010. {
  2011. return hr;
  2012. }
  2013. //
  2014. // Don't copy two slashes
  2015. //
  2016. if ( strUrl.QueryStr()[ 0 ] == L'/' )
  2017. {
  2018. pszSource = strUrl.QueryStr() + 1;
  2019. cchSource = strUrl.QueryCCH() - 1;
  2020. }
  2021. else
  2022. {
  2023. pszSource = strUrl.QueryStr();
  2024. cchSource = strUrl.QueryCCH();
  2025. }
  2026. hr = pstrFullPath->Append( pszSource, cchSource );
  2027. if ( FAILED( hr ) )
  2028. {
  2029. return hr;
  2030. }
  2031. return NO_ERROR;
  2032. }