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.

1749 lines
39 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name :
  4. workerrequest.cxx
  5. Abstract:
  6. UL_NATIVE_REQUEST implementation
  7. Author:
  8. Murali R. Krishnan ( MuraliK ) 23-Oct-1998
  9. Lei Jin ( leijin ) 13-Apr-1999 (Porting)
  10. Environment:
  11. Win32 - User Mode
  12. Project:
  13. ULATQ.DLL
  14. --*/
  15. #include "precomp.hxx"
  16. //
  17. // User supplied completion routines
  18. //
  19. extern PFN_ULATQ_NEW_REQUEST g_pfnNewRequest;
  20. extern PFN_ULATQ_IO_COMPLETION g_pfnIoCompletion;
  21. //
  22. // UL_NATIVE_REQUEST statics
  23. //
  24. ULONG UL_NATIVE_REQUEST::sm_cRequestsServed;
  25. ULONG UL_NATIVE_REQUEST::sm_cRestart;
  26. LONG UL_NATIVE_REQUEST::sm_RestartMsgSent;
  27. LIST_ENTRY UL_NATIVE_REQUEST::sm_RequestListHead;
  28. CRITICAL_SECTION UL_NATIVE_REQUEST::sm_csRequestList;
  29. DWORD UL_NATIVE_REQUEST::sm_cRequests;
  30. PTRACE_LOG UL_NATIVE_REQUEST::sm_pTraceLog;
  31. DWORD UL_NATIVE_REQUEST::sm_cRequestsPending;
  32. DWORD UL_NATIVE_REQUEST::sm_cDesiredPendingRequests;
  33. BOOL UL_NATIVE_REQUEST::sm_fAddingRequests;
  34. ALLOC_CACHE_HANDLER * UL_NATIVE_REQUEST::sm_pachNativeRequests;
  35. DWORD UL_NATIVE_REQUEST::sm_cMaxFreeRequests = DEFAULT_MAX_FREE_REQUESTS;
  36. DWORD UL_NATIVE_REQUEST::sm_cFreeRequests;
  37. #ifdef _WIN64
  38. CSpinLock UL_NATIVE_REQUEST::sm_FreeListLock;
  39. SINGLE_LIST_ENTRY UL_NATIVE_REQUEST::sm_FreeList;
  40. #else
  41. SLIST_HEADER UL_NATIVE_REQUEST::sm_FreeList;
  42. #endif
  43. UL_NATIVE_REQUEST::UL_NATIVE_REQUEST(
  44. VOID
  45. ) : _pbBuffer( _achBuffer ),
  46. _cbBuffer( sizeof( _achBuffer ) ),
  47. _pClientCertInfo( NULL ),
  48. _cbAllocateMemoryOffset( 0 ),
  49. _cRefs( 1 )
  50. {
  51. InitializeListHead( &_ListEntry );
  52. _FreeListEntry.Next = NULL;
  53. AddToRequestList();
  54. Reset();
  55. _dwSignature = UL_NATIVE_REQUEST_SIGNATURE;
  56. }
  57. UL_NATIVE_REQUEST::~UL_NATIVE_REQUEST(
  58. VOID
  59. )
  60. {
  61. DBG_ASSERT( CheckSignature() );
  62. _dwSignature = UL_NATIVE_REQUEST_SIGNATURE_FREE;
  63. if ( !IsListEmpty( &_ListEntry ) )
  64. {
  65. RemoveFromRequestList();
  66. }
  67. DBG_ASSERT( _cRefs == 0 );
  68. Cleanup();
  69. }
  70. VOID
  71. UL_NATIVE_REQUEST::Cleanup(
  72. VOID
  73. )
  74. /*++
  75. Routine Description:
  76. Private helper method called by destructor and Reset()
  77. It assures that resources are cleaned up properly
  78. Arguments:
  79. None
  80. Return Value:
  81. None
  82. --*/
  83. {
  84. if ( _pbBuffer != _achBuffer )
  85. {
  86. LocalFree( _pbBuffer );
  87. }
  88. _pbBuffer = _achBuffer;
  89. _cbBuffer = sizeof( _achBuffer );
  90. //
  91. // http.sys returns token in HTTP_SSL_CLIENT_CERT_INFO structure
  92. // UL_NATIVE_REQUEST must take care of closing the token to avoid leak
  93. //
  94. if ( _pClientCertInfo != NULL &&
  95. _pClientCertInfo->Token != NULL )
  96. {
  97. CloseHandle( _pClientCertInfo->Token );
  98. _pClientCertInfo->Token = NULL;
  99. }
  100. //
  101. // Start allocating from the beginning of the buffer
  102. //
  103. _cbAllocateMemoryOffset = 0;
  104. }
  105. VOID
  106. UL_NATIVE_REQUEST::Reset(
  107. VOID
  108. )
  109. /*++
  110. Routine Description:
  111. Reset a UL_NATIVE_REQUEST for use in the request state machine
  112. Arguments:
  113. None
  114. Return Value:
  115. None
  116. --*/
  117. {
  118. Cleanup();
  119. _ExecState = NREQ_STATE_START;
  120. _pvContext = NULL;
  121. _cbAsyncIOData = 0;
  122. _dwAsyncIOError = NO_ERROR;
  123. _dwClientCertFlags = 0;
  124. ZeroMemory( &_Overlapped, sizeof(_Overlapped) );
  125. }
  126. VOID *
  127. UL_NATIVE_REQUEST::AllocateMemory(
  128. DWORD cbSize
  129. )
  130. /*++
  131. Routine Description:
  132. Allocate some memory for use by W3DT.DLL user
  133. in our private buffer
  134. Arguments:
  135. cbSize - Size to allocate
  136. Return Value:
  137. Pointer to memory (NULL if failed)
  138. --*/
  139. {
  140. DWORD cbSizeNeeded = 0;
  141. VOID * pvRet;
  142. ULONG_PTR ulPointer;
  143. cbSizeNeeded = _cbAllocateMemoryOffset + cbSize + sizeof( ULONG_PTR );
  144. if ( cbSizeNeeded <= sizeof( _abAllocateMemory ) )
  145. {
  146. //
  147. // Allocate inline
  148. //
  149. ulPointer = (ULONG_PTR) _abAllocateMemory + _cbAllocateMemoryOffset;
  150. ulPointer = ( ulPointer + 7 ) & ~7;
  151. pvRet = (VOID*) ulPointer;
  152. _cbAllocateMemoryOffset += cbSize + sizeof( ULONG_PTR );
  153. }
  154. else
  155. {
  156. pvRet = NULL;
  157. }
  158. return pvRet;
  159. }
  160. VOID
  161. UL_NATIVE_REQUEST::DoWork(
  162. DWORD cbData,
  163. DWORD dwError,
  164. LPOVERLAPPED lpo
  165. )
  166. /*++
  167. Routine Description:
  168. The driver of the state machine. It is called off async completions and
  169. initially (with lpo=NULL) to kick off the state machine.
  170. Arguments:
  171. cbData - Bytes completed
  172. dwError - Win32 Error of completion
  173. lpo - Pointer to OVERLAPPED passed in async call
  174. Return Value:
  175. None
  176. --*/
  177. {
  178. NREQ_STATUS Status = NSTATUS_NEXT;
  179. BOOL fError = FALSE;
  180. ReferenceWorkerRequest();
  181. if ( lpo != NULL )
  182. {
  183. //
  184. // This is an async completion. Dereference the request to match
  185. // the reference before posting async operation
  186. //
  187. DereferenceWorkerRequest();
  188. //
  189. // Save away the completion data for state handler use and debugging
  190. // purposes
  191. //
  192. _cbAsyncIOData = cbData;
  193. _dwAsyncIOError = dwError;
  194. ZeroMemory( &_Overlapped, sizeof( _Overlapped ) );
  195. }
  196. //
  197. // Keep on executing the state machine until a state handler returns
  198. // pending. If so, the IO completion will continue the machine
  199. //
  200. // We also break out on error (typical case will be shutdown)
  201. //
  202. while ( !fError && Status == NSTATUS_NEXT )
  203. {
  204. switch ( _ExecState )
  205. {
  206. case NREQ_STATE_START:
  207. Status = DoStateStart();
  208. break;
  209. case NREQ_STATE_READ:
  210. Status = DoStateRead();
  211. break;
  212. case NREQ_STATE_PROCESS:
  213. Status = DoStateProcess();
  214. break;
  215. case NREQ_STATE_ERROR:
  216. fError = TRUE;
  217. DereferenceWorkerRequest();
  218. break;
  219. case NREQ_STATE_CLIENT_CERT:
  220. Status = DoStateClientCertificate();
  221. break;
  222. default:
  223. fError = TRUE;
  224. DBG_ASSERT( FALSE );
  225. break;
  226. }
  227. }
  228. DereferenceWorkerRequest();
  229. }
  230. NREQ_STATUS
  231. UL_NATIVE_REQUEST::DoStateStart(
  232. VOID
  233. )
  234. /*++
  235. Routine Description:
  236. The NREQ_START state. This state does the initial read for a new HTTP
  237. request (it passes a NULL request ID). Continuing the read process (
  238. for example if the buffer is too small) happens in the NREQ_READ state.
  239. Arguments:
  240. None
  241. Return Value:
  242. NSTATUS_PENDING if async IO pending, else NSTATUS_NEXT
  243. --*/
  244. {
  245. ULONG rc;
  246. HTTP_REQUEST_ID RequestId;
  247. HANDLE hAsync;
  248. //
  249. // This is the initial read, therefore we don't know the request ID
  250. //
  251. HTTP_SET_NULL_ID( &RequestId );
  252. //
  253. // If we are in shutdown, then just bail with error
  254. //
  255. if ( g_pwpContext->IsInShutdown() )
  256. {
  257. _ExecState = NREQ_STATE_ERROR;
  258. return NSTATUS_NEXT;
  259. }
  260. //
  261. // Have we served enough requests?
  262. //
  263. if ( sm_cRestart &&
  264. sm_cRequestsServed >= sm_cRestart )
  265. {
  266. //
  267. // Indicate to WAS such and the error out
  268. //
  269. if ( NeedToSendRestartMsg() )
  270. {
  271. g_pwpContext->SendMsgToAdminProcess( IPM_WP_RESTART_COUNT_REACHED );
  272. }
  273. _ExecState = NREQ_STATE_ERROR;
  274. return NSTATUS_NEXT;
  275. }
  276. //
  277. // Make an async call to HttpReceiveHttpRequest to get the next request
  278. //
  279. _ExecState = NREQ_STATE_READ;
  280. InterlockedIncrement( (LPLONG) &sm_cRequestsPending );
  281. ReferenceWorkerRequest();
  282. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  283. if ( hAsync != NULL )
  284. {
  285. rc = HttpReceiveHttpRequest( hAsync,
  286. RequestId,
  287. HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
  288. (HTTP_REQUEST *) _pbBuffer,
  289. _cbBuffer,
  290. NULL,
  291. &_Overlapped );
  292. }
  293. else
  294. {
  295. rc = ERROR_INVALID_HANDLE;
  296. }
  297. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  298. if ( rc == NO_ERROR )
  299. {
  300. rc = ERROR_IO_PENDING;
  301. }
  302. if ( rc != ERROR_IO_PENDING )
  303. {
  304. DBG_ASSERT( rc != NO_ERROR );
  305. InterlockedDecrement( (LPLONG) &sm_cRequestsPending );
  306. _ExecState = NREQ_STATE_ERROR;
  307. DereferenceWorkerRequest();
  308. return NSTATUS_NEXT;
  309. }
  310. else
  311. {
  312. return NSTATUS_PENDING;
  313. }
  314. }
  315. NREQ_STATUS
  316. UL_NATIVE_REQUEST::DoStateRead(
  317. VOID
  318. )
  319. /*++
  320. Routine Description:
  321. The NREQ_READ state. This state is responsible for producing a complete
  322. UL_HTTP_REQUEST for consumption by the NREQ_PROCESS state. Note that
  323. this may require another UlReceiveHttpRequest() if the initial was not
  324. supplied a large enough buffer.
  325. Arguments:
  326. None
  327. Return Value:
  328. NSTATUS_PENDING if async IO pending, else NSTATUS_NEXT
  329. --*/
  330. {
  331. HTTP_REQUEST_ID RequestId;
  332. ULONG cbRequired;
  333. DWORD cCurrentRequestsPending;
  334. HANDLE hAsync;
  335. //
  336. // The initial read is complete. If the error is ERROR_MORE_DATA, then
  337. // our buffer was not large enough. Resize and try again
  338. //
  339. if ( _dwAsyncIOError == ERROR_MORE_DATA )
  340. {
  341. //
  342. // Remember the request ID to retry the the UlReceiveHttpRequest
  343. //
  344. RequestId = QueryRequestId();
  345. DBG_ASSERT( RequestId != HTTP_NULL_ID );
  346. //
  347. // We need to allocate a larger buffer :(
  348. //
  349. if ( _pbBuffer != _achBuffer )
  350. {
  351. //
  352. // We shouldn't be getting ERROR_MORE_DATA if we already
  353. // resized due to an earlier ERROR_MORE_DATA
  354. //
  355. DBG_ASSERT( FALSE );
  356. LocalFree( _pbBuffer );
  357. _pbBuffer = NULL;
  358. }
  359. //
  360. // The completed bytes tells us the required size of our input
  361. // buffer
  362. //
  363. _cbBuffer = _cbAsyncIOData;
  364. _pbBuffer = (UCHAR*) LocalAlloc( LPTR, _cbBuffer );
  365. if ( _pbBuffer == NULL )
  366. {
  367. _ExecState = NREQ_STATE_ERROR;
  368. return NSTATUS_NEXT;
  369. }
  370. //
  371. // Read the HTTP request again (better to do it sychronously, since
  372. // it is all ready now)
  373. //
  374. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  375. if ( hAsync != NULL )
  376. {
  377. _dwAsyncIOError = HttpReceiveHttpRequest(
  378. hAsync,
  379. RequestId,
  380. HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
  381. (HTTP_REQUEST *)_pbBuffer,
  382. _cbBuffer,
  383. &cbRequired,
  384. NULL );
  385. }
  386. else
  387. {
  388. _dwAsyncIOError = ERROR_INVALID_HANDLE;
  389. }
  390. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  391. //
  392. // No reason this should fail again with ERROR_MORE_DATA
  393. //
  394. DBG_ASSERT( _dwAsyncIOError != ERROR_MORE_DATA );
  395. }
  396. if ( _dwAsyncIOError == NO_ERROR )
  397. {
  398. //
  399. // We're done. The read was successful and we have a full
  400. // UL_HTTP_REQUEST. We can now pass off to the NREQ_PROCESS state
  401. //
  402. cCurrentRequestsPending = InterlockedDecrement( (LPLONG)
  403. &sm_cRequestsPending );
  404. if ( cCurrentRequestsPending < sm_cDesiredPendingRequests / 2 )
  405. {
  406. AddPendingRequests( sm_cDesiredPendingRequests - cCurrentRequestsPending );
  407. }
  408. _ExecState = NREQ_STATE_PROCESS;
  409. }
  410. else
  411. {
  412. //
  413. // Some other error. Try again
  414. //
  415. InterlockedDecrement( (LPLONG) &sm_cRequestsPending );
  416. Reset();
  417. }
  418. return NSTATUS_NEXT;
  419. }
  420. NREQ_STATUS
  421. UL_NATIVE_REQUEST::DoStateProcess(
  422. VOID
  423. )
  424. /*++
  425. Routine Description:
  426. The NREQ_PROCESS state. This state actually calls consumer of the
  427. NewRequests and IoCompletions. This state calls the set routines in
  428. W3CORE.DLL
  429. Arguments:
  430. None
  431. Return Value:
  432. NSTATUS_PENDING if async IO pending, else NSTATUS_NEXT
  433. --*/
  434. {
  435. WP_IDLE_TIMER * pTimer;
  436. //
  437. // Reset idle tick since we're not idle if we're processing
  438. //
  439. pTimer = g_pwpContext->QueryIdleTimer();
  440. if ( pTimer != NULL )
  441. {
  442. pTimer->ResetCurrentIdleTick();
  443. }
  444. ReferenceWorkerRequest();
  445. if ( _pvContext == NULL )
  446. {
  447. //
  448. // Extra reference here. The consumer must call UlAtqResetContext()
  449. // to finally cleanup. This complication is brought on by
  450. // scenarios where non-IO-completions are required to finish a request
  451. // (example: async ISAPI)
  452. //
  453. ReferenceWorkerRequest();
  454. DBG_ASSERT( g_pfnNewRequest != NULL );
  455. g_pfnNewRequest( this );
  456. }
  457. else
  458. {
  459. DBG_ASSERT( g_pfnIoCompletion != NULL );
  460. g_pfnIoCompletion( _pvContext,
  461. _cbAsyncIOData,
  462. _dwAsyncIOError,
  463. &_Overlapped );
  464. }
  465. DereferenceWorkerRequest();
  466. return NSTATUS_PENDING;
  467. }
  468. NREQ_STATUS
  469. UL_NATIVE_REQUEST::DoStateClientCertificate(
  470. VOID
  471. )
  472. /*++
  473. Routine Description:
  474. Handle a completion for receiving a client certificate
  475. Arguments:
  476. None
  477. Return Value:
  478. NSTATUS_PENDING if async IO pending, else NSTATUS_NEXT
  479. --*/
  480. {
  481. ULONG Status;
  482. HTTP_REQUEST * pRequest;
  483. HANDLE hAsync;
  484. DBG_ASSERT( _ExecState == NREQ_STATE_CLIENT_CERT );
  485. //
  486. // Is our buffer too small. If so retry the request synchronously with
  487. // a bigger buffer
  488. // Note: STATUS_BUFFER_OVERFLOW is translated to WIN32 Error - ERROR_MORE_DATA
  489. if ( _dwAsyncIOError == ERROR_MORE_DATA )
  490. {
  491. //
  492. // If buffer is not big enough, HTTP.sys will return only HTTP_SSL_CLIENT_CERT_INFO
  493. // structure that contains the size of the client certificate
  494. // The following assert is to assure that HTTP.SYS returns back that
  495. // HTTP_SSL_CLIENT_CERT_INFO structure and nothing more
  496. DBG_ASSERT( _cbAsyncIOData == sizeof( HTTP_SSL_CLIENT_CERT_INFO ) );
  497. //
  498. // We need to allocate enough memory to contain HTTP_SSL_CLIENT_CERT_INFO
  499. // and certificate blob
  500. //
  501. DWORD dwRequiredSize = _pClientCertInfo->CertEncodedSize +
  502. sizeof( HTTP_SSL_CLIENT_CERT_INFO );
  503. DBG_ASSERT( dwRequiredSize > _buffClientCertInfo.QuerySize() );
  504. if ( !_buffClientCertInfo.Resize( dwRequiredSize ) )
  505. {
  506. //
  507. // Funnel the fatal error to the complete
  508. //
  509. _dwAsyncIOError = GetLastError();
  510. }
  511. else
  512. {
  513. //
  514. // Retry the request for client cert synchronously
  515. //
  516. _pClientCertInfo = reinterpret_cast<HTTP_SSL_CLIENT_CERT_INFO *>( _buffClientCertInfo.QueryPtr() );
  517. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  518. if ( hAsync != NULL )
  519. {
  520. Status = HttpReceiveClientCertificate( hAsync,
  521. QueryConnectionId(),
  522. _dwClientCertFlags,
  523. _pClientCertInfo,
  524. _buffClientCertInfo.QuerySize(),
  525. NULL,
  526. NULL );
  527. }
  528. else
  529. {
  530. Status = ERROR_INVALID_HANDLE;
  531. }
  532. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  533. if ( Status != NO_ERROR )
  534. {
  535. DBG_ASSERT( _dwAsyncIOError != ERROR_MORE_DATA );
  536. }
  537. _dwAsyncIOError = Status;
  538. _cbAsyncIOData = dwRequiredSize;
  539. }
  540. }
  541. if ( _dwAsyncIOError == NO_ERROR )
  542. {
  543. pRequest = QueryHttpRequest();
  544. DBG_ASSERT( pRequest->pSslInfo != NULL );
  545. DBG_ASSERT( pRequest->pSslInfo->pClientCertInfo == NULL );
  546. pRequest->pSslInfo->pClientCertInfo = _pClientCertInfo;
  547. }
  548. //
  549. // Regardless of what happened, we are no longer processing a client cert
  550. //
  551. _ExecState = NREQ_STATE_PROCESS;
  552. DBG_ASSERT( g_pfnIoCompletion != NULL );
  553. g_pfnIoCompletion( _pvContext,
  554. _cbAsyncIOData,
  555. _dwAsyncIOError,
  556. &_Overlapped );
  557. return NSTATUS_PENDING;
  558. }
  559. VOID
  560. UL_NATIVE_REQUEST::ResetContext(
  561. VOID
  562. )
  563. /*++
  564. Routine Description:
  565. The implementation of UlAtqResetContext which the consumer of W3DT.DLL
  566. calls to cleanup the context.
  567. Arguments:
  568. None
  569. Return Value:
  570. None
  571. --*/
  572. {
  573. DereferenceWorkerRequest();
  574. }
  575. VOID
  576. UL_NATIVE_REQUEST::ReferenceWorkerRequest(
  577. VOID
  578. )
  579. /*++
  580. Routine Description:
  581. Increment the reference count on the worker request
  582. Arguments:
  583. None
  584. Return Value:
  585. None
  586. --*/
  587. {
  588. LONG cRefs = InterlockedIncrement( &_cRefs );
  589. //
  590. // Log the reference ( sm_pTraceLog!=NULL if DBG=1)
  591. //
  592. if ( sm_pTraceLog != NULL )
  593. {
  594. WriteRefTraceLog( sm_pTraceLog,
  595. cRefs,
  596. this );
  597. }
  598. }
  599. VOID
  600. UL_NATIVE_REQUEST::DereferenceWorkerRequest(
  601. VOID
  602. )
  603. /*++
  604. Routine Description:
  605. Dereference Request. This routine will optionally reset the context
  606. for use for reading the next HTTP request. Putting the reset code in
  607. one place (here) handles all the cases where we would want to reset.
  608. However, there are a few places where we definitely don't want to reset
  609. (in the case of error where the context will be going away)
  610. In either case, if the ref count goes to 0, we can delete the object.
  611. Arguments:
  612. None
  613. Return Value:
  614. None
  615. --*/
  616. {
  617. LONG cRefs = InterlockedDecrement( &_cRefs );
  618. if ( sm_pTraceLog != NULL )
  619. {
  620. WriteRefTraceLog( sm_pTraceLog,
  621. cRefs,
  622. this );
  623. }
  624. if ( cRefs == 0 )
  625. {
  626. //
  627. // If 0, we can definitely cleanup, regardless. This is the error
  628. // case which is used to cleanup contexts on shutdown (on shutdown,
  629. // the apppool handle is closed which will error out all pending
  630. // UlReceiveHttpRequests
  631. //
  632. delete this;
  633. }
  634. else if ( cRefs == 1 && _ExecState != NREQ_STATE_ERROR )
  635. {
  636. //
  637. // Reset the state machine. Now we can increment our served count
  638. //
  639. InterlockedIncrement( (PLONG) &sm_cRequestsServed );
  640. //
  641. // If we have too many outstanding requests, then don't pend
  642. // another receive. Keep the request around ready to go
  643. //
  644. if ( sm_cRequestsPending > sm_cDesiredPendingRequests * 2 )
  645. {
  646. FreeWorkerRequest( this );
  647. }
  648. else
  649. {
  650. Reset();
  651. //
  652. // Re-kickoff the state machine
  653. //
  654. DoWork( 0, 0, NULL );
  655. }
  656. }
  657. }
  658. VOID
  659. UL_NATIVE_REQUEST::RemoveFromRequestList(
  660. VOID
  661. )
  662. /*++
  663. Routine Description:
  664. Remove this UL_NATIVE_REQUEST from the static list of requests. Main
  665. purpose of the list is for debugging.
  666. Arguments:
  667. None
  668. Return Value:
  669. None
  670. --*/
  671. {
  672. EnterCriticalSection( &sm_csRequestList );
  673. RemoveEntryList( &_ListEntry );
  674. sm_cRequests--;
  675. LeaveCriticalSection( &sm_csRequestList );
  676. }
  677. VOID
  678. UL_NATIVE_REQUEST::AddToRequestList(
  679. VOID
  680. )
  681. /*++
  682. Routine Description:
  683. Add this request to the static list of requests. The main purpose of the
  684. list is for debugging.
  685. Arguments:
  686. None
  687. Return Value:
  688. None
  689. --*/
  690. {
  691. EnterCriticalSection( &sm_csRequestList );
  692. sm_cRequests++;
  693. InsertTailList( &sm_RequestListHead, &_ListEntry );
  694. LeaveCriticalSection( &sm_csRequestList );
  695. }
  696. HRESULT
  697. UL_NATIVE_REQUEST::SendResponse(
  698. BOOL fAsync,
  699. DWORD dwFlags,
  700. HTTP_RESPONSE * pResponse,
  701. HTTP_CACHE_POLICY * pCachePolicy,
  702. DWORD *pcbSent,
  703. HTTP_LOG_FIELDS_DATA *pUlLogData
  704. )
  705. /*++
  706. Routine Description:
  707. Send an HTTP response thru UL.
  708. Arguments:
  709. fAsync - TRUE if send is async
  710. dwFlags - UlSendHttpResponse flags
  711. pResponse - Pointer to UL_HTTP_RESPONSE
  712. pCachePolicy - Cache policy
  713. pcbSent - Receives number of bytes send
  714. pULLogData - Logging information
  715. Return Value:
  716. HRESULT (if pending, the return is NO_ERROR)
  717. --*/
  718. {
  719. ULONG Status = NO_ERROR;
  720. HRESULT hr = NO_ERROR;
  721. HANDLE hAsync;
  722. if ( pcbSent == NULL )
  723. {
  724. DBG_ASSERT( FALSE );
  725. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  726. }
  727. if ( fAsync )
  728. {
  729. ReferenceWorkerRequest();
  730. }
  731. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  732. if ( hAsync != NULL )
  733. {
  734. Status = HttpSendHttpResponse( hAsync,
  735. QueryRequestId(),
  736. dwFlags,
  737. pResponse,
  738. pCachePolicy,
  739. fAsync ? NULL : pcbSent,
  740. NULL,
  741. 0,
  742. fAsync ? &(_Overlapped) : NULL ,
  743. pUlLogData );
  744. }
  745. else
  746. {
  747. Status = ERROR_INVALID_HANDLE;
  748. }
  749. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  750. //
  751. // If the response is pending, then we return a successful error code.
  752. // This frees the caller from the ERROR_IO_PENDING checks in common
  753. // case
  754. //
  755. if ( fAsync )
  756. {
  757. if ( Status == NO_ERROR )
  758. {
  759. Status = ERROR_IO_PENDING;
  760. }
  761. DBG_ASSERT( Status != NO_ERROR );
  762. if ( Status != ERROR_IO_PENDING )
  763. {
  764. DereferenceWorkerRequest();
  765. hr = HRESULT_FROM_WIN32( Status );
  766. }
  767. }
  768. else if ( Status != NO_ERROR )
  769. {
  770. hr = HRESULT_FROM_WIN32( Status );
  771. }
  772. return hr;
  773. }
  774. HRESULT
  775. UL_NATIVE_REQUEST::SendEntity(
  776. BOOL fAsync,
  777. DWORD dwFlags,
  778. USHORT cChunks,
  779. HTTP_DATA_CHUNK * pChunks,
  780. DWORD *pcbSent,
  781. HTTP_LOG_FIELDS_DATA *pUlLogData
  782. )
  783. /*++
  784. Routine Description:
  785. Send an HTTP entity thru UL.
  786. Arguments:
  787. fAsync - TRUE if send is async
  788. dwFlags - UlSendHttpResponse flags
  789. cChunks - Number of chunks in response
  790. pChunks - Pointer to array of UL_DATA_CHUNKs
  791. pcbSent - Receives number of bytes sent
  792. pUlLogData - Log information
  793. Return Value:
  794. HRESULT (if pending, the return is NO_ERROR)
  795. --*/
  796. {
  797. ULONG Status = NO_ERROR;
  798. HRESULT hr = NO_ERROR;
  799. HANDLE hAsync;
  800. if ( pcbSent == NULL )
  801. {
  802. DBG_ASSERT( FALSE );
  803. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  804. }
  805. if ( fAsync )
  806. {
  807. ReferenceWorkerRequest();
  808. }
  809. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  810. if ( hAsync != NULL )
  811. {
  812. Status = HttpSendResponseEntityBody( hAsync,
  813. QueryRequestId(),
  814. dwFlags,
  815. cChunks,
  816. pChunks,
  817. fAsync ? NULL : pcbSent,
  818. NULL,
  819. 0,
  820. fAsync ? &(_Overlapped) : NULL,
  821. pUlLogData );
  822. }
  823. else
  824. {
  825. Status = ERROR_INVALID_HANDLE;
  826. }
  827. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  828. //
  829. // If the send is pending, then we return a successful error code.
  830. // This frees the caller from the ERROR_IO_PENDING checks in common
  831. // case
  832. //
  833. if ( fAsync )
  834. {
  835. if ( Status == NO_ERROR )
  836. {
  837. Status = ERROR_IO_PENDING;
  838. }
  839. DBG_ASSERT( Status != NO_ERROR );
  840. if ( Status != ERROR_IO_PENDING )
  841. {
  842. DereferenceWorkerRequest();
  843. hr = HRESULT_FROM_WIN32( Status );
  844. }
  845. }
  846. else if ( Status != NO_ERROR )
  847. {
  848. hr = HRESULT_FROM_WIN32( Status );
  849. }
  850. return hr;
  851. }
  852. HRESULT
  853. UL_NATIVE_REQUEST::ReceiveEntity(
  854. BOOL fAsync,
  855. DWORD dwFlags,
  856. VOID * pBuffer,
  857. DWORD cbBuffer,
  858. DWORD * pBytesReceived
  859. )
  860. /*++
  861. Routine Description:
  862. Receive HTTP entity thru UL.
  863. Arguments:
  864. fAsync - TRUE if receive is async
  865. dwFlags - UlSendHttpResponse flags
  866. pBuffer - A buffer to receive the data
  867. cbBuffer - The size of the receive buffer
  868. pBytesReceived - Upon return, the number of bytes
  869. copied to the buffer
  870. Return Value:
  871. HRESULT (if pending, the return is NO_ERROR)
  872. --*/
  873. {
  874. ULONG Status = NO_ERROR;
  875. HRESULT hr = NO_ERROR;
  876. HANDLE hAsync;
  877. if ( fAsync )
  878. {
  879. ReferenceWorkerRequest();
  880. }
  881. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  882. if ( hAsync != NULL )
  883. {
  884. Status = HttpReceiveRequestEntityBody( hAsync,
  885. QueryRequestId(),
  886. dwFlags,
  887. pBuffer,
  888. cbBuffer,
  889. fAsync ? NULL : pBytesReceived,
  890. fAsync ? &(_Overlapped) : NULL );
  891. }
  892. else
  893. {
  894. Status = ERROR_INVALID_HANDLE;
  895. }
  896. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  897. //
  898. // If the receive is pending, then we return a successful error code.
  899. // This frees the caller from the ERROR_IO_PENDING checks in common
  900. // case
  901. //
  902. if ( fAsync )
  903. {
  904. if ( Status == NO_ERROR )
  905. {
  906. Status = ERROR_IO_PENDING;
  907. }
  908. DBG_ASSERT( Status != NO_ERROR );
  909. if ( Status != ERROR_IO_PENDING )
  910. {
  911. DereferenceWorkerRequest();
  912. hr = HRESULT_FROM_WIN32( Status );
  913. }
  914. }
  915. else if ( Status != NO_ERROR )
  916. {
  917. hr = HRESULT_FROM_WIN32( Status );
  918. }
  919. return hr;
  920. }
  921. HRESULT
  922. UL_NATIVE_REQUEST::ReceiveClientCertificate(
  923. BOOL fAsync,
  924. BOOL fDoCertMap,
  925. HTTP_SSL_CLIENT_CERT_INFO **ppClientCertInfo
  926. )
  927. /*++
  928. Routine Description:
  929. Receive a client certificate
  930. Arguments:
  931. fAsync - TRUE if receive should be async
  932. fDoCertMap - TRUE if we should map client certificate to token
  933. ppClientCertInfo - Set to point to client cert info on success
  934. Return Value:
  935. HRESULT (if pending, the return is NO_ERROR)
  936. --*/
  937. {
  938. ULONG Status;
  939. HTTP_REQUEST * pHttpRequest;
  940. HRESULT hr = NO_ERROR;
  941. HANDLE hAsync;
  942. if ( ppClientCertInfo == NULL )
  943. {
  944. DBG_ASSERT( FALSE );
  945. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  946. }
  947. *ppClientCertInfo = NULL;
  948. //
  949. // If this request is not SSL enabled, then getting the client cert is
  950. // a no-go
  951. //
  952. pHttpRequest = QueryHttpRequest();
  953. DBG_ASSERT( pHttpRequest != NULL );
  954. if ( pHttpRequest->pSslInfo == NULL )
  955. {
  956. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  957. }
  958. //
  959. // Do we already have a cert associated with this request?
  960. //
  961. DBG_ASSERT( pHttpRequest->pSslInfo != NULL );
  962. if ( pHttpRequest->pSslInfo->pClientCertInfo != NULL )
  963. {
  964. if ( fAsync )
  965. {
  966. //
  967. // BUGBUG: Probably should support this case. And if I do, then
  968. // need to fake a completion!
  969. //
  970. DBG_ASSERT( FALSE );
  971. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  972. }
  973. *ppClientCertInfo = pHttpRequest->pSslInfo->pClientCertInfo;
  974. return NO_ERROR;
  975. }
  976. //
  977. // OK. We'll have to ask UL to renegotiate. We must be processing
  978. // a request
  979. //
  980. DBG_ASSERT( _ExecState == NREQ_STATE_PROCESS );
  981. if ( !_buffClientCertInfo.Resize( INITIAL_CERT_INFO_SIZE ) )
  982. {
  983. return HRESULT_FROM_WIN32( GetLastError() );
  984. }
  985. ZeroMemory( _buffClientCertInfo.QueryPtr(), INITIAL_CERT_INFO_SIZE );
  986. _pClientCertInfo = reinterpret_cast<HTTP_SSL_CLIENT_CERT_INFO *>( _buffClientCertInfo.QueryPtr() );
  987. //
  988. // Are we cert mapping?
  989. //
  990. if ( fDoCertMap )
  991. {
  992. _dwClientCertFlags = HTTP_RECEIVE_CLIENT_CERT_FLAG_MAP;
  993. }
  994. else
  995. {
  996. _dwClientCertFlags = 0;
  997. }
  998. //
  999. // If we're doing this async, then manage state such that
  1000. // DoStateClientCert gets the completion
  1001. //
  1002. if ( fAsync )
  1003. {
  1004. ReferenceWorkerRequest();
  1005. _ExecState = NREQ_STATE_CLIENT_CERT;
  1006. }
  1007. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  1008. if ( hAsync != NULL )
  1009. {
  1010. Status = HttpReceiveClientCertificate( hAsync,
  1011. QueryConnectionId(),
  1012. _dwClientCertFlags,
  1013. _pClientCertInfo,
  1014. _buffClientCertInfo.QuerySize(),
  1015. NULL,
  1016. fAsync ? &_Overlapped : NULL );
  1017. }
  1018. else
  1019. {
  1020. Status = ERROR_INVALID_HANDLE;
  1021. }
  1022. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  1023. if ( fAsync )
  1024. {
  1025. if ( Status == NO_ERROR )
  1026. {
  1027. Status = ERROR_IO_PENDING;
  1028. }
  1029. DBG_ASSERT( Status != NO_ERROR );
  1030. if ( Status != ERROR_IO_PENDING )
  1031. {
  1032. DereferenceWorkerRequest();
  1033. hr = HRESULT_FROM_WIN32( Status );
  1034. _ExecState = NREQ_STATE_PROCESS;
  1035. }
  1036. }
  1037. else if ( Status != NO_ERROR )
  1038. {
  1039. hr = HRESULT_FROM_WIN32( Status );
  1040. }
  1041. return hr;
  1042. }
  1043. //static
  1044. HRESULT
  1045. UL_NATIVE_REQUEST::Initialize(
  1046. VOID
  1047. )
  1048. /*++
  1049. Routine Description:
  1050. Static initialization of UL_NATIVE_REQUESTs
  1051. Arguments:
  1052. None
  1053. Return Value:
  1054. HRESULT
  1055. --*/
  1056. {
  1057. ALLOC_CACHE_CONFIGURATION acConfig;
  1058. HKEY hKey;
  1059. BOOL fRet;
  1060. HRESULT hr;
  1061. //
  1062. // Setup allocation lookaside
  1063. //
  1064. acConfig.nConcurrency = 1;
  1065. acConfig.nThreshold = 100;
  1066. acConfig.cbSize = sizeof( UL_NATIVE_REQUEST );
  1067. DBG_ASSERT( sm_pachNativeRequests == NULL );
  1068. sm_pachNativeRequests = new ALLOC_CACHE_HANDLER( "UL_NATIVE_REQUEST",
  1069. &acConfig );
  1070. if ( sm_pachNativeRequests == NULL )
  1071. {
  1072. return HRESULT_FROM_WIN32( GetLastError() );
  1073. }
  1074. fRet = InitializeCriticalSectionAndSpinCount( &sm_csRequestList,
  1075. UL_NATIVE_REQUEST_CS_SPINS );
  1076. if ( !fRet )
  1077. {
  1078. hr = HRESULT_FROM_WIN32( GetLastError() );
  1079. delete sm_pachNativeRequests;
  1080. sm_pachNativeRequests = NULL;
  1081. return hr;
  1082. }
  1083. InitializeListHead( &sm_RequestListHead );
  1084. #ifdef _WIN64
  1085. sm_FreeList.Next = NULL;
  1086. #else
  1087. InitializeSListHead( &sm_FreeList );
  1088. #endif
  1089. sm_cRequestsServed = 0;
  1090. sm_cRestart = 0;
  1091. sm_RestartMsgSent = 0;
  1092. sm_cRequestsPending = 0;
  1093. //
  1094. // If the number of pending HttpReceiveHttpRequest is configured, use
  1095. // that rather than the default value
  1096. //
  1097. if (RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1098. REGISTRY_KEY_W3SVC_PERFORMANCE_KEY_W,
  1099. 0,
  1100. KEY_READ,
  1101. &hKey ) == ERROR_SUCCESS)
  1102. {
  1103. DWORD cbBuffer = sizeof(DWORD);
  1104. DWORD dwType;
  1105. if (RegQueryValueEx( hKey,
  1106. L"ReceiveRequestsPending",
  1107. NULL,
  1108. &dwType,
  1109. (LPBYTE)&sm_cDesiredPendingRequests,
  1110. &cbBuffer ) != NO_ERROR ||
  1111. dwType != REG_DWORD)
  1112. {
  1113. sm_cDesiredPendingRequests = DESIRED_PENDING_REQUESTS;
  1114. }
  1115. RegCloseKey( hKey );
  1116. }
  1117. else
  1118. {
  1119. sm_cDesiredPendingRequests = DESIRED_PENDING_REQUESTS;
  1120. }
  1121. sm_fAddingRequests = FALSE;
  1122. #if DBG
  1123. sm_pTraceLog = CreateRefTraceLog( 2000, 0 );
  1124. #endif
  1125. return NO_ERROR;
  1126. }
  1127. //static
  1128. VOID
  1129. UL_NATIVE_REQUEST::StopListening(
  1130. VOID
  1131. )
  1132. /*++
  1133. Routine Description:
  1134. Shutdown the apppool in preparation for shutdown
  1135. Arguments:
  1136. None
  1137. Return Value:
  1138. None
  1139. --*/
  1140. {
  1141. HANDLE hAsync;
  1142. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  1143. if ( hAsync != NULL )
  1144. {
  1145. //
  1146. // This will cause us to cancel all pending HttpReceiveHttpRequest calls
  1147. // and not get any more but other operations will still go on
  1148. //
  1149. HttpShutdownAppPool( hAsync );
  1150. }
  1151. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  1152. }
  1153. //static
  1154. VOID
  1155. UL_NATIVE_REQUEST::Terminate(
  1156. VOID
  1157. )
  1158. /*++
  1159. Routine Description:
  1160. Static termination
  1161. Arguments:
  1162. None
  1163. Return Value:
  1164. None
  1165. --*/
  1166. {
  1167. if ( sm_pTraceLog != NULL )
  1168. {
  1169. DestroyRefTraceLog( sm_pTraceLog );
  1170. sm_pTraceLog = NULL;
  1171. }
  1172. DeleteCriticalSection( &sm_csRequestList );
  1173. if ( sm_pachNativeRequests != NULL )
  1174. {
  1175. delete sm_pachNativeRequests;
  1176. sm_pachNativeRequests = NULL;
  1177. }
  1178. }
  1179. //static
  1180. HRESULT
  1181. UL_NATIVE_REQUEST::AddPendingRequests(
  1182. DWORD cRequests
  1183. )
  1184. /*++
  1185. Routine Description:
  1186. Pools calls to UlReceiveHttpRequest by creating new UL_NATIVE_REQUESTs
  1187. and kicking off their state machines
  1188. Arguments:
  1189. cRequests - Number of requests to read
  1190. Return Value:
  1191. HRESULT
  1192. --*/
  1193. {
  1194. UL_NATIVE_REQUEST * pRequest;
  1195. if ( sm_fAddingRequests )
  1196. {
  1197. return NO_ERROR;
  1198. }
  1199. if ( InterlockedCompareExchange( (LPLONG) &sm_fAddingRequests,
  1200. TRUE,
  1201. FALSE ) == FALSE )
  1202. {
  1203. for ( DWORD i = 0; i < cRequests; i++ )
  1204. {
  1205. pRequest = AllocateWorkerRequest();
  1206. if ( pRequest == NULL )
  1207. {
  1208. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  1209. }
  1210. pRequest->DoWork( 0, 0, NULL );
  1211. }
  1212. sm_fAddingRequests = FALSE;
  1213. }
  1214. return NO_ERROR;
  1215. }
  1216. //static
  1217. HRESULT
  1218. UL_NATIVE_REQUEST::ReleaseAllWorkerRequests(
  1219. VOID
  1220. )
  1221. /*++
  1222. Routine Description:
  1223. Wait for all outstanding UL_NATIVE_REQUESTs to drain
  1224. Arguments:
  1225. None
  1226. Return Value:
  1227. HRESULT
  1228. --*/
  1229. {
  1230. UL_NATIVE_REQUEST * pRequest;
  1231. //
  1232. // First clear out any of our freelist items
  1233. //
  1234. for ( ; ; )
  1235. {
  1236. pRequest = PopFreeList();
  1237. if ( pRequest == NULL )
  1238. {
  1239. break;
  1240. }
  1241. DBG_ASSERT( pRequest != NULL );
  1242. DBG_ASSERT( pRequest->CheckSignature() );
  1243. //
  1244. // Free it up
  1245. //
  1246. pRequest->DereferenceWorkerRequest();
  1247. }
  1248. //
  1249. // Now, wait for all requests to be destructed
  1250. //
  1251. while ( sm_cRequests )
  1252. {
  1253. Sleep( 1000 );
  1254. DBGPRINTF(( DBG_CONTEXT,
  1255. "UL_NATIVE_REQUEST::ReleaseAllWorkerRequests waiting for %d requests to drain.\n",
  1256. sm_cRequests ));
  1257. }
  1258. return NO_ERROR;
  1259. }
  1260. //static
  1261. VOID
  1262. UL_NATIVE_REQUEST::FreeWorkerRequest(
  1263. UL_NATIVE_REQUEST * pWorkerRequest
  1264. )
  1265. /*++
  1266. Routine Description:
  1267. Free worker request
  1268. Arguments:
  1269. pNativeRequest - Worker request to retrieve
  1270. Return Value:
  1271. None
  1272. --*/
  1273. {
  1274. DBG_ASSERT( pWorkerRequest != NULL );
  1275. if ( sm_cFreeRequests > sm_cMaxFreeRequests )
  1276. {
  1277. //
  1278. // Don't keep too many around. Just free this guy
  1279. // by dereferencing one more time
  1280. //
  1281. pWorkerRequest->DereferenceWorkerRequest();
  1282. }
  1283. else
  1284. {
  1285. pWorkerRequest->Reset();
  1286. PushFreeList( pWorkerRequest );
  1287. sm_cFreeRequests++;
  1288. }
  1289. }
  1290. //static
  1291. UL_NATIVE_REQUEST *
  1292. UL_NATIVE_REQUEST::AllocateWorkerRequest(
  1293. VOID
  1294. )
  1295. /*++
  1296. Routine Description:
  1297. Allocate a new request
  1298. Arguments:
  1299. None
  1300. Return Value:
  1301. Pointer to new request or NULL if error
  1302. --*/
  1303. {
  1304. UL_NATIVE_REQUEST * pRequest;
  1305. if ( sm_cFreeRequests )
  1306. {
  1307. pRequest = PopFreeList();
  1308. if ( pRequest != NULL )
  1309. {
  1310. DBG_ASSERT( pRequest->CheckSignature() );
  1311. sm_cFreeRequests--;
  1312. return pRequest;
  1313. }
  1314. }
  1315. //
  1316. // If we got to here, we have to allocate a new request
  1317. //
  1318. pRequest = new UL_NATIVE_REQUEST;
  1319. return pRequest;
  1320. }