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.

2956 lines
70 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name :
  4. maincontext.cxx
  5. Abstract:
  6. Drive the state machine
  7. Author:
  8. Bilal Alam (balam) 10-Mar-2000
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULW3.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. #include "rawconnection.hxx"
  16. #include "sspiprovider.hxx"
  17. #include "basicprovider.hxx"
  18. #include "servervar.hxx"
  19. //
  20. // Global alloc cache and context list
  21. //
  22. ALLOC_CACHE_HANDLER * W3_MAIN_CONTEXT::sm_pachMainContexts = NULL;
  23. W3_STATE * W3_MAIN_CONTEXT::sm_pStates[ STATE_COUNT ];
  24. SHORT W3_MAIN_CONTEXT::sm_rgInline[ STATE_COUNT ];
  25. USHORT W3_MAIN_CONTEXT::sm_cbInlineBytes = 0;
  26. DWORD W3_MAIN_CONTEXT::sm_dwTimeout = 0;
  27. HANDLE W3_MAIN_CONTEXT::sm_hTraceFile = INVALID_HANDLE_VALUE;
  28. W3_TRACE_LOG_FACTORY * W3_MAIN_CONTEXT::sm_pLogFactory = NULL;
  29. VOID
  30. W3_MAIN_CONTEXT::DoWork(
  31. DWORD cbCompletion,
  32. DWORD dwCompletionStatus,
  33. BOOL fIoCompletion
  34. )
  35. /*++
  36. Routine Description:
  37. Drives the W3 state machine
  38. Arguments:
  39. cbCompletion - Number of bytes in an async completion
  40. dwCompletionStatus - Error status of a completion
  41. fIoCompletion - TRUE if this was an IO completion,
  42. FALSE if this was a new request completion
  43. Return Value:
  44. None
  45. --*/
  46. {
  47. CONTEXT_STATUS Status = CONTEXT_STATUS_CONTINUE;
  48. BOOL fLastState = FALSE;
  49. W3_CONTEXT * pCurrentContext = NULL;
  50. if (fIoCompletion)
  51. {
  52. if (QueryLastIOPending() == LOG_WRITE_IO)
  53. {
  54. _LogContext.m_dwBytesSent += cbCompletion;
  55. }
  56. else if (QueryLastIOPending() == LOG_READ_IO)
  57. {
  58. IncrementBytesRecvd( cbCompletion );
  59. if ( _cbRemainingEntityFromUL != INFINITE )
  60. {
  61. if ( _cbRemainingEntityFromUL >= cbCompletion )
  62. {
  63. _cbRemainingEntityFromUL -= cbCompletion;
  64. }
  65. else
  66. {
  67. _cbRemainingEntityFromUL = 0;
  68. }
  69. }
  70. }
  71. }
  72. //
  73. // Progress thru states until we are finished or a state operation
  74. // is performed asynchronously
  75. //
  76. while ( !fLastState )
  77. {
  78. W3_STATE * pState;
  79. //
  80. // Get the next function to call, and then call it
  81. //
  82. pState = sm_pStates[ _currentState ];
  83. DBG_ASSERT( pState != NULL );
  84. //
  85. // Manage the _nextState which indicates what the next state will be
  86. // if the DoWork() returns CONTEXT_STATUS_CONTINUE. Note that this
  87. // state can be overriden by W3_MAIN_CONTEXT::SetFinishedResponse
  88. //
  89. _nextState = _currentState + 1;
  90. //
  91. // If this is the last state, remember that so we can cleanup
  92. //
  93. if ( _currentState == CONTEXT_STATE_DONE )
  94. {
  95. fLastState = TRUE;
  96. }
  97. if ( !fIoCompletion )
  98. {
  99. Status = pState->DoWork( this,
  100. cbCompletion,
  101. dwCompletionStatus );
  102. }
  103. else
  104. {
  105. pCurrentContext = QueryCurrentContext();
  106. //
  107. // First try to complete handler contexts if any.
  108. //
  109. Status = pCurrentContext->ExecuteHandlerCompletion(
  110. cbCompletion,
  111. dwCompletionStatus );
  112. if ( Status == CONTEXT_STATUS_CONTINUE )
  113. {
  114. //
  115. // Excellent. All handlers for this context have
  116. // completed. Now we finally complete the original
  117. // state which originally started the async ball rolling
  118. //
  119. Status = pState->OnCompletion( this,
  120. cbCompletion,
  121. dwCompletionStatus );
  122. }
  123. //
  124. // Reset fIoCompletion so we can continue the state machine
  125. // after the completion function is done
  126. //
  127. fIoCompletion = FALSE;
  128. }
  129. //
  130. // An async operation was posted, bail immediately
  131. //
  132. if ( Status == CONTEXT_STATUS_PENDING )
  133. {
  134. return;
  135. }
  136. DBG_ASSERT( Status == CONTEXT_STATUS_CONTINUE );
  137. _currentState = _nextState;
  138. }
  139. //
  140. // If we get here, we must have executed the last state, so cleanup the
  141. // MAIN_CONTEXT
  142. //
  143. DBG_ASSERT( fLastState );
  144. //
  145. // If we have a raw connection, detach ourselves from it now
  146. //
  147. if ( _pRawConnection != NULL )
  148. {
  149. _pRawConnection->SetMainContext( NULL );
  150. }
  151. DereferenceMainContext();
  152. }
  153. VOID
  154. W3_MAIN_CONTEXT::UpdateSkipped(
  155. HTTP_DATA_CHUNK * pChunks,
  156. DWORD cChunks
  157. )
  158. /*++
  159. Routine Description:
  160. Update the amount of worker process data to skip
  161. Arguments:
  162. pChunks - Array of chunks
  163. cChunks - Number of chunks
  164. Return Value:
  165. None
  166. --*/
  167. {
  168. ULARGE_INTEGER liTotalData;
  169. ULARGE_INTEGER liFileSize;
  170. ULARGE_INTEGER liChunkSize;
  171. HTTP_DATA_CHUNK * pDataChunk;
  172. HTTP_BYTE_RANGE * pByteRange;
  173. BOOL fRet;
  174. DBG_ASSERT( (pChunks != NULL) || (cChunks == 0) );
  175. if ( _pRawConnection == NULL )
  176. {
  177. return;
  178. }
  179. liTotalData.QuadPart = 0;
  180. for ( int i = 0; i < cChunks; i++ )
  181. {
  182. pDataChunk = &( pChunks[ i ] );
  183. if ( pDataChunk->DataChunkType == HttpDataChunkFromMemory )
  184. {
  185. liTotalData.QuadPart += pDataChunk->FromMemory.BufferLength;
  186. }
  187. else if ( pDataChunk->DataChunkType == HttpDataChunkFromFileHandle )
  188. {
  189. pByteRange = &( pDataChunk->FromFileHandle.ByteRange );
  190. if ( pByteRange->StartingOffset.QuadPart == HTTP_BYTE_RANGE_TO_EOF )
  191. {
  192. liTotalData.QuadPart += pByteRange->Length.QuadPart;
  193. }
  194. else if ( pByteRange->Length.QuadPart == HTTP_BYTE_RANGE_TO_EOF )
  195. {
  196. fRet = GetFileSizeEx( pDataChunk->FromFileHandle.FileHandle,
  197. (PLARGE_INTEGER) &liFileSize );
  198. if ( fRet )
  199. {
  200. liChunkSize.QuadPart = liFileSize.QuadPart - pByteRange->StartingOffset.QuadPart;
  201. liTotalData.QuadPart += liChunkSize.QuadPart;
  202. }
  203. }
  204. else
  205. {
  206. liTotalData.QuadPart += pByteRange->Length.QuadPart;
  207. }
  208. }
  209. }
  210. _pRawConnection->AddSkippedData( liTotalData );
  211. }
  212. VOID
  213. W3_MAIN_CONTEXT::BackupStateMachine(
  214. VOID
  215. )
  216. /*++
  217. Routine Description:
  218. Backup in state machine to the URL_INFO state. This should be used only
  219. by AUTH_COMPLETE filters
  220. Arguments:
  221. None
  222. Return Value:
  223. None
  224. --*/
  225. {
  226. URL_CONTEXT * pUrlContext;
  227. DBG_ASSERT( IsNotificationNeeded( SF_NOTIFY_AUTH_COMPLETE ) );
  228. //
  229. // Clear the URL context
  230. //
  231. pUrlContext = QueryUrlContext();
  232. DBG_ASSERT( pUrlContext != NULL );
  233. SetUrlContext( NULL );
  234. delete pUrlContext;
  235. //
  236. // Reset our access check state.
  237. //
  238. ResetAccessCheck();
  239. //
  240. // Back that state up
  241. //
  242. _nextState = CONTEXT_STATE_URLINFO;
  243. }
  244. // static
  245. HRESULT
  246. W3_MAIN_CONTEXT::SetupStateMachine(
  247. VOID
  248. )
  249. /*++
  250. Routine Description:
  251. Setup state machine
  252. Arguments:
  253. None
  254. Return Value:
  255. HRESULT
  256. --*/
  257. {
  258. HRESULT hr = NO_ERROR;
  259. W3_STATE * pState = NULL;
  260. DWORD cState = CONTEXT_STATE_START;
  261. //
  262. // First create all the states
  263. //
  264. //
  265. // Start State
  266. //
  267. pState = (W3_STATE*) new W3_STATE_START();
  268. if ( pState == NULL )
  269. {
  270. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  271. goto Failure;
  272. }
  273. else if ( FAILED( hr = pState->QueryResult() ) )
  274. {
  275. goto Failure;
  276. }
  277. sm_pStates[ cState ] = pState;
  278. cState++;
  279. //
  280. // URLINFO State
  281. //
  282. pState = (W3_STATE*) new W3_STATE_URLINFO();
  283. if ( pState == NULL )
  284. {
  285. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  286. goto Failure;
  287. }
  288. else if ( FAILED( hr = pState->QueryResult() ) )
  289. {
  290. goto Failure;
  291. }
  292. sm_pStates[ cState ] = pState;
  293. cState++;
  294. //
  295. // Authentication State
  296. //
  297. pState = (W3_STATE*) new W3_STATE_AUTHENTICATION();
  298. if ( pState == NULL )
  299. {
  300. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  301. goto Failure;
  302. }
  303. else if ( FAILED( hr = pState->QueryResult() ) )
  304. {
  305. goto Failure;
  306. }
  307. sm_pStates[ cState ] = pState;
  308. cState++;
  309. //
  310. // Authorization State
  311. //
  312. pState = (W3_STATE*) new W3_STATE_AUTHORIZATION();
  313. if ( pState == NULL )
  314. {
  315. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  316. goto Failure;
  317. }
  318. else if ( FAILED( hr = pState->QueryResult() ) )
  319. {
  320. goto Failure;
  321. }
  322. sm_pStates[ cState ] = pState;
  323. cState++;
  324. //
  325. // Handle Request State
  326. //
  327. pState = (W3_STATE*) new W3_STATE_HANDLE_REQUEST();
  328. if ( pState == NULL )
  329. {
  330. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  331. goto Failure;
  332. }
  333. else if ( FAILED( hr = pState->QueryResult() ) )
  334. {
  335. goto Failure;
  336. }
  337. sm_pStates[ cState ] = pState;
  338. cState++;
  339. //
  340. // Response State
  341. //
  342. pState = (W3_STATE*) new W3_STATE_RESPONSE();
  343. if ( pState == NULL )
  344. {
  345. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  346. goto Failure;
  347. }
  348. else if ( FAILED( hr = pState->QueryResult() ) )
  349. {
  350. goto Failure;
  351. }
  352. sm_pStates[ cState ] = pState;
  353. cState++;
  354. //
  355. // Log State
  356. //
  357. pState = (W3_STATE*) new W3_STATE_LOG();
  358. if ( pState == NULL )
  359. {
  360. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  361. goto Failure;
  362. }
  363. else if ( FAILED( hr = pState->QueryResult() ) )
  364. {
  365. goto Failure;
  366. }
  367. sm_pStates[ cState ] = pState;
  368. cState++;
  369. //
  370. // Done State
  371. //
  372. pState = (W3_STATE*) new W3_STATE_DONE();
  373. if ( pState == NULL )
  374. {
  375. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  376. goto Failure;
  377. }
  378. else if ( FAILED( hr = pState->QueryResult() ) )
  379. {
  380. goto Failure;
  381. }
  382. sm_pStates[ cState ] = pState;
  383. cState++;
  384. return NO_ERROR;
  385. Failure:
  386. for ( int i = 0; i < STATE_COUNT; i++ )
  387. {
  388. if ( sm_pStates[ i ] != NULL )
  389. {
  390. delete sm_pStates[ i ];
  391. sm_pStates[ i ] = NULL;
  392. }
  393. }
  394. return hr;
  395. }
  396. // static
  397. VOID
  398. W3_MAIN_CONTEXT::CleanupStateMachine(
  399. VOID
  400. )
  401. /*++
  402. Routine Description:
  403. Cleanup state machine
  404. Arguments:
  405. None
  406. Return Value:
  407. None
  408. --*/
  409. {
  410. for ( int i = CONTEXT_STATE_START;
  411. i < STATE_COUNT;
  412. i++ )
  413. {
  414. if ( sm_pStates[ i ] != NULL )
  415. {
  416. delete sm_pStates[ i ];
  417. sm_pStates[ i ] = NULL;
  418. }
  419. }
  420. }
  421. BOOL
  422. W3_MAIN_CONTEXT::SetupContext(
  423. HTTP_REQUEST * pUlHttpRequest,
  424. ULATQ_CONTEXT ulatqContext
  425. )
  426. /*++
  427. Routine Description:
  428. Sets up a MAIN_CONTEXT before executing the state machine for a new
  429. incoming request.
  430. Arguments:
  431. pUlHttpRequest - the HTTP_REQUEST from UL
  432. ulatqContext - used to send/receive data thru ULATQ
  433. Return Value:
  434. TRUE if successful, else FALSE
  435. --*/
  436. {
  437. memset( _rgStateContexts, 0, sizeof( _rgStateContexts ) );
  438. //
  439. // Should we generate a content-length header
  440. //
  441. if ( pUlHttpRequest->Verb == HttpVerbHEAD )
  442. {
  443. _fGenerateContentLength = TRUE;
  444. }
  445. //
  446. // Associate HTTP_REQUEST with W3_REQUEST wrapper
  447. //
  448. _request.SetHttpRequest( pUlHttpRequest );
  449. //
  450. // Associate context for async IO (if any)
  451. //
  452. _ulatqContext = ulatqContext;
  453. UlAtqSetContextProperty( _ulatqContext,
  454. ULATQ_PROPERTY_COMPLETION_CONTEXT,
  455. this );
  456. //
  457. // Setup the state machine
  458. //
  459. _currentState = CONTEXT_STATE_START;
  460. _nextState = CONTEXT_STATE_START;
  461. //
  462. // Setup current context to receive IO completions. Naturally on
  463. // startup, this context will be 'this'. But it can change depending
  464. // on whether child executes are called
  465. //
  466. _pCurrentContext = this;
  467. return TRUE;
  468. }
  469. W3_CONNECTION_STATE *
  470. W3_MAIN_CONTEXT::QueryConnectionState(
  471. VOID
  472. )
  473. /*++
  474. Routine Description:
  475. Get any context associated with this connection and this state.
  476. Arguments:
  477. None
  478. Return Value:
  479. A W3_CONNECTION_STATE * or NULL if there is no state
  480. --*/
  481. {
  482. //
  483. // Since we are just looking for any existing connection state, make
  484. // sure we don't create a connection object if none is already associated
  485. // (creating a connection object is expensive)
  486. //
  487. W3_CONNECTION * pConn = QueryConnection( FALSE );
  488. return pConn ? pConn->QueryConnectionState( _currentState ) : NULL;
  489. }
  490. VOID
  491. W3_MAIN_CONTEXT::SetConnectionState(
  492. W3_CONNECTION_STATE * pConnectionState
  493. )
  494. /*++
  495. Routine Description:
  496. Set any context to be associated with the connection and current state
  497. Arguments:
  498. pConnectionState - Context to associate
  499. Return Value:
  500. None
  501. --*/
  502. {
  503. if ( QueryConnection() )
  504. {
  505. QueryConnection()->SetConnectionState( _currentState,
  506. pConnectionState );
  507. }
  508. }
  509. W3_MAIN_CONTEXT::W3_MAIN_CONTEXT(
  510. HTTP_REQUEST * pUlHttpRequest,
  511. ULATQ_CONTEXT ulAtqContext
  512. )
  513. : W3_CONTEXT ( 0,
  514. 0 /* Recursion Level */),
  515. _pSite ( NULL ),
  516. _pFilterContext ( NULL ),
  517. _fDisconnect ( FALSE ),
  518. _fNeedFinalDone ( FALSE ),
  519. _fAssociationChecked ( FALSE ),
  520. _pConnection ( NULL ),
  521. _pUrlContext ( NULL ),
  522. _pUserContext ( NULL ),
  523. _fProviderHandled ( FALSE ),
  524. _fCheckAnonAuthTypeSupported ( FALSE ),
  525. _fDoneWithCompression ( FALSE ),
  526. _pCompressionContext ( NULL ),
  527. _fIsUlCacheable ( TRUE ),
  528. _pCertificateContext ( NULL ),
  529. _cbRemainingEntityFromUL ( 0 ),
  530. _cbEntityReadSoFar ( 0 ),
  531. _fGenerateContentLength ( FALSE ),
  532. _pRawConnection ( NULL ),
  533. _cRefs ( 1 ),
  534. _hTimer ( NULL ),
  535. _dwLastPostLineNumber ( 0 ),
  536. _pszLastPostFileName ( NULL ),
  537. _pTraceLog ( NULL ),
  538. _fIgnoreAppPoolCheck ( FALSE )
  539. {
  540. _LogContext.m_msStartTickCount = GetTickCount();
  541. SetupContext( pUlHttpRequest, ulAtqContext );
  542. _hTimer = NULL;
  543. if (sm_dwTimeout)
  544. {
  545. BOOL fRet;
  546. fRet = CreateTimerQueueTimer(&_hTimer,
  547. NULL,
  548. W3_MAIN_CONTEXT::TimerCallback,
  549. this,
  550. sm_dwTimeout,
  551. 0,
  552. WT_EXECUTEONLYONCE
  553. );
  554. DBG_ASSERT(fRet);
  555. }
  556. if ( sm_pLogFactory )
  557. {
  558. sm_pLogFactory->CreateTraceLog( &_pTraceLog );
  559. }
  560. }
  561. W3_MAIN_CONTEXT::~W3_MAIN_CONTEXT()
  562. /*++
  563. Routine Description:
  564. Main context destructor
  565. Arguments:
  566. None
  567. Return Value:
  568. None
  569. --*/
  570. {
  571. //
  572. // Cleanup context state
  573. //
  574. for ( DWORD i = 0; i < STATE_COUNT; i++ )
  575. {
  576. if ( _rgStateContexts[ i ] != NULL )
  577. {
  578. ((W3_MAIN_CONTEXT_STATE*) _rgStateContexts[ i ])->Cleanup( this );
  579. _rgStateContexts[ i ] = NULL;
  580. }
  581. }
  582. //
  583. // Let our filter context go
  584. //
  585. if ( _pFilterContext != NULL )
  586. {
  587. _pFilterContext->SetMainContext( NULL );
  588. //
  589. // Only dereference if this is a detached context
  590. //
  591. if ( _pFilterContext != &_FilterContext )
  592. {
  593. _pFilterContext->DereferenceFilterContext();
  594. }
  595. _pFilterContext = NULL;
  596. }
  597. //
  598. // Let go of reference to associated connection
  599. //
  600. if ( _pConnection != NULL )
  601. {
  602. _pConnection->DereferenceConnection();
  603. _pConnection = NULL;
  604. }
  605. //
  606. // Cleanup URL-Context
  607. //
  608. if ( _pUrlContext != NULL )
  609. {
  610. delete _pUrlContext;
  611. _pUrlContext = NULL;
  612. }
  613. //
  614. // Release our user context
  615. //
  616. if ( _pUserContext != NULL )
  617. {
  618. // perf ctr
  619. if (_pUserContext->QueryAuthType() == MD_AUTH_ANONYMOUS)
  620. {
  621. _pSite->DecAnonUsers();
  622. }
  623. else
  624. {
  625. _pSite->DecNonAnonUsers();
  626. }
  627. _pUserContext->DereferenceUserContext();
  628. _pUserContext = NULL;
  629. }
  630. //
  631. // Release the compression context
  632. //
  633. if ( _pCompressionContext != NULL )
  634. {
  635. delete _pCompressionContext;
  636. _pCompressionContext = NULL;
  637. }
  638. //
  639. // Cleanup RDNS crud
  640. //
  641. _IpAddressCheck.UnbindAddr();
  642. //
  643. // Cleanup client certificate context
  644. //
  645. if ( _pCertificateContext != NULL )
  646. {
  647. delete _pCertificateContext;
  648. _pCertificateContext = NULL;
  649. }
  650. //
  651. // Release the raw connection now
  652. //
  653. if ( _pRawConnection != NULL )
  654. {
  655. _pRawConnection->DereferenceRawConnection();
  656. _pRawConnection = NULL;
  657. }
  658. //
  659. // Finally release the site
  660. //
  661. if ( _pSite != NULL )
  662. {
  663. _pSite->DereferenceSite();
  664. _pSite = NULL;
  665. }
  666. if (_hTimer != NULL )
  667. {
  668. BOOL fRet;
  669. fRet = DeleteTimerQueueTimer(NULL,
  670. _hTimer,
  671. INVALID_HANDLE_VALUE);
  672. DBG_ASSERT(fRet);
  673. _hTimer = NULL;
  674. }
  675. if ( _pTraceLog != NULL )
  676. {
  677. _pTraceLog->DestroyTraceLog();
  678. _pTraceLog = NULL;
  679. }
  680. }
  681. // static
  682. HRESULT
  683. W3_MAIN_CONTEXT::Initialize(
  684. VOID
  685. )
  686. /*++
  687. Routine Description:
  688. Global initialization routine for W3_MAIN_CONTEXTs
  689. Arguments:
  690. None
  691. Return Value:
  692. HRESULT
  693. --*/
  694. {
  695. ALLOC_CACHE_CONFIGURATION acConfig;
  696. HRESULT hr = NO_ERROR;
  697. // ignore the return value- if we can't setup trace logging, we can't setup trace logging
  698. SetupTraceLogging();
  699. //
  700. // Setup global state machine. We do this BEFORE we setup the
  701. // allocation cache because the state machine setup will tell how much
  702. // inline buffer space is needed for state
  703. //
  704. hr = SetupStateMachine();
  705. if ( FAILED( hr ) )
  706. {
  707. return hr;
  708. }
  709. //
  710. // Setup allocation lookaside
  711. //
  712. acConfig.nConcurrency = 1;
  713. acConfig.nThreshold = 100;
  714. acConfig.cbSize = sizeof( W3_MAIN_CONTEXT );
  715. DBG_ASSERT( sm_pachMainContexts == NULL );
  716. sm_pachMainContexts = new ALLOC_CACHE_HANDLER( "W3_MAIN_CONTEXT",
  717. &acConfig );
  718. if ( sm_pachMainContexts == NULL )
  719. {
  720. CleanupStateMachine();
  721. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  722. }
  723. sm_dwTimeout = ReadRegDword(HKEY_LOCAL_MACHINE,
  724. REGISTRY_KEY_INETINFO_PARAMETERS_W,
  725. L"RequestTimeoutBreak",
  726. 0);
  727. return NO_ERROR;
  728. }
  729. // static
  730. VOID
  731. W3_MAIN_CONTEXT::Terminate(
  732. VOID
  733. )
  734. /*++
  735. Routine Description:
  736. Terminate MAIN_CONTEXT globals
  737. Arguments:
  738. None
  739. Return Value:
  740. None
  741. --*/
  742. {
  743. CleanupStateMachine();
  744. if ( sm_pachMainContexts != NULL )
  745. {
  746. delete sm_pachMainContexts;
  747. sm_pachMainContexts = NULL;
  748. }
  749. CleanupTraceLogging();
  750. }
  751. W3_USER_CONTEXT *
  752. W3_MAIN_CONTEXT::QueryConnectionUserContext(
  753. VOID
  754. )
  755. /*++
  756. Routine Description:
  757. Get any user context associated with this connection
  758. Arguments:
  759. None
  760. Return Value:
  761. Pointer to W3_USER_CONTEXT (or NULL if no used associated)
  762. --*/
  763. {
  764. W3_CONNECTION * pConnection = NULL;
  765. pConnection = QueryConnection( FALSE );
  766. if ( pConnection != NULL )
  767. {
  768. return pConnection->QueryUserContext();
  769. }
  770. else
  771. {
  772. return NULL;
  773. }
  774. }
  775. VOID
  776. W3_MAIN_CONTEXT::SetConnectionUserContext(
  777. W3_USER_CONTEXT * pUserContext
  778. )
  779. /*++
  780. Routine Description:
  781. Associate user context with connection
  782. Arguments:
  783. pUserContext - User context to associate
  784. Return Value:
  785. None
  786. --*/
  787. {
  788. W3_CONNECTION * pConnection = NULL;
  789. pConnection = QueryConnection( TRUE );
  790. if ( pConnection != NULL )
  791. {
  792. pConnection->SetUserContext( pUserContext );
  793. }
  794. else
  795. {
  796. DBG_ASSERT( FALSE );
  797. }
  798. }
  799. HRESULT
  800. W3_MAIN_CONTEXT::ReceiveEntityBody(
  801. BOOL fAsync,
  802. VOID * pBuffer,
  803. DWORD cbBuffer,
  804. DWORD * pBytesReceived
  805. )
  806. /*++
  807. Routine Description:
  808. Receives entity data from the client
  809. Arguments:
  810. fAsync - TRUE if this is an async request
  811. pBuffer - The buffer to store the data
  812. cbBuffer - The size of the buffer
  813. pBytesReceived - Upon return, the amount of data copied
  814. into the buffer
  815. Return Value:
  816. HRESULT
  817. --*/
  818. {
  819. HRESULT hr = UlAtqReceiveEntityBody( QueryUlatqContext(),
  820. fAsync,
  821. 0,
  822. pBuffer,
  823. cbBuffer,
  824. pBytesReceived );
  825. //
  826. // Keep track of how much we're reading
  827. //
  828. if (!fAsync &&
  829. SUCCEEDED(hr))
  830. {
  831. if ( _cbRemainingEntityFromUL != INFINITE )
  832. {
  833. if ( _cbRemainingEntityFromUL >= *pBytesReceived )
  834. {
  835. _cbRemainingEntityFromUL -= *pBytesReceived;
  836. }
  837. else
  838. {
  839. _cbRemainingEntityFromUL = 0;
  840. }
  841. }
  842. }
  843. return hr;
  844. }
  845. W3_CONNECTION *
  846. W3_MAIN_CONTEXT::QueryConnection(
  847. BOOL fCreateIfNotFound
  848. )
  849. /*++
  850. Routine Description:
  851. Get the W3_CONNECTION object associated with this request
  852. Arguments:
  853. fCreateIfNotFound - If not found in hash table, create it
  854. Return Value:
  855. Pointer to W3_CONNECTION.
  856. --*/
  857. {
  858. HRESULT hr;
  859. if ( _pConnection == NULL )
  860. {
  861. //
  862. // Get the connection associated with this request
  863. //
  864. if ( !fCreateIfNotFound && _fAssociationChecked )
  865. {
  866. //
  867. // If we have already looked for the connection, and we're not
  868. // required to create one, then we can fast path
  869. //
  870. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  871. }
  872. else
  873. {
  874. hr = W3_CONNECTION::RetrieveConnection( _request.QueryConnectionId(),
  875. fCreateIfNotFound,
  876. &_pConnection );
  877. }
  878. if ( FAILED( hr ) )
  879. {
  880. if ( fCreateIfNotFound )
  881. {
  882. DBGPRINTF(( DBG_CONTEXT,
  883. "Error retrieving connection. hr = %x\n",
  884. hr ));
  885. }
  886. else
  887. {
  888. //
  889. // Not really an error. We were just querying the hash table
  890. // for an associated connection (but not creating one)
  891. //
  892. }
  893. }
  894. else
  895. {
  896. DBG_ASSERT( _pConnection != NULL );
  897. }
  898. //
  899. // Don't try to repeat connection lookup again
  900. //
  901. _fAssociationChecked = TRUE;
  902. }
  903. return _pConnection;
  904. }
  905. BOOL
  906. W3_MAIN_CONTEXT::NotifyFilters(
  907. DWORD dwNotification,
  908. PVOID pvFilterInfo,
  909. BOOL * pfFinished
  910. )
  911. /*++
  912. Routine Description:
  913. Notify all applicable filters for a given notification. This is a
  914. wrapper of the W3_FILTER_CONTEXT call to actually do the work. The
  915. notifications made in this routine are those which would occur during
  916. the worker process state machine. (excludes end_of_net_session and
  917. raw data notifications)
  918. Arguments:
  919. dwNotification - Notification in question
  920. pvFilterInfo - Points to any info object passed to filter
  921. pfFinished - Set to TRUE if the filter decided to complete work
  922. Return Value:
  923. BOOL
  924. --*/
  925. {
  926. BOOL fRet = FALSE;
  927. BOOL fSynchronized = FALSE;
  928. DBG_ASSERT( _pFilterContext != NULL );
  929. _pFilterContext->FilterLock();
  930. switch( dwNotification )
  931. {
  932. case SF_NOTIFY_PREPROC_HEADERS:
  933. fRet = _pFilterContext->NotifyPreProcHeaderFilters( pfFinished );
  934. break;
  935. case SF_NOTIFY_URL_MAP:
  936. fRet = _pFilterContext->NotifyUrlMap( (HTTP_FILTER_URL_MAP*) pvFilterInfo,
  937. pfFinished );
  938. break;
  939. case SF_NOTIFY_AUTHENTICATION:
  940. fRet = _pFilterContext->NotifyAuthentication( (HTTP_FILTER_AUTHENT*) pvFilterInfo,
  941. pfFinished );
  942. break;
  943. case SF_NOTIFY_AUTH_COMPLETE:
  944. fRet = _pFilterContext->NotifyAuthComplete(
  945. ( HTTP_FILTER_AUTH_COMPLETE_INFO * )pvFilterInfo,
  946. pfFinished );
  947. break;
  948. case SF_NOTIFY_SEND_RESPONSE:
  949. fRet = _pFilterContext->NotifySendResponseFilters(
  950. (HTTP_FILTER_SEND_RESPONSE*) pvFilterInfo,
  951. pfFinished );
  952. break;
  953. case SF_NOTIFY_END_OF_REQUEST:
  954. fRet = _pFilterContext->NotifyEndOfRequest();
  955. break;
  956. case SF_NOTIFY_LOG:
  957. fRet = _pFilterContext->NotifyLogFilters((HTTP_FILTER_LOG *)pvFilterInfo);
  958. break;
  959. case SF_NOTIFY_SEND_RAW_DATA:
  960. fRet = _pFilterContext->NotifySendRawFilters(
  961. (HTTP_FILTER_RAW_DATA*) pvFilterInfo,
  962. pfFinished );
  963. break;
  964. default:
  965. DBG_ASSERT( FALSE );
  966. fRet = FALSE;
  967. }
  968. _pFilterContext->FilterUnlock();
  969. return fRet;
  970. }
  971. W3_FILTER_CONTEXT *
  972. W3_MAIN_CONTEXT::QueryFilterContext(
  973. BOOL fCreateIfNotFound
  974. )
  975. /*++
  976. Routine Description:
  977. Get a filter context to associate with the MAIN_CONTEXT and to also (
  978. AAAAAAAARRRRRRRGGGGGGGHHHHHH) associate with the connection on the
  979. W3_CONTXT
  980. Arguments:
  981. fCreateIfNotFound - Should we create a context if it doesn't already exist
  982. (default TRUE)
  983. Return Value:
  984. Pointer to a new W3_FILTER_CONTEXT
  985. --*/
  986. {
  987. BOOL fSecure;
  988. BOOL fCreateNew = FALSE;
  989. if ( _pFilterContext == NULL &&
  990. fCreateIfNotFound )
  991. {
  992. //
  993. // OK. Now it gets interesting.
  994. //
  995. // Every W3_MAIN_CONTEXT has inline with it a W3_FILTER_CONTEXT.
  996. // This is sufficient for all cases except for filters which
  997. // require an END_OF_NET_SESSION notification. In this case
  998. // the W3_FILTER_CONTEXT must have a lifetime beyond the
  999. // W3_MAIN_CONTEXT. When creating a W3_FILTER_CONTEXT here,
  1000. // we check whether an END_OF_NET_SESSION notification is needed
  1001. // If so we create a new filter context to associate with this
  1002. // request
  1003. //
  1004. DBG_ASSERT( _pSite != NULL );
  1005. fSecure = QueryRequest()->IsSecureRequest();
  1006. if ( _pSite->QueryFilterList() != NULL )
  1007. {
  1008. if ( _pSite->QueryFilterList()->IsNotificationNeeded( SF_NOTIFY_END_OF_NET_SESSION,
  1009. fSecure ) )
  1010. {
  1011. fCreateNew = TRUE;
  1012. }
  1013. }
  1014. if ( fCreateNew )
  1015. {
  1016. _pFilterContext = new W3_FILTER_CONTEXT;
  1017. }
  1018. else
  1019. {
  1020. _pFilterContext = &_FilterContext;
  1021. }
  1022. if ( _pFilterContext != NULL )
  1023. {
  1024. _pFilterContext->InitializeFilterContext( fSecure,
  1025. _pSite->QueryFilterList(),
  1026. fCreateNew ? FALSE : TRUE );
  1027. _pFilterContext->SetMainContext( this );
  1028. }
  1029. }
  1030. return _pFilterContext;
  1031. }
  1032. BOOL
  1033. W3_MAIN_CONTEXT::IsNotificationNeeded(
  1034. DWORD dwNotification
  1035. )
  1036. /*++
  1037. Routine Description:
  1038. Is a specific filter notification applicable for this request
  1039. Arguments:
  1040. dwNotification - Notification in question
  1041. Return Value:
  1042. BOOL
  1043. --*/
  1044. {
  1045. BOOL fNeeded = FALSE;
  1046. FILTER_LIST * pFilterList = NULL;
  1047. W3_FILTER_CONTEXT * pFilterContext = NULL;
  1048. if ( _pSite != NULL )
  1049. {
  1050. //
  1051. // To avoid creating connection contexts, do the simple fast check
  1052. // to determine whether the given contexts site supports the
  1053. // notification. If it does, then we have to do the more robust
  1054. // check to determine whether this specific request requires the
  1055. // notification (there is a difference because a filter can
  1056. // disable itself on the fly for any given request)
  1057. //
  1058. pFilterList = _pSite->QueryFilterList();
  1059. DBG_ASSERT( pFilterList != NULL );
  1060. if ( pFilterList->IsNotificationNeeded( dwNotification,
  1061. QueryRequest()->IsSecureRequest() ) )
  1062. {
  1063. pFilterContext = QueryFilterContext();
  1064. if ( pFilterContext != NULL )
  1065. {
  1066. fNeeded = pFilterContext->IsNotificationNeeded( dwNotification );
  1067. }
  1068. }
  1069. }
  1070. return fNeeded;
  1071. }
  1072. BOOL
  1073. W3_MAIN_CONTEXT::QueryExpiry(
  1074. LARGE_INTEGER * pExpiry
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. Queries the expiration date/time for logon user
  1079. Arguments:
  1080. pExpiry - ptr to buffer to update with expiration date
  1081. Return Value:
  1082. TRUE if successful, FALSE if not available
  1083. --*/
  1084. {
  1085. SECURITY_STATUS ss;
  1086. SecPkgContext_PasswordExpiry speExpiry;
  1087. SSPI_SECURITY_CONTEXT * pSecurityContext;
  1088. W3_USER_CONTEXT * pW3UserContext;
  1089. LARGE_INTEGER * pUserAcctExpiry = NULL;
  1090. pUserAcctExpiry = _pUserContext->QueryExpiry();
  1091. if ( pUserAcctExpiry == NULL )
  1092. {
  1093. ((LARGE_INTEGER*)pExpiry)->HighPart = 0x7fffffff;
  1094. ((LARGE_INTEGER*)pExpiry)->LowPart = 0xffffffff;
  1095. return FALSE;
  1096. }
  1097. else
  1098. {
  1099. memcpy( pExpiry,
  1100. pUserAcctExpiry,
  1101. sizeof( LARGE_INTEGER ) );
  1102. }
  1103. return TRUE;
  1104. }
  1105. HRESULT
  1106. W3_MAIN_CONTEXT::ExecuteExpiredUrl(
  1107. STRU & strExpUrl
  1108. )
  1109. /*++
  1110. Routine Description:
  1111. Do child execution on the server configed expire url
  1112. Arguments:
  1113. strExpUrl - The configed expire url to be executed
  1114. Return Value:
  1115. HRESULT
  1116. --*/
  1117. {
  1118. HRESULT hr;
  1119. AUTH_PROVIDER * pAnonymousProvider = NULL;
  1120. STRA strNewHeader;
  1121. STRA strNewValue;
  1122. BOOL fFilterFinished = FALSE;
  1123. W3_USER_CONTEXT * pUserContext = QueryUserContext();
  1124. if( pUserContext != NULL )
  1125. {
  1126. SetConnectionUserContext( NULL );
  1127. pUserContext->DereferenceUserContext();
  1128. pUserContext = NULL;
  1129. }
  1130. pAnonymousProvider = W3_STATE_AUTHENTICATION::QueryAnonymousProvider();
  1131. DBG_ASSERT( pAnonymousProvider != NULL );
  1132. hr = pAnonymousProvider->DoAuthenticate( this,
  1133. &fFilterFinished );
  1134. if( FAILED( hr ) )
  1135. {
  1136. return hr;
  1137. }
  1138. //
  1139. // Execute a child request
  1140. //
  1141. QueryResponse()->Clear();
  1142. QueryResponse()->SetStatus( HttpStatusOk );
  1143. //
  1144. // Reset the new url to be executed
  1145. //
  1146. hr = QueryRequest()->SetUrl( strExpUrl );
  1147. if( FAILED( hr ) )
  1148. {
  1149. return hr;
  1150. }
  1151. //
  1152. // Add CFG_ENC_CAPS header and set its value to 1 to indicate
  1153. // the site support SSL, to 0 if not.
  1154. //
  1155. strNewHeader.Copy( "CFG-ENC-CAPS" );
  1156. if( QuerySite()->QuerySSLSupported() )
  1157. {
  1158. strNewValue.Copy( "1" );
  1159. }
  1160. else
  1161. {
  1162. strNewValue.Copy( "0" );
  1163. }
  1164. hr = QueryRequest()->SetHeader( strNewHeader,
  1165. strNewValue,
  1166. TRUE );
  1167. if( FAILED( hr ) )
  1168. {
  1169. return hr;
  1170. }
  1171. //
  1172. // Set the auth access check flag to FALSE so the
  1173. // child execution won't do auth access check
  1174. //
  1175. SetAuthAccessCheckRequired( FALSE );
  1176. //
  1177. // Execute child request
  1178. //
  1179. hr = ExecuteChildRequest( QueryRequest(),
  1180. FALSE,
  1181. W3_FLAG_ASYNC );
  1182. return hr;
  1183. }
  1184. HRESULT
  1185. W3_MAIN_CONTEXT::PasswdExpireNotify(
  1186. VOID
  1187. )
  1188. /*++
  1189. Routine Description:
  1190. Check if the user password has been expired
  1191. Arguments:
  1192. None
  1193. Return Value:
  1194. HRESULT
  1195. --*/
  1196. {
  1197. HRESULT hr = S_FALSE;
  1198. LARGE_INTEGER cExpire;
  1199. FILETIME ftNow;
  1200. DWORD dwExpireInDay;
  1201. DWORD dwTotalRequired;
  1202. STACK_STRU ( strExpUrl, MAX_PATH );
  1203. STACK_STRU ( strFullUrl, MAX_PATH );
  1204. STRU * pstrAdvNotPwdExpUrl;
  1205. BYTE byTokenInfo[ SID_DEFAULT_SIZE + sizeof( TOKEN_USER ) ];
  1206. PSID pSid;
  1207. if ( QueryExpiry( &cExpire ) )
  1208. {
  1209. if ( cExpire.HighPart == 0x7fffffff )
  1210. {
  1211. //
  1212. // Password never expire
  1213. //
  1214. return hr;
  1215. }
  1216. else
  1217. {
  1218. GetSystemTimeAsFileTime( &ftNow );
  1219. if ( *( __int64 * )&cExpire > *( __int64 * )&ftNow )
  1220. {
  1221. dwExpireInDay = ( DWORD )( ( * ( __int64 * )&cExpire
  1222. - *( __int64 * )&ftNow )
  1223. / ( ( __int64 )10000000 * 86400 ) );
  1224. if ( QuerySite()->QueryAdvNotPwdExpInDays() &&
  1225. dwExpireInDay <= QuerySite()->QueryAdvNotPwdExpInDays() )
  1226. {
  1227. pstrAdvNotPwdExpUrl = QuerySite()->QueryAdvNotPwdExpUrl();
  1228. if( pstrAdvNotPwdExpUrl == NULL )
  1229. {
  1230. //
  1231. // Advanced password expire notification disabled
  1232. //
  1233. return hr;
  1234. }
  1235. //
  1236. // Check this SID has not already been notified
  1237. // of pwd expiration
  1238. //
  1239. if ( GetTokenInformation(
  1240. QueryUserContext()->QueryPrimaryToken(),
  1241. TokenUser,
  1242. ( LPVOID )byTokenInfo,
  1243. sizeof( byTokenInfo ),
  1244. &dwTotalRequired ) )
  1245. {
  1246. pSid = ( ( TOKEN_USER * )byTokenInfo )->User.Sid;
  1247. if( !PenCheckPresentAndResetTtl(
  1248. pSid,
  1249. QuerySite()->QueryAdvCacheTTL() ) )
  1250. {
  1251. PenAddToCache(
  1252. pSid,
  1253. QuerySite()->QueryAdvCacheTTL() );
  1254. //
  1255. // flush cache when connection close
  1256. // so that account change will not be masked
  1257. // by cached information
  1258. //
  1259. if( QueryUserContext()->QueryAuthType() ==
  1260. MD_AUTH_BASIC )
  1261. {
  1262. g_pW3Server->QueryTokenCache()->FlushCacheEntry(
  1263. ( ( BASIC_USER_CONTEXT * )QueryUserContext() )
  1264. ->QueryCachedToken()->QueryCacheKey() );
  1265. }
  1266. hr = strExpUrl.Copy( pstrAdvNotPwdExpUrl->
  1267. QueryStr() );
  1268. if( FAILED( hr ) )
  1269. {
  1270. return hr;
  1271. }
  1272. if ( strExpUrl.QueryStr()[0] == NULL )
  1273. {
  1274. return E_FAIL;
  1275. }
  1276. //
  1277. // Add the arg to be passed to the
  1278. // password-change URL - argument is the
  1279. // URL the user is pointed to after all
  1280. // the password-change processing is done
  1281. //
  1282. hr = strExpUrl.Append( L"?" );
  1283. if( FAILED( hr ) )
  1284. {
  1285. return hr;
  1286. }
  1287. hr = QueryRequest()->GetOriginalFullUrl(
  1288. &strFullUrl );
  1289. if( FAILED( hr ) )
  1290. {
  1291. return hr;
  1292. }
  1293. hr = strExpUrl.Append( strFullUrl );
  1294. if( FAILED( hr ) )
  1295. {
  1296. return hr;
  1297. }
  1298. return ExecuteExpiredUrl( strExpUrl );
  1299. }
  1300. }
  1301. }
  1302. }
  1303. else
  1304. {
  1305. //
  1306. // flush cache when connection close
  1307. // since the password has expired
  1308. //
  1309. if( QueryUserContext()->QueryAuthType() == MD_AUTH_BASIC )
  1310. {
  1311. g_pW3Server->QueryTokenCache()->FlushCacheEntry(
  1312. ( ( BASIC_USER_CONTEXT * )QueryUserContext() )
  1313. ->QueryCachedToken()->QueryCacheKey() );
  1314. }
  1315. return PasswdChangeExecute();
  1316. }
  1317. }
  1318. }
  1319. return hr;
  1320. }
  1321. HRESULT
  1322. W3_MAIN_CONTEXT::PasswdChangeExecute(
  1323. VOID
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. This method handles password expiration notification
  1328. Arguments:
  1329. None
  1330. Return Value:
  1331. HRESULT
  1332. --*/
  1333. {
  1334. HRESULT hr = S_FALSE;
  1335. STACK_STRU ( strExpUrl, MAX_PATH );
  1336. STACK_STRU ( strFullUrl, MAX_PATH );
  1337. STACK_STRU ( strUrl, MAX_PATH );
  1338. STRU * pstrAuthExpiredUrl;
  1339. pstrAuthExpiredUrl = QuerySite()->QueryAuthExpiredUrl();
  1340. if( pstrAuthExpiredUrl == NULL )
  1341. {
  1342. //
  1343. // S_FALSE means password change disabled
  1344. //
  1345. return hr;
  1346. }
  1347. hr = strExpUrl.Copy( pstrAuthExpiredUrl->QueryStr() );
  1348. if( FAILED( hr ) )
  1349. {
  1350. return hr;
  1351. }
  1352. if ( strExpUrl.QueryStr()[0] == NULL )
  1353. {
  1354. return E_FAIL;
  1355. }
  1356. hr = QueryRequest()->GetUrl( &strUrl );
  1357. if( FAILED( hr ) )
  1358. {
  1359. return hr;
  1360. }
  1361. //
  1362. // Add the arg to be passed to the password-change URL - argument
  1363. // is the URL the user is pointed to after all the password-change
  1364. // processing is done
  1365. //
  1366. hr = strExpUrl.Append( L"?" );
  1367. if ( FAILED( hr ) )
  1368. {
  1369. return hr;
  1370. }
  1371. hr = QueryRequest()->GetOriginalFullUrl( &strFullUrl );
  1372. if( FAILED( hr ) )
  1373. {
  1374. return hr;
  1375. }
  1376. hr = strExpUrl.Append( strFullUrl );
  1377. if( FAILED( hr ) )
  1378. {
  1379. return hr;
  1380. }
  1381. return ExecuteExpiredUrl( strExpUrl );
  1382. }
  1383. HRESULT
  1384. W3_MAIN_CONTEXT::GetRemoteDNSName(
  1385. STRA * pstrDNSName
  1386. )
  1387. /*++
  1388. Routine Description:
  1389. Get remote client's DNS name if it is resolved
  1390. Arguments:
  1391. pstrDNSName - Filled with DNS name on success
  1392. Return Value:
  1393. HRESULT
  1394. --*/
  1395. {
  1396. DBG_ASSERT( pstrDNSName != NULL );
  1397. if ( _IpAddressCheck.IsDnsResolved() &&
  1398. _IpAddressCheck.QueryResolvedDnsName()[0] != '\0' )
  1399. {
  1400. return pstrDNSName->Copy( _IpAddressCheck.QueryResolvedDnsName() );
  1401. }
  1402. else
  1403. {
  1404. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  1405. }
  1406. }
  1407. VOID *
  1408. W3_MAIN_CONTEXT::operator new(
  1409. size_t uiSize,
  1410. VOID * pPlacement
  1411. )
  1412. /*++
  1413. Routine Description:
  1414. Allocate a new W3_MAIN_CONTEXT (from inline or ACache)
  1415. Arguments:
  1416. uiSize - Size to allocate
  1417. pPlacement - UL_NATIVE_REQUEST
  1418. Return Value:
  1419. Pointer to memory (or NULL on failure)
  1420. --*/
  1421. {
  1422. ULATQ_CONTEXT ulatqContext;
  1423. //
  1424. // If read filtering is needed, then W3_MAIN_CONTEXTs have a lifetime
  1425. // beyond their UL_NATIVE_REQUEST lifetime. Therefore use
  1426. // the regular ACache
  1427. //
  1428. if ( RAW_CONNECTION::QueryDoReadRawFiltering() )
  1429. {
  1430. return sm_pachMainContexts->Alloc();
  1431. }
  1432. else
  1433. {
  1434. ulatqContext = (ULATQ_CONTEXT) pPlacement;
  1435. return UlAtqAllocateMemory( ulatqContext, uiSize );
  1436. }
  1437. }
  1438. VOID
  1439. W3_MAIN_CONTEXT::operator delete(
  1440. VOID * pMainContext
  1441. )
  1442. /*++
  1443. Routine Description:
  1444. Delete a W3_MAIN_CONTEXT
  1445. Arguments:
  1446. pMainContext - context to delete
  1447. Return Value:
  1448. None
  1449. --*/
  1450. {
  1451. if ( RAW_CONNECTION::QueryDoReadRawFiltering() )
  1452. {
  1453. sm_pachMainContexts->Free( pMainContext );
  1454. }
  1455. }
  1456. VOID *
  1457. W3_MAIN_CONTEXT::AllocateFromInlineMemory(
  1458. DWORD cbSize
  1459. )
  1460. /*++
  1461. Routine Description:
  1462. Allocate from UL_NATIVE_REQUEST structure
  1463. Arguments:
  1464. cbSize - size to allocate
  1465. Return Value:
  1466. Pointer to memory (or NULL if failure)
  1467. --*/
  1468. {
  1469. if ( RAW_CONNECTION::QueryDoReadRawFiltering() )
  1470. {
  1471. return NULL;
  1472. }
  1473. else
  1474. {
  1475. return UlAtqAllocateMemory( _ulatqContext, cbSize );
  1476. }
  1477. }
  1478. CONTEXT_STATUS
  1479. W3_STATE_START::DoWork(
  1480. W3_MAIN_CONTEXT * pMainContext,
  1481. DWORD cbCompletion,
  1482. DWORD dwCompletionStatus
  1483. )
  1484. /*++
  1485. Routine Description:
  1486. Initial start state handling
  1487. Arguments:
  1488. pMainContext - W3_MAIN_CONTEXT representing an execution of the state machine
  1489. cbCompletion - Number of bytes on completion
  1490. dwCompletionStatus - Win32 Error on completion (if any)
  1491. Return Value:
  1492. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  1493. else stop executing the machine and free up the current thread
  1494. --*/
  1495. {
  1496. W3_REQUEST * pRequest;
  1497. DWORD dwSiteId;
  1498. HRESULT hr;
  1499. W3_SITE * pSite;
  1500. BOOL fFinished = FALSE;
  1501. BOOL fNeedRawRead = FALSE;
  1502. BOOL fNeedRealRawWrite = FALSE;
  1503. RAW_CONNECTION * pRawConnection = NULL;
  1504. W3_FILTER_CONTEXT * pFilterContext = NULL;
  1505. W3_TRACE_LOG * pTraceLog = pMainContext->QueryTraceLog();
  1506. //
  1507. // Get the request out of the context and the SiteId out of the request
  1508. //
  1509. pRequest = pMainContext->QueryRequest();
  1510. DBG_ASSERT( pRequest != NULL );
  1511. if ( pTraceLog != NULL )
  1512. {
  1513. pTraceLog->Trace( L"%I64x: Received new request\n",
  1514. pRequest->QueryRequestId() );
  1515. }
  1516. dwSiteId = pRequest->QuerySiteId();
  1517. //
  1518. // Check if this site already exists
  1519. //
  1520. pSite = g_pW3Server->FindSite( dwSiteId );
  1521. //
  1522. // Now we need to do some locking while adding this site
  1523. //
  1524. if ( pSite == NULL )
  1525. {
  1526. g_pW3Server->WriteLockSiteList();
  1527. //
  1528. // try again, avoid race condition
  1529. //
  1530. pSite = g_pW3Server->FindSite( dwSiteId );
  1531. if ( pSite == NULL )
  1532. {
  1533. //
  1534. // Need to create a new site!
  1535. //
  1536. pSite = new W3_SITE( dwSiteId );
  1537. if ( pSite == NULL )
  1538. {
  1539. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1540. }
  1541. else
  1542. {
  1543. hr = pSite->Initialize();
  1544. }
  1545. if ( FAILED( hr ) )
  1546. {
  1547. if ( pSite != NULL )
  1548. {
  1549. pSite->DereferenceSite();
  1550. pSite = NULL;
  1551. }
  1552. pMainContext->SetErrorStatus( hr );
  1553. pMainContext->SetFinishedResponse();
  1554. }
  1555. else
  1556. {
  1557. g_pW3Server->AddSite( pSite );
  1558. }
  1559. }
  1560. g_pW3Server->WriteUnlockSiteList();
  1561. }
  1562. if ( pSite == NULL )
  1563. {
  1564. if ( pTraceLog != NULL )
  1565. {
  1566. pTraceLog->Trace( L"%I64x: Failed to find site %d\n",
  1567. pRequest->QueryRequestId(),
  1568. dwSiteId );
  1569. }
  1570. return CONTEXT_STATUS_CONTINUE;
  1571. }
  1572. if ( pTraceLog != NULL )
  1573. {
  1574. pTraceLog->Trace( L"%I64x: Successfully associated site %d\n",
  1575. pRequest->QueryRequestId(),
  1576. dwSiteId );
  1577. }
  1578. //
  1579. // If we found a site, associate it so that all future consumers can
  1580. // get at site configuration settings
  1581. //
  1582. pMainContext->AssociateSite( pSite );
  1583. //
  1584. // Let the raw data fun begin.
  1585. //
  1586. // If this request has gone thru the stream filter, then we'll need
  1587. // to associate the current W3_CONNECTION with a RAW_CONNECTION. Also,
  1588. // we'll have to retrieve a filter context
  1589. //
  1590. fNeedRawRead = FILTER_LIST::QueryGlobalList()->IsNotificationNeeded(
  1591. SF_NOTIFY_READ_RAW_DATA,
  1592. pRequest->IsSecureRequest() );
  1593. //
  1594. // If we are in backward compat mode, AND send raw notifications are
  1595. // needed, then we will use streamfilt to get the data which WPs do
  1596. // not generate
  1597. //
  1598. if ( g_pW3Server->QueryInBackwardCompatibilityMode() )
  1599. {
  1600. fNeedRealRawWrite = FILTER_LIST::QueryGlobalList()->IsNotificationNeeded(
  1601. SF_NOTIFY_SEND_RAW_DATA,
  1602. pRequest->IsSecureRequest() );
  1603. if ( fNeedRealRawWrite )
  1604. {
  1605. pMainContext->SetNeedFinalDone();
  1606. }
  1607. }
  1608. if ( pRequest->QueryRawConnectionId() != HTTP_NULL_ID &&
  1609. ( fNeedRawRead || fNeedRealRawWrite ) )
  1610. {
  1611. //
  1612. // Raw read filters should be loaded only in old mode
  1613. //
  1614. DBG_ASSERT( g_pW3Server->QueryInBackwardCompatibilityMode() );
  1615. //
  1616. // Find a raw connection for this request
  1617. //
  1618. hr = RAW_CONNECTION::FindConnection( pRequest->QueryRawConnectionId(),
  1619. &pRawConnection );
  1620. if ( FAILED( hr ) )
  1621. {
  1622. pMainContext->SetErrorStatus( hr );
  1623. pMainContext->SetFinishedResponse();
  1624. pMainContext->SetDisconnect( TRUE );
  1625. return CONTEXT_STATUS_CONTINUE;
  1626. }
  1627. DBG_ASSERT( pRawConnection != NULL );
  1628. //
  1629. // We assume we don't have to skip bytes until a send raw filter
  1630. // causes us to
  1631. //
  1632. if ( fNeedRealRawWrite )
  1633. {
  1634. pRawConnection->EnableSkip();
  1635. }
  1636. //
  1637. // We will need to copy over context pointers and allocated memory
  1638. // from any existing read data filters
  1639. //
  1640. pFilterContext = pMainContext->QueryFilterContext();
  1641. if ( pFilterContext == NULL )
  1642. {
  1643. pMainContext->SetErrorStatus( hr );
  1644. pMainContext->SetFinishedResponse();
  1645. pMainContext->SetDisconnect( TRUE );
  1646. return CONTEXT_STATUS_CONTINUE;
  1647. }
  1648. pRawConnection->CopyContextPointers( pFilterContext );
  1649. pRawConnection->CopyAllocatedFilterMemory( pFilterContext );
  1650. hr = pRawConnection->CopyHeaders( pFilterContext );
  1651. if ( FAILED( hr ) )
  1652. {
  1653. pMainContext->SetErrorStatus( hr );
  1654. pMainContext->SetFinishedResponse();
  1655. pMainContext->SetDisconnect( TRUE );
  1656. return CONTEXT_STATUS_CONTINUE;
  1657. }
  1658. //
  1659. // Associate the raw connection with the main context
  1660. //
  1661. pRawConnection->SetMainContext( pMainContext );
  1662. pMainContext->SetRawConnection( pRawConnection );
  1663. }
  1664. //
  1665. // We can notify filters now that we have a site associated
  1666. //
  1667. if ( pMainContext->IsNotificationNeeded( SF_NOTIFY_PREPROC_HEADERS ) )
  1668. {
  1669. if ( !pMainContext->NotifyFilters( SF_NOTIFY_PREPROC_HEADERS,
  1670. NULL,
  1671. &fFinished ) )
  1672. {
  1673. DWORD dwError = GetLastError();
  1674. pMainContext->SetErrorStatus( HRESULT_FROM_WIN32( dwError ) );
  1675. if ( dwError == ERROR_ACCESS_DENIED )
  1676. {
  1677. URL_CONTEXT * pUrlContext;
  1678. pMainContext->QueryResponse()->SetStatus( HttpStatusUnauthorized,
  1679. Http401Filter );
  1680. //
  1681. // In order for the ACCESS_DENIED notification to fire,
  1682. // and the correct 401 customer error to get returned,
  1683. // we need to associate a URL_CONTEXT with this request.
  1684. //
  1685. // It's not necessary to handle the failure case, since
  1686. // a failure will still result in a "default" 401
  1687. // response.
  1688. //
  1689. URL_CONTEXT::RetrieveUrlContext( pMainContext,
  1690. pMainContext->QueryRequest(),
  1691. &pUrlContext,
  1692. &fFinished,
  1693. TRUE );
  1694. }
  1695. else if ( dwError == ERROR_FILE_NOT_FOUND ||
  1696. dwError == ERROR_PATH_NOT_FOUND )
  1697. {
  1698. pMainContext->QueryResponse()->SetStatus( HttpStatusNotFound );
  1699. }
  1700. else
  1701. {
  1702. pMainContext->QueryResponse()->SetStatus( HttpStatusServerError );
  1703. }
  1704. pMainContext->SetFinishedResponse();
  1705. pMainContext->SetDisconnect( TRUE );
  1706. return CONTEXT_STATUS_CONTINUE;
  1707. }
  1708. if ( fFinished )
  1709. {
  1710. pMainContext->SetFinishedResponse();
  1711. }
  1712. }
  1713. //
  1714. // If we need an END_OF_NET_SESSION notification, then get a connect
  1715. //
  1716. if ( pMainContext->IsNotificationNeeded( SF_NOTIFY_END_OF_NET_SESSION ) )
  1717. {
  1718. pFilterContext = pMainContext->QueryFilterContext();
  1719. DBG_ASSERT( pFilterContext != NULL );
  1720. pFilterContext->QueryConnectionContext( TRUE );
  1721. }
  1722. //
  1723. // Determine the amount of bytes available to be read thru UL
  1724. //
  1725. pMainContext->DetermineRemainingEntity();
  1726. pMainContext->SetInitialEntityReadSize( pRequest->QueryAvailableBytes() );
  1727. //
  1728. // Now that filters have been notified, we can increment the appropriate
  1729. // verb perf counter.
  1730. //
  1731. pSite->IncReqType( pRequest->QueryVerbType() );
  1732. return CONTEXT_STATUS_CONTINUE;
  1733. }
  1734. VOID *
  1735. W3_MAIN_CONTEXT_STATE::operator new(
  1736. size_t uiSize,
  1737. VOID * pPlacement
  1738. )
  1739. /*++
  1740. Routine Description:
  1741. Allocate from the inline buffer contained in the main context
  1742. Arguments:
  1743. uiSize - Size to allocate
  1744. pPlacement - Points to a W3_CONTEXT to allocate from
  1745. Return Value:
  1746. None
  1747. --*/
  1748. {
  1749. W3_CONTEXT * pContext;
  1750. PVOID pBuffer;
  1751. pContext = (W3_CONTEXT*) pPlacement;
  1752. DBG_ASSERT( pContext != NULL );
  1753. DBG_ASSERT( pContext->CheckSignature() );
  1754. pBuffer = pContext->ContextAlloc( (UINT)uiSize );
  1755. DBG_ASSERT( pBuffer != NULL );
  1756. return pBuffer;
  1757. }
  1758. VOID
  1759. W3_MAIN_CONTEXT_STATE::operator delete(
  1760. VOID * pContext
  1761. )
  1762. {
  1763. //
  1764. // Do nothing here. Either
  1765. // a) memory was allocated from inline W3_MAIN_CONTEXT buffer and thus should
  1766. // not be freeed
  1767. // b) memory was allocated from heap because inline buffer didn't have
  1768. // enough space. In this case, the memory is freed on MAIN_CONTEXT
  1769. // cleanup
  1770. //
  1771. }
  1772. VOID
  1773. W3_MAIN_CONTEXT::DetermineRemainingEntity(
  1774. VOID
  1775. )
  1776. /*++
  1777. Routine Description:
  1778. Determine remaining entity body to be read from UL
  1779. Arguments:
  1780. None
  1781. Return Value:
  1782. None
  1783. --*/
  1784. {
  1785. LPCSTR pszContentLength;
  1786. DWORD cbContentLength;
  1787. if ( _request.QueryMoreEntityBodyExists() )
  1788. {
  1789. pszContentLength = _request.GetHeader( HttpHeaderContentLength );
  1790. if ( pszContentLength != NULL )
  1791. {
  1792. cbContentLength = atoi( pszContentLength );
  1793. if ( _request.QueryAvailableBytes() <= cbContentLength )
  1794. {
  1795. _cbRemainingEntityFromUL = cbContentLength - _request.QueryAvailableBytes();
  1796. }
  1797. else
  1798. {
  1799. _cbRemainingEntityFromUL = 0;
  1800. }
  1801. }
  1802. else
  1803. {
  1804. _cbRemainingEntityFromUL = INFINITE;
  1805. }
  1806. }
  1807. else
  1808. {
  1809. _cbRemainingEntityFromUL = 0;
  1810. }
  1811. }
  1812. HRESULT
  1813. W3_MAIN_CONTEXT::SetupCertificateContext(
  1814. HTTP_SSL_CLIENT_CERT_INFO * pClientCertInfo
  1815. )
  1816. /*++
  1817. Routine Description:
  1818. Create a CERTIFICATE_CONTEXT representing the given client certificate
  1819. Arguments:
  1820. pClientCertInfo - Client cert info from stream filter
  1821. Return Value:
  1822. HRESULT
  1823. --*/
  1824. {
  1825. if ( pClientCertInfo == NULL )
  1826. {
  1827. DBG_ASSERT( FALSE );
  1828. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1829. }
  1830. //
  1831. // Just for completeness sake, attach the raw cert descriptor to the
  1832. // main request, as it automatically be for subsequent requests on this
  1833. // connection
  1834. //
  1835. QueryRequest()->SetClientCertInfo( pClientCertInfo );
  1836. //
  1837. // Create a client certificate descriptor and associate it with
  1838. //
  1839. DBG_ASSERT( _pCertificateContext == NULL );
  1840. _pCertificateContext = new CERTIFICATE_CONTEXT( pClientCertInfo );
  1841. if ( _pCertificateContext == NULL )
  1842. {
  1843. return HRESULT_FROM_WIN32( GetLastError() );
  1844. }
  1845. return NO_ERROR;
  1846. }
  1847. VOID
  1848. W3_MAIN_CONTEXT::SetRawConnection(
  1849. RAW_CONNECTION * pRawConnection
  1850. )
  1851. /*++
  1852. Routine Description:
  1853. Set a raw connection for this context. This raw connection is stored so
  1854. that we can disassociate ourselves with it when the state machine is
  1855. complete
  1856. Arguments:
  1857. pRawConnection - Raw connection
  1858. Return Value:
  1859. None
  1860. --*/
  1861. {
  1862. _pRawConnection = pRawConnection;
  1863. }
  1864. VOID
  1865. W3_MAIN_CONTEXT::SetRawConnectionClientContext(
  1866. DWORD dwCurrentFilter,
  1867. VOID * pvContext
  1868. )
  1869. /*++
  1870. Routine Description:
  1871. Sets a filter's client context in the raw connection for this
  1872. context, if it exists. This is necessary so that an
  1873. SF_NOTIFY_READ_RAW_DATA event for a new request over this
  1874. connection will see the client context set by a previous
  1875. request.
  1876. Arguments:
  1877. dwCurrentFilter - The current filter
  1878. pvContext - The client's context
  1879. Return Value:
  1880. None
  1881. --*/
  1882. {
  1883. if ( _pRawConnection )
  1884. {
  1885. _pRawConnection->SetLocalClientContext( dwCurrentFilter,
  1886. pvContext );
  1887. }
  1888. }
  1889. BOOL
  1890. W3_MAIN_CONTEXT::QueryRawConnectionNotificationChanged(
  1891. VOID
  1892. )
  1893. {
  1894. BOOL fRet = FALSE;
  1895. if ( _pRawConnection )
  1896. {
  1897. fRet = _pRawConnection->QueryRawConnectionNotificationChanged();
  1898. }
  1899. return fRet;
  1900. }
  1901. BOOL
  1902. W3_MAIN_CONTEXT::IsRawConnectionDisableNotificationNeeded(
  1903. DWORD dwFilter,
  1904. DWORD dwNotification
  1905. )
  1906. {
  1907. BOOL fRet = FALSE;
  1908. if ( _pRawConnection )
  1909. {
  1910. fRet = _pRawConnection->IsRawConnectionDisableNotificationNeeded( dwFilter,
  1911. dwNotification );
  1912. }
  1913. return fRet;
  1914. }
  1915. CONTEXT_STATUS
  1916. W3_STATE_DONE::DoWork(
  1917. W3_MAIN_CONTEXT * pMainContext,
  1918. DWORD cbCompletion,
  1919. DWORD dwCompletionStatus
  1920. )
  1921. /*++
  1922. Routine Description:
  1923. Do the done state stuff
  1924. Arguments:
  1925. pMainContext - W3_MAIN_CONTEXT representing an execution of the state machine
  1926. cbCompletion - Number of bytes on completion
  1927. dwCompletionStatus - Win32 Error on completion (if any)
  1928. Return Value:
  1929. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  1930. else stop executing the machine and free up the current thread
  1931. --*/
  1932. {
  1933. W3_TRACE_LOG * pTraceLog = pMainContext->QueryTraceLog();
  1934. W3_REQUEST *pRequest = pMainContext->QueryRequest();
  1935. HTTP_REQUEST_ID RequestId = pRequest->QueryRequestId();
  1936. DWORD cbSent = pMainContext->QueryLogContext()->m_dwBytesSent;
  1937. if ( pTraceLog != NULL )
  1938. {
  1939. pTraceLog->Trace( L"%I64x: Finished request\n",
  1940. RequestId );
  1941. }
  1942. if ( ETW_IS_TRACE_ON(ETW_LEVEL_CP) )
  1943. {
  1944. //
  1945. // Trace END of request
  1946. //
  1947. g_pEtwTracer->EtwTraceEvent(&IISEventGuid, ETW_TYPE_END,
  1948. &RequestId, sizeof(HTTP_REQUEST_ID),
  1949. &cbSent, sizeof(DWORD),
  1950. NULL, 0);
  1951. }
  1952. return CONTEXT_STATUS_CONTINUE;
  1953. }
  1954. CONTEXT_STATUS
  1955. W3_STATE_DONE::OnCompletion(
  1956. W3_MAIN_CONTEXT * pMainContext,
  1957. DWORD cbCompletion,
  1958. DWORD dwCompletionStatus
  1959. )
  1960. /*++
  1961. Routine Description:
  1962. Complete the done state
  1963. Arguments:
  1964. pMainContext - W3_MAIN_CONTEXT representing an execution of the state machine
  1965. cbCompletion - Number of bytes on completion
  1966. dwCompletionStatus - Win32 Error on completion (if any)
  1967. Return Value:
  1968. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  1969. else stop executing the machine and free up the current thread
  1970. --*/
  1971. {
  1972. DBG_ASSERT( pMainContext != NULL );
  1973. //
  1974. // We could only get to here, if a send raw notification caused us to
  1975. // pend the done state until the connection goes away, or the current
  1976. // context is disassociated with the connection
  1977. //
  1978. DBG_ASSERT( pMainContext->IsNotificationNeeded( SF_NOTIFY_SEND_RAW_DATA ) );
  1979. return CONTEXT_STATUS_CONTINUE;
  1980. }
  1981. //static
  1982. VOID
  1983. W3_MAIN_CONTEXT::OnNewRequest(
  1984. ULATQ_CONTEXT ulatqContext
  1985. )
  1986. /*++
  1987. Routine Description:
  1988. Completion routine called when a new request is dequeued to be handled
  1989. Arguments:
  1990. ulatqContext - ULATQ_CONTEXT representing the request
  1991. Return Value:
  1992. None
  1993. --*/
  1994. {
  1995. HTTP_REQUEST * pUlHttpRequest = NULL;
  1996. W3_CONNECTION * pConnection = NULL;
  1997. W3_MAIN_CONTEXT * pMainContext = NULL;
  1998. HRESULT hr = NO_ERROR;
  1999. //
  2000. // Get the HTTP_REQUEST for this new request
  2001. //
  2002. pUlHttpRequest = (HTTP_REQUEST *)UlAtqGetContextProperty(
  2003. ulatqContext,
  2004. ULATQ_PROPERTY_HTTP_REQUEST );
  2005. DBG_ASSERT( pUlHttpRequest != NULL );
  2006. //
  2007. // Setup the MAIN_CONTEXT for this new request
  2008. //
  2009. pMainContext = new (ulatqContext) W3_MAIN_CONTEXT( pUlHttpRequest,
  2010. ulatqContext );
  2011. if (NULL == pMainContext)
  2012. {
  2013. UlAtqFreeContext( ulatqContext );
  2014. return;
  2015. }
  2016. pMainContext->_LogContext.m_dwBytesRecvd = pUlHttpRequest->BytesReceived;
  2017. if ( ETW_IS_TRACE_ON(ETW_LEVEL_CP) )
  2018. {
  2019. g_pEtwTracer->EtwTraceEvent( &IISEventGuid,
  2020. ETW_TYPE_START,
  2021. &pUlHttpRequest->RequestId,
  2022. sizeof( HTTP_REQUEST_ID ),
  2023. NULL,
  2024. 0 );
  2025. }
  2026. //
  2027. // Start the state machine
  2028. //
  2029. pMainContext->DoWork( 0,
  2030. 0,
  2031. FALSE );
  2032. }
  2033. //static
  2034. VOID
  2035. W3_MAIN_CONTEXT::PostMainCompletion(
  2036. CHAR * pszFileName,
  2037. DWORD dwLineNumber,
  2038. W3_MAIN_CONTEXT * pMainContext
  2039. )
  2040. /*++
  2041. Routine Description:
  2042. Post to the thread pool to continue the state machine. Before doing so,
  2043. record the filename and linenumber of the poster so that it makes it
  2044. easier to identify who posted, in the case of state machine breaks
  2045. (heaven forbid)
  2046. Arguments:
  2047. pszFileName - Name of source file doing the post
  2048. dwLineNumber - Line number of the post
  2049. pMainContext - Main context to post
  2050. Return Value:
  2051. None
  2052. --*/
  2053. {
  2054. BOOL fRet;
  2055. DBG_ASSERT( pszFileName != NULL );
  2056. DBG_ASSERT( dwLineNumber != 0 );
  2057. DBG_ASSERT( pMainContext != NULL );
  2058. DBG_ASSERT( pMainContext->CheckSignature() );
  2059. pMainContext->_pszLastPostFileName = pszFileName;
  2060. pMainContext->_dwLastPostLineNumber = dwLineNumber;
  2061. fRet = ThreadPoolPostCompletion( 0,
  2062. W3_MAIN_CONTEXT::OnPostedCompletion,
  2063. (OVERLAPPED*) pMainContext );
  2064. DBG_ASSERT( fRet );
  2065. }
  2066. //static
  2067. VOID
  2068. W3_MAIN_CONTEXT::OnPostedCompletion(
  2069. DWORD dwCompletionStatus,
  2070. DWORD cbTransferred,
  2071. LPOVERLAPPED lpo
  2072. )
  2073. /*++
  2074. Routine Description:
  2075. Fake completion routine called when we want to fake a completion for
  2076. asynchronous sanity sake
  2077. Arguments:
  2078. dwCompletionStatus - Error (if any) on the completion
  2079. cbTransferred - Bytes Written
  2080. lpo - Overlapped
  2081. Return Value:
  2082. None
  2083. --*/
  2084. {
  2085. W3_MAIN_CONTEXT * pMainContext;
  2086. pMainContext = (W3_MAIN_CONTEXT *)lpo;
  2087. DBG_ASSERT( pMainContext != NULL );
  2088. //
  2089. // Continue the state machine
  2090. //
  2091. pMainContext->DoWork( cbTransferred,
  2092. dwCompletionStatus,
  2093. TRUE );
  2094. }
  2095. //static
  2096. VOID
  2097. W3_MAIN_CONTEXT::OnIoCompletion(
  2098. PVOID pvContext,
  2099. DWORD cbTransferred,
  2100. DWORD dwCompletionStatus,
  2101. OVERLAPPED * lpo
  2102. )
  2103. /*++
  2104. Routine Description:
  2105. Completion routine called on async IO completions for a given request
  2106. Arguments:
  2107. pvContext - Completion context (a UL_REQUEST*)
  2108. cbTransferred - Bytes on the completion
  2109. dwCompletionStatus - Error (if any) on the completion
  2110. lpo - Overlapped
  2111. Return Value:
  2112. None
  2113. --*/
  2114. {
  2115. W3_MAIN_CONTEXT * pMainContext;
  2116. HRESULT hr;
  2117. pMainContext = (W3_MAIN_CONTEXT*) pvContext;
  2118. DBG_ASSERT( pMainContext != NULL );
  2119. DBG_ASSERT( pMainContext->CheckSignature() );
  2120. //
  2121. // First give the response a chance to handle the completion
  2122. //
  2123. hr = pMainContext->QueryResponse()->OnIoCompletion(
  2124. pMainContext->QueryCurrentContext(),
  2125. cbTransferred,
  2126. dwCompletionStatus );
  2127. if ( hr == NO_ERROR )
  2128. {
  2129. return;
  2130. }
  2131. //
  2132. // A failure from W3_RESPONSE__OnIoCompletion means the response wanted
  2133. // nothing to do with this completion, so we can funnel it to the
  2134. // state machine
  2135. //
  2136. //
  2137. // Continue the state machine
  2138. //
  2139. pMainContext->DoWork( cbTransferred,
  2140. dwCompletionStatus,
  2141. TRUE );
  2142. }
  2143. //static
  2144. VOID
  2145. W3_MAIN_CONTEXT::AddressResolutionCallback(
  2146. ADDRCHECKARG pContext,
  2147. BOOL fUnused,
  2148. LPSTR pszUnused
  2149. )
  2150. /*++
  2151. Routine Description:
  2152. Callback called when RDNS crud has done its resolution
  2153. Arguments:
  2154. pContext - Context (in our case, pointer to W3_MAIN_CONTEXT so that
  2155. we can resume state machine)
  2156. fUnused - Not used
  2157. pszUnused - Not used
  2158. Return Value:
  2159. None
  2160. --*/
  2161. {
  2162. W3_MAIN_CONTEXT * pMainContext;
  2163. pMainContext = (W3_MAIN_CONTEXT*) pContext;
  2164. DBG_ASSERT( pMainContext != NULL );
  2165. DBG_ASSERT( pMainContext->CheckSignature() );
  2166. POST_MAIN_COMPLETION( pMainContext );
  2167. }
  2168. VOID
  2169. W3_MAIN_CONTEXT::TimerCallback(LPVOID pvParam,
  2170. BOOLEAN fReason)
  2171. /*++
  2172. Routine Description:
  2173. Callback called when W3_MAIN_CONTEXT has existed for too long
  2174. OutputDebugString to tell people why we are doing this
  2175. and DebugBreak if a debugger is attached.
  2176. If no debugger is attached, ignore the callback.
  2177. Arguments:
  2178. pvParam - pointer to W3_MAIN_CONTEXT that has exceeded its maximum lifetime
  2179. fReason - not used
  2180. Return Value:
  2181. void
  2182. --*/
  2183. {
  2184. W3_MAIN_CONTEXT* pThis = (W3_MAIN_CONTEXT*)pvParam;
  2185. if (IsDebuggerPresent())
  2186. {
  2187. OutputDebugString(L"****************\nIIS (w3core.dll) has called DebugBreak because\nHKLM\\System\\CurrentControlSet\\Services\\InetInfo\\Parameters\\RequestTimeoutBreak\nwas set.\nAnd a request has taken longer than the specified maximium time in milliseconds\n****************\n");
  2188. DebugBreak();
  2189. }
  2190. return;
  2191. }
  2192. BOOL
  2193. W3_MAIN_CONTEXT::QueryDisconnect()
  2194. {
  2195. if (QueryUrlContext() == NULL ||
  2196. QueryUrlContext()->QueryMetaData() == NULL ||
  2197. QueryUrlContext()->QueryMetaData()->QueryKeepAliveEnabled())
  2198. {
  2199. return _fDisconnect;
  2200. }
  2201. return TRUE;
  2202. }
  2203. //static
  2204. HRESULT
  2205. W3_MAIN_CONTEXT::SetupTraceLogging()
  2206. {
  2207. HRESULT hr = S_OK;
  2208. HKEY hKey = NULL;
  2209. LONG lRet = 0;
  2210. STACK_STRU(struFileName, MAX_PATH);
  2211. DWORD cbSize = MAX_PATH * sizeof( WCHAR );
  2212. DWORD dwType;
  2213. WCHAR buffer[sizeof("0123456789")] = {0};
  2214. lRet = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2215. REGISTRY_KEY_W3SVC_PARAMETERS_W,
  2216. 0,
  2217. KEY_READ,
  2218. &hKey); //RegOpenKeyEx
  2219. if ( ERROR_SUCCESS != lRet )
  2220. {
  2221. hr = HRESULT_FROM_WIN32(GetLastError());
  2222. goto exit;
  2223. }
  2224. lRet = RegQueryValueEx(hKey,
  2225. L"TraceFile",
  2226. NULL,
  2227. &dwType,
  2228. (LPBYTE)struFileName.QueryStr(),
  2229. &cbSize); //RegQueryValueEx
  2230. if (ERROR_SUCCESS != lRet ||
  2231. REG_SZ != dwType )
  2232. {
  2233. hr = HRESULT_FROM_WIN32(GetLastError());
  2234. goto exit;
  2235. }
  2236. struFileName.QueryStr()[ cbSize / sizeof( WCHAR ) - 1 ] = L'\0';
  2237. struFileName.SyncWithBuffer();
  2238. wsprintf( buffer, L"%lu", GetCurrentProcessId() );
  2239. hr = struFileName.Append(buffer);
  2240. if (FAILED(hr))
  2241. {
  2242. goto exit;
  2243. }
  2244. sm_hTraceFile = CreateFile(struFileName.QueryStr(),
  2245. GENERIC_WRITE,
  2246. FILE_SHARE_READ,
  2247. NULL,
  2248. OPEN_ALWAYS,
  2249. FILE_ATTRIBUTE_NORMAL,
  2250. NULL); // CreateFile
  2251. if (INVALID_HANDLE_VALUE == sm_hTraceFile)
  2252. {
  2253. hr = HRESULT_FROM_WIN32(GetLastError());
  2254. goto exit;
  2255. }
  2256. //
  2257. // Create TraceLog factory
  2258. //
  2259. hr = W3_TRACE_LOG_FACTORY::CreateTraceLogFactory(&sm_pLogFactory, sm_hTraceFile);
  2260. if (FAILED(hr))
  2261. {
  2262. goto exit;
  2263. }
  2264. exit:
  2265. if (FAILED(hr))
  2266. {
  2267. CleanupTraceLogging();
  2268. }
  2269. if (hKey)
  2270. {
  2271. RegCloseKey(hKey);
  2272. hKey = NULL;
  2273. }
  2274. return hr;
  2275. }
  2276. //static
  2277. VOID
  2278. W3_MAIN_CONTEXT::CleanupTraceLogging()
  2279. {
  2280. if ( sm_pLogFactory != NULL )
  2281. {
  2282. sm_pLogFactory->DestroyTraceLogFactory();
  2283. sm_pLogFactory = NULL;
  2284. }
  2285. if ( sm_hTraceFile != INVALID_HANDLE_VALUE )
  2286. {
  2287. CloseHandle(sm_hTraceFile);
  2288. sm_hTraceFile = INVALID_HANDLE_VALUE;
  2289. }
  2290. return;
  2291. }