Leaked source code of windows server 2003
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.

2486 lines
59 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. isapi_handler.cxx
  5. Abstract:
  6. Handle ISAPI extension requests
  7. Author:
  8. Taylor Weiss (TaylorW) 27-Jan-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include <initguid.h>
  15. #include "precomp.hxx"
  16. #include "isapi_handler.h"
  17. #include <wmrgexp.h>
  18. #include <iisextp.h>
  19. #include <errno.h>
  20. HMODULE W3_ISAPI_HANDLER::sm_hIsapiModule;
  21. PFN_ISAPI_TERM_MODULE W3_ISAPI_HANDLER::sm_pfnTermIsapiModule;
  22. PFN_ISAPI_PROCESS_REQUEST W3_ISAPI_HANDLER::sm_pfnProcessIsapiRequest;
  23. PFN_ISAPI_PROCESS_COMPLETION W3_ISAPI_HANDLER::sm_pfnProcessIsapiCompletion;
  24. W3_INPROC_ISAPI_HASH * W3_ISAPI_HANDLER::sm_pInprocIsapiHash;
  25. CRITICAL_SECTION W3_ISAPI_HANDLER::sm_csInprocHashLock;
  26. CRITICAL_SECTION W3_ISAPI_HANDLER::sm_csBigHurkinWamRegLock;
  27. WAM_PROCESS_MANAGER * W3_ISAPI_HANDLER::sm_pWamProcessManager;
  28. BOOL W3_ISAPI_HANDLER::sm_fWamActive;
  29. CHAR W3_ISAPI_HANDLER::sm_szInstanceId[SIZE_CLSID_STRING];
  30. BOOL sg_Initialized = FALSE;
  31. /***********************************************************************
  32. Local Declarations
  33. ***********************************************************************/
  34. VOID
  35. AddFiltersToMultiSz(
  36. IN const MB & mb,
  37. IN LPCWSTR szFilterPath,
  38. IN OUT MULTISZ * pmsz
  39. );
  40. VOID
  41. AddAllFiltersToMultiSz(
  42. IN const MB & mb,
  43. IN OUT MULTISZ * pmsz
  44. );
  45. /***********************************************************************
  46. Module Definitions
  47. ***********************************************************************/
  48. CONTEXT_STATUS
  49. W3_ISAPI_HANDLER::DoWork(
  50. VOID
  51. )
  52. /*++
  53. Routine Description:
  54. Main ISAPI handler routine
  55. Return Value:
  56. CONTEXT_STATUS_PENDING if async pending,
  57. else CONTEXT_STATUS_CONTINUE
  58. --*/
  59. {
  60. W3_CONTEXT *pW3Context = QueryW3Context();
  61. DBG_ASSERT( pW3Context != NULL );
  62. HRESULT hr;
  63. BOOL fComplete = FALSE;
  64. W3_REQUEST *pRequest = pW3Context->QueryRequest();
  65. W3_METADATA *pMetaData = pW3Context->QueryUrlContext()->QueryMetaData();
  66. //
  67. // Preload entity if needed
  68. //
  69. hr = pRequest->PreloadEntityBody( pW3Context,
  70. &fComplete );
  71. //
  72. // If we cannot read the request entity, we will assume it is the
  73. // client's fault
  74. //
  75. if ( FAILED( hr ) )
  76. {
  77. if ( hr == HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY ) )
  78. {
  79. pW3Context->SetErrorStatus( hr );
  80. pW3Context->QueryResponse()->SetStatus( HttpStatusServerError );
  81. }
  82. else if ( hr == HRESULT_FROM_WIN32( ERROR_CONNECTION_INVALID ) )
  83. {
  84. pW3Context->QueryResponse()->SetStatus( HttpStatusEntityTooLarge );
  85. }
  86. else
  87. {
  88. pW3Context->SetErrorStatus( hr );
  89. pW3Context->QueryResponse()->SetStatus( HttpStatusBadRequest );
  90. }
  91. return CONTEXT_STATUS_CONTINUE;
  92. }
  93. if ( !fComplete )
  94. {
  95. //
  96. // Async read pending. Just bail
  97. //
  98. return CONTEXT_STATUS_PENDING;
  99. }
  100. //
  101. // If we've already exceeded the maximum allowed entity, we
  102. // need to fail.
  103. //
  104. if ( pW3Context->QueryMainContext()->QueryEntityReadSoFar() >
  105. pMetaData->QueryMaxRequestEntityAllowed() )
  106. {
  107. pW3Context->QueryResponse()->SetStatus( HttpStatusEntityTooLarge );
  108. return CONTEXT_STATUS_CONTINUE;
  109. }
  110. _fEntityBodyPreloadComplete = TRUE;
  111. _State = ISAPI_STATE_INITIALIZING;
  112. return IsapiDoWork( pW3Context );
  113. }
  114. CONTEXT_STATUS
  115. W3_ISAPI_HANDLER::IsapiDoWork(
  116. W3_CONTEXT * pW3Context
  117. )
  118. /*++
  119. Routine Description:
  120. Called to execute an ISAPI. This routine must be called only after
  121. we have preloaded entity for the request
  122. Arguments:
  123. pW3Context - Context for this request
  124. Return Value:
  125. CONTEXT_STATUS_PENDING if async pending,
  126. else CONTEXT_STATUS_CONTINUE
  127. --*/
  128. {
  129. DWORD dwHseResult;
  130. HRESULT hr = NOERROR;
  131. HANDLE hOopToken;
  132. URL_CONTEXT * pUrlContext;
  133. BOOL fIsVrToken;
  134. DWORD dwWamSubError = 0;
  135. HTTP_SUB_ERROR httpSubError;
  136. //
  137. // We must have preloaded entity by the time this is called
  138. //
  139. DBG_ASSERT( _State == ISAPI_STATE_INITIALIZING );
  140. DBG_ASSERT( _fEntityBodyPreloadComplete );
  141. DBG_ASSERT( sm_pfnProcessIsapiRequest );
  142. DBG_ASSERT( sm_pfnProcessIsapiCompletion );
  143. DBG_REQUIRE( ( pUrlContext = pW3Context->QueryUrlContext() ) != NULL );
  144. IF_DEBUG( ISAPI )
  145. {
  146. DBGPRINTF((
  147. DBG_CONTEXT,
  148. "IsapiDoWork called for new request.\r\n"
  149. ));
  150. }
  151. //
  152. // Initialize the ISAPI_CORE_DATA and ISAPI_CORE_INTERFACE
  153. // for this request
  154. //
  155. if ( FAILED( hr = InitCoreData( &fIsVrToken ) ) )
  156. {
  157. goto ErrorExit;
  158. }
  159. DBG_ASSERT( _pCoreData );
  160. //
  161. // If the gateway image is not enabled, then we should fail the
  162. // request with a 404.
  163. //
  164. if ( g_pW3Server->QueryIsIsapiImageEnabled( _pCoreData->szGatewayImage ) == FALSE )
  165. {
  166. _State = ISAPI_STATE_FAILED;
  167. DBGPRINTF(( DBG_CONTEXT,
  168. "ISAPI image disabled: %S.\r\n",
  169. _pCoreData->szGatewayImage ));
  170. pW3Context->SetErrorStatus( ERROR_ACCESS_DISABLED_BY_POLICY );
  171. pW3Context->QueryResponse()->SetStatus( HttpStatusNotFound,
  172. Http404DeniedByPolicy );
  173. hr = pW3Context->SendResponse( W3_FLAG_ASYNC );
  174. if ( SUCCEEDED( hr ) )
  175. {
  176. return CONTEXT_STATUS_PENDING;
  177. }
  178. else
  179. {
  180. return CONTEXT_STATUS_CONTINUE;
  181. }
  182. }
  183. _pIsapiRequest = new (pW3Context) ISAPI_REQUEST( pW3Context, _pCoreData->fIsOop );
  184. if ( _pIsapiRequest == NULL )
  185. {
  186. hr = E_OUTOFMEMORY;
  187. goto ErrorExit;
  188. }
  189. if ( FAILED( hr = _pIsapiRequest->Create() ) )
  190. {
  191. goto ErrorExit;
  192. }
  193. //
  194. // If the request should run OOP, get the WAM process and
  195. // duplicate the impersonation token
  196. //
  197. if ( _pCoreData->fIsOop )
  198. {
  199. DBG_ASSERT( sm_pWamProcessManager );
  200. DBG_ASSERT( _pCoreData->szWamClsid[0] != L'\0' );
  201. hr = sm_pWamProcessManager->GetWamProcess(
  202. (LPCWSTR)&_pCoreData->szWamClsid,
  203. _pCoreData->szApplMdPathW,
  204. &dwWamSubError,
  205. &_pWamProcess,
  206. sm_szInstanceId
  207. );
  208. if ( FAILED( hr ) )
  209. {
  210. goto ErrorExit;
  211. }
  212. //
  213. // We have to modify the token that we're passing to
  214. // the OOP process.
  215. //
  216. if( ( fIsVrToken && !pW3Context->QueryVrToken()->QueryOOPToken() ) ||
  217. ( !fIsVrToken && !pW3Context->QueryUserContext()->QueryIsCachedToken() ) ||
  218. ( !fIsVrToken && !pW3Context->QueryUserContext()->QueryCachedToken()->QueryOOPToken() ) )
  219. {
  220. hr = GrantWpgAccessToToken( _pCoreData->hToken );
  221. if ( FAILED( hr ) )
  222. {
  223. goto ErrorExit;
  224. }
  225. hr = AddWpgToTokenDefaultDacl( _pCoreData->hToken );
  226. if ( FAILED( hr ) )
  227. {
  228. goto ErrorExit;
  229. }
  230. }
  231. if ( DuplicateHandle( GetCurrentProcess(), _pCoreData->hToken,
  232. _pWamProcess->QueryProcess(), &hOopToken,
  233. 0, FALSE, DUPLICATE_SAME_ACCESS ) )
  234. {
  235. _pCoreData->hToken = hOopToken;
  236. }
  237. else
  238. {
  239. hr = HRESULT_FROM_WIN32( GetLastError() );
  240. //
  241. // CODEWORK - If the target process has exited, then
  242. // DuplicateHandle fails with ERROR_ACCESS_DENIED. This
  243. // will confuse our error handling logic because it'll
  244. // thing that we really got this error attempting to
  245. // process the request.
  246. //
  247. // For the time being, we'll detect this error and let
  248. // it call into ProcessRequest. If the process really
  249. // has exited, this will cause the WAM_PROCESS cleanup
  250. // code to recover everything.
  251. //
  252. // In the future, we should consider waiting on the
  253. // process handle to detect steady-state crashes of
  254. // OOP hosts so that we don't have to discover the
  255. // problem only when something trys to talk to the
  256. // process.
  257. //
  258. // Another thing to consider is that we could trigger
  259. // the crash recovery directly and call GetWamProcess
  260. // again to get a new process. This would make the
  261. // crash completely transparent to the client, which
  262. // would be an improvement over the current solution
  263. // (and IIS 4 and 5) which usually waits until a client
  264. // request fails before recovering.
  265. //
  266. _pCoreData->hToken = NULL;
  267. if ( hr != HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) )
  268. {
  269. goto ErrorExit;
  270. }
  271. }
  272. }
  273. //
  274. // Handle the request
  275. //
  276. _State = ISAPI_STATE_PENDING;
  277. //
  278. // Temporarily up the thread threshold since we don't know when the
  279. // ISAPI will return
  280. //
  281. ThreadPoolSetInfo( ThreadPoolIncMaxPoolThreads, 0 );
  282. if ( !_pCoreData->fIsOop )
  283. {
  284. IF_DEBUG( ISAPI )
  285. {
  286. DBGPRINTF((
  287. DBG_CONTEXT,
  288. "Processing ISAPI_REQUEST %p OOP.\r\n",
  289. _pIsapiRequest
  290. ));
  291. }
  292. hr = sm_pfnProcessIsapiRequest(
  293. _pIsapiRequest,
  294. _pCoreData,
  295. &dwHseResult
  296. );
  297. }
  298. else
  299. {
  300. hr = _pWamProcess->ProcessRequest(
  301. _pIsapiRequest,
  302. _pCoreData,
  303. &dwHseResult
  304. );
  305. }
  306. //
  307. // Back down the count since the ISAPI has returned
  308. //
  309. ThreadPoolSetInfo( ThreadPoolDecMaxPoolThreads, 0 );
  310. if ( FAILED( hr ) )
  311. {
  312. _State = ISAPI_STATE_FAILED;
  313. goto ErrorExit;
  314. }
  315. //
  316. // Determine whether the extension was synchronous or pending.
  317. // We need to do this before releasing our reference on the
  318. // ISAPI_REQUEST since the final release will check the state
  319. // to determine if an additional completion is necessary.
  320. //
  321. // In either case, we should just return with the appropriate
  322. // return code after setting the state.
  323. //
  324. if ( dwHseResult != HSE_STATUS_PENDING &&
  325. _pCoreData->fIsOop == FALSE )
  326. {
  327. _State = ISAPI_STATE_DONE;
  328. //
  329. // This had better be the final release...
  330. //
  331. LONG Refs = _pIsapiRequest->Release();
  332. //
  333. // Make /W3 happy on a free build...
  334. //
  335. if ( Refs != 0 )
  336. {
  337. DBG_ASSERT( Refs == 0 );
  338. }
  339. return CONTEXT_STATUS_CONTINUE;
  340. }
  341. //
  342. // This may or may not be the final release...
  343. //
  344. _pIsapiRequest->Release();
  345. return CONTEXT_STATUS_PENDING;
  346. ErrorExit:
  347. DBG_ASSERT( FAILED( hr ) );
  348. //
  349. // Spew on failure.
  350. //
  351. if ( FAILED( hr ) )
  352. {
  353. DBGPRINTF((
  354. DBG_CONTEXT,
  355. "Attempt to process ISAPI request failed. Error 0x%08x.\r\n",
  356. hr
  357. ));
  358. }
  359. //
  360. // Set the error status now.
  361. //
  362. pW3Context->SetErrorStatus( hr );
  363. //
  364. // If we've failed, and the state is ISAPI_STATE_INITIALIZING, then
  365. // we never made the call out to the extension. It's therefore
  366. // safe to handle the error and advance the state machine.
  367. //
  368. // It's also safe to advance the state machine in the special case
  369. // error where the attempt to call the extension results in
  370. // ERROR_ACCESS_DENIED.
  371. //
  372. if ( _State == ISAPI_STATE_INITIALIZING ||
  373. hr == HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED) )
  374. {
  375. //
  376. // Setting the state to ISAPI_STATE_DONE will cause the
  377. // next completion to advance the state machine.
  378. //
  379. _State = ISAPI_STATE_DONE;
  380. //
  381. // The _pWamProcess and _pCoreData members are cleaned up
  382. // by the destructor. We don't need to worry about them.
  383. // We also don't need to worry about any tokens that we
  384. // are using. The tokens local to this process are owned
  385. // by W3_USER_CONTEXT; any duplicates for OOP are the
  386. // responsibility of the dllhost process (if it still
  387. // exists).
  388. //
  389. // We do need to clean up the _pIsapiRequest if we've
  390. // created it. This had better well be the final release.
  391. //
  392. if ( _pIsapiRequest )
  393. {
  394. _pIsapiRequest->Release();
  395. }
  396. //
  397. // Set the HTTP status and send it asynchronously.
  398. // This will ultimately trigger the completion that
  399. // advances the state machine.
  400. //
  401. if ( hr == HRESULT_FROM_WIN32( ERROR_ACCESS_DENIED ) )
  402. {
  403. pW3Context->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  404. Http401Resource );
  405. }
  406. else
  407. {
  408. pW3Context->QueryResponse()->SetStatus( HttpStatusServerError );
  409. if ( dwWamSubError != 0 )
  410. {
  411. httpSubError.dwStringId = dwWamSubError;
  412. pW3Context->QueryResponse()->SetSubError( &httpSubError );
  413. }
  414. }
  415. hr = pW3Context->SendResponse( W3_FLAG_ASYNC );
  416. if ( SUCCEEDED( hr ) )
  417. {
  418. return CONTEXT_STATUS_PENDING;
  419. }
  420. //
  421. // Ouch - couldn't send the error page...
  422. //
  423. _State = ISAPI_STATE_FAILED;
  424. return CONTEXT_STATUS_CONTINUE;
  425. }
  426. //
  427. // If we get here, then an error has occured during or after
  428. // our call into the extension. Because it's possible for an
  429. // OOP call to fail after entering the extension, we can't
  430. // generally know our state.
  431. //
  432. // Because of this, we'll assume that the extension has
  433. // outstanding references to the ISAPI_REQUEST on its behalf.
  434. // We'll set the state to ISAPI_STATE_PENDING and let the
  435. // destructor on the ISAPI_REQUEST trigger the final
  436. // completion.
  437. //
  438. // Also, we'll set the error status, just in case the extension
  439. // didn't get a response off before it failed.
  440. //
  441. pW3Context->QueryResponse()->SetStatus( HttpStatusServerError );
  442. _State = ISAPI_STATE_FAILED;
  443. //
  444. // This may or may not be the final release on the ISAPI_REQUEST.
  445. //
  446. // It had better be non-NULL if we got past ISAPI_STATE_INITIALIZING.
  447. //
  448. DBG_ASSERT( _pIsapiRequest );
  449. _pIsapiRequest->Release();
  450. return CONTEXT_STATUS_PENDING;
  451. }
  452. CONTEXT_STATUS
  453. W3_ISAPI_HANDLER::OnCompletion(
  454. DWORD cbCompletion,
  455. DWORD dwCompletionStatus
  456. )
  457. /*++
  458. Routine Description:
  459. ISAPI async completion handler.
  460. Arguments:
  461. cbCompletion - Number of bytes in an async completion
  462. dwCompletionStatus - Error status of a completion
  463. Return Value:
  464. CONTEXT_STATUS_PENDING if async pending,
  465. else CONTEXT_STATUS_CONTINUE
  466. --*/
  467. {
  468. HRESULT hr;
  469. W3_CONTEXT * pW3Context;
  470. pW3Context = QueryW3Context();
  471. DBG_ASSERT( pW3Context != NULL );
  472. //
  473. // Is this completion for the entity body preload? If so note the
  474. // number of bytes and start handling the ISAPI request
  475. //
  476. if ( !_fEntityBodyPreloadComplete )
  477. {
  478. BOOL fComplete = FALSE;
  479. //
  480. // This completion is for entity body preload
  481. //
  482. W3_REQUEST *pRequest = pW3Context->QueryRequest();
  483. hr = pRequest->PreloadCompletion(pW3Context,
  484. cbCompletion,
  485. dwCompletionStatus,
  486. &fComplete);
  487. //
  488. // If we cannot read the request entity, we will assume it is the
  489. // client's fault
  490. //
  491. if ( FAILED( hr ) )
  492. {
  493. if ( hr == HRESULT_FROM_WIN32( ERROR_CONNECTION_INVALID ) )
  494. {
  495. pW3Context->QueryResponse()->SetStatus( HttpStatusEntityTooLarge );
  496. }
  497. else
  498. {
  499. pW3Context->SetErrorStatus( hr );
  500. pW3Context->QueryResponse()->SetStatus( HttpStatusBadRequest );
  501. }
  502. return CONTEXT_STATUS_CONTINUE;
  503. }
  504. if (!fComplete)
  505. {
  506. return CONTEXT_STATUS_PENDING;
  507. }
  508. _fEntityBodyPreloadComplete = TRUE;
  509. _State = ISAPI_STATE_INITIALIZING;
  510. //
  511. // Finally we can call the ISAPI
  512. //
  513. return IsapiDoWork( pW3Context );
  514. }
  515. DBG_ASSERT( _fEntityBodyPreloadComplete );
  516. return IsapiOnCompletion( cbCompletion, dwCompletionStatus );
  517. }
  518. CONTEXT_STATUS
  519. W3_ISAPI_HANDLER::IsapiOnCompletion(
  520. DWORD cbCompletion,
  521. DWORD dwCompletionStatus
  522. )
  523. /*++
  524. Routine Description:
  525. Funnels a completion to an ISAPI
  526. Arguments:
  527. cbCompletion - Bytes of completion
  528. dwCompletionStatus - Win32 Error status of completion
  529. Return Value:
  530. CONTEXT_STATUS_PENDING if async pending,
  531. else CONTEXT_STATUS_CONTINUE
  532. --*/
  533. {
  534. DWORD64 IsapiContext;
  535. HRESULT hr = NO_ERROR;
  536. //
  537. // If the state is ISAPI_STATE_DONE, then we should
  538. // advance the state machine now.
  539. //
  540. if ( _State == ISAPI_STATE_DONE ||
  541. _State == ISAPI_STATE_FAILED )
  542. {
  543. return CONTEXT_STATUS_CONTINUE;
  544. }
  545. //
  546. // If we get here, then this completion should be passed
  547. // along to the extension.
  548. //
  549. DBG_ASSERT( _pCoreData );
  550. DBG_ASSERT( _pIsapiRequest );
  551. IsapiContext = _pIsapiRequest->QueryIsapiContext();
  552. DBG_ASSERT( IsapiContext != 0 );
  553. //
  554. // Process the completion.
  555. //
  556. _pIsapiRequest->AddRef();
  557. //
  558. // Temporarily up the thread threshold since we don't know when the
  559. // ISAPI will return
  560. //
  561. ThreadPoolSetInfo( ThreadPoolIncMaxPoolThreads, 0 );
  562. if ( !_pCoreData->fIsOop )
  563. {
  564. //
  565. // Need to reset the ISAPI context in case the extension
  566. // does another async operation before the below call returns
  567. //
  568. _pIsapiRequest->ResetIsapiContext();
  569. hr = sm_pfnProcessIsapiCompletion(
  570. IsapiContext,
  571. cbCompletion,
  572. dwCompletionStatus
  573. );
  574. }
  575. else
  576. {
  577. DBG_ASSERT( _pWamProcess );
  578. //
  579. // _pWamProcess->ProcessCompletion depends on the ISAPI
  580. // context, so it will make the Reset call.
  581. //
  582. hr = _pWamProcess->ProcessCompletion(
  583. _pIsapiRequest,
  584. IsapiContext,
  585. cbCompletion,
  586. dwCompletionStatus
  587. );
  588. }
  589. //
  590. // Back down the count since the ISAPI has returned
  591. //
  592. ThreadPoolSetInfo( ThreadPoolDecMaxPoolThreads, 0 );
  593. _pIsapiRequest->Release();
  594. return CONTEXT_STATUS_PENDING;
  595. }
  596. HRESULT
  597. W3_ISAPI_HANDLER::InitCoreData(
  598. BOOL * pfIsVrToken
  599. )
  600. /*++
  601. Routine Description:
  602. Initializes the ISAPI_CORE_DATA for a request
  603. Arguments:
  604. None
  605. Return Value:
  606. HRESULT
  607. --*/
  608. {
  609. HRESULT hr = NO_ERROR;
  610. W3_CONTEXT * pW3Context;
  611. URL_CONTEXT * pUrlContext;
  612. W3_URL_INFO * pUrlInfo;
  613. W3_METADATA * pMetadata;
  614. W3_REQUEST * pRequest = NULL;
  615. LPCSTR szContentLength = NULL;
  616. STRU stru;
  617. STRU * pstru = NULL;
  618. BOOL fRequestIsScript = FALSE;
  619. BOOL fUsePathInfo;
  620. DWORD dwAppType = APP_INPROC;
  621. DBG_REQUIRE( ( pW3Context = QueryW3Context() ) != NULL );
  622. DBG_REQUIRE( ( pRequest = pW3Context->QueryRequest() ) != NULL );
  623. DBG_REQUIRE( ( pUrlContext = pW3Context->QueryUrlContext() ) != NULL );
  624. DBG_REQUIRE( ( pUrlInfo = pUrlContext->QueryUrlInfo() ) != NULL );
  625. DBG_REQUIRE( ( pMetadata = pUrlContext->QueryMetaData() ) != NULL );
  626. //
  627. // Check for script
  628. //
  629. if ( QueryScriptMapEntry() )
  630. {
  631. fRequestIsScript = TRUE;
  632. }
  633. //
  634. // Populate data directly into the inline core data.
  635. // Assume everything is inproc. In the case of an
  636. // OOP request, the SerializeCoreDataForOop function
  637. // will take care of any needed changes.
  638. //
  639. _pCoreData = &_InlineCoreData;
  640. //
  641. // Structure size information
  642. //
  643. _pCoreData->cbSize = sizeof(ISAPI_CORE_DATA);
  644. //
  645. // WAM information - Always set to inproc for w3wp.exe
  646. //
  647. _pCoreData->szWamClsid[0] = L'\0';
  648. _pCoreData->fIsOop = FALSE;
  649. //
  650. // Secure request?
  651. //
  652. _pCoreData->fSecure = pRequest->IsSecureRequest();
  653. //
  654. // Client HTTP version
  655. //
  656. _pCoreData->dwVersionMajor = pRequest->QueryVersion().MajorVersion;
  657. _pCoreData->dwVersionMinor = pRequest->QueryVersion().MinorVersion;
  658. //
  659. // Site instance ID
  660. //
  661. _pCoreData->dwInstanceId = pRequest->QuerySiteId();
  662. //
  663. // Request content-length
  664. //
  665. if ( pRequest->IsChunkedRequest() )
  666. {
  667. _pCoreData->dwContentLength = (DWORD) -1;
  668. }
  669. else
  670. {
  671. szContentLength = pRequest->GetHeader( HttpHeaderContentLength );
  672. if ( szContentLength != NULL )
  673. {
  674. errno = 0;
  675. _pCoreData->dwContentLength = strtoul( szContentLength, NULL, 10 );
  676. //
  677. // Check for overflow
  678. //
  679. if ( ( _pCoreData->dwContentLength == ULONG_MAX ||
  680. _pCoreData->dwContentLength == 0 ) &&
  681. errno == ERANGE )
  682. {
  683. hr = HRESULT_FROM_WIN32( ERROR_ARITHMETIC_OVERFLOW );
  684. goto ErrorExit;
  685. }
  686. }
  687. else
  688. {
  689. _pCoreData->dwContentLength = 0;
  690. }
  691. }
  692. //
  693. // Client authentication information
  694. //
  695. _pCoreData->hToken = pW3Context->QueryImpersonationToken( pfIsVrToken );
  696. _pCoreData->pSid = pW3Context->QueryUserContext()->QuerySid();
  697. //
  698. // Request ID
  699. //
  700. _pCoreData->RequestId = pRequest->QueryRequestId();
  701. //
  702. // Gateway image
  703. //
  704. // There are 3 cases to consider:
  705. //
  706. // 1) If this is a DAV request, then use DAV image
  707. // 2) If this is script mapped, use script executable
  708. // 3) Else use URL physical path
  709. //
  710. if ( _fIsDavRequest )
  711. {
  712. pstru = &_strDavIsapiImage;
  713. }
  714. else if ( fRequestIsScript )
  715. {
  716. pstru = QueryScriptMapEntry()->QueryExecutable();
  717. }
  718. else
  719. {
  720. pstru = pUrlContext->QueryPhysicalPath();
  721. }
  722. DBG_ASSERT( pstru );
  723. _pCoreData->szGatewayImage = pstru->QueryStr();
  724. _pCoreData->cbGatewayImage = pstru->QueryCB() + sizeof(WCHAR);
  725. pstru = NULL;
  726. //
  727. // Get the app type.
  728. //
  729. if ( sm_fWamActive )
  730. {
  731. dwAppType = pMetadata->QueryAppIsolated();
  732. if ( dwAppType == APP_ISOLATED ||
  733. dwAppType == APP_POOL )
  734. {
  735. if ( IsInprocIsapi( _pCoreData->szGatewayImage ) )
  736. {
  737. dwAppType = APP_INPROC;
  738. }
  739. }
  740. }
  741. //
  742. // Physical Path - Not Needed? Just set it to an empty string for now.
  743. //
  744. hr = _PhysicalPath.Copy( "" );
  745. if ( FAILED( hr ) )
  746. {
  747. goto ErrorExit;
  748. }
  749. _pCoreData->szPhysicalPath = _PhysicalPath.QueryStr();
  750. _pCoreData->cbPhysicalPath = _PhysicalPath.QueryCB() + sizeof(CHAR);
  751. //
  752. // Path info
  753. //
  754. // 1) If this is a DAV request, PATH_INFO is the URL
  755. // 2) If this is a script, and AllowPathInfoForScriptMappings is
  756. // FALSE, then PATH_INFO is the URL.
  757. // 3) Else, we use the "real" PATH_INFO
  758. //
  759. // We will set a flag indicating whether we are using the URL or
  760. // the "real" data, so that we can be efficient about deriving
  761. // PATH_TRANSLATED.
  762. //
  763. fUsePathInfo = TRUE;
  764. if ( _fIsDavRequest )
  765. {
  766. hr = pRequest->GetUrl( &stru );
  767. fUsePathInfo = FALSE;
  768. }
  769. else if ( fRequestIsScript )
  770. {
  771. if ( pW3Context->QuerySite()->QueryAllowPathInfoForScriptMappings() )
  772. {
  773. hr = stru.Copy( *pUrlInfo->QueryPathInfo() );
  774. }
  775. else
  776. {
  777. hr = pRequest->GetUrl( &stru );
  778. fUsePathInfo = FALSE;
  779. }
  780. }
  781. else
  782. {
  783. hr = stru.Copy( *pUrlInfo->QueryPathInfo() );
  784. }
  785. if ( FAILED( hr ) )
  786. {
  787. goto ErrorExit;
  788. }
  789. hr = _PathInfo.CopyW( stru.QueryStr(),
  790. stru.QueryCCH() );
  791. if ( FAILED( hr ) )
  792. {
  793. goto ErrorExit;
  794. }
  795. _pCoreData->szPathInfo = _PathInfo.QueryStr();
  796. _pCoreData->cbPathInfo = _PathInfo.QueryCB() + sizeof(CHAR);
  797. //
  798. // Method
  799. //
  800. hr = pRequest->GetVerbString( &_Method );
  801. if (FAILED( hr ) )
  802. {
  803. goto ErrorExit;
  804. }
  805. _pCoreData->szMethod = _Method.QueryStr();
  806. _pCoreData->cbMethod = _Method.QueryCB() + sizeof(CHAR);
  807. //
  808. // Query string
  809. //
  810. hr = pRequest->GetQueryStringA( &_QueryString );
  811. if (FAILED( hr ) )
  812. {
  813. goto ErrorExit;
  814. }
  815. _pCoreData->szQueryString = _QueryString.QueryStr();
  816. _pCoreData->cbQueryString = _QueryString.QueryCB() + sizeof(CHAR);
  817. //
  818. // Path translated (and we'll do the UNICODE version while we're at it)
  819. //
  820. hr = pUrlInfo->GetPathTranslated( pW3Context,
  821. fUsePathInfo,
  822. &_PathTranslatedW );
  823. if ( FAILED( hr ) )
  824. {
  825. goto ErrorExit;
  826. }
  827. hr = _PathTranslated.CopyW( _PathTranslatedW.QueryStr(),
  828. _PathTranslatedW.QueryCCH() );
  829. if ( FAILED( hr ) )
  830. {
  831. goto ErrorExit;
  832. }
  833. _pCoreData->szPathTranslated = _PathTranslated.QueryStr();
  834. _pCoreData->cbPathTranslated = _PathTranslated.QueryCB() + sizeof(CHAR);
  835. _pCoreData->szPathTranslatedW = _PathTranslatedW.QueryStr();
  836. _pCoreData->cbPathTranslatedW = _PathTranslatedW.QueryCB() + sizeof(WCHAR);
  837. //
  838. // Content type
  839. //
  840. _pCoreData->szContentType = (LPSTR)pRequest->GetHeader( HttpHeaderContentType );
  841. if ( !_pCoreData->szContentType )
  842. {
  843. _pCoreData->szContentType = CONTENT_TYPE_PLACEHOLDER;
  844. }
  845. _pCoreData->cbContentType = (DWORD)strlen( _pCoreData->szContentType ) + sizeof(CHAR);
  846. //
  847. // Connection
  848. //
  849. _pCoreData->szConnection = (LPSTR)pRequest->GetHeader( HttpHeaderConnection );
  850. if ( !_pCoreData->szConnection )
  851. {
  852. _pCoreData->szConnection = CONNECTION_PLACEHOLDER;
  853. }
  854. _pCoreData->cbConnection = (DWORD)strlen( _pCoreData->szConnection ) + sizeof(CHAR);
  855. //
  856. // UserAgent
  857. //
  858. _pCoreData->szUserAgent = (LPSTR)pRequest->GetHeader( HttpHeaderUserAgent );
  859. if ( !_pCoreData->szUserAgent )
  860. {
  861. _pCoreData->szUserAgent = USER_AGENT_PLACEHOLDER;
  862. }
  863. _pCoreData->cbUserAgent = (DWORD)strlen( _pCoreData->szUserAgent ) + sizeof(CHAR);
  864. //
  865. // Cookie
  866. //
  867. _pCoreData->szCookie = (LPSTR)pRequest->GetHeader( HttpHeaderCookie );
  868. if ( !_pCoreData->szCookie )
  869. {
  870. _pCoreData->szCookie = COOKIE_PLACEHOLDER;
  871. }
  872. _pCoreData->cbCookie = (DWORD)strlen( _pCoreData->szCookie ) + sizeof(CHAR);
  873. //
  874. // Appl MD path
  875. //
  876. hr = GetServerVariableApplMdPath( pW3Context, &_ApplMdPath );
  877. if( FAILED(hr) )
  878. {
  879. goto ErrorExit;
  880. }
  881. _pCoreData->szApplMdPath = _ApplMdPath.QueryStr();
  882. _pCoreData->cbApplMdPath = _ApplMdPath.QueryCB() + sizeof(CHAR);
  883. //
  884. // szApplMdPathW is only populated in
  885. // the OOF case.
  886. //
  887. _pCoreData->szApplMdPathW = NULL;
  888. _pCoreData->cbApplMdPathW = 0;
  889. //
  890. // Entity data
  891. //
  892. pW3Context->QueryAlreadyAvailableEntity( &_pCoreData->pAvailableEntity,
  893. &_pCoreData->cbAvailableEntity );
  894. //
  895. // Keep alive
  896. //
  897. _pCoreData->fAllowKeepAlive = pMetadata->QueryKeepAliveEnabled();
  898. //
  899. // If this is an OOP request, then we need to serialize the core data
  900. //
  901. if ( dwAppType == APP_ISOLATED ||
  902. dwAppType == APP_POOL )
  903. {
  904. hr = SerializeCoreDataForOop( dwAppType );
  905. if ( FAILED( hr ) )
  906. {
  907. goto ErrorExit;
  908. }
  909. }
  910. DBG_ASSERT( SUCCEEDED( hr ) );
  911. return hr;
  912. ErrorExit:
  913. DBG_ASSERT( FAILED( hr ) );
  914. _pCoreData = NULL;
  915. return hr;
  916. }
  917. HRESULT
  918. W3_ISAPI_HANDLER::SerializeCoreDataForOop(
  919. DWORD dwAppType
  920. )
  921. {
  922. W3_CONTEXT * pW3Context;
  923. URL_CONTEXT * pUrlContext;
  924. W3_URL_INFO * pUrlInfo;
  925. W3_METADATA * pMetadata;
  926. STRU * pstru;
  927. DWORD cbNeeded;
  928. BYTE * pCursor;
  929. ISAPI_CORE_DATA * pSerialized;
  930. HRESULT hr = NO_ERROR;
  931. //
  932. // Caution. This code must be kept in sync
  933. // with the FixupCoreData function in w3isapi.dll
  934. //
  935. DBG_ASSERT( sm_fWamActive );
  936. DBG_ASSERT( dwAppType == APP_ISOLATED ||
  937. dwAppType == APP_POOL );
  938. DBG_REQUIRE( ( pW3Context = QueryW3Context() ) != NULL );
  939. DBG_REQUIRE( ( pUrlContext = pW3Context->QueryUrlContext() ) != NULL );
  940. DBG_REQUIRE( ( pUrlInfo = pUrlContext->QueryUrlInfo() ) != NULL );
  941. DBG_REQUIRE( ( pMetadata = pUrlContext->QueryMetaData() ) != NULL );
  942. //
  943. // Set the WAM information and NULL out the pSid dude
  944. //
  945. if ( dwAppType == APP_ISOLATED )
  946. {
  947. pstru = pMetadata->QueryWamClsId();
  948. DBG_ASSERT( pstru );
  949. if ( pstru == NULL )
  950. {
  951. hr = HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND );
  952. goto ErrorExit;
  953. }
  954. wcsncpy( _pCoreData->szWamClsid,
  955. pstru->QueryStr(),
  956. SIZE_CLSID_STRING );
  957. _pCoreData->szWamClsid[SIZE_CLSID_STRING-1] = L'\0';
  958. }
  959. else
  960. {
  961. wcsncpy( _pCoreData->szWamClsid,
  962. POOL_WAM_CLSID,
  963. SIZE_CLSID_STRING );
  964. _pCoreData->szWamClsid[SIZE_CLSID_STRING-1] = L'\0';
  965. }
  966. _pCoreData->fIsOop = TRUE;
  967. _pCoreData->pSid = NULL;
  968. //
  969. // ApplMdPathW
  970. //
  971. hr = GetServerVariableApplMdPathW( pW3Context, &_ApplMdPathW );
  972. if ( FAILED( hr ) )
  973. {
  974. goto ErrorExit;
  975. }
  976. _pCoreData->szApplMdPathW = _ApplMdPathW.QueryStr();
  977. _pCoreData->cbApplMdPathW = _ApplMdPathW.QueryCB() + sizeof(WCHAR);
  978. //
  979. // Calculate the size needed for the core data and
  980. // set up the buffer to contain it.
  981. //
  982. cbNeeded = sizeof(ISAPI_CORE_DATA);
  983. cbNeeded += _pCoreData->cbGatewayImage;
  984. cbNeeded += _pCoreData->cbPhysicalPath;
  985. cbNeeded += _pCoreData->cbPathInfo;
  986. cbNeeded += _pCoreData->cbMethod;
  987. cbNeeded += _pCoreData->cbQueryString;
  988. cbNeeded += _pCoreData->cbPathTranslated;
  989. cbNeeded += _pCoreData->cbContentType;
  990. cbNeeded += _pCoreData->cbConnection;
  991. cbNeeded += _pCoreData->cbUserAgent;
  992. cbNeeded += _pCoreData->cbCookie;
  993. cbNeeded += _pCoreData->cbApplMdPath;
  994. cbNeeded += _pCoreData->cbApplMdPathW;
  995. cbNeeded += _pCoreData->cbPathTranslatedW;
  996. cbNeeded += _pCoreData->cbAvailableEntity;
  997. hr = _buffCoreData.Resize( cbNeeded );
  998. if ( FAILED( hr ) )
  999. {
  1000. goto ErrorExit;
  1001. }
  1002. //
  1003. // Copy the core data into the buffer
  1004. //
  1005. pSerialized = (ISAPI_CORE_DATA*)_buffCoreData.QueryPtr();
  1006. pCursor = (BYTE*)pSerialized;
  1007. CopyMemory( pCursor,
  1008. _pCoreData,
  1009. sizeof(ISAPI_CORE_DATA) );
  1010. pSerialized->cbSize = cbNeeded;
  1011. pCursor += sizeof(ISAPI_CORE_DATA);
  1012. //
  1013. // Add gateway image
  1014. //
  1015. pSerialized->szGatewayImage = (LPWSTR)pCursor;
  1016. CopyMemory( pSerialized->szGatewayImage,
  1017. _pCoreData->szGatewayImage,
  1018. _pCoreData->cbGatewayImage );
  1019. pCursor += _pCoreData->cbGatewayImage;
  1020. //
  1021. // Add ApplMdPathW
  1022. //
  1023. pSerialized->szApplMdPathW = (LPWSTR)pCursor;
  1024. CopyMemory( pSerialized->szApplMdPathW,
  1025. _pCoreData->szApplMdPathW,
  1026. _pCoreData->cbApplMdPathW );
  1027. pCursor += _pCoreData->cbApplMdPathW;
  1028. //
  1029. // Add PathTranslatedW
  1030. //
  1031. pSerialized->szPathTranslatedW = (LPWSTR)pCursor;
  1032. CopyMemory( pSerialized->szPathTranslatedW,
  1033. _pCoreData->szPathTranslatedW,
  1034. _pCoreData->cbPathTranslatedW );
  1035. pCursor += _pCoreData->cbPathTranslatedW;
  1036. //
  1037. // Add physical path
  1038. //
  1039. pSerialized->szPhysicalPath = (LPSTR)pCursor;
  1040. CopyMemory( pSerialized->szPhysicalPath,
  1041. _pCoreData->szPhysicalPath,
  1042. _pCoreData->cbPhysicalPath );
  1043. pCursor += _pCoreData->cbPhysicalPath;
  1044. //
  1045. // Add path info
  1046. //
  1047. pSerialized->szPathInfo = (LPSTR)pCursor;
  1048. CopyMemory( pSerialized->szPathInfo,
  1049. _pCoreData->szPathInfo,
  1050. _pCoreData->cbPathInfo );
  1051. pCursor += _pCoreData->cbPathInfo;
  1052. //
  1053. // Add method
  1054. //
  1055. pSerialized->szMethod = (LPSTR)pCursor;
  1056. CopyMemory( pSerialized->szMethod,
  1057. _pCoreData->szMethod,
  1058. _pCoreData->cbMethod );
  1059. pCursor += _pCoreData->cbMethod;
  1060. //
  1061. // Add query string
  1062. //
  1063. pSerialized->szQueryString = (LPSTR)pCursor;
  1064. CopyMemory( pSerialized->szQueryString,
  1065. _pCoreData->szQueryString,
  1066. _pCoreData->cbQueryString );
  1067. pCursor += _pCoreData->cbQueryString;
  1068. //
  1069. // Add path translated
  1070. //
  1071. pSerialized->szPathTranslated = (LPSTR)pCursor;
  1072. CopyMemory( pSerialized->szPathTranslated,
  1073. _pCoreData->szPathTranslated,
  1074. _pCoreData->cbPathTranslated );
  1075. pCursor += _pCoreData->cbPathTranslated;
  1076. //
  1077. // Add content type
  1078. //
  1079. pSerialized->szContentType = (LPSTR)pCursor;
  1080. CopyMemory( pSerialized->szContentType,
  1081. _pCoreData->szContentType,
  1082. _pCoreData->cbContentType );
  1083. pCursor += _pCoreData->cbContentType;
  1084. //
  1085. // Add connection
  1086. //
  1087. pSerialized->szConnection = (LPSTR)pCursor;
  1088. CopyMemory( pSerialized->szConnection,
  1089. _pCoreData->szConnection,
  1090. _pCoreData->cbConnection );
  1091. pCursor += _pCoreData->cbConnection;
  1092. //
  1093. // Add user agent
  1094. //
  1095. pSerialized->szUserAgent = (LPSTR)pCursor;
  1096. CopyMemory( pSerialized->szUserAgent,
  1097. _pCoreData->szUserAgent,
  1098. _pCoreData->cbUserAgent );
  1099. pCursor += _pCoreData->cbUserAgent;
  1100. //
  1101. // Add cookie
  1102. //
  1103. pSerialized->szCookie = (LPSTR)pCursor;
  1104. CopyMemory( pSerialized->szCookie,
  1105. _pCoreData->szCookie,
  1106. _pCoreData->cbCookie );
  1107. pCursor += _pCoreData->cbCookie;
  1108. //
  1109. // Add ApplMdPath
  1110. //
  1111. pSerialized->szApplMdPath = (LPSTR)pCursor;
  1112. CopyMemory( pSerialized->szApplMdPath,
  1113. _pCoreData->szApplMdPath,
  1114. _pCoreData->cbApplMdPath );
  1115. pCursor += _pCoreData->cbApplMdPath;
  1116. //
  1117. // Add entity data
  1118. //
  1119. if ( _pCoreData->cbAvailableEntity )
  1120. {
  1121. pSerialized->pAvailableEntity = (LPWSTR)pCursor;
  1122. CopyMemory( pSerialized->pAvailableEntity,
  1123. _pCoreData->pAvailableEntity,
  1124. _pCoreData->cbAvailableEntity );
  1125. }
  1126. //
  1127. // Point _pCoreData at the new buffer and we're done
  1128. //
  1129. _pCoreData = pSerialized;
  1130. DBG_ASSERT( SUCCEEDED( hr ) );
  1131. return hr;
  1132. ErrorExit:
  1133. DBG_ASSERT( FAILED( hr ) );
  1134. return hr;
  1135. }
  1136. HRESULT
  1137. W3_ISAPI_HANDLER::DuplicateWamProcessHandleForLocalUse(
  1138. HANDLE hWamProcessHandle,
  1139. HANDLE * phLocalHandle
  1140. )
  1141. /*++
  1142. Routine Description:
  1143. Duplicates a handle defined in a WAM process to a local
  1144. handle useful in the IIS core
  1145. Arguments:
  1146. hWamProcessHandle - The value of the handle from the WAM process
  1147. phLocalHandle - Upon successful return, the handle useable in
  1148. the core process
  1149. Return Value:
  1150. HRESULT
  1151. --*/
  1152. {
  1153. HANDLE hWamProcess;
  1154. HRESULT hr = NOERROR;
  1155. DBG_ASSERT( _pWamProcess );
  1156. DBG_REQUIRE( ( hWamProcess = _pWamProcess->QueryProcess() ) != NULL );
  1157. if ( !DuplicateHandle( hWamProcess, hWamProcessHandle, GetCurrentProcess(),
  1158. phLocalHandle, 0, FALSE, DUPLICATE_SAME_ACCESS ) )
  1159. {
  1160. hr = HRESULT_FROM_WIN32( GetLastError() );
  1161. }
  1162. return hr;
  1163. }
  1164. HRESULT
  1165. W3_ISAPI_HANDLER::MarshalAsyncReadBuffer(
  1166. DWORD64 pWamExecInfo,
  1167. LPBYTE pBuffer,
  1168. DWORD cbBuffer
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. Pushes a buffer into a WAM process. This function is called
  1173. to copy a local read buffer into the WAM process just prior
  1174. to notifying the I/O completion function of an OOP extension.
  1175. Arguments:
  1176. pWamExecInfo - A WAM_EXEC_INFO pointer that identifies the request
  1177. to the OOP host.
  1178. pBuffer - The buffer to copy
  1179. cbBuffer - The amount of data in pBuffer
  1180. Return Value:
  1181. HRESULT
  1182. --*/
  1183. {
  1184. DBG_ASSERT( sm_fWamActive );
  1185. DBG_ASSERT( _pWamProcess );
  1186. return _pWamProcess->MarshalAsyncReadBuffer( pWamExecInfo, pBuffer,
  1187. cbBuffer );
  1188. }
  1189. VOID
  1190. W3_ISAPI_HANDLER::IsapiRequestFinished(
  1191. VOID
  1192. )
  1193. /*++
  1194. Routine Description:
  1195. This function is called by the destructor for the
  1196. ISAPI_REQUEST associated with this request. If the
  1197. current state of the W3_ISAPI_HANDLER is
  1198. ISAPI_STATE_PENDING, then it will advance the core
  1199. state machine.
  1200. Arguments:
  1201. None
  1202. Return Value:
  1203. None
  1204. --*/
  1205. {
  1206. W3_CONTEXT * pW3Context = QueryW3Context();
  1207. HRESULT hr = NO_ERROR;
  1208. DBG_ASSERT( pW3Context );
  1209. if ( _State == ISAPI_STATE_FAILED )
  1210. {
  1211. if ( pW3Context->QueryResponseSent() == FALSE )
  1212. {
  1213. //
  1214. // The ISAPI didn't send a response, we need to send
  1215. // it now. If our send is successful, we should return
  1216. // immediately.
  1217. //
  1218. hr = pW3Context->SendResponse( W3_FLAG_ASYNC );
  1219. if ( SUCCEEDED( hr ) )
  1220. {
  1221. return;
  1222. }
  1223. else
  1224. {
  1225. pW3Context->SetErrorStatus( hr );
  1226. }
  1227. }
  1228. //
  1229. // Since we didn't end up sending a response, we need
  1230. // to set the status to pending. This will result in
  1231. // the below code triggering a completion to clean up
  1232. // the state machine.
  1233. //
  1234. _State = ISAPI_STATE_PENDING;
  1235. }
  1236. if ( _State == ISAPI_STATE_PENDING )
  1237. {
  1238. RestartCoreStateMachine();
  1239. }
  1240. }
  1241. VOID
  1242. W3_ISAPI_HANDLER::RestartCoreStateMachine(
  1243. VOID
  1244. )
  1245. /*++
  1246. Routine Description:
  1247. Advances the core state machine by setting state
  1248. to ISAPI_STATE_DONE and triggering an I/O completion.
  1249. Note that this function is only expected to be called
  1250. if the object state is ISAPI_STATE_PENDING.
  1251. Arguments:
  1252. None
  1253. Return Value:
  1254. None
  1255. --*/
  1256. {
  1257. W3_CONTEXT * pW3Context = QueryW3Context();
  1258. DBG_ASSERT( pW3Context );
  1259. DBG_ASSERT( _State == ISAPI_STATE_PENDING );
  1260. //
  1261. // Need to set state to ISAPI_STATE_DONE so that the
  1262. // resulting completion does the advance for us.
  1263. //
  1264. _State = ISAPI_STATE_DONE;
  1265. //
  1266. // If this is the main request, then we can resume the state
  1267. // machine on the ISAPIs thread. Therefore no need to marshall
  1268. // to another thread. If it is not the main request, the we
  1269. // don't want to risk doing a long running operation (i.e. the
  1270. // completion of the parent request) on the ISAPI thread
  1271. //
  1272. if ( pW3Context == pW3Context->QueryMainContext() )
  1273. {
  1274. W3_MAIN_CONTEXT::OnPostedCompletion( NO_ERROR,
  1275. 0,
  1276. (OVERLAPPED*) pW3Context->QueryMainContext() );
  1277. }
  1278. else
  1279. {
  1280. POST_MAIN_COMPLETION( pW3Context->QueryMainContext() );
  1281. }
  1282. }
  1283. //static
  1284. HRESULT
  1285. W3_ISAPI_HANDLER::Initialize(
  1286. VOID
  1287. )
  1288. /*++
  1289. Routine Description:
  1290. Initializes W3_ISAPI_HANDLER
  1291. Arguments:
  1292. None
  1293. Return Value:
  1294. HRESULT
  1295. --*/
  1296. {
  1297. HRESULT hr = NOERROR;
  1298. DBGPRINTF(( DBG_CONTEXT, "W3_ISAPI_HANDLER::Initialize()\n" ));
  1299. //
  1300. // For debugging purposes, create a unique instance ID for this
  1301. // instance of the handler.
  1302. //
  1303. #ifdef DBG
  1304. UUID uuid;
  1305. RPC_STATUS rpcStatus;
  1306. unsigned char * szRpcString;
  1307. rpcStatus = UuidCreate( &uuid );
  1308. if ( (rpcStatus != RPC_S_OK) && (rpcStatus != RPC_S_UUID_LOCAL_ONLY) )
  1309. {
  1310. SetLastError( rpcStatus );
  1311. goto error_exit;
  1312. }
  1313. rpcStatus = UuidToStringA( &uuid, &szRpcString );
  1314. if ( rpcStatus != RPC_S_OK )
  1315. {
  1316. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  1317. goto error_exit;
  1318. }
  1319. strncpy( sm_szInstanceId, (LPSTR)szRpcString, SIZE_CLSID_STRING );
  1320. sm_szInstanceId[SIZE_CLSID_STRING - 1] = '\0';
  1321. RpcStringFreeA( &szRpcString );
  1322. DBGPRINTF((
  1323. DBG_CONTEXT,
  1324. "W3_ISAPI_HANDLER initialized instance %s.\r\n",
  1325. sm_szInstanceId
  1326. ));
  1327. #else
  1328. sm_szInstanceId[0] = '\0';
  1329. #endif _DBG
  1330. PFN_ISAPI_INIT_MODULE pfnInit = NULL;
  1331. sm_hIsapiModule = LoadLibrary( ISAPI_MODULE_NAME );
  1332. if( sm_hIsapiModule == NULL )
  1333. {
  1334. hr = HRESULT_FROM_WIN32( GetLastError() );
  1335. goto error_exit;
  1336. }
  1337. sm_pfnTermIsapiModule =
  1338. (PFN_ISAPI_TERM_MODULE)GetProcAddress( sm_hIsapiModule,
  1339. ISAPI_TERM_MODULE
  1340. );
  1341. sm_pfnProcessIsapiRequest =
  1342. (PFN_ISAPI_PROCESS_REQUEST)GetProcAddress( sm_hIsapiModule,
  1343. ISAPI_PROCESS_REQUEST
  1344. );
  1345. sm_pfnProcessIsapiCompletion =
  1346. (PFN_ISAPI_PROCESS_COMPLETION)GetProcAddress( sm_hIsapiModule,
  1347. ISAPI_PROCESS_COMPLETION
  1348. );
  1349. if( !sm_pfnTermIsapiModule ||
  1350. !sm_pfnProcessIsapiRequest ||
  1351. !sm_pfnProcessIsapiCompletion )
  1352. {
  1353. hr = E_FAIL;
  1354. goto error_exit;
  1355. }
  1356. pfnInit =
  1357. (PFN_ISAPI_INIT_MODULE)GetProcAddress( sm_hIsapiModule,
  1358. ISAPI_INIT_MODULE
  1359. );
  1360. if( !pfnInit )
  1361. {
  1362. hr = E_FAIL;
  1363. goto error_exit;
  1364. }
  1365. hr = pfnInit(
  1366. NULL,
  1367. sm_szInstanceId,
  1368. GetCurrentProcessId()
  1369. );
  1370. if( FAILED(hr) )
  1371. {
  1372. goto error_exit;
  1373. }
  1374. DBG_REQUIRE( ISAPI_REQUEST::InitClass() );
  1375. sm_pInprocIsapiHash = NULL;
  1376. //
  1377. // If we're running in backward compatibility mode, initialize
  1378. // the WAM process manager and inprocess ISAPI app list
  1379. //
  1380. if ( g_pW3Server->QueryInBackwardCompatibilityMode() )
  1381. {
  1382. WCHAR szIsapiModule[MAX_PATH];
  1383. //
  1384. // Store away the full path to the loaded ISAPI module
  1385. // so that we can pass it to OOP processes so that they
  1386. // know how to load it
  1387. //
  1388. if ( GetModuleFileNameW(
  1389. GetModuleHandleW( ISAPI_MODULE_NAME ),
  1390. szIsapiModule,
  1391. MAX_PATH
  1392. ) == 0 )
  1393. {
  1394. hr = HRESULT_FROM_WIN32( GetLastError() );
  1395. goto error_exit;
  1396. }
  1397. DBG_ASSERT( szIsapiModule[0] != '\0' );
  1398. //
  1399. // Initialize the WAM_PROCESS_MANAGER
  1400. //
  1401. sm_pWamProcessManager = new WAM_PROCESS_MANAGER( szIsapiModule );
  1402. if ( !sm_pWamProcessManager )
  1403. {
  1404. goto error_exit;
  1405. }
  1406. hr = sm_pWamProcessManager->Create();
  1407. if ( FAILED( hr ) )
  1408. {
  1409. sm_pWamProcessManager->Release();
  1410. sm_pWamProcessManager = NULL;
  1411. goto error_exit;
  1412. }
  1413. //
  1414. // Hook up wamreg
  1415. //
  1416. hr = WamReg_RegisterSinkNotify( W3SVC_WamRegSink );
  1417. if ( FAILED( hr ) )
  1418. {
  1419. goto error_exit;
  1420. }
  1421. INITIALIZE_CRITICAL_SECTION( &sm_csInprocHashLock );
  1422. UpdateInprocIsapiHash();
  1423. INITIALIZE_CRITICAL_SECTION( &sm_csBigHurkinWamRegLock );
  1424. sm_fWamActive = TRUE;
  1425. }
  1426. else
  1427. {
  1428. sm_pWamProcessManager = NULL;
  1429. sm_fWamActive = FALSE;
  1430. }
  1431. sg_Initialized = TRUE;
  1432. return hr;
  1433. error_exit:
  1434. DBGPRINTF(( DBG_CONTEXT,
  1435. "W3_ISAPI_HANDLER::Initialize() Error=%08x\n",
  1436. hr
  1437. ));
  1438. if ( sm_hIsapiModule )
  1439. {
  1440. FreeLibrary( sm_hIsapiModule );
  1441. sm_hIsapiModule = NULL;
  1442. }
  1443. sm_pfnTermIsapiModule = NULL;
  1444. return hr;
  1445. }
  1446. //static
  1447. VOID
  1448. W3_ISAPI_HANDLER::Terminate(
  1449. VOID
  1450. )
  1451. /*++
  1452. Routine Description:
  1453. Terminates W3_ISAPI_HANDLER
  1454. Arguments:
  1455. None
  1456. Return Value:
  1457. None
  1458. --*/
  1459. {
  1460. DBGPRINTF(( DBG_CONTEXT, "W3_ISAPI_HANDLER::Terminate()\n" ));
  1461. sg_Initialized = FALSE;
  1462. DBG_ASSERT( sm_pfnTermIsapiModule );
  1463. DBG_ASSERT( sm_hIsapiModule );
  1464. if( sm_pfnTermIsapiModule )
  1465. {
  1466. sm_pfnTermIsapiModule();
  1467. sm_pfnTermIsapiModule = NULL;
  1468. }
  1469. if( sm_hIsapiModule )
  1470. {
  1471. FreeLibrary( sm_hIsapiModule );
  1472. sm_hIsapiModule = NULL;
  1473. }
  1474. if ( sm_pInprocIsapiHash )
  1475. {
  1476. delete sm_pInprocIsapiHash;
  1477. }
  1478. if ( sm_fWamActive )
  1479. {
  1480. //
  1481. // Disconnect wamreg
  1482. //
  1483. WamReg_UnRegisterSinkNotify();
  1484. if ( sm_pWamProcessManager )
  1485. {
  1486. sm_pWamProcessManager->Shutdown();
  1487. sm_pWamProcessManager->Release();
  1488. sm_pWamProcessManager = NULL;
  1489. }
  1490. DeleteCriticalSection( &sm_csInprocHashLock );
  1491. DeleteCriticalSection( &sm_csBigHurkinWamRegLock );
  1492. }
  1493. ISAPI_REQUEST::CleanupClass();
  1494. }
  1495. // static
  1496. HRESULT
  1497. W3_ISAPI_HANDLER::W3SVC_WamRegSink(
  1498. LPCSTR szAppPath,
  1499. const DWORD dwCommand,
  1500. DWORD * pdwResult
  1501. )
  1502. {
  1503. HRESULT hr = NOERROR;
  1504. WAM_PROCESS * pWamProcess = NULL;
  1505. WAM_APP_INFO * pWamAppInfo = NULL;
  1506. DWORD dwWamSubError = 0;
  1507. BOOL fIsLoaded = FALSE;
  1508. //
  1509. // Scary monsters live in the land where this function
  1510. // is allowed to run willy nilly
  1511. //
  1512. LockWamReg();
  1513. DBG_ASSERT( szAppPath );
  1514. DBG_ASSERT( sm_pWamProcessManager );
  1515. DBGPRINTF((
  1516. DBG_CONTEXT,
  1517. "WAM_PROCESS_MANAGER received a Sink Notify on MD path %S, cmd = %d.\r\n",
  1518. (LPCWSTR)szAppPath,
  1519. dwCommand
  1520. ));
  1521. *pdwResult = APPSTATUS_UnLoaded;
  1522. switch ( dwCommand )
  1523. {
  1524. case APPCMD_UNLOAD:
  1525. case APPCMD_DELETE:
  1526. case APPCMD_CHANGETOINPROC:
  1527. case APPCMD_CHANGETOOUTPROC:
  1528. //
  1529. // Unload the specified wam process.
  1530. //
  1531. // Note that we're casting the incoming app path to
  1532. // UNICODE. This is because wamreg would normally
  1533. // convert the MD path (which is nativly UNICODE) to
  1534. // MBCS in IIS 5.x. It's smart enough to know that
  1535. // for 6.0 we want to work directly with UNICODE.
  1536. //
  1537. hr = sm_pWamProcessManager->GetWamProcessInfo(
  1538. reinterpret_cast<LPCWSTR>(szAppPath),
  1539. &pWamAppInfo,
  1540. &fIsLoaded
  1541. );
  1542. if ( FAILED( hr ) )
  1543. {
  1544. goto Done;
  1545. }
  1546. DBG_ASSERT( pWamAppInfo );
  1547. //
  1548. // If the app has not been loaded by the WAM_PROCESS_MANAGER
  1549. // then there is nothing more to do.
  1550. //
  1551. if ( fIsLoaded == FALSE )
  1552. {
  1553. break;
  1554. }
  1555. hr = sm_pWamProcessManager->GetWamProcess(
  1556. pWamAppInfo->_szClsid,
  1557. pWamAppInfo->_szAppPath,
  1558. &dwWamSubError,
  1559. &pWamProcess,
  1560. sm_szInstanceId
  1561. );
  1562. if ( FAILED( hr ) )
  1563. {
  1564. //
  1565. // Hey, this app was loaded just a moment ago!
  1566. //
  1567. DBG_ASSERT( FALSE );
  1568. goto Done;
  1569. }
  1570. DBG_ASSERT( pWamProcess );
  1571. hr = pWamProcess->Unload( 0 );
  1572. if ( FAILED( hr ) )
  1573. {
  1574. goto Done;
  1575. }
  1576. break;
  1577. case APPCMD_GETSTATUS:
  1578. hr = sm_pWamProcessManager->GetWamProcessInfo(
  1579. reinterpret_cast<LPCWSTR>(szAppPath),
  1580. &pWamAppInfo,
  1581. &fIsLoaded
  1582. );
  1583. if ( SUCCEEDED( hr ) )
  1584. {
  1585. if ( fIsLoaded )
  1586. {
  1587. *pdwResult = APPSTATUS_Running;
  1588. }
  1589. else
  1590. {
  1591. *pdwResult = APPSTATUS_Stopped;
  1592. }
  1593. }
  1594. break;
  1595. }
  1596. Done:
  1597. UnlockWamReg();
  1598. if ( pWamAppInfo )
  1599. {
  1600. pWamAppInfo->Release();
  1601. pWamAppInfo = NULL;
  1602. }
  1603. if ( pWamProcess )
  1604. {
  1605. pWamProcess->Release();
  1606. pWamProcess = NULL;
  1607. }
  1608. if ( FAILED( hr ) )
  1609. {
  1610. *pdwResult = APPSTATUS_Error;
  1611. }
  1612. return hr;
  1613. }
  1614. // static
  1615. HRESULT
  1616. W3_ISAPI_HANDLER::UpdateInprocIsapiHash(
  1617. VOID
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. Updates the table of InProcessIsapiApps
  1622. Arguments:
  1623. None
  1624. Return Value:
  1625. HRESULT
  1626. --*/
  1627. {
  1628. MB mb( g_pW3Server->QueryMDObject() );
  1629. W3_INPROC_ISAPI_HASH * pNewTable = NULL;
  1630. W3_INPROC_ISAPI_HASH * pOldTable = NULL;
  1631. DWORD i;
  1632. LPWSTR psz;
  1633. HRESULT hr = NOERROR;
  1634. LK_RETCODE lkr = LK_SUCCESS;
  1635. //
  1636. // Allocate a new table and populate it.
  1637. //
  1638. pNewTable = new W3_INPROC_ISAPI_HASH;
  1639. if ( !pNewTable )
  1640. {
  1641. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1642. goto ErrorExit;
  1643. }
  1644. if ( !mb.Open( L"/LM/W3SVC/" ) )
  1645. {
  1646. hr = HRESULT_FROM_WIN32(GetLastError());
  1647. goto ErrorExit;
  1648. }
  1649. if ( !mb.GetMultisz( L"",
  1650. MD_IN_PROCESS_ISAPI_APPS,
  1651. IIS_MD_UT_SERVER,
  1652. &pNewTable->_mszImages) )
  1653. {
  1654. hr = HRESULT_FROM_WIN32(GetLastError());
  1655. mb.Close();
  1656. goto ErrorExit;
  1657. }
  1658. //
  1659. // Merge ISAPI filter images into the list
  1660. //
  1661. AddAllFiltersToMultiSz( mb, &pNewTable->_mszImages );
  1662. mb.Close();
  1663. //
  1664. // Now that we have a complete list, add them to the
  1665. // hash table.
  1666. //
  1667. for ( i = 0, psz = (LPWSTR)pNewTable->_mszImages.First();
  1668. psz != NULL;
  1669. i++, psz = (LPWSTR)pNewTable->_mszImages.Next( psz ) )
  1670. {
  1671. W3_INPROC_ISAPI * pNewRecord;
  1672. //
  1673. // Allocate a new W3_INPROC_ISAPI object and add
  1674. // it to the table
  1675. //
  1676. pNewRecord = new W3_INPROC_ISAPI;
  1677. if ( !pNewRecord )
  1678. {
  1679. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1680. goto ErrorExit;
  1681. }
  1682. hr = pNewRecord->Create( psz );
  1683. if ( FAILED( hr ) )
  1684. {
  1685. pNewRecord->DereferenceInprocIsapi();
  1686. pNewRecord = NULL;
  1687. goto ErrorExit;
  1688. }
  1689. lkr = pNewTable->InsertRecord( pNewRecord, TRUE );
  1690. pNewRecord->DereferenceInprocIsapi();
  1691. pNewRecord = NULL;
  1692. if ( lkr != LK_SUCCESS && lkr != LK_KEY_EXISTS )
  1693. {
  1694. hr = E_FAIL;
  1695. goto ErrorExit;
  1696. }
  1697. }
  1698. //
  1699. // Now swap in the new table and delete the old one
  1700. //
  1701. EnterCriticalSection( &sm_csInprocHashLock );
  1702. pOldTable = sm_pInprocIsapiHash;
  1703. sm_pInprocIsapiHash = pNewTable;
  1704. LeaveCriticalSection( &sm_csInprocHashLock );
  1705. if ( pOldTable )
  1706. {
  1707. delete pOldTable;
  1708. }
  1709. DBG_ASSERT( SUCCEEDED( hr ) );
  1710. return hr;
  1711. ErrorExit:
  1712. DBG_ASSERT( FAILED( hr ) );
  1713. if ( pNewTable )
  1714. {
  1715. delete pNewTable;
  1716. };
  1717. return hr;
  1718. }
  1719. VOID
  1720. AddFiltersToMultiSz(
  1721. IN const MB & mb,
  1722. IN LPCWSTR szFilterPath,
  1723. IN OUT MULTISZ * pmsz
  1724. )
  1725. /*++
  1726. Description:
  1727. Add the ISAPI filters at the specified metabase path to pmsz.
  1728. Called by AddAllFiltersToMultiSz.
  1729. Arguments:
  1730. mb metabase key open to /LM/W3SVC
  1731. szFilterPath path of /Filters key relative to /LM/W3SVC
  1732. pmsz multisz containing the in proc dlls
  1733. Return:
  1734. Nothing - failure cases ignored.
  1735. --*/
  1736. {
  1737. WCHAR szKeyName[MAX_PATH + 1];
  1738. STRU strFilterPath;
  1739. STRU strFullKeyName;
  1740. INT pchFilterPath = (INT)wcslen( szFilterPath );
  1741. if ( FAILED( strFullKeyName.Copy( szFilterPath ) ) )
  1742. {
  1743. return;
  1744. }
  1745. DWORD i = 0;
  1746. if( SUCCEEDED( strFullKeyName.Append( L"/", 1 ) ) )
  1747. {
  1748. while ( const_cast<MB &>(mb).EnumObjects( szFilterPath,
  1749. szKeyName,
  1750. i++ ) )
  1751. {
  1752. if( SUCCEEDED( strFullKeyName.Append( szKeyName ) ) )
  1753. {
  1754. if( const_cast<MB &>(mb).GetStr( strFullKeyName.QueryStr(),
  1755. MD_FILTER_IMAGE_PATH,
  1756. IIS_MD_UT_SERVER,
  1757. &strFilterPath ) )
  1758. {
  1759. pmsz->Append( strFilterPath );
  1760. }
  1761. }
  1762. strFullKeyName.SetLen( pchFilterPath + 1 );
  1763. }
  1764. }
  1765. }
  1766. VOID
  1767. AddAllFiltersToMultiSz(
  1768. IN const MB & mb,
  1769. IN OUT MULTISZ * pmsz
  1770. )
  1771. /*++
  1772. Description:
  1773. This is designed to prevent ISAPI extension/filter
  1774. combination dlls from running out of process.
  1775. Add the base set of filters defined for the service to pmsz.
  1776. Iterate through the sites and add the filters defined for
  1777. each site.
  1778. Arguments:
  1779. mb metabase key open to /LM/W3SVC
  1780. pmsz multisz containing the in proc dlls
  1781. Return:
  1782. Nothing - failure cases ignored.
  1783. --*/
  1784. {
  1785. WCHAR szKeyName[MAX_PATH + 1];
  1786. STRU strFullKeyName;
  1787. DWORD i = 0;
  1788. DWORD dwInstanceId = 0;
  1789. if ( FAILED( strFullKeyName.Copy( L"/" ) ) )
  1790. {
  1791. return;
  1792. }
  1793. AddFiltersToMultiSz( mb, L"/Filters", pmsz );
  1794. while ( const_cast<MB &>(mb).EnumObjects( L"",
  1795. szKeyName,
  1796. i++ ) )
  1797. {
  1798. dwInstanceId = _wtoi( szKeyName );
  1799. if( 0 != dwInstanceId )
  1800. {
  1801. // This is a site.
  1802. if( SUCCEEDED( strFullKeyName.Append( szKeyName ) ) &&
  1803. SUCCEEDED( strFullKeyName.Append( L"/Filters" ) ) )
  1804. {
  1805. AddFiltersToMultiSz( mb, strFullKeyName.QueryStr(), pmsz );
  1806. }
  1807. strFullKeyName.SetLen( 1 );
  1808. }
  1809. }
  1810. }
  1811. HRESULT
  1812. W3_ISAPI_HANDLER::SetupUlCachedResponse(
  1813. W3_CONTEXT * pW3Context,
  1814. HTTP_CACHE_POLICY *pCachePolicy
  1815. )
  1816. /*++
  1817. Routine Description:
  1818. Setup a response to be cached by UL.
  1819. Arguments:
  1820. pW3Context - Context
  1821. pCachePolicy - Cache policy to be filled in if caching desired
  1822. Return Value:
  1823. HRESULT
  1824. --*/
  1825. {
  1826. STACK_STRU( strFlushUrl, MAX_PATH );
  1827. HRESULT hr;
  1828. DWORD dwTTL = 0;
  1829. if ( pW3Context == NULL )
  1830. {
  1831. DBG_ASSERT( FALSE );
  1832. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1833. }
  1834. //
  1835. // Find out if caching is enabled for this isapi request
  1836. //
  1837. if (!_pIsapiRequest->QueryCacheResponse())
  1838. {
  1839. return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  1840. }
  1841. W3_RESPONSE *pResponse = pW3Context->QueryResponse();
  1842. LPCSTR pszExpires = pResponse->GetHeader( HttpHeaderExpires );
  1843. if ( pszExpires != NULL )
  1844. {
  1845. LARGE_INTEGER liExpireTime;
  1846. LARGE_INTEGER liCurrentTime;
  1847. if ( !StringTimeToFileTime( pszExpires,
  1848. &liExpireTime ) )
  1849. {
  1850. return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  1851. }
  1852. GetSystemTimeAsFileTime( (FILETIME *)&liCurrentTime );
  1853. if ( liExpireTime.QuadPart <= liCurrentTime.QuadPart )
  1854. {
  1855. return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  1856. }
  1857. dwTTL = ( liExpireTime.QuadPart - liCurrentTime.QuadPart ) / 10000000;
  1858. }
  1859. //
  1860. // Get the exact URL used to flush UL cache
  1861. //
  1862. hr = pW3Context->QueryMainContext()->QueryRequest()->GetOriginalFullUrl(
  1863. &strFlushUrl );
  1864. if ( FAILED( hr ) )
  1865. {
  1866. return hr;
  1867. }
  1868. //
  1869. // Setup UL cache response token
  1870. //
  1871. DBG_ASSERT( g_pW3Server->QueryUlCache() != NULL );
  1872. hr = g_pW3Server->QueryUlCache()->SetupUlCachedResponse(
  1873. pW3Context,
  1874. strFlushUrl,
  1875. FALSE,
  1876. NULL );
  1877. if ( SUCCEEDED( hr ) )
  1878. {
  1879. if (pszExpires == NULL)
  1880. {
  1881. pCachePolicy->Policy = HttpCachePolicyUserInvalidates;
  1882. }
  1883. else
  1884. {
  1885. pCachePolicy->Policy = HttpCachePolicyTimeToLive;
  1886. pCachePolicy->SecondsToLive = dwTTL;
  1887. }
  1888. }
  1889. return hr;
  1890. }