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

2459 lines
55 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. LONG W3_MAIN_CONTEXT::sm_cOutstandingThreads = 0;
  27. DWORD W3_MAIN_CONTEXT::sm_dwTimeout = 0;
  28. VOID
  29. W3_MAIN_CONTEXT::DoWork(
  30. DWORD cbCompletion,
  31. DWORD dwCompletionStatus,
  32. BOOL fIoCompletion
  33. )
  34. /*++
  35. Routine Description:
  36. Drives the W3 state machine
  37. Arguments:
  38. cbCompletion - Number of bytes in an async completion
  39. dwCompletionStatus - Error status of a completion
  40. fIoCompletion - TRUE if this was an IO completion,
  41. FALSE if this was a new request completion
  42. Return Value:
  43. None
  44. --*/
  45. {
  46. CONTEXT_STATUS Status = CONTEXT_STATUS_CONTINUE;
  47. BOOL fLastState = FALSE;
  48. W3_CONTEXT * pCurrentContext = NULL;
  49. if (fIoCompletion)
  50. {
  51. if (QueryLastIOPending() == LOG_WRITE_IO)
  52. {
  53. _LogContext.m_dwBytesSent += cbCompletion;
  54. }
  55. else if (QueryLastIOPending() == LOG_READ_IO)
  56. {
  57. _LogContext.m_dwBytesRecvd += cbCompletion;
  58. if ( _cbRemainingEntityFromUL != INFINITE )
  59. {
  60. if ( _cbRemainingEntityFromUL >= cbCompletion )
  61. {
  62. _cbRemainingEntityFromUL -= cbCompletion;
  63. }
  64. else
  65. {
  66. _cbRemainingEntityFromUL = 0;
  67. }
  68. }
  69. }
  70. }
  71. //
  72. // Progress thru states until we are finished or a state operation
  73. // is performed asynchronously
  74. //
  75. while ( !fLastState )
  76. {
  77. W3_STATE * pState;
  78. //
  79. // Get the next function to call, and then call it
  80. //
  81. pState = sm_pStates[ _currentState ];
  82. DBG_ASSERT( pState != NULL );
  83. //
  84. // Manage the _nextState which indicates what the next state will be
  85. // if the DoWork() returns CONTEXT_STATUS_CONTINUE. Note that this
  86. // state can be overriden by W3_MAIN_CONTEXT::SetFinishedResponse
  87. //
  88. _nextState = _currentState + 1;
  89. //
  90. // If this is the last state, remember that so we can cleanup
  91. //
  92. if ( _currentState == CONTEXT_STATE_DONE )
  93. {
  94. fLastState = TRUE;
  95. }
  96. if ( !fIoCompletion )
  97. {
  98. Status = pState->DoWork( this,
  99. cbCompletion,
  100. dwCompletionStatus );
  101. }
  102. else
  103. {
  104. pCurrentContext = QueryCurrentContext();
  105. //
  106. // First try to complete handler contexts if any.
  107. //
  108. Status = pCurrentContext->ExecuteHandlerCompletion(
  109. cbCompletion,
  110. dwCompletionStatus );
  111. if ( Status == CONTEXT_STATUS_CONTINUE )
  112. {
  113. //
  114. // Excellent. All handlers for this context have
  115. // completed. Now we finally complete the original
  116. // state which originally started the async ball rolling
  117. //
  118. Status = pState->OnCompletion( this,
  119. cbCompletion,
  120. dwCompletionStatus );
  121. }
  122. //
  123. // Reset fIoCompletion so we can continue the state machine
  124. // after the completion function is done
  125. //
  126. fIoCompletion = FALSE;
  127. }
  128. //
  129. // An async operation was posted, bail immediately
  130. //
  131. if ( Status == CONTEXT_STATUS_PENDING )
  132. {
  133. return;
  134. }
  135. DBG_ASSERT( Status == CONTEXT_STATUS_CONTINUE );
  136. _currentState = _nextState;
  137. }
  138. //
  139. // If we get here, we must have executed the last state, so cleanup the
  140. // MAIN_CONTEXT
  141. //
  142. DBG_ASSERT( fLastState );
  143. //
  144. // If we have a raw connection, detach ourselves from it now
  145. //
  146. if ( _pRawConnection != NULL )
  147. {
  148. _pRawConnection->SetMainContext( NULL );
  149. }
  150. DereferenceMainContext();
  151. }
  152. VOID
  153. W3_MAIN_CONTEXT::BackupStateMachine(
  154. VOID
  155. )
  156. /*++
  157. Routine Description:
  158. Backup in state machine to the URL_INFO state. This should be used only
  159. by AUTH_COMPLETE filters
  160. Arguments:
  161. None
  162. Return Value:
  163. None
  164. --*/
  165. {
  166. URL_CONTEXT * pUrlContext;
  167. DBG_ASSERT( IsNotificationNeeded( SF_NOTIFY_AUTH_COMPLETE ) );
  168. //
  169. // Clear the URL context
  170. //
  171. pUrlContext = QueryUrlContext();
  172. DBG_ASSERT( pUrlContext != NULL );
  173. SetUrlContext( NULL );
  174. delete pUrlContext;
  175. //
  176. // Reset our access check state.
  177. //
  178. ResetAccessCheck();
  179. //
  180. // Back that state up
  181. //
  182. _nextState = CONTEXT_STATE_URLINFO;
  183. }
  184. // static
  185. HRESULT
  186. W3_MAIN_CONTEXT::SetupStateMachine(
  187. VOID
  188. )
  189. /*++
  190. Routine Description:
  191. Setup state machine
  192. Arguments:
  193. None
  194. Return Value:
  195. HRESULT
  196. --*/
  197. {
  198. HRESULT hr = NO_ERROR;
  199. W3_STATE * pState = NULL;
  200. USHORT cbContextSize = 0;
  201. DWORD cState = CONTEXT_STATE_START;
  202. //
  203. // First create all the states
  204. //
  205. //
  206. // Start State
  207. //
  208. pState = (W3_STATE*) new W3_STATE_START();
  209. if ( pState == NULL )
  210. {
  211. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  212. goto Failure;
  213. }
  214. else if ( FAILED( hr = pState->QueryResult() ) )
  215. {
  216. goto Failure;
  217. }
  218. sm_pStates[ cState ] = pState;
  219. cbContextSize += pState->QueryContextSize();
  220. //
  221. // provide space for 8 bit alignment
  222. //
  223. cbContextSize = (cbContextSize + 7) & ~7;
  224. cState++;
  225. //
  226. // URLINFO State
  227. //
  228. pState = (W3_STATE*) new W3_STATE_URLINFO();
  229. if ( pState == NULL )
  230. {
  231. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  232. goto Failure;
  233. }
  234. else if ( FAILED( hr = pState->QueryResult() ) )
  235. {
  236. goto Failure;
  237. }
  238. sm_pStates[ cState ] = pState;
  239. cbContextSize += pState->QueryContextSize();
  240. //
  241. // provide space for 8 bit alignment
  242. //
  243. cbContextSize = (cbContextSize + 7) & ~7;
  244. cState++;
  245. //
  246. // Authentication State
  247. //
  248. pState = (W3_STATE*) new W3_STATE_AUTHENTICATION();
  249. if ( pState == NULL )
  250. {
  251. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  252. goto Failure;
  253. }
  254. else if ( FAILED( hr = pState->QueryResult() ) )
  255. {
  256. goto Failure;
  257. }
  258. sm_pStates[ cState ] = pState;
  259. cbContextSize += pState->QueryContextSize();
  260. //
  261. // provide space for 8 bit alignment
  262. //
  263. cbContextSize = (cbContextSize + 7) & ~7;
  264. cState++;
  265. //
  266. // Authorization State
  267. //
  268. pState = (W3_STATE*) new W3_STATE_AUTHORIZATION();
  269. if ( pState == NULL )
  270. {
  271. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  272. goto Failure;
  273. }
  274. else if ( FAILED( hr = pState->QueryResult() ) )
  275. {
  276. goto Failure;
  277. }
  278. sm_pStates[ cState ] = pState;
  279. cbContextSize += pState->QueryContextSize();
  280. //
  281. // provide space for 8 bit alignment
  282. //
  283. cbContextSize = (cbContextSize + 7) & ~7;
  284. cState++;
  285. //
  286. // Handle Request State
  287. //
  288. pState = (W3_STATE*) new W3_STATE_HANDLE_REQUEST();
  289. if ( pState == NULL )
  290. {
  291. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  292. goto Failure;
  293. }
  294. else if ( FAILED( hr = pState->QueryResult() ) )
  295. {
  296. goto Failure;
  297. }
  298. sm_pStates[ cState ] = pState;
  299. cbContextSize += pState->QueryContextSize();
  300. //
  301. // provide space for 8 bit alignment
  302. //
  303. cbContextSize = (cbContextSize + 7) & ~7;
  304. cState++;
  305. //
  306. // Response State
  307. //
  308. pState = (W3_STATE*) new W3_STATE_RESPONSE();
  309. if ( pState == NULL )
  310. {
  311. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  312. goto Failure;
  313. }
  314. else if ( FAILED( hr = pState->QueryResult() ) )
  315. {
  316. goto Failure;
  317. }
  318. sm_pStates[ cState ] = pState;
  319. cbContextSize += pState->QueryContextSize();
  320. //
  321. // provide space for 8 bit alignment
  322. //
  323. cbContextSize = (cbContextSize + 7) & ~7;
  324. cState++;
  325. //
  326. // Log State
  327. //
  328. pState = (W3_STATE*) new W3_STATE_LOG();
  329. if ( pState == NULL )
  330. {
  331. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  332. goto Failure;
  333. }
  334. else if ( FAILED( hr = pState->QueryResult() ) )
  335. {
  336. goto Failure;
  337. }
  338. sm_pStates[ cState ] = pState;
  339. cbContextSize += pState->QueryContextSize();
  340. //
  341. // provide space for 8 bit alignment
  342. //
  343. cbContextSize = (cbContextSize + 7) & ~7;
  344. cState++;
  345. //
  346. // Done State
  347. //
  348. pState = (W3_STATE*) new W3_STATE_DONE();
  349. if ( pState == NULL )
  350. {
  351. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  352. goto Failure;
  353. }
  354. else if ( FAILED( hr = pState->QueryResult() ) )
  355. {
  356. goto Failure;
  357. }
  358. sm_pStates[ cState ] = pState;
  359. cbContextSize += pState->QueryContextSize();
  360. //
  361. // provide space for 8 bit alignment
  362. //
  363. cbContextSize = (cbContextSize + 7) & ~7;
  364. cState++;
  365. //
  366. // Keep track of total number of state bytes needed so that we can
  367. // initialize allocation cache properly
  368. //
  369. // throw in 8 more bytes, alignment may cause us to need it
  370. sm_cbInlineBytes = cbContextSize + 8;
  371. return NO_ERROR;
  372. Failure:
  373. for ( int i = 0; i < STATE_COUNT; i++ )
  374. {
  375. if ( sm_pStates[ i ] != NULL )
  376. {
  377. delete sm_pStates[ i ];
  378. sm_pStates[ i ] = NULL;
  379. }
  380. }
  381. return hr;
  382. }
  383. // static
  384. VOID
  385. W3_MAIN_CONTEXT::CleanupStateMachine(
  386. VOID
  387. )
  388. /*++
  389. Routine Description:
  390. Cleanup state machine
  391. Arguments:
  392. None
  393. Return Value:
  394. None
  395. --*/
  396. {
  397. for ( int i = CONTEXT_STATE_START;
  398. i < STATE_COUNT;
  399. i++ )
  400. {
  401. if ( sm_pStates[ i ] != NULL )
  402. {
  403. delete sm_pStates[ i ];
  404. sm_pStates[ i ] = NULL;
  405. }
  406. }
  407. }
  408. BOOL
  409. W3_MAIN_CONTEXT::SetupContext(
  410. HTTP_REQUEST * pUlHttpRequest,
  411. ULATQ_CONTEXT ulatqContext
  412. )
  413. /*++
  414. Routine Description:
  415. Sets up a MAIN_CONTEXT before executing the state machine for a new
  416. incoming request.
  417. Arguments:
  418. pUlHttpRequest - the HTTP_REQUEST from UL
  419. ulatqContext - used to send/receive data thru ULATQ
  420. Return Value:
  421. TRUE if successful, else FALSE
  422. --*/
  423. {
  424. memset( _rgStateContexts, 0, sizeof( _rgStateContexts ) );
  425. //
  426. // Should we generate a content-length header
  427. //
  428. if ( pUlHttpRequest->Verb == HttpVerbHEAD )
  429. {
  430. _fGenerateContentLength = TRUE;
  431. }
  432. //
  433. // Associate HTTP_REQUEST with W3_REQUEST wrapper
  434. //
  435. _request.SetHttpRequest( pUlHttpRequest );
  436. //
  437. // Associate context for async IO (if any)
  438. //
  439. _ulatqContext = ulatqContext;
  440. UlAtqSetContextProperty( _ulatqContext,
  441. ULATQ_PROPERTY_COMPLETION_CONTEXT,
  442. this );
  443. //
  444. // Setup the state machine
  445. //
  446. _currentState = CONTEXT_STATE_START;
  447. _nextState = CONTEXT_STATE_START;
  448. //
  449. // Setup current context to receive IO completions. Naturally on
  450. // startup, this context will be 'this'. But it can change depending
  451. // on whether child executes are called
  452. //
  453. _pCurrentContext = this;
  454. return TRUE;
  455. }
  456. W3_CONNECTION_STATE *
  457. W3_MAIN_CONTEXT::QueryConnectionState(
  458. VOID
  459. )
  460. /*++
  461. Routine Description:
  462. Get any context associated with this connection and this state.
  463. Arguments:
  464. None
  465. Return Value:
  466. A W3_CONNECTION_STATE * or NULL if there is no state
  467. --*/
  468. {
  469. //
  470. // Since we are just looking for any existing connection state, make
  471. // sure we don't create a connection object if none is already associated
  472. // (creating a connection object is expensive)
  473. //
  474. W3_CONNECTION * pConn = QueryConnection( FALSE );
  475. return pConn ? pConn->QueryConnectionState( _currentState ) : NULL;
  476. }
  477. VOID
  478. W3_MAIN_CONTEXT::SetConnectionState(
  479. W3_CONNECTION_STATE * pConnectionState
  480. )
  481. /*++
  482. Routine Description:
  483. Set any context to be associated with the connection and current state
  484. Arguments:
  485. pConnectionState - Context to associate
  486. Return Value:
  487. None
  488. --*/
  489. {
  490. if ( QueryConnection() )
  491. {
  492. QueryConnection()->SetConnectionState( _currentState,
  493. pConnectionState );
  494. }
  495. }
  496. W3_MAIN_CONTEXT::W3_MAIN_CONTEXT(
  497. HTTP_REQUEST * pUlHttpRequest,
  498. ULATQ_CONTEXT ulAtqContext
  499. )
  500. : W3_CONTEXT ( 0 ),
  501. _pSite ( NULL ),
  502. _pFilterContext ( NULL ),
  503. _fDisconnect ( FALSE ),
  504. _fNeedFinalDone ( FALSE ),
  505. _fAssociationChecked ( FALSE ),
  506. _pConnection ( NULL ),
  507. _pUrlContext ( NULL ),
  508. _pUserContext ( NULL ),
  509. _fProviderHandled ( FALSE ),
  510. _cbInlineOffset ( 0 ),
  511. _fDoneWithCompression ( FALSE ),
  512. _pCompressionContext ( NULL ),
  513. _fIsUlCacheable ( TRUE ),
  514. _pCertificateContext ( NULL ),
  515. _cbRemainingEntityFromUL ( 0 ),
  516. _fGenerateContentLength( FALSE ),
  517. _pRawConnection ( NULL ),
  518. _cRefs ( 1 ),
  519. _hTimer (NULL)
  520. {
  521. _LogContext.m_msStartTickCount = GetTickCount();
  522. SetupContext( pUlHttpRequest, ulAtqContext );
  523. _hTimer = NULL;
  524. if (sm_dwTimeout)
  525. {
  526. BOOL fRet;
  527. fRet = CreateTimerQueueTimer(&_hTimer,
  528. NULL,
  529. W3_MAIN_CONTEXT::TimerCallback,
  530. this,
  531. sm_dwTimeout,
  532. 0,
  533. WT_EXECUTEONLYONCE
  534. );
  535. DBG_ASSERT(fRet);
  536. }
  537. }
  538. W3_MAIN_CONTEXT::~W3_MAIN_CONTEXT()
  539. /*++
  540. Routine Description:
  541. Main context destructor
  542. Arguments:
  543. None
  544. Return Value:
  545. None
  546. --*/
  547. {
  548. //
  549. // Cleanup context state
  550. //
  551. for ( DWORD i = 0; i < STATE_COUNT; i++ )
  552. {
  553. if ( _rgStateContexts[ i ] != NULL )
  554. {
  555. ((W3_MAIN_CONTEXT_STATE*) _rgStateContexts[ i ])->Cleanup( this );
  556. _rgStateContexts[ i ] = NULL;
  557. }
  558. }
  559. //
  560. // Let our filter context go
  561. //
  562. if ( _pFilterContext != NULL )
  563. {
  564. _pFilterContext->SetMainContext( NULL );
  565. _pFilterContext->DereferenceFilterContext();
  566. _pFilterContext = NULL;
  567. }
  568. //
  569. // Let go of reference to associated connection
  570. //
  571. if ( _pConnection != NULL )
  572. {
  573. _pConnection->DereferenceConnection();
  574. _pConnection = NULL;
  575. }
  576. //
  577. // Cleanup URL-Context
  578. //
  579. if ( _pUrlContext != NULL )
  580. {
  581. delete _pUrlContext;
  582. _pUrlContext = NULL;
  583. }
  584. //
  585. // Release our user context
  586. //
  587. if ( _pUserContext != NULL )
  588. {
  589. // perf ctr
  590. if (_pUserContext->QueryAuthType() == MD_AUTH_ANONYMOUS)
  591. {
  592. _pSite->DecAnonUsers();
  593. }
  594. else
  595. {
  596. _pSite->DecNonAnonUsers();
  597. }
  598. _pUserContext->DereferenceUserContext();
  599. _pUserContext = NULL;
  600. }
  601. //
  602. // Release the compression context
  603. //
  604. if ( _pCompressionContext != NULL )
  605. {
  606. delete _pCompressionContext;
  607. _pCompressionContext = NULL;
  608. }
  609. //
  610. // Cleanup RDNS crud
  611. //
  612. _IpAddressCheck.UnbindAddr();
  613. //
  614. // Cleanup client certificate context
  615. //
  616. if ( _pCertificateContext != NULL )
  617. {
  618. delete _pCertificateContext;
  619. _pCertificateContext = NULL;
  620. }
  621. //
  622. // Release the raw connection now
  623. //
  624. if ( _pRawConnection != NULL )
  625. {
  626. _pRawConnection->DereferenceRawConnection();
  627. _pRawConnection = NULL;
  628. }
  629. //
  630. // Allow ULATQ to cleanup itself up and to read the next request
  631. //
  632. UlAtqFreeContext( _ulatqContext );
  633. _ulatqContext = NULL;
  634. //
  635. // Finally release the site
  636. //
  637. if ( _pSite )
  638. {
  639. _pSite->Release();
  640. _pSite = NULL;
  641. }
  642. if (_hTimer)
  643. {
  644. BOOL fRet;
  645. fRet = DeleteTimerQueueTimer(NULL,
  646. _hTimer,
  647. INVALID_HANDLE_VALUE);
  648. DBG_ASSERT(fRet);
  649. _hTimer = NULL;
  650. }
  651. }
  652. // static
  653. HRESULT
  654. W3_MAIN_CONTEXT::Initialize(
  655. VOID
  656. )
  657. /*++
  658. Routine Description:
  659. Global initialization routine for W3_MAIN_CONTEXTs
  660. Arguments:
  661. None
  662. Return Value:
  663. HRESULT
  664. --*/
  665. {
  666. ALLOC_CACHE_CONFIGURATION acConfig;
  667. HRESULT hr = NO_ERROR;
  668. //
  669. // Setup global state machine. We do this BEFORE we setup the
  670. // allocation cache because the state machine setup will tell how much
  671. // inline buffer space is needed for state
  672. //
  673. hr = SetupStateMachine();
  674. if ( FAILED( hr ) )
  675. {
  676. return hr;
  677. }
  678. //
  679. // Setup allocation lookaside
  680. //
  681. acConfig.nConcurrency = 1;
  682. acConfig.nThreshold = 100;
  683. acConfig.cbSize = sizeof( W3_MAIN_CONTEXT ) + sm_cbInlineBytes;
  684. DBG_ASSERT( sm_pachMainContexts == NULL );
  685. sm_pachMainContexts = new ALLOC_CACHE_HANDLER( "W3_MAIN_CONTEXT",
  686. &acConfig );
  687. if ( sm_pachMainContexts == NULL )
  688. {
  689. CleanupStateMachine();
  690. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  691. }
  692. sm_dwTimeout = ReadRegDword(HKEY_LOCAL_MACHINE,
  693. REGISTRY_KEY_INETINFO_PARAMETERS_W,
  694. L"RequestTimeoutBreak",
  695. 0);
  696. return NO_ERROR;
  697. }
  698. // static
  699. VOID
  700. W3_MAIN_CONTEXT::WaitForThreadDrain(
  701. VOID
  702. )
  703. /*++
  704. Routine Description:
  705. Wait for all threads doing W3CORE stuff to drain away
  706. Arguments:
  707. None
  708. Return Value:
  709. None
  710. --*/
  711. {
  712. while ( sm_cOutstandingThreads != 0 )
  713. {
  714. Sleep( 200 );
  715. }
  716. }
  717. // static
  718. VOID
  719. W3_MAIN_CONTEXT::Terminate(
  720. VOID
  721. )
  722. /*++
  723. Routine Description:
  724. Terminate MAIN_CONTEXT globals
  725. Arguments:
  726. None
  727. Return Value:
  728. None
  729. --*/
  730. {
  731. CleanupStateMachine();
  732. if ( sm_pachMainContexts != NULL )
  733. {
  734. delete sm_pachMainContexts;
  735. sm_pachMainContexts = NULL;
  736. }
  737. }
  738. W3_USER_CONTEXT *
  739. W3_MAIN_CONTEXT::QueryConnectionUserContext(
  740. VOID
  741. )
  742. /*++
  743. Routine Description:
  744. Get any user context associated with this connection
  745. Arguments:
  746. None
  747. Return Value:
  748. Pointer to W3_USER_CONTEXT (or NULL if no used associated)
  749. --*/
  750. {
  751. W3_CONNECTION * pConnection = NULL;
  752. pConnection = QueryConnection( FALSE );
  753. if ( pConnection != NULL )
  754. {
  755. return pConnection->QueryUserContext();
  756. }
  757. else
  758. {
  759. return NULL;
  760. }
  761. }
  762. VOID
  763. W3_MAIN_CONTEXT::SetConnectionUserContext(
  764. W3_USER_CONTEXT * pUserContext
  765. )
  766. /*++
  767. Routine Description:
  768. Associate user context with connection
  769. Arguments:
  770. pUserContext - User context to associate
  771. Return Value:
  772. None
  773. --*/
  774. {
  775. W3_CONNECTION * pConnection = NULL;
  776. pConnection = QueryConnection( TRUE );
  777. if ( pConnection != NULL )
  778. {
  779. pConnection->SetUserContext( pUserContext );
  780. }
  781. else
  782. {
  783. DBG_ASSERT( FALSE );
  784. }
  785. }
  786. HRESULT
  787. W3_MAIN_CONTEXT::ReceiveEntityBody(
  788. BOOL fAsync,
  789. VOID * pBuffer,
  790. DWORD cbBuffer,
  791. DWORD * pBytesReceived
  792. )
  793. /*++
  794. Routine Description:
  795. Receives entity data from the client
  796. Arguments:
  797. fAsync - TRUE if this is an async request
  798. pBuffer - The buffer to store the data
  799. cbBuffer - The size of the buffer
  800. pBytesReceived - Upon return, the amount of data copied
  801. into the buffer
  802. Return Value:
  803. HRESULT
  804. --*/
  805. {
  806. HRESULT hr = UlAtqReceiveEntityBody( QueryUlatqContext(),
  807. fAsync,
  808. 0,
  809. pBuffer,
  810. cbBuffer,
  811. pBytesReceived );
  812. //
  813. // Keep track of how much we're reading
  814. //
  815. if (!fAsync &&
  816. SUCCEEDED(hr))
  817. {
  818. if ( _cbRemainingEntityFromUL != INFINITE )
  819. {
  820. if ( _cbRemainingEntityFromUL >= *pBytesReceived )
  821. {
  822. _cbRemainingEntityFromUL -= *pBytesReceived;
  823. }
  824. else
  825. {
  826. _cbRemainingEntityFromUL = 0;
  827. }
  828. }
  829. }
  830. return hr;
  831. }
  832. W3_CONNECTION *
  833. W3_MAIN_CONTEXT::QueryConnection(
  834. BOOL fCreateIfNotFound
  835. )
  836. /*++
  837. Routine Description:
  838. Get the W3_CONNECTION object associated with this request
  839. Arguments:
  840. fCreateIfNotFound - If not found in hash table, create it
  841. Return Value:
  842. Pointer to W3_CONNECTION.
  843. --*/
  844. {
  845. HRESULT hr;
  846. if ( _pConnection == NULL )
  847. {
  848. //
  849. // Get the connection associated with this request
  850. //
  851. if ( !fCreateIfNotFound && _fAssociationChecked )
  852. {
  853. //
  854. // If we have already looked for the connection, and we're not
  855. // required to create one, then we can fast path
  856. //
  857. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  858. }
  859. else
  860. {
  861. hr = W3_CONNECTION::RetrieveConnection( _request.QueryConnectionId(),
  862. fCreateIfNotFound,
  863. &_pConnection );
  864. }
  865. if ( FAILED( hr ) )
  866. {
  867. if ( fCreateIfNotFound )
  868. {
  869. DBGPRINTF(( DBG_CONTEXT,
  870. "Error retrieving connection. hr = %x\n",
  871. hr ));
  872. }
  873. else
  874. {
  875. //
  876. // Not really an error. We were just querying the hash table
  877. // for an associated connection (but not creating one)
  878. //
  879. }
  880. }
  881. else
  882. {
  883. DBG_ASSERT( _pConnection != NULL );
  884. }
  885. //
  886. // Don't try to repeat connection lookup again
  887. //
  888. _fAssociationChecked = TRUE;
  889. }
  890. return _pConnection;
  891. }
  892. VOID *
  893. W3_MAIN_CONTEXT::ContextAlloc(
  894. UINT cbSize
  895. )
  896. /*++
  897. Routine Description:
  898. Allocate context space from inline buffer in MAIN_CONTEXT. This
  899. complicated mechanism allows for states to allocate small state
  900. without going to the heap.
  901. Arguments:
  902. cbSize - Size to allocate
  903. Return Value:
  904. Pointer to buffer
  905. --*/
  906. {
  907. BYTE *pOrigBuffer = (PBYTE) QueryInlineBuffer() + _cbInlineOffset;
  908. //
  909. // Make space for 8 byte alignment
  910. //
  911. VOID *pBuffer = (VOID *)(((DWORD_PTR)pOrigBuffer + 7) & ~7);
  912. _cbInlineOffset += DIFF((PBYTE)pBuffer - pOrigBuffer);
  913. if ( _cbInlineOffset + cbSize > sm_cbInlineBytes )
  914. {
  915. DBG_ASSERT( FALSE );
  916. return NULL;
  917. }
  918. _cbInlineOffset += cbSize;
  919. return pBuffer;
  920. }
  921. BOOL
  922. W3_MAIN_CONTEXT::NotifyFilters(
  923. DWORD dwNotification,
  924. PVOID pvFilterInfo,
  925. BOOL * pfFinished
  926. )
  927. /*++
  928. Routine Description:
  929. Notify all applicable filters for a given notification. This is a
  930. wrapper of the W3_FILTER_CONTEXT call to actually do the work. The
  931. notifications made in this routine are those which would occur during
  932. the worker process state machine. (excludes end_of_net_session and
  933. raw data notifications)
  934. Arguments:
  935. dwNotification - Notification in question
  936. pvFilterInfo - Points to any info object passed to filter
  937. pfFinished - Set to TRUE if the filter decided to complete work
  938. Return Value:
  939. BOOL
  940. --*/
  941. {
  942. BOOL fRet = FALSE;
  943. BOOL fSynchronized = FALSE;
  944. DBG_ASSERT( _pFilterContext != NULL );
  945. _pFilterContext->FilterLock();
  946. switch( dwNotification )
  947. {
  948. case SF_NOTIFY_PREPROC_HEADERS:
  949. fRet = _pFilterContext->NotifyPreProcHeaderFilters( pfFinished );
  950. break;
  951. case SF_NOTIFY_URL_MAP:
  952. fRet = _pFilterContext->NotifyUrlMap( (HTTP_FILTER_URL_MAP*) pvFilterInfo,
  953. pfFinished );
  954. break;
  955. case SF_NOTIFY_AUTHENTICATION:
  956. fRet = _pFilterContext->NotifyAuthentication( (HTTP_FILTER_AUTHENT*) pvFilterInfo,
  957. pfFinished );
  958. break;
  959. case SF_NOTIFY_AUTH_COMPLETE:
  960. fRet = _pFilterContext->NotifyAuthComplete(
  961. ( HTTP_FILTER_AUTH_COMPLETE_INFO * )pvFilterInfo,
  962. pfFinished );
  963. break;
  964. case SF_NOTIFY_SEND_RESPONSE:
  965. fRet = _pFilterContext->NotifySendResponseFilters(
  966. (HTTP_FILTER_SEND_RESPONSE*) pvFilterInfo,
  967. pfFinished );
  968. break;
  969. case SF_NOTIFY_END_OF_REQUEST:
  970. fRet = _pFilterContext->NotifyEndOfRequest();
  971. break;
  972. case SF_NOTIFY_LOG:
  973. fRet = _pFilterContext->NotifyLogFilters((HTTP_FILTER_LOG *)pvFilterInfo);
  974. break;
  975. case SF_NOTIFY_SEND_RAW_DATA:
  976. fRet = _pFilterContext->NotifySendRawFilters(
  977. (HTTP_FILTER_RAW_DATA*) pvFilterInfo,
  978. pfFinished );
  979. break;
  980. default:
  981. DBG_ASSERT( FALSE );
  982. fRet = FALSE;
  983. }
  984. _pFilterContext->FilterUnlock();
  985. return fRet;
  986. }
  987. W3_FILTER_CONTEXT *
  988. W3_MAIN_CONTEXT::QueryFilterContext(
  989. BOOL fCreateIfNotFound
  990. )
  991. /*++
  992. Routine Description:
  993. Get a filter context to associate with the MAIN_CONTEXT and to also (
  994. AAAAAAAARRRRRRRGGGGGGGHHHHHH) associate with the connection on the
  995. W3_CONTXT
  996. Arguments:
  997. fCreateIfNotFound - Should we create a context if it doesn't already exist
  998. Return Value:
  999. Pointer to a new W3_FILTER_CONTEXT
  1000. --*/
  1001. {
  1002. BOOL fSecure;
  1003. if ( _pFilterContext == NULL &&
  1004. fCreateIfNotFound )
  1005. {
  1006. fSecure = QueryRequest()->IsSecureRequest();
  1007. DBG_ASSERT( _pSite != NULL );
  1008. _pFilterContext = new W3_FILTER_CONTEXT( fSecure,
  1009. _pSite->QueryFilterList() );
  1010. if ( _pFilterContext != NULL )
  1011. {
  1012. _pFilterContext->SetMainContext( this );
  1013. }
  1014. else
  1015. {
  1016. DBG_ASSERT( FALSE );
  1017. }
  1018. }
  1019. return _pFilterContext;
  1020. }
  1021. BOOL
  1022. W3_MAIN_CONTEXT::IsNotificationNeeded(
  1023. DWORD dwNotification
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. Is a specific filter notification applicable for this request
  1028. Arguments:
  1029. dwNotification - Notification in question
  1030. Return Value:
  1031. BOOL
  1032. --*/
  1033. {
  1034. BOOL fNeeded = FALSE;
  1035. FILTER_LIST * pFilterList = NULL;
  1036. W3_FILTER_CONTEXT * pW3Context = NULL;
  1037. if ( _pSite != NULL )
  1038. {
  1039. //
  1040. // To avoid creating connection contexts, do the simple fast check
  1041. // to determine whether the given contexts site supports the
  1042. // notification. If it does, then we have to do the more robust
  1043. // check to determine whether this specific request requires the
  1044. // notification (there is a difference because a filter can
  1045. // disable itself on the fly for any given request)
  1046. //
  1047. pFilterList = _pSite->QueryFilterList();
  1048. DBG_ASSERT( pFilterList != NULL );
  1049. if ( pFilterList->IsNotificationNeeded( dwNotification,
  1050. QueryRequest()->IsSecureRequest() ) )
  1051. {
  1052. pW3Context = QueryFilterContext();
  1053. if ( pW3Context != NULL )
  1054. {
  1055. fNeeded = pW3Context->IsNotificationNeeded( dwNotification );
  1056. }
  1057. }
  1058. }
  1059. return fNeeded;
  1060. }
  1061. BOOL
  1062. W3_MAIN_CONTEXT::QueryExpiry(
  1063. LARGE_INTEGER * pExpiry
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. Queries the expiration date/time for logon user
  1068. Arguments:
  1069. pExpiry - ptr to buffer to update with expiration date
  1070. Return Value:
  1071. TRUE if successful, FALSE if not available
  1072. --*/
  1073. {
  1074. SECURITY_STATUS ss;
  1075. SecPkgContext_PasswordExpiry speExpiry;
  1076. SSPI_SECURITY_CONTEXT * pSecurityContext;
  1077. W3_USER_CONTEXT * pW3UserContext;
  1078. LARGE_INTEGER * pUserAcctExpiry = NULL;
  1079. pUserAcctExpiry = _pUserContext->QueryExpiry();
  1080. if ( pUserAcctExpiry == NULL )
  1081. {
  1082. ((LARGE_INTEGER*)pExpiry)->HighPart = 0x7fffffff;
  1083. ((LARGE_INTEGER*)pExpiry)->LowPart = 0xffffffff;
  1084. return FALSE;
  1085. }
  1086. else
  1087. {
  1088. memcpy( pExpiry,
  1089. pUserAcctExpiry,
  1090. sizeof( LARGE_INTEGER ) );
  1091. }
  1092. return TRUE;
  1093. }
  1094. HRESULT
  1095. W3_MAIN_CONTEXT::ExecuteExpiredUrl(
  1096. STRU & strExpUrl
  1097. )
  1098. /*++
  1099. Routine Description:
  1100. Do child execution on the server configed expire url
  1101. Arguments:
  1102. strExpUrl - The configed expire url to be executed
  1103. Return Value:
  1104. HRESULT
  1105. --*/
  1106. {
  1107. HRESULT hr;
  1108. AUTH_PROVIDER * pAnonymousProvider = NULL;
  1109. STRA strNewHeader;
  1110. STRA strNewValue;
  1111. pAnonymousProvider = W3_STATE_AUTHENTICATION::QueryAnonymousProvider();
  1112. DBG_ASSERT( pAnonymousProvider != NULL );
  1113. hr = pAnonymousProvider->DoAuthenticate( this );
  1114. if( FAILED( hr ) )
  1115. {
  1116. return hr;
  1117. }
  1118. //
  1119. // Execute a child request
  1120. //
  1121. QueryResponse()->Clear();
  1122. QueryResponse()->SetStatus( HttpStatusOk );
  1123. //
  1124. // Reset the new url to be executed
  1125. //
  1126. hr = QueryRequest()->SetUrl( strExpUrl );
  1127. if( FAILED( hr ) )
  1128. {
  1129. return hr;
  1130. }
  1131. //
  1132. // Add CFG_ENC_CAPS header and set its value to 1 to indicate
  1133. // the site support SSL, to 0 if not.
  1134. //
  1135. strNewHeader.Copy( "CFG-ENC-CAPS" );
  1136. if( QuerySite()->QuerySSLSupported() )
  1137. {
  1138. strNewValue.Copy( "1" );
  1139. }
  1140. else
  1141. {
  1142. strNewValue.Copy( "0" );
  1143. }
  1144. hr = QueryRequest()->SetHeader( strNewHeader,
  1145. strNewValue,
  1146. TRUE );
  1147. if( FAILED( hr ) )
  1148. {
  1149. return hr;
  1150. }
  1151. //
  1152. // Set the auth access check flag to FALSE so the
  1153. // child execution won't do auth access check
  1154. //
  1155. SetAuthAccessCheckRequired( FALSE );
  1156. //
  1157. // Set finished response for parent
  1158. //
  1159. SetFinishedResponse();
  1160. //
  1161. // Execute child request
  1162. //
  1163. hr = ExecuteChildRequest( QueryRequest(),
  1164. FALSE,
  1165. W3_FLAG_ASYNC );
  1166. return hr;
  1167. }
  1168. HRESULT
  1169. W3_MAIN_CONTEXT::PasswdExpireNotify(
  1170. VOID
  1171. )
  1172. /*++
  1173. Routine Description:
  1174. Check if the user password has been expired
  1175. Arguments:
  1176. None
  1177. Return Value:
  1178. HRESULT
  1179. --*/
  1180. {
  1181. HRESULT hr = S_FALSE;
  1182. LARGE_INTEGER cExpire;
  1183. FILETIME ftNow;
  1184. DWORD dwExpireInDay;
  1185. DWORD dwTotalRequired;
  1186. STACK_STRU ( strExpUrl, MAX_PATH );
  1187. STACK_STRU ( strFullUrl, MAX_PATH );
  1188. STRU * pstrAdvNotPwdExpUrl;
  1189. BYTE byTokenInfo[ SID_DEFAULT_SIZE + sizeof( TOKEN_USER ) ];
  1190. PSID pSid;
  1191. if ( QueryExpiry( &cExpire ) )
  1192. {
  1193. if ( cExpire.HighPart == 0x7fffffff )
  1194. {
  1195. //
  1196. // Password never expire
  1197. //
  1198. return hr;
  1199. }
  1200. else
  1201. {
  1202. GetSystemTimeAsFileTime( &ftNow );
  1203. if ( *( __int64 * )&cExpire > *( __int64 * )&ftNow )
  1204. {
  1205. dwExpireInDay = ( DWORD )( ( * ( __int64 * )&cExpire
  1206. - *( __int64 * )&ftNow )
  1207. / ( ( __int64 )10000000 * 86400 ) );
  1208. if ( QuerySite()->QueryAdvNotPwdExpInDays() &&
  1209. dwExpireInDay <= QuerySite()->QueryAdvNotPwdExpInDays() )
  1210. {
  1211. pstrAdvNotPwdExpUrl = QuerySite()->QueryAdvNotPwdExpUrl();
  1212. if( pstrAdvNotPwdExpUrl == NULL )
  1213. {
  1214. //
  1215. // Advanced password expire notification disabled
  1216. //
  1217. return hr;
  1218. }
  1219. //
  1220. // Check this SID has not already been notified
  1221. // of pwd expiration
  1222. //
  1223. if ( GetTokenInformation(
  1224. QueryUserContext()->QueryPrimaryToken(),
  1225. TokenUser,
  1226. ( LPVOID )byTokenInfo,
  1227. sizeof( byTokenInfo ),
  1228. &dwTotalRequired ) )
  1229. {
  1230. pSid = ( ( TOKEN_USER * )byTokenInfo )->User.Sid;
  1231. if( !PenCheckPresentAndResetTtl(
  1232. pSid,
  1233. QuerySite()->QueryAdvCacheTTL() ) )
  1234. {
  1235. PenAddToCache(
  1236. pSid,
  1237. QuerySite()->QueryAdvCacheTTL() );
  1238. //
  1239. // flush cache when connection close
  1240. // so that account change will not be masked
  1241. // by cached information
  1242. //
  1243. if( QueryUserContext()->QueryAuthType() ==
  1244. MD_AUTH_BASIC )
  1245. {
  1246. g_pW3Server->QueryTokenCache()->FlushCacheEntry(
  1247. ( ( BASIC_USER_CONTEXT * )QueryUserContext() )
  1248. ->QueryCachedToken()->QueryCacheKey() );
  1249. }
  1250. hr = strExpUrl.Copy( pstrAdvNotPwdExpUrl->
  1251. QueryStr() );
  1252. if( FAILED( hr ) )
  1253. {
  1254. return hr;
  1255. }
  1256. if ( strExpUrl.QueryStr()[0] == NULL )
  1257. {
  1258. return E_FAIL;
  1259. }
  1260. //
  1261. // Add the arg to be passed to the
  1262. // password-change URL - argument is the
  1263. // URL the user is pointed to after all
  1264. // the password-change processing is done
  1265. //
  1266. hr = strExpUrl.Append( L"?" );
  1267. if( FAILED( hr ) )
  1268. {
  1269. return hr;
  1270. }
  1271. hr = QueryRequest()->GetOriginalFullUrl(
  1272. &strFullUrl );
  1273. if( FAILED( hr ) )
  1274. {
  1275. return hr;
  1276. }
  1277. hr = strExpUrl.Append( strFullUrl );
  1278. if( FAILED( hr ) )
  1279. {
  1280. return hr;
  1281. }
  1282. return ExecuteExpiredUrl( strExpUrl );
  1283. }
  1284. }
  1285. }
  1286. }
  1287. else
  1288. {
  1289. //
  1290. // flush cache when connection close
  1291. // since the password has expired
  1292. //
  1293. if( QueryUserContext()->QueryAuthType() == MD_AUTH_BASIC )
  1294. {
  1295. g_pW3Server->QueryTokenCache()->FlushCacheEntry(
  1296. ( ( BASIC_USER_CONTEXT * )QueryUserContext() )
  1297. ->QueryCachedToken()->QueryCacheKey() );
  1298. }
  1299. return PasswdChangeExecute();
  1300. }
  1301. }
  1302. }
  1303. return hr;
  1304. }
  1305. HRESULT
  1306. W3_MAIN_CONTEXT::PasswdChangeExecute(
  1307. VOID
  1308. )
  1309. /*++
  1310. Routine Description:
  1311. This method handles password expiration notification
  1312. Arguments:
  1313. None
  1314. Return Value:
  1315. HRESULT
  1316. --*/
  1317. {
  1318. HRESULT hr = S_FALSE;
  1319. STACK_STRU ( strExpUrl, MAX_PATH );
  1320. STACK_STRU ( strFullUrl, MAX_PATH );
  1321. STACK_STRU ( strUrl, MAX_PATH );
  1322. STRU * pstrAuthExpiredUrl;
  1323. pstrAuthExpiredUrl = QuerySite()->QueryAuthExpiredUrl();
  1324. if( pstrAuthExpiredUrl == NULL )
  1325. {
  1326. //
  1327. // S_FALSE means password change disabled
  1328. //
  1329. return hr;
  1330. }
  1331. hr = strExpUrl.Copy( pstrAuthExpiredUrl->QueryStr() );
  1332. if( FAILED( hr ) )
  1333. {
  1334. return hr;
  1335. }
  1336. if ( strExpUrl.QueryStr()[0] == NULL )
  1337. {
  1338. return E_FAIL;
  1339. }
  1340. hr = QueryRequest()->GetUrl( &strUrl );
  1341. if( FAILED( hr ) )
  1342. {
  1343. return hr;
  1344. }
  1345. //
  1346. // Add the arg to be passed to the password-change URL - argument
  1347. // is the URL the user is pointed to after all the password-change
  1348. // processing is done
  1349. //
  1350. hr = strExpUrl.Append( L"?" );
  1351. if ( FAILED( hr ) )
  1352. {
  1353. return hr;
  1354. }
  1355. hr = QueryRequest()->GetOriginalFullUrl( &strFullUrl );
  1356. if( FAILED( hr ) )
  1357. {
  1358. return hr;
  1359. }
  1360. hr = strExpUrl.Append( strFullUrl );
  1361. if( FAILED( hr ) )
  1362. {
  1363. return hr;
  1364. }
  1365. return ExecuteExpiredUrl( strExpUrl );
  1366. }
  1367. HRESULT
  1368. W3_MAIN_CONTEXT::GetRemoteDNSName(
  1369. STRA * pstrDNSName
  1370. )
  1371. /*++
  1372. Routine Description:
  1373. Get remote client's DNS name if it is resolved
  1374. Arguments:
  1375. pstrDNSName - Filled with DNS name on success
  1376. Return Value:
  1377. HRESULT
  1378. --*/
  1379. {
  1380. DBG_ASSERT( pstrDNSName != NULL );
  1381. if ( _IpAddressCheck.IsDnsResolved() )
  1382. {
  1383. return pstrDNSName->Copy( _IpAddressCheck.QueryResolvedDnsName() );
  1384. }
  1385. else
  1386. {
  1387. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  1388. }
  1389. }
  1390. CONTEXT_STATUS
  1391. W3_STATE_START::DoWork(
  1392. W3_MAIN_CONTEXT * pMainContext,
  1393. DWORD cbCompletion,
  1394. DWORD dwCompletionStatus
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. Initial start state handling
  1399. Arguments:
  1400. pMainContext - W3_MAIN_CONTEXT representing an execution of the state machine
  1401. cbCompletion - Number of bytes on completion
  1402. dwCompletionStatus - Win32 Error on completion (if any)
  1403. Return Value:
  1404. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  1405. else stop executing the machine and free up the current thread
  1406. --*/
  1407. {
  1408. W3_REQUEST * pRequest;
  1409. DWORD dwSiteId;
  1410. HRESULT hr;
  1411. W3_SITE * pSite;
  1412. BOOL fFinished = FALSE;
  1413. BOOL fNeedRawRead = FALSE;
  1414. RAW_CONNECTION * pRawConnection = NULL;
  1415. W3_FILTER_CONTEXT * pFilterContext = NULL;
  1416. //
  1417. // Get the request out of the context and the SiteId out of the request
  1418. //
  1419. pRequest = pMainContext->QueryRequest();
  1420. DBG_ASSERT( pRequest != NULL );
  1421. dwSiteId = pRequest->QuerySiteId();
  1422. //
  1423. // Check if this site already exists
  1424. //
  1425. pSite = g_pW3Server->FindSite( dwSiteId );
  1426. //
  1427. // Now we need to do some locking while adding this site
  1428. //
  1429. if ( pSite == NULL )
  1430. {
  1431. g_pW3Server->WriteLockSiteList();
  1432. //
  1433. // try again, avoid race condition
  1434. //
  1435. pSite = g_pW3Server->FindSite( dwSiteId );
  1436. if ( pSite == NULL )
  1437. {
  1438. //
  1439. // Need to create a new site!
  1440. //
  1441. pSite = new W3_SITE( dwSiteId );
  1442. if ( pSite == NULL )
  1443. {
  1444. hr = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1445. }
  1446. else
  1447. {
  1448. hr = pSite->Initialize();
  1449. }
  1450. if ( FAILED( hr ) )
  1451. {
  1452. if ( pSite != NULL )
  1453. {
  1454. pSite->Release();
  1455. pSite = NULL;
  1456. }
  1457. pMainContext->SetErrorStatus( hr );
  1458. pMainContext->SetFinishedResponse();
  1459. }
  1460. else
  1461. {
  1462. g_pW3Server->AddSite( pSite );
  1463. }
  1464. }
  1465. g_pW3Server->WriteUnlockSiteList();
  1466. }
  1467. if ( pSite == NULL )
  1468. {
  1469. return CONTEXT_STATUS_CONTINUE;
  1470. }
  1471. //
  1472. // If we found a site, associate it so that all future consumers can
  1473. // get at site configuration settings
  1474. //
  1475. pMainContext->AssociateSite( pSite );
  1476. //
  1477. // Let the raw data fun begin.
  1478. //
  1479. // If this request has gone thru the stream filter, then we'll need
  1480. // to associate the current W3_CONNECTION with a RAW_CONNECTION. Also,
  1481. // we'll have to retrieve a filter context
  1482. //
  1483. fNeedRawRead = FILTER_LIST::QueryGlobalList()->IsNotificationNeeded(
  1484. SF_NOTIFY_READ_RAW_DATA,
  1485. FALSE );
  1486. if ( pRequest->QueryRawConnectionId() != HTTP_NULL_ID &&
  1487. fNeedRawRead )
  1488. {
  1489. //
  1490. // Raw read filters should be loaded only in old mode
  1491. //
  1492. DBG_ASSERT( g_pW3Server->QueryInBackwardCompatibilityMode() );
  1493. //
  1494. // Find a raw connection for this request
  1495. //
  1496. hr = RAW_CONNECTION::FindConnection( pRequest->QueryRawConnectionId(),
  1497. &pRawConnection );
  1498. if ( FAILED( hr ) )
  1499. {
  1500. pMainContext->SetErrorStatus( hr );
  1501. pMainContext->SetFinishedResponse();
  1502. pMainContext->SetDisconnect( TRUE );
  1503. return CONTEXT_STATUS_CONTINUE;
  1504. }
  1505. DBG_ASSERT( pRawConnection != NULL );
  1506. //
  1507. // We will need to copy over context pointers and allocated memory
  1508. // from any existing read data filters
  1509. //
  1510. pFilterContext = pMainContext->QueryFilterContext();
  1511. if ( pFilterContext == NULL )
  1512. {
  1513. pMainContext->SetErrorStatus( hr );
  1514. pMainContext->SetFinishedResponse();
  1515. pMainContext->SetDisconnect( TRUE );
  1516. return CONTEXT_STATUS_CONTINUE;
  1517. }
  1518. pRawConnection->CopyContextPointers( pFilterContext );
  1519. pRawConnection->CopyAllocatedFilterMemory( pFilterContext );
  1520. hr = pRawConnection->CopyHeaders( pFilterContext );
  1521. if ( FAILED( hr ) )
  1522. {
  1523. pMainContext->SetErrorStatus( hr );
  1524. pMainContext->SetFinishedResponse();
  1525. pMainContext->SetDisconnect( TRUE );
  1526. return CONTEXT_STATUS_CONTINUE;
  1527. }
  1528. //
  1529. // Associate the raw connection with the main context
  1530. //
  1531. pRawConnection->SetMainContext( pMainContext );
  1532. pMainContext->SetRawConnection( pRawConnection );
  1533. }
  1534. //
  1535. // We can notify filters now that we have a site associated
  1536. //
  1537. if ( pMainContext->IsNotificationNeeded( SF_NOTIFY_PREPROC_HEADERS ) )
  1538. {
  1539. pMainContext->NotifyFilters( SF_NOTIFY_PREPROC_HEADERS,
  1540. NULL,
  1541. &fFinished );
  1542. if ( fFinished )
  1543. {
  1544. pMainContext->SetFinishedResponse();
  1545. }
  1546. }
  1547. //
  1548. // Determine the amount of bytes available to be read thru UL
  1549. //
  1550. pMainContext->DetermineRemainingEntity();
  1551. //
  1552. // Now that filters have been notified, we can increment the appropriate
  1553. // verb perf counter.
  1554. //
  1555. pSite->IncReqType( pRequest->QueryVerbType() );
  1556. return CONTEXT_STATUS_CONTINUE;
  1557. }
  1558. VOID *
  1559. W3_MAIN_CONTEXT_STATE::operator new(
  1560. size_t uiSize,
  1561. VOID * pPlacement
  1562. )
  1563. {
  1564. W3_MAIN_CONTEXT * pContext;
  1565. W3_MAIN_CONTEXT_STATE * pState;
  1566. PVOID pBuffer;
  1567. pContext = (W3_MAIN_CONTEXT*) pPlacement;
  1568. DBG_ASSERT( pContext != NULL );
  1569. DBG_ASSERT( pContext->CheckSignature() );
  1570. pBuffer = pContext->ContextAlloc( (UINT)uiSize );
  1571. DBG_ASSERT( pBuffer != NULL );
  1572. return pBuffer;
  1573. }
  1574. VOID
  1575. W3_MAIN_CONTEXT_STATE::operator delete(
  1576. VOID * pContext
  1577. )
  1578. {
  1579. //
  1580. // Do nothing here. Either
  1581. // a) memory was allocated from inline W3_MAIN_CONTEXT buffer and thus should
  1582. // not be freeed
  1583. // b) memory was allocated from heap because inline buffer didn't have
  1584. // enough space. In this case, the memory is freed on MAIN_CONTEXT
  1585. // cleanup
  1586. //
  1587. }
  1588. VOID
  1589. W3_MAIN_CONTEXT::DetermineRemainingEntity(
  1590. VOID
  1591. )
  1592. /*++
  1593. Routine Description:
  1594. Determine remaining entity body to be read from UL
  1595. Arguments:
  1596. None
  1597. Return Value:
  1598. None
  1599. --*/
  1600. {
  1601. CHAR * pszContentLength;
  1602. DWORD cbContentLength;
  1603. if ( _request.QueryMoreEntityBodyExists() )
  1604. {
  1605. pszContentLength = _request.GetHeader( HttpHeaderContentLength );
  1606. if ( pszContentLength != NULL )
  1607. {
  1608. cbContentLength = atoi( pszContentLength );
  1609. if ( _request.QueryAvailableBytes() <= cbContentLength )
  1610. {
  1611. _cbRemainingEntityFromUL = cbContentLength - _request.QueryAvailableBytes();
  1612. }
  1613. else
  1614. {
  1615. _cbRemainingEntityFromUL = 0;
  1616. }
  1617. }
  1618. else
  1619. {
  1620. _cbRemainingEntityFromUL = INFINITE;
  1621. }
  1622. }
  1623. else
  1624. {
  1625. _cbRemainingEntityFromUL = 0;
  1626. }
  1627. }
  1628. HRESULT
  1629. W3_MAIN_CONTEXT::SetupCertificateContext(
  1630. HTTP_SSL_CLIENT_CERT_INFO * pClientCertInfo
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. Create a CERTIFICATE_CONTEXT representing the given client certificate
  1635. Arguments:
  1636. pClientCertInfo - Client cert info from stream filter
  1637. Return Value:
  1638. HRESULT
  1639. --*/
  1640. {
  1641. if ( pClientCertInfo == NULL )
  1642. {
  1643. DBG_ASSERT( FALSE );
  1644. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  1645. }
  1646. //
  1647. // Just for completeness sake, attach the raw cert descriptor to the
  1648. // main request, as it automatically be for subsequent requests on this
  1649. // connection
  1650. //
  1651. QueryRequest()->SetClientCertInfo( pClientCertInfo );
  1652. //
  1653. // Create a client certificate descriptor and associate it with
  1654. //
  1655. DBG_ASSERT( _pCertificateContext == NULL );
  1656. _pCertificateContext = new CERTIFICATE_CONTEXT( pClientCertInfo );
  1657. if ( _pCertificateContext == NULL )
  1658. {
  1659. return HRESULT_FROM_WIN32( GetLastError() );
  1660. }
  1661. return NO_ERROR;
  1662. }
  1663. VOID
  1664. W3_MAIN_CONTEXT::SetRawConnection(
  1665. RAW_CONNECTION * pRawConnection
  1666. )
  1667. /*++
  1668. Routine Description:
  1669. Set a raw connection for this context. This raw connection is stored so
  1670. that we can disassociate ourselves with it when the state machine is
  1671. complete
  1672. Arguments:
  1673. pRawConnection - Raw connection
  1674. Return Value:
  1675. None
  1676. --*/
  1677. {
  1678. pRawConnection->ReferenceRawConnection();
  1679. _pRawConnection = pRawConnection;
  1680. }
  1681. CONTEXT_STATUS
  1682. W3_STATE_DONE::DoWork(
  1683. W3_MAIN_CONTEXT * pMainContext,
  1684. DWORD cbCompletion,
  1685. DWORD dwCompletionStatus
  1686. )
  1687. /*++
  1688. Routine Description:
  1689. Do the done state stuff
  1690. Arguments:
  1691. pMainContext - W3_MAIN_CONTEXT representing an execution of the state machine
  1692. cbCompletion - Number of bytes on completion
  1693. dwCompletionStatus - Win32 Error on completion (if any)
  1694. Return Value:
  1695. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  1696. else stop executing the machine and free up the current thread
  1697. --*/
  1698. {
  1699. return CONTEXT_STATUS_CONTINUE;
  1700. }
  1701. CONTEXT_STATUS
  1702. W3_STATE_DONE::OnCompletion(
  1703. W3_MAIN_CONTEXT * pMainContext,
  1704. DWORD cbCompletion,
  1705. DWORD dwCompletionStatus
  1706. )
  1707. /*++
  1708. Routine Description:
  1709. Complete the done state
  1710. Arguments:
  1711. pMainContext - W3_MAIN_CONTEXT representing an execution of the state machine
  1712. cbCompletion - Number of bytes on completion
  1713. dwCompletionStatus - Win32 Error on completion (if any)
  1714. Return Value:
  1715. CONTEXT_STATUS_CONTINUE - if we should continue in state machine
  1716. else stop executing the machine and free up the current thread
  1717. --*/
  1718. {
  1719. DBG_ASSERT( pMainContext != NULL );
  1720. //
  1721. // We could only get to here, if a send raw notification caused us to
  1722. // pend the done state until the connection goes away, or the current
  1723. // context is disassociated with the connection
  1724. //
  1725. DBG_ASSERT( pMainContext->IsNotificationNeeded( SF_NOTIFY_SEND_RAW_DATA ) );
  1726. return CONTEXT_STATUS_CONTINUE;
  1727. }
  1728. //static
  1729. VOID
  1730. W3_MAIN_CONTEXT::OnNewRequest(
  1731. ULATQ_CONTEXT ulatqContext
  1732. )
  1733. /*++
  1734. Routine Description:
  1735. Completion routine called when a new request is dequeued to be handled
  1736. Arguments:
  1737. ulatqContext - ULATQ_CONTEXT representing the request
  1738. Return Value:
  1739. None
  1740. --*/
  1741. {
  1742. HTTP_REQUEST * pUlHttpRequest = NULL;
  1743. W3_CONNECTION * pConnection = NULL;
  1744. W3_MAIN_CONTEXT * pMainContext = NULL;
  1745. HRESULT hr = NO_ERROR;
  1746. InterlockedIncrement( &sm_cOutstandingThreads );
  1747. //
  1748. // Get the HTTP_REQUEST for this new request
  1749. //
  1750. pUlHttpRequest = (HTTP_REQUEST *)UlAtqGetContextProperty(
  1751. ulatqContext,
  1752. ULATQ_PROPERTY_HTTP_REQUEST );
  1753. DBG_ASSERT( pUlHttpRequest != NULL );
  1754. //
  1755. // Setup the MAIN_CONTEXT for this new request
  1756. //
  1757. pMainContext = new W3_MAIN_CONTEXT( pUlHttpRequest,
  1758. ulatqContext );
  1759. if (NULL == pMainContext)
  1760. {
  1761. UlAtqFreeContext(ulatqContext);
  1762. goto done;
  1763. }
  1764. pMainContext->_LogContext.m_dwBytesRecvd = pUlHttpRequest->BytesReceived;
  1765. //
  1766. // Start the state machine
  1767. //
  1768. pMainContext->DoWork( 0,
  1769. 0,
  1770. FALSE );
  1771. done:
  1772. InterlockedDecrement( &sm_cOutstandingThreads );
  1773. }
  1774. //static
  1775. VOID
  1776. W3_MAIN_CONTEXT::OnPostedCompletion(
  1777. DWORD dwCompletionStatus,
  1778. DWORD cbTransferred,
  1779. LPOVERLAPPED lpo
  1780. )
  1781. /*++
  1782. Routine Description:
  1783. Fake completion routine called when we want to fake a completion for
  1784. asynchronous sanity sake
  1785. Arguments:
  1786. dwCompletionStatus - Error (if any) on the completion
  1787. cbTransferred - Bytes Written
  1788. lpo - Overlapped
  1789. Return Value:
  1790. None
  1791. --*/
  1792. {
  1793. W3_MAIN_CONTEXT * pMainContext;
  1794. InterlockedIncrement( &sm_cOutstandingThreads );
  1795. pMainContext = (W3_MAIN_CONTEXT *)lpo;
  1796. DBG_ASSERT( pMainContext != NULL );
  1797. //
  1798. // Continue the state machine
  1799. //
  1800. pMainContext->DoWork( cbTransferred,
  1801. dwCompletionStatus,
  1802. TRUE );
  1803. InterlockedDecrement( &sm_cOutstandingThreads );
  1804. }
  1805. //static
  1806. VOID
  1807. W3_MAIN_CONTEXT::OnIoCompletion(
  1808. PVOID pvContext,
  1809. DWORD cbTransferred,
  1810. DWORD dwCompletionStatus,
  1811. OVERLAPPED * lpo
  1812. )
  1813. /*++
  1814. Routine Description:
  1815. Completion routine called on async IO completions for a given request
  1816. Arguments:
  1817. pvContext - Completion context (a UL_REQUEST*)
  1818. cbTransferred - Bytes on the completion
  1819. dwCompletionStatus - Error (if any) on the completion
  1820. lpo - Overlapped
  1821. Return Value:
  1822. None
  1823. --*/
  1824. {
  1825. W3_MAIN_CONTEXT * pMainContext;
  1826. InterlockedIncrement( &sm_cOutstandingThreads );
  1827. pMainContext = (W3_MAIN_CONTEXT*) pvContext;
  1828. DBG_ASSERT( pMainContext != NULL );
  1829. DBG_ASSERT( pMainContext->CheckSignature() );
  1830. //
  1831. // Continue the state machine
  1832. //
  1833. pMainContext->DoWork( cbTransferred,
  1834. dwCompletionStatus,
  1835. TRUE );
  1836. InterlockedDecrement( &sm_cOutstandingThreads );
  1837. }
  1838. //static
  1839. VOID
  1840. W3_MAIN_CONTEXT::AddressResolutionCallback(
  1841. ADDRCHECKARG pContext,
  1842. BOOL fUnused,
  1843. LPSTR pszUnused
  1844. )
  1845. /*++
  1846. Routine Description:
  1847. Callback called when RDNS crud has done its resolution
  1848. Arguments:
  1849. pContext - Context (in our case, pointer to W3_MAIN_CONTEXT so that
  1850. we can resume state machine)
  1851. fUnused - Not used
  1852. pszUnused - Not used
  1853. Return Value:
  1854. None
  1855. --*/
  1856. {
  1857. W3_MAIN_CONTEXT * pMainContext;
  1858. pMainContext = (W3_MAIN_CONTEXT*) pContext;
  1859. DBG_ASSERT( pMainContext != NULL );
  1860. DBG_ASSERT( pMainContext->CheckSignature() );
  1861. ThreadPoolPostCompletion( 0,
  1862. W3_MAIN_CONTEXT::OnPostedCompletion,
  1863. (OVERLAPPED*) pMainContext );
  1864. }
  1865. VOID
  1866. W3_MAIN_CONTEXT::TimerCallback(LPVOID pvParam,
  1867. BOOLEAN fReason)
  1868. /*++
  1869. Routine Description:
  1870. Callback called when W3_MAIN_CONTEXT has existed for too long
  1871. OutputDebugString to tell people why we are doing this
  1872. and DebugBreak if a debugger is attached.
  1873. If no debugger is attached, ignore the callback.
  1874. Arguments:
  1875. pvParam - pointer to W3_MAIN_CONTEXT that has exceeded its maximum lifetime
  1876. fReason - not used
  1877. Return Value:
  1878. void
  1879. --*/
  1880. {
  1881. W3_MAIN_CONTEXT* pThis = (W3_MAIN_CONTEXT*)pvParam;
  1882. if (IsDebuggerPresent())
  1883. {
  1884. 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");
  1885. DebugBreak();
  1886. }
  1887. return;
  1888. }