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.

1085 lines
24 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. urlinfo.cxx
  5. Abstract:
  6. Implementation of URL cache
  7. Author:
  8. Bilal Alam (balam) 8-Jan-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. //
  16. // This is the maximum size for a script map extension
  17. //
  18. #define MAX_EXT_LEN 128
  19. ALLOC_CACHE_HANDLER * W3_URL_INFO::sm_pachW3UrlInfo;
  20. DWORD W3_URL_INFO::sm_cMaxDots;
  21. HRESULT
  22. W3_URL_INFO_KEY::CreateCacheKey(
  23. WCHAR * pszKey,
  24. DWORD cchKey,
  25. DWORD cchSitePrefix,
  26. BOOL fCopy
  27. )
  28. /*++
  29. Description:
  30. Setup a URI cache key
  31. Arguments:
  32. pszKey - URL of cache key
  33. cchKey - size of URL
  34. cchSitePrefix - Size of site prefix ("LM/W3SVC/<n>")
  35. fCopy - Set to TRUE if we should copy the URL, else we just keep a ref
  36. Return:
  37. HRESULT
  38. --*/
  39. {
  40. HRESULT hr;
  41. _cchSitePrefix = cchSitePrefix;
  42. if ( fCopy )
  43. {
  44. hr = _strKey.Copy( pszKey );
  45. if ( FAILED( hr ) )
  46. {
  47. return hr;
  48. }
  49. _pszKey = _strKey.QueryStr();
  50. _cchKey = _strKey.QueryCCH();
  51. }
  52. else
  53. {
  54. _pszKey = pszKey;
  55. _cchKey = cchKey;
  56. }
  57. return NO_ERROR;
  58. }
  59. //static
  60. HRESULT
  61. W3_URL_INFO::Initialize(
  62. VOID
  63. )
  64. /*++
  65. Description:
  66. URI entry lookaside initialization
  67. Arguments:
  68. None
  69. Return:
  70. HRESULT
  71. --*/
  72. {
  73. ALLOC_CACHE_CONFIGURATION acConfig;
  74. HRESULT hr;
  75. DWORD dwError;
  76. HKEY hKey = NULL;
  77. DWORD cbData;
  78. DWORD dwType;
  79. DWORD dwValue;
  80. //
  81. // Default max dots is 100
  82. //
  83. sm_cMaxDots = 100;
  84. //
  85. // Look for a registry override to the max dot value
  86. // (one of the more useful configurable options in IIS)
  87. //
  88. dwError = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  89. L"System\\CurrentControlSet\\Services\\inetinfo\\Parameters",
  90. 0,
  91. KEY_READ,
  92. &hKey );
  93. if ( dwError == ERROR_SUCCESS )
  94. {
  95. DBG_ASSERT( hKey != NULL );
  96. //
  97. // Should we be file caching at all?
  98. //
  99. cbData = sizeof( DWORD );
  100. dwError = RegQueryValueEx( hKey,
  101. L"MaxDepthDots",
  102. NULL,
  103. &dwType,
  104. (LPBYTE) &dwValue,
  105. &cbData );
  106. if ( dwError == ERROR_SUCCESS && dwType == REG_DWORD )
  107. {
  108. sm_cMaxDots = dwValue;
  109. }
  110. }
  111. //
  112. // Initialize allocation lookaside
  113. //
  114. acConfig.nConcurrency = 1;
  115. acConfig.nThreshold = 100;
  116. acConfig.cbSize = sizeof( W3_URL_INFO );
  117. DBG_ASSERT( sm_pachW3UrlInfo == NULL );
  118. sm_pachW3UrlInfo = new ALLOC_CACHE_HANDLER( "W3_URL_INFO",
  119. &acConfig );
  120. if ( sm_pachW3UrlInfo == NULL )
  121. {
  122. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  123. DBGPRINTF(( DBG_CONTEXT,
  124. "Error initializing sm_pachW3UrlInfo. hr = 0x%x\n",
  125. hr ));
  126. return hr;
  127. }
  128. return NO_ERROR;
  129. }
  130. //static
  131. VOID
  132. W3_URL_INFO::Terminate(
  133. VOID
  134. )
  135. /*++
  136. Description:
  137. URI cache cleanup
  138. Arguments:
  139. None
  140. Return:
  141. None
  142. --*/
  143. {
  144. if ( sm_pachW3UrlInfo != NULL )
  145. {
  146. delete sm_pachW3UrlInfo;
  147. sm_pachW3UrlInfo = NULL;
  148. }
  149. }
  150. HRESULT
  151. W3_URL_INFO::Create(
  152. STRU & strUrl,
  153. STRU & strMetadataPath
  154. )
  155. /*++
  156. Description:
  157. Initialize a W3_URL_INFO
  158. Arguments:
  159. strUrl - Url key for this entry
  160. strMetadataPath - Full metadata path used for key
  161. Return:
  162. HRESULT
  163. --*/
  164. {
  165. HRESULT hr;
  166. hr = _cacheKey.CreateCacheKey( strMetadataPath.QueryStr(),
  167. strMetadataPath.QueryCCH(),
  168. strMetadataPath.QueryCCH() - strUrl.QueryCCH(),
  169. TRUE );
  170. if ( FAILED( hr ) )
  171. {
  172. return hr;
  173. }
  174. //
  175. // Process the URL for execution info (and splitting path_info/url)
  176. //
  177. hr = ProcessUrl( strUrl );
  178. if( FAILED( hr ) )
  179. {
  180. return hr;
  181. }
  182. //
  183. // Now create physical path
  184. //
  185. hr = _pMetaData->BuildPhysicalPath( _strProcessedUrl,
  186. &_strPhysicalPath );
  187. if ( FAILED( hr ) )
  188. {
  189. return hr;
  190. }
  191. //
  192. // Now create translation of the whole URL. Note: this is not always
  193. // PathTranslated, so we do not name it so
  194. //
  195. hr = _pMetaData->BuildPhysicalPath( strUrl,
  196. &_strUrlTranslated );
  197. if ( FAILED( hr ) )
  198. {
  199. return hr;
  200. }
  201. return NO_ERROR;
  202. }
  203. HRESULT
  204. W3_URL_INFO::GetPathTranslated(
  205. W3_CONTEXT * pW3Context,
  206. BOOL fUsePathInfo,
  207. STRU * pstrPathTranslated
  208. )
  209. /*++
  210. Routine Description:
  211. Given the PATH_INFO of this cached entry, determine PATH_TRANSLATED.
  212. This involves:
  213. 1) Mapping PATH_INFO to a physical path
  214. 2) Calling filters if necessary for this path
  215. We cache the output of step 1)
  216. Arguments:
  217. pW3Context - W3Context
  218. pstrPathTranslated - Filled with physical path on success
  219. Return Value:
  220. HRESULT
  221. --*/
  222. {
  223. HRESULT hr = S_OK;
  224. W3_URL_INFO * pUrlInfo = NULL;
  225. if ( pW3Context == NULL ||
  226. pstrPathTranslated == NULL )
  227. {
  228. DBG_ASSERT( FALSE );
  229. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  230. }
  231. //
  232. // Check for cached path translated entry. If its there and flushed,
  233. // then release it (and try again)
  234. //
  235. if ( _pUrlInfoPathTranslated != NULL )
  236. {
  237. LockCacheEntry();
  238. if ( _pUrlInfoPathTranslated != NULL )
  239. {
  240. if ( _pUrlInfoPathTranslated->QueryIsFlushed() )
  241. {
  242. _pUrlInfoPathTranslated->DereferenceCacheEntry();
  243. _pUrlInfoPathTranslated = NULL;
  244. }
  245. else
  246. {
  247. _pUrlInfoPathTranslated->ReferenceCacheEntry();
  248. pUrlInfo = _pUrlInfoPathTranslated;
  249. }
  250. }
  251. UnlockCacheEntry();
  252. }
  253. //
  254. // Use the cached translated entry if there
  255. //
  256. if ( pUrlInfo == NULL )
  257. {
  258. //
  259. // Get and keep the metadata and urlinfo for this path
  260. //
  261. DBG_ASSERT( g_pW3Server->QueryUrlInfoCache() != NULL );
  262. if ( fUsePathInfo )
  263. {
  264. hr = g_pW3Server->QueryUrlInfoCache()->GetUrlInfo( pW3Context,
  265. _strPathInfo,
  266. &pUrlInfo );
  267. }
  268. else
  269. {
  270. pUrlInfo = this;
  271. pUrlInfo->ReferenceCacheEntry();
  272. }
  273. if ( FAILED( hr ) )
  274. {
  275. return hr;
  276. }
  277. DBG_ASSERT( pUrlInfo != NULL );
  278. //
  279. // Store away the URL info, provided it is an empty string.
  280. //
  281. // Basically, we're trying to optimize the case of "/foobar.dll".
  282. // In this case, path info is empty, and we want to avoid doing the
  283. // extra URL lookup for empty string.
  284. //
  285. if ( pUrlInfo->QueryCached() &&
  286. pUrlInfo->QueryUrl()[0] == L'\0' )
  287. {
  288. LockCacheEntry();
  289. if ( _pUrlInfoPathTranslated == NULL )
  290. {
  291. _pUrlInfoPathTranslated = pUrlInfo;
  292. }
  293. else
  294. {
  295. pUrlInfo->DereferenceCacheEntry();
  296. pUrlInfo = _pUrlInfoPathTranslated;
  297. }
  298. pUrlInfo->ReferenceCacheEntry();
  299. UnlockCacheEntry();
  300. }
  301. }
  302. DBG_ASSERT( pUrlInfo != NULL );
  303. //
  304. // Now call into the filter
  305. //
  306. hr = W3_STATE_URLINFO::FilterMapPath( pW3Context,
  307. pUrlInfo,
  308. pstrPathTranslated );
  309. pUrlInfo->DereferenceCacheEntry();
  310. return hr;
  311. }
  312. HRESULT
  313. W3_URL_INFO::GetFileInfo(
  314. FILE_CACHE_USER * pOpeningUser,
  315. BOOL fDoCache,
  316. W3_FILE_INFO ** ppFileInfo
  317. )
  318. /*++
  319. Routine Description:
  320. Get file info associated with this cache entry. If it doesn't exist,
  321. then go to file cache directly to open the file
  322. Arguments:
  323. pOpeningUser - Opening user
  324. fDoCache - Should we cache the file
  325. ppFileInfo - Set to file cache entry on success
  326. Return Value:
  327. HRESULT
  328. --*/
  329. {
  330. W3_FILE_INFO * pFileInfo = NULL;
  331. BOOL fCleanup = FALSE;
  332. HRESULT hr;
  333. if ( ppFileInfo == NULL ||
  334. pOpeningUser == NULL )
  335. {
  336. DBG_ASSERT( FALSE );
  337. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  338. }
  339. *ppFileInfo = NULL;
  340. //
  341. // Do we already have a file entry associated? If so use it, if it was
  342. // not already flushed
  343. //
  344. LockCacheEntry();
  345. if ( _pFileInfo != NULL )
  346. {
  347. if ( _pFileInfo->Checkout() )
  348. {
  349. pFileInfo = _pFileInfo;
  350. }
  351. else
  352. {
  353. _pFileInfo->DereferenceCacheEntry();
  354. _pFileInfo = NULL;
  355. }
  356. }
  357. UnlockCacheEntry();
  358. //
  359. // If we got a file entry, we're done, assuming access check is ok
  360. //
  361. if ( pFileInfo != NULL )
  362. {
  363. hr = pFileInfo->DoAccessCheck( pOpeningUser );
  364. if ( SUCCEEDED( hr ) )
  365. {
  366. *ppFileInfo = pFileInfo;
  367. return NO_ERROR;
  368. }
  369. else
  370. {
  371. pFileInfo->DereferenceCacheEntry();
  372. return hr;
  373. }
  374. }
  375. //
  376. // We'll have to go to file cache directly
  377. //
  378. DBG_ASSERT( g_pW3Server->QueryFileCache() != NULL );
  379. hr = g_pW3Server->QueryFileCache()->GetFileInfo(
  380. _strPhysicalPath,
  381. _pMetaData->QueryDirmonConfig(),
  382. pOpeningUser,
  383. fDoCache,
  384. &pFileInfo );
  385. if ( FAILED( hr ) )
  386. {
  387. return hr;
  388. }
  389. DBG_ASSERT( pFileInfo != NULL );
  390. //
  391. // Now try to stuff the file descriptor into this object (bearing in mind
  392. // that another thread may try to do the same thing for this W3_URL_INFO)
  393. //
  394. if ( pFileInfo->QueryCached() )
  395. {
  396. LockCacheEntry();
  397. if ( _pFileInfo == NULL )
  398. {
  399. pFileInfo->ReferenceCacheEntry();
  400. _pFileInfo = pFileInfo;
  401. }
  402. UnlockCacheEntry();
  403. }
  404. //
  405. // It is OK if this thread was not able to associate the file entry.
  406. //
  407. *ppFileInfo = pFileInfo;
  408. return NO_ERROR;
  409. }
  410. HRESULT
  411. W3_URL_INFO::ProcessUrl(
  412. STRU & strUrl
  413. )
  414. /*++
  415. Routine Description:
  416. Process the URL and assocate execution information with
  417. the W3_URL_INFO.
  418. Called before adding a new URL info to the cache.
  419. Look through the url for script-mapped or executable extensions
  420. and update the W3_URL_INFO with the actual URL to execute,
  421. path-info, gateway type, etc.
  422. Arguments:
  423. strUrl - Original requested URL
  424. Return Value:
  425. SUCCEEDED()/FAILED()
  426. CODEWORK
  427. 1. Handle wildcard mappings
  428. --*/
  429. {
  430. HRESULT hr = NOERROR;
  431. DWORD cDots = 0;
  432. DBG_ASSERT( _pMetaData );
  433. STACK_STRU( strExtension, MAX_EXT_LEN );
  434. //
  435. // Reference the URL_INFO's data
  436. //
  437. STRU * pstrProcessedUrl = &_strProcessedUrl;
  438. STRU * pstrPathInfo = &_strPathInfo;
  439. //
  440. // Iterate over pstrProcessedUrl. These always point at the
  441. // pstrProcessedUrl string.
  442. //
  443. WCHAR * pszExtensionIter = NULL;
  444. WCHAR * pszPathInfoIter = NULL;
  445. //
  446. // Make a working copy of the URL, this will be modified if an
  447. // exectuable extension is found before the terminal node in the
  448. // path.
  449. //
  450. hr = pstrProcessedUrl->Copy( strUrl );
  451. if( FAILED(hr) )
  452. {
  453. goto failure;
  454. }
  455. //
  456. // Search the URL for an extension that matches something
  457. // we know how to execute.
  458. //
  459. pszExtensionIter = pstrProcessedUrl->QueryStr();
  460. while( pszExtensionIter = wcschr( pszExtensionIter, L'.' ) )
  461. {
  462. //
  463. // Maintain a count of the dots we encounter, any more than
  464. // sm_cMaxDots and we fail the request
  465. //
  466. cDots++;
  467. if ( cDots > sm_cMaxDots )
  468. {
  469. break;
  470. }
  471. //
  472. // Save the extension string
  473. //
  474. hr = strExtension.Copy( pszExtensionIter );
  475. if( FAILED(hr) )
  476. {
  477. goto failure;
  478. }
  479. //
  480. // Find the end of the string or the beginning of the path info
  481. //
  482. pszPathInfoIter = wcschr( pszExtensionIter, L'/' );
  483. if( pszPathInfoIter != NULL )
  484. {
  485. DBG_REQUIRE(
  486. strExtension.SetLen(
  487. DIFF(pszPathInfoIter - pszExtensionIter)
  488. )
  489. );
  490. }
  491. //
  492. // Lowercase the extension string to allow case-insensitive
  493. // comparisons.
  494. //
  495. _wcslwr( strExtension.QueryStr() );
  496. //
  497. // Try to find a matching script map entry
  498. //
  499. META_SCRIPT_MAP * pScriptMap;
  500. META_SCRIPT_MAP_ENTRY * pScriptMapEntry;
  501. pScriptMap = _pMetaData->QueryScriptMap();
  502. DBG_ASSERT( pScriptMap );
  503. if( pScriptMap->FindEntry( strExtension, &pScriptMapEntry ) )
  504. {
  505. DBG_ASSERT( pScriptMapEntry );
  506. _pScriptMapEntry = pScriptMapEntry;
  507. if( pszPathInfoIter )
  508. {
  509. hr = pstrPathInfo->Copy( pszPathInfoIter );
  510. if( FAILED(hr) )
  511. {
  512. goto failure;
  513. }
  514. //
  515. // Make sure that we truncate the URL so that we don't end
  516. // up downloading a source file by mistake.
  517. //
  518. DBG_REQUIRE(
  519. pstrProcessedUrl->SetLen(
  520. DIFF(pszPathInfoIter - pstrProcessedUrl->QueryStr())
  521. )
  522. );
  523. }
  524. else
  525. {
  526. pstrPathInfo->Reset();
  527. }
  528. //
  529. // Since we found the entry, we are done
  530. //
  531. break;
  532. }
  533. //
  534. // No matching script map, so check if this is a wellknown
  535. // Gateway type.
  536. //
  537. DBG_ASSERT( pScriptMapEntry == NULL );
  538. DBG_ASSERT( _pScriptMapEntry == NULL );
  539. //
  540. // Avoid all the string comps if we will never match.
  541. //
  542. if( strExtension.QueryCCH() == 4 )
  543. {
  544. GATEWAY_TYPE Gateway;
  545. Gateway = GATEWAY_UNKNOWN;
  546. //
  547. // Test extension against known gateway extensions.
  548. //
  549. // Does it make sense to allow the known extensions to be
  550. // configured?
  551. //
  552. if( wcscmp( L".dll", strExtension.QueryStr() ) == 0 ||
  553. wcscmp( L".isa", strExtension.QueryStr() ) == 0
  554. )
  555. {
  556. Gateway = GATEWAY_ISAPI;
  557. }
  558. else if( !wcscmp( L".exe", strExtension.QueryStr() ) ||
  559. !wcscmp( L".cgi", strExtension.QueryStr() ) ||
  560. !wcscmp( L".com", strExtension.QueryStr() ) )
  561. {
  562. Gateway = GATEWAY_CGI;
  563. }
  564. else if( wcscmp( L".map", strExtension.QueryStr() ) == 0 )
  565. {
  566. Gateway = GATEWAY_MAP;
  567. }
  568. //
  569. // OK. Before we continue, if the request was a GATEWAY_ISAPI
  570. // or GATEWAY_CGI and we do NOT have EXECUTE permissions, then
  571. // this really isn't a ISA/CGI after all
  572. //
  573. if ( Gateway == GATEWAY_CGI ||
  574. Gateway == GATEWAY_ISAPI )
  575. {
  576. if ( !( _pMetaData->QueryAccessPerms() & VROOT_MASK_EXECUTE ) )
  577. {
  578. Gateway = GATEWAY_UNKNOWN;
  579. }
  580. }
  581. //
  582. // The gateway is specified in the URL and we recognize it.
  583. //
  584. if( Gateway != GATEWAY_UNKNOWN )
  585. {
  586. _Gateway = Gateway;
  587. //
  588. // Save everthing after the matching extension as
  589. // path-info and truncate the URL so that it doesn't
  590. // include the path info
  591. //
  592. if( pszPathInfoIter )
  593. {
  594. hr = pstrPathInfo->Copy( pszPathInfoIter );
  595. if( FAILED(hr) )
  596. {
  597. goto failure;
  598. }
  599. DBG_REQUIRE(
  600. pstrProcessedUrl->SetLen(
  601. DIFF(pszPathInfoIter - pstrProcessedUrl->QueryStr())
  602. )
  603. );
  604. }
  605. else
  606. {
  607. pstrPathInfo->Reset();
  608. }
  609. //
  610. // We have a match so exit the loop
  611. //
  612. break;
  613. }
  614. }
  615. //
  616. // We do not have a matching entry, so continue to look for an
  617. // executable extension.
  618. //
  619. pszExtensionIter++;
  620. } // while (pszExtensionIter)
  621. //
  622. // Now associate the ContentType for this entry
  623. //
  624. if (FAILED(hr = SelectMimeMappingForFileExt(pstrProcessedUrl->QueryStr(),
  625. _pMetaData->QueryMimeMap(),
  626. &_strContentType)))
  627. {
  628. goto failure;
  629. }
  630. return S_OK;
  631. failure:
  632. DBG_ASSERT( FAILED(hr) );
  633. return FAILED(hr) ? hr : E_FAIL;
  634. }
  635. HRESULT
  636. W3_URL_INFO_CACHE::Initialize(
  637. VOID
  638. )
  639. /*++
  640. Description:
  641. Initialize URI cache
  642. Arguments:
  643. None
  644. Return:
  645. HRESULT
  646. --*/
  647. {
  648. HRESULT hr;
  649. DWORD dwData;
  650. DWORD dwType;
  651. DWORD cbData = sizeof( DWORD );
  652. DWORD csecTTL = DEFAULT_W3_URL_INFO_CACHE_TTL;
  653. HKEY hKey;
  654. //
  655. // What is the TTL for the URI cache
  656. //
  657. if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  658. L"System\\CurrentControlSet\\Services\\inetinfo\\Parameters",
  659. 0,
  660. KEY_READ,
  661. &hKey ) == ERROR_SUCCESS )
  662. {
  663. DBG_ASSERT( hKey != NULL );
  664. if ( RegQueryValueEx( hKey,
  665. L"ObjectCacheTTL",
  666. NULL,
  667. &dwType,
  668. (LPBYTE) &dwData,
  669. &cbData ) == ERROR_SUCCESS &&
  670. dwType == REG_DWORD )
  671. {
  672. csecTTL = dwData;
  673. }
  674. RegCloseKey( hKey );
  675. }
  676. //
  677. // We'll use TTL for scavenge period, and expect two inactive periods to
  678. // flush
  679. //
  680. hr = SetCacheConfiguration( csecTTL * 1000,
  681. csecTTL * 1000,
  682. CACHE_INVALIDATION_METADATA,
  683. NULL );
  684. if ( FAILED( hr ) )
  685. {
  686. return hr;
  687. }
  688. return W3_URL_INFO::Initialize();
  689. }
  690. HRESULT
  691. W3_URL_INFO_CACHE::GetUrlInfo(
  692. W3_CONTEXT * pW3Context,
  693. STRU & strUrl,
  694. W3_URL_INFO ** ppUrlInfo
  695. )
  696. /*++
  697. Routine Description:
  698. Retrieve a W3_URL_INFO, creating it if necessary
  699. Arguments:
  700. pW3Context - W3 context
  701. strUrl - Url to lookup
  702. ppUrlInfo - Filled with cache entry if successful
  703. Return Value:
  704. HRESULT
  705. --*/
  706. {
  707. W3_URL_INFO_KEY uriKey;
  708. W3_URL_INFO * pUrlInfo;
  709. STACK_STRU( strUpperKey, MAX_PATH );
  710. STRU * pstrMBRoot;
  711. HRESULT hr;
  712. if ( pW3Context == NULL ||
  713. ppUrlInfo == NULL )
  714. {
  715. DBG_ASSERT( FALSE );
  716. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  717. }
  718. *ppUrlInfo = NULL;
  719. //
  720. // The key is the full metadata path. Start with the site prefix minus
  721. // the trailing '/'
  722. //
  723. pstrMBRoot = pW3Context->QuerySite()->QueryMBRoot();
  724. DBG_ASSERT( pstrMBRoot != NULL );
  725. hr = strUpperKey.Copy( pstrMBRoot->QueryStr(),
  726. pstrMBRoot->QueryCCH() - 1 );
  727. if ( FAILED( hr ) )
  728. {
  729. return hr;
  730. }
  731. //
  732. // Now add the URL and upper case it to avoid insensitive compares later
  733. //
  734. hr = strUpperKey.Append( strUrl );
  735. if ( FAILED( hr ) )
  736. {
  737. return hr;
  738. }
  739. _wcsupr( strUpperKey.QueryStr() );
  740. //
  741. // Setup a key to lookup
  742. //
  743. hr = uriKey.CreateCacheKey( strUpperKey.QueryStr(),
  744. strUpperKey.QueryCCH(),
  745. pW3Context->QuerySite()->QueryMBRoot()->QueryCCH(),
  746. FALSE );
  747. if ( FAILED( hr ) )
  748. {
  749. return hr;
  750. }
  751. //
  752. // Look it up
  753. //
  754. hr = FindCacheEntry( &uriKey,
  755. (CACHE_ENTRY**) &pUrlInfo );
  756. if ( SUCCEEDED( hr ) )
  757. {
  758. DBG_ASSERT( pUrlInfo != NULL );
  759. *ppUrlInfo = pUrlInfo;
  760. return NO_ERROR;
  761. }
  762. //
  763. // We need to create a URI cache entry
  764. //
  765. hr = CreateNewUrlInfo( pW3Context,
  766. strUrl,
  767. strUpperKey,
  768. &pUrlInfo );
  769. if ( FAILED( hr ) )
  770. {
  771. return hr;
  772. }
  773. DBG_ASSERT( pUrlInfo != NULL );
  774. //
  775. // Add to the cache
  776. //
  777. AddCacheEntry( pUrlInfo );
  778. *ppUrlInfo = pUrlInfo;
  779. return NO_ERROR;
  780. }
  781. HRESULT
  782. W3_URL_INFO_CACHE::CreateNewUrlInfo(
  783. W3_CONTEXT * pW3Context,
  784. STRU & strUrl,
  785. STRU & strMetadataPath,
  786. W3_URL_INFO ** ppUrlInfo
  787. )
  788. /*++
  789. Routine Description:
  790. Create a new URI cache entry
  791. Arguments:
  792. pW3Context - Main context
  793. strUrl - Url
  794. strMetadataPath - Full metadata path used as key
  795. ppUrlInfo - Set to URI cache entry
  796. Return Value:
  797. HRESULT
  798. --*/
  799. {
  800. W3_METADATA * pMetaData = NULL;
  801. W3_URL_INFO * pUrlInfo = NULL;
  802. HRESULT hr;
  803. if ( pW3Context == NULL ||
  804. ppUrlInfo == NULL )
  805. {
  806. DBG_ASSERT( FALSE );
  807. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  808. }
  809. *ppUrlInfo = NULL;
  810. //
  811. // Find a metacache entry
  812. //
  813. DBG_ASSERT( g_pW3Server->QueryMetaCache() != NULL );
  814. hr = g_pW3Server->QueryMetaCache()->GetMetaData( pW3Context,
  815. strUrl,
  816. &pMetaData );
  817. if ( FAILED( hr ) )
  818. {
  819. return hr;
  820. }
  821. DBG_ASSERT( pMetaData != NULL );
  822. //
  823. // Create a W3_URL_INFO
  824. //
  825. pUrlInfo = new W3_URL_INFO( this, pMetaData );
  826. if ( pUrlInfo == NULL )
  827. {
  828. hr = HRESULT_FROM_WIN32( GetLastError() );
  829. pMetaData->DereferenceCacheEntry();
  830. return hr;
  831. }
  832. hr = pUrlInfo->Create( strUrl,
  833. strMetadataPath );
  834. if ( FAILED( hr ) )
  835. {
  836. pUrlInfo->DereferenceCacheEntry();
  837. return hr;
  838. }
  839. *ppUrlInfo = pUrlInfo;
  840. return NO_ERROR;
  841. }