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.

954 lines
19 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name :
  4. ulatq.cxx
  5. Abstract:
  6. Exported ULATQ.DLL routines
  7. Author:
  8. Bilal Alam (balam) 13-Dec-1999
  9. Environment:
  10. Win32 - User Mode
  11. Project:
  12. ULATQ.DLL
  13. --*/
  14. #include "precomp.hxx"
  15. //
  16. // Configuration parameters registry key.
  17. //
  18. #define INET_INFO_KEY \
  19. "System\\CurrentControlSet\\Services\\w3svc"
  20. #define INET_INFO_PARAMETERS_KEY \
  21. INET_INFO_KEY "\\Parameters"
  22. const CHAR g_pszWpRegLocation[] =
  23. INET_INFO_PARAMETERS_KEY "\\w3dt";
  24. DECLARE_DEBUG_PRINTS_OBJECT();
  25. DECLARE_DEBUG_VARIABLE();
  26. DECLARE_PLATFORM_TYPE();
  27. WP_CONTEXT * g_pwpContext = NULL;
  28. //
  29. // Completion routines for new requests, io completions, and disconnect
  30. // notifications.
  31. //
  32. // CODEWORK: Can we get away with these being global
  33. //
  34. PFN_ULATQ_NEW_REQUEST g_pfnNewRequest = NULL;
  35. PFN_ULATQ_IO_COMPLETION g_pfnIoCompletion = NULL;
  36. PFN_ULATQ_DISCONNECT g_pfnDisconnect = NULL;
  37. PFN_ULATQ_ON_SHUTDOWN g_pfnOnShutdown = NULL;
  38. PFN_ULATQ_COLLECT_PERF_COUNTERS g_pfnCollectCounters = NULL;
  39. HRESULT
  40. UlAtqInitialize(
  41. INT argc,
  42. LPWSTR argv[],
  43. ULATQ_CONFIG * pConfig
  44. )
  45. /*++
  46. Routine Description:
  47. Initialize ULATQ
  48. Arguments:
  49. argc - Number of command line parameters to worker process
  50. argv - Command line parameters
  51. pConfig - Configuration settings for ULATQ
  52. Return Value:
  53. HRESULT
  54. --*/
  55. {
  56. HRESULT rc = NO_ERROR;
  57. BOOL fUlInit = FALSE;
  58. BOOL fThreadPoolInit = FALSE;
  59. HTTPAPI_VERSION HttpVersion = HTTPAPI_VERSION_1;
  60. CREATE_DEBUG_PRINT_OBJECT("w3dt");
  61. #if DBG
  62. if (!VALID_DEBUG_PRINT_OBJECT())
  63. {
  64. return E_FAIL;
  65. }
  66. #endif
  67. LOAD_DEBUG_FLAGS_FROM_REG_STR( g_pszWpRegLocation, DEBUG_ERROR );
  68. INITIALIZE_PLATFORM_TYPE();
  69. //
  70. // Honour ULATQ_CONFIG settings. Set completion routines
  71. // Need to set this up before we do any other initialization
  72. //
  73. g_pfnNewRequest = pConfig->pfnNewRequest;
  74. g_pfnIoCompletion = pConfig->pfnIoCompletion;
  75. g_pfnDisconnect = pConfig->pfnDisconnect;
  76. g_pfnOnShutdown = pConfig->pfnOnShutdown;
  77. g_pfnCollectCounters = pConfig->pfnCollectCounters;
  78. //
  79. // Initialize the thread pool
  80. //
  81. rc = ThreadPoolInitialize( 0 ); // Use the process default stack size
  82. if ( FAILED( rc ) )
  83. {
  84. goto Finished;
  85. }
  86. fThreadPoolInit = TRUE;
  87. //
  88. // Init UL
  89. //
  90. rc = HttpInitialize( HttpVersion, 0, NULL );
  91. if ( rc != NO_ERROR )
  92. {
  93. rc = HRESULT_FROM_WIN32( rc );
  94. DBGPRINTF(( DBG_CONTEXT, "Error (rc=%08x) in UlInitialize. Exiting\n",
  95. rc ));
  96. goto Finished;
  97. }
  98. fUlInit = TRUE;
  99. //
  100. // Create global state object
  101. //
  102. g_pwpContext = new WP_CONTEXT;
  103. if ( g_pwpContext == NULL )
  104. {
  105. rc = HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  106. goto Finished;
  107. }
  108. //
  109. // Do global state initialization
  110. //
  111. rc = g_pwpContext->Initialize( argc, argv );
  112. if ( rc != NO_ERROR )
  113. {
  114. //
  115. // WP_CONTEXT::Initialize returns a Win32 error code
  116. //
  117. rc = HRESULT_FROM_WIN32( rc );
  118. goto Finished;
  119. }
  120. Finished:
  121. if ( rc != NO_ERROR )
  122. {
  123. if ( g_pwpContext != NULL )
  124. {
  125. delete g_pwpContext;
  126. g_pwpContext = NULL;
  127. }
  128. if ( fUlInit )
  129. {
  130. HttpTerminate(0, NULL);
  131. }
  132. if ( fThreadPoolInit )
  133. {
  134. ThreadPoolTerminate();
  135. }
  136. }
  137. return rc;
  138. }
  139. HRESULT
  140. UlAtqStartListen(
  141. VOID
  142. )
  143. /*++
  144. Routine Description:
  145. Begin listening for HTTP requests from UL. This call must happen only
  146. after ULATQ has been initialized correctly (for example, completion
  147. routines should be set).
  148. Arguments:
  149. None
  150. Return Value:
  151. HRESULT
  152. --*/
  153. {
  154. HRESULT hr = NO_ERROR;
  155. DBG_ASSERT( g_pfnIoCompletion != NULL );
  156. DBG_ASSERT( g_pfnNewRequest != NULL );
  157. //
  158. // Make some UlReceiveHttpRequest calls
  159. //
  160. hr = g_pwpContext->Start();
  161. if ( FAILED(hr) )
  162. {
  163. //
  164. // If we failed to start, we may outstanding requests to cleanup.
  165. //
  166. goto DoShutdown;
  167. }
  168. //
  169. // Send message to WAS that our initialization is complete
  170. //
  171. g_pwpContext->SendInitCompleteMessage( S_OK );
  172. //
  173. // Wait for shutdown because of WAS/request-count-max/etc.
  174. //
  175. g_pwpContext->RunMainThreadLoop();
  176. DoShutdown:
  177. //
  178. // Do stuff needed to stop listening for new requests
  179. //
  180. UL_NATIVE_REQUEST::StopListening();
  181. //
  182. // Before connection drain, allow the user to execute some code
  183. //
  184. if ( g_pfnOnShutdown != NULL )
  185. {
  186. g_pfnOnShutdown( g_pwpContext->QueryDoImmediateShutdown() );
  187. }
  188. //
  189. // Before we return, wait for outstanding requests to drain. This
  190. // prevents race before caller's shutdown and new requests coming in
  191. //
  192. g_pwpContext->CleanupOutstandingRequests();
  193. return hr;
  194. }
  195. VOID
  196. UlAtqTerminate(
  197. HRESULT hrToSend
  198. )
  199. /*++
  200. Routine Description:
  201. Terminate ULATQ
  202. Arguments:
  203. None
  204. Return Value:
  205. None
  206. --*/
  207. {
  208. if ( g_pwpContext != NULL )
  209. {
  210. if (FAILED(hrToSend))
  211. {
  212. g_pwpContext->SendInitCompleteMessage( hrToSend );
  213. }
  214. g_pwpContext->Terminate();
  215. delete g_pwpContext;
  216. g_pwpContext = NULL;
  217. }
  218. HttpTerminate(0, NULL);
  219. ThreadPoolTerminate();
  220. DELETE_DEBUG_PRINT_OBJECT();
  221. }
  222. VOID *
  223. UlAtqGetContextProperty(
  224. ULATQ_CONTEXT pContext,
  225. ULATQ_CONTEXT_PROPERTY_ID PropertyId
  226. )
  227. /*++
  228. Routine Description:
  229. Get the UL_HTTP_REQUEST from the ULATQ_CONTEXT
  230. Arguments:
  231. pContext - ULATQ_CONTEXT
  232. PropertyId - Property Id to set
  233. Return Value:
  234. The actual property
  235. --*/
  236. {
  237. switch (PropertyId)
  238. {
  239. case ULATQ_PROPERTY_HTTP_REQUEST:
  240. UL_NATIVE_REQUEST * pRequest;
  241. pRequest = (UL_NATIVE_REQUEST*) pContext;
  242. DBG_ASSERT( pRequest != NULL );
  243. return pRequest->QueryHttpRequest();
  244. case ULATQ_PROPERTY_APP_POOL_ID:
  245. return (VOID *)g_pwpContext->QueryConfig()->QueryAppPoolName();
  246. case ULATQ_PROPERTY_IS_COMMAND_LINE_LAUNCH:
  247. return (VOID *)!(g_pwpContext->QueryConfig()->QueryRegisterWithWAS());
  248. case ULATQ_PROPERTY_DO_CENTRAL_BINARY_LOGGING:
  249. return (VOID *)(DWORD_PTR)g_pwpContext->QueryConfig()->QueryDoCentralBinaryLogging();
  250. default:
  251. DBG_ASSERT(FALSE);
  252. }
  253. return NULL;
  254. }
  255. VOID
  256. UlAtqSetContextProperty(
  257. ULATQ_CONTEXT pContext,
  258. ULATQ_CONTEXT_PROPERTY_ID PropertyId,
  259. PVOID pvData
  260. )
  261. /*++
  262. Routine Description:
  263. Set a property of the ULATQ_CONTEXT
  264. Arguments:
  265. pContext - ULATQ_CONTEXT
  266. PropertyId - Property Id to set
  267. pvData - Data specific to the property being set
  268. Return Value:
  269. None
  270. --*/
  271. {
  272. UL_NATIVE_REQUEST * pRequest;
  273. pRequest = (UL_NATIVE_REQUEST*) pContext;
  274. DBG_ASSERT( pRequest != NULL );
  275. switch ( PropertyId )
  276. {
  277. case ULATQ_PROPERTY_COMPLETION_CONTEXT:
  278. pRequest->SetContext( pvData );
  279. break;
  280. default:
  281. DBG_ASSERT( FALSE );
  282. }
  283. }
  284. VOID
  285. UlAtqFreeContext(
  286. ULATQ_CONTEXT pContext
  287. )
  288. /*++
  289. Routine Description:
  290. Frees the ULATQ_CONTEXT so that it can be used to retrieve next request
  291. Arguments:
  292. pContext - ULATQ_CONTEXT
  293. Return Value:
  294. None
  295. --*/
  296. {
  297. UL_NATIVE_REQUEST * pRequest;
  298. pRequest = (UL_NATIVE_REQUEST*) pContext;
  299. DBG_ASSERT( pRequest != NULL );
  300. pRequest->ResetContext();
  301. }
  302. HRESULT
  303. UlAtqSendHttpResponse(
  304. ULATQ_CONTEXT pContext,
  305. BOOL fAsync,
  306. DWORD dwFlags,
  307. HTTP_RESPONSE * pResponse,
  308. HTTP_CACHE_POLICY * pCachePolicy,
  309. DWORD *pcbSent,
  310. HTTP_LOG_FIELDS_DATA *pUlLogData
  311. )
  312. /*++
  313. Routine Description:
  314. Send a response to the client
  315. Arguments:
  316. pContext - ULATQ_CONTEXT
  317. fAsync - Asynchronous or not?
  318. dwFlags - Response flags (like killing the connection)
  319. pResponse - UL_HTTP_RESPONSE to send
  320. pCachePolicy - Cache policy
  321. Return Value:
  322. Win32 Error
  323. --*/
  324. {
  325. UL_NATIVE_REQUEST * pRequest;
  326. pRequest = (UL_NATIVE_REQUEST*) pContext;
  327. DBG_ASSERT( pRequest != NULL );
  328. return pRequest->SendResponse( fAsync,
  329. dwFlags,
  330. pResponse,
  331. pCachePolicy,
  332. pcbSent,
  333. pUlLogData );
  334. }
  335. HRESULT
  336. UlAtqSendEntityBody(
  337. ULATQ_CONTEXT pContext,
  338. BOOL fAsync,
  339. DWORD dwFlags,
  340. USHORT cChunks,
  341. HTTP_DATA_CHUNK * pChunks,
  342. DWORD *pcbSent,
  343. HTTP_LOG_FIELDS_DATA *pUlLogData
  344. )
  345. /*++
  346. Routine Description:
  347. Send entity to the client
  348. Arguments:
  349. pContext - ULATQ_CONTEXT
  350. fAsync - Asynchronous or not?
  351. dwFlags - Response flags (like killing the connection)
  352. cChunks - Number of chunks in the response
  353. pChunks - Points to array of chunks
  354. Return Value:
  355. HRESULT
  356. --*/
  357. {
  358. UL_NATIVE_REQUEST * pRequest;
  359. pRequest = (UL_NATIVE_REQUEST*) pContext;
  360. DBG_ASSERT( pRequest != NULL );
  361. return pRequest->SendEntity( fAsync,
  362. dwFlags,
  363. cChunks,
  364. pChunks,
  365. pcbSent,
  366. pUlLogData );
  367. }
  368. HRESULT
  369. UlAtqReceiveEntityBody(
  370. ULATQ_CONTEXT pContext,
  371. BOOL fAsync,
  372. DWORD dwFlags,
  373. VOID * pBuffer,
  374. DWORD cbBuffer,
  375. DWORD * pBytesReceived
  376. )
  377. /*++
  378. Routine Description:
  379. Receive entity from the client
  380. Arguments:
  381. pContext - ULATQ_CONTEXT
  382. fAsync - Asynchronous or not?
  383. dwFlags - Response flags (like killing the connection)
  384. pBuffer - Buffer to store the data
  385. cbBuffer - The size of the receive buffer
  386. pBytesReceived - The number of bytes copied to the buffer upon return
  387. Return Value:
  388. HRESULT
  389. --*/
  390. {
  391. UL_NATIVE_REQUEST * pRequest;
  392. pRequest = (UL_NATIVE_REQUEST*) pContext;
  393. DBG_ASSERT( pRequest != NULL );
  394. return pRequest->ReceiveEntity( fAsync,
  395. dwFlags,
  396. pBuffer,
  397. cbBuffer,
  398. pBytesReceived);
  399. }
  400. HRESULT
  401. UlAtqWaitForDisconnect(
  402. HTTP_CONNECTION_ID connectionId,
  403. BOOL fAsync,
  404. PVOID pvContext,
  405. BOOL * pfAlreadyCompleted
  406. )
  407. /*++
  408. Routine Description:
  409. Used to wait for a connection to close.
  410. Arguments:
  411. connectionId - connection in question
  412. fAsync - should we wait asynchronously?
  413. pvContext - context to pass back on async disconnect wait
  414. Return Value:
  415. HRESULT
  416. --*/
  417. {
  418. UL_DISCONNECT_CONTEXT * pContext;
  419. ULONG Status;
  420. HRESULT hr = NO_ERROR;
  421. HANDLE hAsync;
  422. //
  423. // Allocate an async context which will be freed once the connection
  424. // has been closed
  425. //
  426. pContext = new UL_DISCONNECT_CONTEXT( pvContext );
  427. if ( pContext == NULL )
  428. {
  429. return HRESULT_FROM_WIN32( ERROR_NOT_ENOUGH_MEMORY );
  430. }
  431. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  432. pContext->ReferenceUlDisconnectContext();
  433. if ( hAsync != NULL )
  434. {
  435. //
  436. // Do the wait
  437. //
  438. Status = HttpWaitForDisconnect( hAsync,
  439. connectionId,
  440. fAsync ? &(pContext->_Overlapped) : NULL );
  441. }
  442. else
  443. {
  444. Status = ERROR_INVALID_HANDLE;
  445. }
  446. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  447. if ( pfAlreadyCompleted )
  448. {
  449. *pfAlreadyCompleted = HasOverlappedIoCompleted( &(pContext->_Overlapped) );
  450. }
  451. if ( Status != ERROR_IO_PENDING && Status != NO_ERROR )
  452. {
  453. hr = HRESULT_FROM_WIN32( Status );
  454. pContext->DereferenceUlDisconnectContext();
  455. }
  456. pContext->DereferenceUlDisconnectContext();
  457. return hr;
  458. }
  459. HRESULT
  460. UlAtqInduceShutdown(
  461. BOOL fImmediate
  462. )
  463. /*++
  464. Routine Description:
  465. Induce shutdown (used when IIS+ hosted in inetinfo.exe). Simulates
  466. WAS telling us to shutdown
  467. Arguments:
  468. None
  469. Return Value:
  470. HRESULT
  471. --*/
  472. {
  473. DBG_ASSERT( g_pwpContext != NULL );
  474. if ( !g_pwpContext->IndicateShutdown( fImmediate ) )
  475. {
  476. return HRESULT_FROM_WIN32( GetLastError() );
  477. }
  478. return NO_ERROR;
  479. }
  480. HRESULT
  481. UlAtqReceiveClientCertificate(
  482. ULATQ_CONTEXT pContext,
  483. BOOL fAsync,
  484. BOOL fDoCertMap,
  485. HTTP_SSL_CLIENT_CERT_INFO **ppClientCertInfo
  486. )
  487. /*++
  488. Routine Description:
  489. Receive client certificate
  490. Arguments:
  491. pContext - ULATQ context
  492. fAsync - TRUE if we should do it asynchronously
  493. fDoCertMap - Map client certificate to token
  494. ppClientCertInfo - Set to point to client cert on success
  495. Return Value:
  496. HRESULT
  497. --*/
  498. {
  499. UL_NATIVE_REQUEST * pRequest;
  500. pRequest = (UL_NATIVE_REQUEST*) pContext;
  501. DBG_ASSERT( pRequest != NULL );
  502. DBG_ASSERT( pRequest->CheckSignature() );
  503. return pRequest->ReceiveClientCertificate( fAsync,
  504. fDoCertMap,
  505. ppClientCertInfo );
  506. }
  507. HRESULT
  508. UlAtqFlushUlCache(
  509. WCHAR * pszUrlPrefix
  510. )
  511. /*++
  512. Routine Description:
  513. Flush the UL cache at the given URL prefix
  514. Arguments:
  515. pszUrlPrefix - UL prefix to flush
  516. Return Value:
  517. HRESULT
  518. --*/
  519. {
  520. HANDLE hAsync;
  521. if ( pszUrlPrefix == NULL )
  522. {
  523. DBG_ASSERT( FALSE );
  524. return HRESULT_FROM_WIN32( ERROR_INVALID_PARAMETER );
  525. }
  526. if ( g_pwpContext == NULL )
  527. {
  528. //
  529. // Before removing this assert, please think hard (and then
  530. // think again)
  531. //
  532. DBG_ASSERT( FALSE );
  533. return HRESULT_FROM_WIN32( ERROR_NOT_SUPPORTED );
  534. }
  535. //
  536. // The AppPool handle may already have been closed, eg during shutdown
  537. //
  538. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  539. if ( hAsync != NULL )
  540. {
  541. HttpFlushResponseCache( hAsync,
  542. pszUrlPrefix,
  543. 0,
  544. NULL );
  545. }
  546. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  547. //
  548. // Mask the error since we may be flushing URLs which aren't
  549. // in the cache (that's OK)
  550. //
  551. return NO_ERROR;
  552. }
  553. VOID
  554. UlAtqSetUnhealthy(
  555. VOID
  556. )
  557. /*++
  558. Routine Description:
  559. Marks the state of the process as unhealthy
  560. Arguments:
  561. None
  562. Return Value:
  563. None
  564. --*/
  565. {
  566. g_pwpContext->SetUnhealthy();
  567. }
  568. HRESULT
  569. UlAtqAddFragmentToCache(
  570. HTTP_DATA_CHUNK * pDataChunk,
  571. WCHAR * pszFragmentName
  572. )
  573. /*++
  574. Routine Description:
  575. Add the fragment to cache
  576. Arguments:
  577. pDataChunk - The chunk to be added
  578. pszFragmentName - name of the fragment
  579. Return Value:
  580. HRESULT
  581. --*/
  582. {
  583. DWORD err;
  584. HANDLE hAsync;
  585. HTTP_CACHE_POLICY cachePolicy = { HttpCachePolicyUserInvalidates, 0 };
  586. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  587. if ( hAsync != NULL )
  588. {
  589. err = HttpAddFragmentToCache( hAsync,
  590. pszFragmentName,
  591. pDataChunk,
  592. &cachePolicy,
  593. NULL );
  594. }
  595. else
  596. {
  597. err = ERROR_INVALID_HANDLE;
  598. }
  599. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  600. return HRESULT_FROM_WIN32(err);
  601. }
  602. HRESULT
  603. UlAtqReadFragmentFromCache(
  604. WCHAR * pszFragmentName,
  605. BYTE * pvBuffer,
  606. DWORD cbSize,
  607. DWORD * pcbCopied
  608. )
  609. /*++
  610. Routine Description:
  611. Read the fragment from cache
  612. Arguments:
  613. pszFragmentName - name of the fragment
  614. pvBuffer - the buffer to read in
  615. cbSize - the size of the buffer
  616. pcbCopied - the amount copied in on return
  617. Return Value:
  618. HRESULT
  619. --*/
  620. {
  621. DWORD err;
  622. HANDLE hAsync;
  623. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  624. if ( hAsync != NULL )
  625. {
  626. err = HttpReadFragmentFromCache( hAsync,
  627. pszFragmentName,
  628. NULL,
  629. pvBuffer,
  630. cbSize,
  631. pcbCopied,
  632. NULL);
  633. }
  634. else
  635. {
  636. err = ERROR_INVALID_HANDLE;
  637. }
  638. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  639. return HRESULT_FROM_WIN32(err);
  640. }
  641. HRESULT
  642. UlAtqRemoveFragmentFromCache(
  643. WCHAR * pszFragmentName
  644. )
  645. /*++
  646. Routine Description:
  647. Remove the fragment from cache
  648. Arguments:
  649. pszFragmentName - name of the fragment
  650. Return Value:
  651. HRESULT
  652. --*/
  653. {
  654. DWORD err;
  655. HANDLE hAsync;
  656. hAsync = g_pwpContext->GetAndLockAsyncHandle();
  657. if ( hAsync != NULL )
  658. {
  659. err = HttpFlushResponseCache( hAsync,
  660. pszFragmentName,
  661. 0,
  662. NULL);
  663. }
  664. else
  665. {
  666. err = ERROR_INVALID_HANDLE;
  667. }
  668. DBG_REQUIRE(SUCCEEDED(g_pwpContext->UnlockAsyncHandle()));
  669. return HRESULT_FROM_WIN32(err);
  670. }
  671. VOID *
  672. UlAtqAllocateMemory(
  673. ULATQ_CONTEXT pContext,
  674. DWORD cbSize
  675. )
  676. /*++
  677. Routine Description:
  678. Allocate some memory associated with the native request
  679. Arguments:
  680. pContext - ULATQ Context
  681. cbSize - Size to allocate
  682. Return Value:
  683. Pointer to memory or NULL if failed
  684. --*/
  685. {
  686. UL_NATIVE_REQUEST * pRequest;
  687. if ( pContext == NULL )
  688. {
  689. DBG_ASSERT( FALSE );
  690. SetLastError( ERROR_INVALID_PARAMETER );
  691. return NULL;
  692. }
  693. pRequest = (UL_NATIVE_REQUEST*) pContext;
  694. DBG_ASSERT( pRequest->CheckSignature() );
  695. return pRequest->AllocateMemory( cbSize );
  696. }