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.

4991 lines
120 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. apool.cxx
  5. Abstract:
  6. Note that most of the routines in this module assume they are called
  7. at PASSIVE_LEVEL.
  8. Author:
  9. Paul McDaniel (paulmcd) 28-Jan-1999
  10. Revision History:
  11. --*/
  12. #include "precomp.h" // project wide headers
  13. #include "apoolp.h" // private header
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text( INIT, UlInitializeAP )
  16. #pragma alloc_text( PAGE, UlTerminateAP )
  17. #pragma alloc_text( PAGE, UlAttachProcessToAppPool )
  18. #pragma alloc_text( PAGE, UlDeliverRequestToProcess )
  19. #if REFERENCE_DEBUG
  20. #pragma alloc_text( PAGE, UlDereferenceAppPool )
  21. #pragma alloc_text( PAGE, UlReferenceAppPool )
  22. #endif
  23. #pragma alloc_text( PAGE, UlDeleteAppPool )
  24. #pragma alloc_text( PAGE, UlGetPoolFromHandle )
  25. #pragma alloc_text( PAGE, UlQueryAppPoolInformation )
  26. #pragma alloc_text( PAGE, UlSetAppPoolInformation )
  27. #pragma alloc_text( PAGE, UlpSetAppPoolState )
  28. #pragma alloc_text( PAGE, UlWaitForDemandStart )
  29. #pragma alloc_text( PAGE, UlAppPoolObjectFromProcess )
  30. #pragma alloc_text( PAGE, UlLinkConfigGroupToAppPool )
  31. #pragma alloc_text( PAGE, UlpCancelDemandStartWorker )
  32. #pragma alloc_text( PAGE, UlpCancelHttpReceiveWorker )
  33. #pragma alloc_text( PAGE, UlpCopyRequestToIrp )
  34. #pragma alloc_text( PAGE, UlpCopyRequestToBuffer )
  35. #pragma alloc_text( PAGE, UlpPopNewIrp )
  36. #pragma alloc_text( PAGE, UlpIsProcessInAppPool )
  37. #pragma alloc_text( PAGE, UlpRedeliverRequestWorker )
  38. #pragma alloc_text( PAGE, UlpIsRequestQueueEmpty )
  39. #pragma alloc_text( PAGE, UlpSetAppPoolQueueLength )
  40. #pragma alloc_text( PAGE, UlpGetAppPoolQueueLength )
  41. #endif // ALLOC_PRAGMA
  42. #if 0
  43. NOT PAGEABLE -- UlDetachProcessFromAppPool
  44. NOT PAGEABLE -- UlReceiveHttpRequest
  45. NOT PAGEABLE -- UlUnlinkRequestFromProcess
  46. NOT PAGEABLE -- UlWaitForDisconnect
  47. NOT PAGEABLE -- UlpPopIrpFromProcess
  48. NOT PAGEABLE -- UlpQueuePendingRequest
  49. NOT PAGEABLE -- UlpQueueUnboundRequest
  50. NOT PAGEABLE -- UlpDequeueNewRequest
  51. NOT PAGEABLE -- UlpUnbindQueuedRequests
  52. NOT PAGEABLE -- UlCompleteAllWaitForDisconnect
  53. NOT PAGEABLE -- UlpCancelDemandStart
  54. NOT PAGEABLE -- UlpCancelHttpReceive
  55. NOT PAGEABLE -- UlpCancelWaitForDisconnect
  56. #endif
  57. //
  58. // Globals
  59. //
  60. LIST_ENTRY g_AppPoolListHead = {NULL,NULL};
  61. BOOLEAN g_InitAPCalled = FALSE;
  62. /***************************************************************************++
  63. Routine Description:
  64. creates a new process object and attaches it to an apool .
  65. called by handle create and returns the process object to attach to the
  66. handle.
  67. Arguments:
  68. pName - the name of the apool to attach to.
  69. NameLength - the byte count of pName.
  70. Create - whether or not a new apool should be created if pName does not
  71. exist.
  72. pAccessState -
  73. DesiredAccess -
  74. RequestorMode -
  75. ppProcess - returns the newly created PROCESS object.
  76. Return Value:
  77. NTSTATUS - Completion status.
  78. --***************************************************************************/
  79. NTSTATUS
  80. UlAttachProcessToAppPool(
  81. IN PWCHAR pName OPTIONAL,
  82. IN ULONG NameLength,
  83. IN BOOLEAN Create,
  84. IN PACCESS_STATE pAccessState,
  85. IN ACCESS_MASK DesiredAccess,
  86. IN KPROCESSOR_MODE RequestorMode,
  87. OUT PUL_APP_POOL_PROCESS * ppProcess
  88. )
  89. {
  90. NTSTATUS Status;
  91. PUL_APP_POOL_OBJECT pObject = NULL;
  92. PUL_APP_POOL_PROCESS pProcess = NULL;
  93. LIST_ENTRY * pEntry;
  94. //
  95. // Sanity check.
  96. //
  97. PAGED_CODE();
  98. ASSERT(ppProcess != NULL);
  99. Status = STATUS_SUCCESS;
  100. *ppProcess = NULL;
  101. //
  102. // try and find an existing app pool of this name
  103. //
  104. //
  105. // CODEWORK: try and grab the lock shared first then upgrade to
  106. // exclusive if we need to create.
  107. //
  108. // also potentially pre-allocate the memory.
  109. //
  110. //
  111. UlAcquireResourceExclusive(&g_pUlNonpagedData->AppPoolResource, TRUE);
  112. if (pName != NULL)
  113. {
  114. pEntry = g_AppPoolListHead.Flink;
  115. while (pEntry != &g_AppPoolListHead)
  116. {
  117. pObject = CONTAINING_RECORD(
  118. pEntry,
  119. UL_APP_POOL_OBJECT,
  120. ListEntry
  121. );
  122. if (pObject->NameLength == NameLength &&
  123. _wcsnicmp(pObject->pName, pName, NameLength/sizeof(WCHAR)) == 0)
  124. {
  125. //
  126. // match!
  127. //
  128. break;
  129. }
  130. pEntry = pEntry->Flink;
  131. }
  132. //
  133. // found 1?
  134. //
  135. if (pEntry == &g_AppPoolListHead)
  136. {
  137. pObject = NULL;
  138. }
  139. }
  140. //
  141. // Found 1?
  142. //
  143. if (pObject == NULL)
  144. {
  145. //
  146. // nope, allowed to create?
  147. //
  148. if (!Create)
  149. {
  150. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  151. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  152. goto end;
  153. }
  154. //
  155. // create it
  156. //
  157. //
  158. // allocate the object memory
  159. //
  160. pObject = UL_ALLOCATE_STRUCT_WITH_SPACE(
  161. NonPagedPoolCacheAligned,
  162. UL_APP_POOL_OBJECT,
  163. NameLength + sizeof(WCHAR),
  164. UL_APP_POOL_OBJECT_POOL_TAG
  165. );
  166. if (pObject == NULL)
  167. {
  168. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  169. Status = STATUS_NO_MEMORY;
  170. goto end;
  171. }
  172. RtlZeroMemory(
  173. pObject,
  174. NameLength + sizeof(WCHAR) +
  175. sizeof(UL_APP_POOL_OBJECT)
  176. );
  177. pObject->Signature = UL_APP_POOL_OBJECT_POOL_TAG;
  178. pObject->RefCount = 1;
  179. pObject->NameLength = NameLength;
  180. pObject->Enabled = HttpEnabledStateActive;
  181. InitializeListHead(&pObject->ProcessListHead);
  182. UlInitializeNotifyHead(
  183. &pObject->TransientHead,
  184. &g_pUlNonpagedData->ConfigGroupResource
  185. );
  186. Status = UlpInitRequestQueue(
  187. &pObject->NewRequestQueue,
  188. DEFAULT_APP_POOL_QUEUE_MAX
  189. );
  190. ASSERT(NT_SUCCESS(Status)); // default size can't be invalid.
  191. UlInitializeSpinLock(&pObject->QueueSpinLock, "QueueSpinLock");
  192. //
  193. // allocate the resource for sync
  194. //
  195. pObject->pResource = UlResourceNew(UL_APP_POOL_OBJECT_POOL_TAG);
  196. if (pObject->pResource == NULL)
  197. {
  198. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  199. Status = STATUS_NO_MEMORY;
  200. goto end;
  201. }
  202. if (pName != NULL)
  203. {
  204. RtlCopyMemory(
  205. pObject->pName,
  206. pName,
  207. NameLength + sizeof(WCHAR)
  208. );
  209. }
  210. //
  211. // Set the security descriptor.
  212. //
  213. Status = UlAssignSecurity(
  214. &pObject->pSecurityDescriptor,
  215. pAccessState
  216. );
  217. if (!NT_SUCCESS(Status))
  218. {
  219. goto end;
  220. }
  221. //
  222. // Insert it into the global list
  223. //
  224. InsertHeadList(&g_AppPoolListHead, &pObject->ListEntry);
  225. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  226. UlTrace(
  227. REFCOUNT,
  228. ("ul!UlAttachProcessToAppPool ap=%p refcount=%d\n",
  229. pObject,
  230. pObject->RefCount)
  231. );
  232. }
  233. else // if (pObject == NULL)
  234. {
  235. //
  236. // reference it
  237. //
  238. REFERENCE_APP_POOL( pObject );
  239. //
  240. // let the lock go
  241. //
  242. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  243. //
  244. // we found one. were we trying to create?
  245. //
  246. if (Create)
  247. {
  248. Status = STATUS_OBJECT_NAME_COLLISION;
  249. goto end;
  250. }
  251. //
  252. // Perform an access check against the app pool.
  253. //
  254. Status = UlAccessCheck(
  255. pObject->pSecurityDescriptor,
  256. pAccessState,
  257. DesiredAccess,
  258. RequestorMode,
  259. pName
  260. );
  261. if (!NT_SUCCESS(Status))
  262. {
  263. goto end;
  264. }
  265. }
  266. //
  267. // Create a process entry for it
  268. //
  269. pProcess = UlCreateAppPoolProcess(pObject);
  270. if (pProcess == NULL)
  271. {
  272. Status = STATUS_NO_MEMORY;
  273. goto end;
  274. }
  275. //
  276. // put it in the app pool list
  277. //
  278. UlAcquireResourceExclusive(&pObject->pResource->Resource, TRUE);
  279. if (DesiredAccess & WRITE_OWNER)
  280. {
  281. pProcess->Controller = 1;
  282. }
  283. else
  284. {
  285. pObject->NumberActiveProcesses++;
  286. }
  287. InsertHeadList(&pObject->ProcessListHead, &pProcess->ListEntry);
  288. UlReleaseResource(&pObject->pResource->Resource);
  289. //
  290. // Return it
  291. //
  292. *ppProcess = pProcess;
  293. end:
  294. if (NT_SUCCESS(Status) == FALSE)
  295. {
  296. if (pObject != NULL)
  297. {
  298. DEREFERENCE_APP_POOL(pObject);
  299. pObject = NULL;
  300. }
  301. if (pProcess != NULL)
  302. {
  303. UL_FREE_POOL_WITH_SIG(pProcess, UL_APP_POOL_PROCESS_POOL_TAG);
  304. }
  305. }
  306. return Status;
  307. }
  308. /***************************************************************************++
  309. Routine Description:
  310. this is called by UlCleanup when the handle count goes to 0. it removes
  311. the PROCESS object from the apool, cancelling all i/o .
  312. Arguments:
  313. pProcess - the process to detach.
  314. Return Value:
  315. NTSTATUS - Completion status.
  316. --***************************************************************************/
  317. NTSTATUS
  318. UlDetachProcessFromAppPool(
  319. IN PUL_APP_POOL_PROCESS pProcess
  320. )
  321. {
  322. LIST_ENTRY PendingRequestHead;
  323. PUL_APP_POOL_OBJECT pAppPool;
  324. NTSTATUS CancelStatus = STATUS_CANCELLED;
  325. PUL_INTERNAL_REQUEST pRequest;
  326. KLOCK_QUEUE_HANDLE LockHandle;
  327. UlTrace(ROUTING, (
  328. "ul!UlDetachProcessFromAppPool(%p, %S)\n",
  329. pProcess,
  330. pProcess->pAppPool->pName
  331. ));
  332. //
  333. // Sanity check.
  334. //
  335. PAGED_CODE();
  336. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  337. pAppPool = pProcess->pAppPool;
  338. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  339. UlAcquireResourceExclusive(&pAppPool->pResource->Resource, TRUE);
  340. //
  341. // Mark the process as InCleanup so new I/O won't be attached
  342. //
  343. ASSERT( !pProcess->InCleanup );
  344. pProcess->InCleanup = 1;
  345. //
  346. // Unlink from the App Pool list.
  347. //
  348. RemoveEntryList(&pProcess->ListEntry);
  349. pProcess->ListEntry.Flink = pProcess->ListEntry.Blink = NULL;
  350. //
  351. // Kill our transient URL bindings
  352. //
  353. UlNotifyAllEntries(
  354. UlNotifyOrphanedConfigGroup,
  355. &pProcess->pAppPool->TransientHead,
  356. NULL
  357. );
  358. //
  359. // cancel any pending io.
  360. //
  361. if (pAppPool->pDemandStartIrp != NULL &&
  362. pAppPool->pDemandStartProcess == PsGetCurrentProcess())
  363. {
  364. if (IoSetCancelRoutine(pAppPool->pDemandStartIrp, NULL) == NULL)
  365. {
  366. //
  367. // IoCancelIrp pop'd it first
  368. //
  369. // ok to just ignore this irp, it's been pop'd off the queue
  370. // and will be completed in the cancel routine.
  371. //
  372. // no need to complete it
  373. //
  374. }
  375. else
  376. {
  377. IoGetCurrentIrpStackLocation(
  378. pAppPool->pDemandStartIrp
  379. )->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  380. pAppPool->pDemandStartIrp->IoStatus.Status = STATUS_CANCELLED;
  381. pAppPool->pDemandStartIrp->IoStatus.Information = 0;
  382. UlCompleteRequest(pAppPool->pDemandStartIrp, g_UlPriorityBoost);
  383. }
  384. pAppPool->pDemandStartIrp = NULL;
  385. pAppPool->pDemandStartProcess = NULL;
  386. }
  387. while (IsListEmpty(&pProcess->NewIrpHead) == FALSE)
  388. {
  389. PLIST_ENTRY pEntry;
  390. PIRP pIrp;
  391. //
  392. // Pop it off the list.
  393. //
  394. pEntry = RemoveHeadList(&pProcess->NewIrpHead);
  395. pEntry->Blink = pEntry->Flink = NULL;
  396. pIrp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
  397. ASSERT(IS_VALID_IRP(pIrp));
  398. //
  399. // pop the cancel routine
  400. //
  401. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  402. {
  403. //
  404. // IoCancelIrp pop'd it first
  405. //
  406. // ok to just ignore this irp, it's been pop'd off the queue
  407. // and will be completed in the cancel routine.
  408. //
  409. // keep looping
  410. //
  411. pIrp = NULL;
  412. }
  413. else
  414. {
  415. PUL_APP_POOL_OBJECT pProcessAppPool;
  416. //
  417. // cancel it. even if pIrp->Cancel == TRUE we are supposed to
  418. // complete it, our cancel routine will never run.
  419. //
  420. pProcessAppPool = (PUL_APP_POOL_OBJECT)(
  421. IoGetCurrentIrpStackLocation(pIrp)->
  422. Parameters.DeviceIoControl.Type3InputBuffer
  423. );
  424. ASSERT(pProcessAppPool == pAppPool);
  425. DEREFERENCE_APP_POOL(pProcessAppPool);
  426. IoGetCurrentIrpStackLocation(pIrp)->
  427. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  428. pIrp->IoStatus.Status = STATUS_CANCELLED;
  429. pIrp->IoStatus.Information = 0;
  430. UlCompleteRequest(pIrp, g_UlPriorityBoost);
  431. pIrp = NULL;
  432. }
  433. }
  434. //
  435. // cancel I/O and move requests to local list
  436. //
  437. InitializeListHead(&PendingRequestHead);
  438. UlAcquireInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  439. while (pRequest = UlpDequeueRequest(&pProcess->PendingRequestQueue))
  440. {
  441. //
  442. // move the entry to local list so we can close its
  443. // connection outside the app pool lock
  444. //
  445. InsertTailList(&PendingRequestHead, &pRequest->AppPool.AppPoolEntry);
  446. }
  447. UlReleaseInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  448. //
  449. // tank any queued new requests
  450. //
  451. UlpUnbindQueuedRequests(pProcess);
  452. //
  453. // adjust number of active processes
  454. //
  455. if (!pProcess->Controller)
  456. {
  457. pAppPool->NumberActiveProcesses--;
  458. }
  459. UlReleaseResource(&pAppPool->pResource->Resource);
  460. //
  461. // close connections associated with the requests
  462. //
  463. while ( !IsListEmpty(&PendingRequestHead) )
  464. {
  465. PLIST_ENTRY pEntry;
  466. PUL_INTERNAL_REQUEST pRequest;
  467. NTSTATUS Status;
  468. pEntry = RemoveHeadList(&PendingRequestHead);
  469. pEntry->Flink = pEntry->Blink = NULL;
  470. pRequest = CONTAINING_RECORD(
  471. pEntry,
  472. UL_INTERNAL_REQUEST,
  473. AppPool.AppPoolEntry
  474. );
  475. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  476. UlTrace(ROUTING, (
  477. "ul!UlDetachProcessFromAppPool(%p, %S): tanking pending req=%p\n",
  478. pProcess,
  479. pAppPool->pName,
  480. pRequest
  481. ));
  482. //
  483. // cancel any pending io
  484. //
  485. UlAcquireResourceExclusive(&(pRequest->pHttpConn->Resource), TRUE);
  486. UlCancelRequestIo(pRequest);
  487. UlReleaseResource(&(pRequest->pHttpConn->Resource));
  488. //
  489. // abort the connection this request is associated with
  490. //
  491. Status = UlCloseConnection(
  492. pRequest->pHttpConn->pConnection,
  493. TRUE,
  494. NULL,
  495. NULL
  496. );
  497. CHECK_STATUS(Status);
  498. //
  499. // drop our list's reference
  500. //
  501. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  502. }
  503. ASSERT( IsListEmpty(&PendingRequestHead) );
  504. //
  505. // Cancel any remaining WaitForDisconnect IRPs
  506. //
  507. UlAcquireResourceExclusive( &g_pUlNonpagedData->DisconnectResource, TRUE );
  508. UlNotifyAllEntries(
  509. UlpNotifyCompleteWaitForDisconnect,
  510. &pProcess->WaitForDisconnectHead,
  511. &CancelStatus
  512. );
  513. UlReleaseResource( &g_pUlNonpagedData->DisconnectResource );
  514. //
  515. // Dereference
  516. //
  517. DEREFERENCE_APP_POOL(pAppPool);
  518. //
  519. // Kill any cache entries related to this process
  520. //
  521. UlFlushCacheByProcess(pProcess);
  522. return STATUS_SUCCESS;
  523. }
  524. #if REFERENCE_DEBUG
  525. /***************************************************************************++
  526. Routine Description:
  527. increments the refcount.
  528. Arguments:
  529. pAppPool - the object to increment.
  530. Return Value:
  531. NTSTATUS - Completion status.
  532. --***************************************************************************/
  533. VOID
  534. UlReferenceAppPool(
  535. IN PUL_APP_POOL_OBJECT pAppPool
  536. REFERENCE_DEBUG_FORMAL_PARAMS
  537. )
  538. {
  539. LONG refCount;
  540. //
  541. // Sanity check.
  542. //
  543. PAGED_CODE();
  544. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  545. refCount = InterlockedIncrement( &pAppPool->RefCount );
  546. WRITE_REF_TRACE_LOG(
  547. g_pAppPoolTraceLog,
  548. REF_ACTION_REFERENCE_APP_POOL,
  549. refCount,
  550. pAppPool,
  551. pFileName,
  552. LineNumber
  553. );
  554. UlTrace(
  555. REFCOUNT,
  556. ("ul!UlReferenceAppPool ap=%p refcount=%d\n",
  557. pAppPool,
  558. refCount)
  559. );
  560. } // UlReferenceAppPool
  561. /***************************************************************************++
  562. Routine Description:
  563. decrements the refcount. if it hits 0, destruct's the apool, cancelling
  564. all i/o and dumping all queued requests.
  565. Arguments:
  566. pAppPool - the object to decrement.
  567. Return Value:
  568. NTSTATUS - Completion status.
  569. --***************************************************************************/
  570. VOID
  571. UlDereferenceAppPool(
  572. IN PUL_APP_POOL_OBJECT pAppPool
  573. REFERENCE_DEBUG_FORMAL_PARAMS
  574. )
  575. {
  576. LONG refCount;
  577. NTSTATUS Status;
  578. //
  579. // Sanity check.
  580. //
  581. PAGED_CODE();
  582. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  583. refCount = InterlockedDecrement( &pAppPool->RefCount );
  584. //
  585. // Tracing.
  586. //
  587. WRITE_REF_TRACE_LOG(
  588. g_pAppPoolTraceLog,
  589. REF_ACTION_DEREFERENCE_APP_POOL,
  590. refCount,
  591. pAppPool,
  592. pFileName,
  593. LineNumber
  594. );
  595. UlTrace(
  596. REFCOUNT,
  597. ("ul!UlDereferenceAppPool ap=%p refcount=%d\n",
  598. pAppPool,
  599. refCount)
  600. );
  601. //
  602. // Clean up if necessary.
  603. //
  604. if (refCount == 0)
  605. {
  606. DELETE_APP_POOL(pAppPool);
  607. }
  608. } // UlDereferenceAppPool
  609. #endif
  610. /***************************************************************************++
  611. Routine Description:
  612. decrements the refcount. if it hits 0, destruct's the apool, cancelling
  613. all i/o and dumping all queued requests.
  614. Arguments:
  615. pAppPool - the object to decrement.
  616. Return Value:
  617. NTSTATUS - Completion status.
  618. --***************************************************************************/
  619. VOID
  620. UlDeleteAppPool(
  621. IN PUL_APP_POOL_OBJECT pAppPool
  622. REFERENCE_DEBUG_FORMAL_PARAMS
  623. )
  624. {
  625. PUL_INTERNAL_REQUEST pRequest;
  626. UlAcquireResourceExclusive(&g_pUlNonpagedData->AppPoolResource, TRUE);
  627. RemoveEntryList(&pAppPool->ListEntry);
  628. pAppPool->ListEntry.Flink = pAppPool->ListEntry.Blink = NULL;
  629. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  630. ASSERT( UlDbgResourceUnownedExclusive( &pAppPool->pResource->Resource ) );
  631. //
  632. // there better not be any process objects hanging around
  633. //
  634. ASSERT(IsListEmpty(&pAppPool->ProcessListHead));
  635. //
  636. // there should not be any transient bindings around
  637. //
  638. ASSERT(IsListEmpty(&pAppPool->TransientHead.ListHead));
  639. //
  640. // tank any pending reqeusts
  641. //
  642. //
  643. // CODEWORK, BUGBUG: need to close the connection ?
  644. //
  645. while (pRequest = UlpDequeueRequest(&pAppPool->NewRequestQueue))
  646. {
  647. //
  648. // mark it as unlinked and undo references
  649. //
  650. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  651. }
  652. //
  653. // Cleanup any security descriptor on the object.
  654. //
  655. UlDeassignSecurity( &pAppPool->pSecurityDescriptor );
  656. //
  657. // delete the resource
  658. //
  659. DEREFERENCE_RESOURCE( pAppPool->pResource );
  660. pAppPool->pResource = NULL;
  661. // CODEWORK: is this code right?
  662. UL_FREE_POOL_WITH_SIG(pAppPool, UL_APP_POOL_OBJECT_POOL_TAG);
  663. } // UlDeleteAppPool
  664. /***************************************************************************++
  665. Routine Description:
  666. Queries the app-pool queue length. If the supplied output buffer is NULL
  667. the required length is returned in the optional length argument.
  668. Arguments:
  669. Return Value:
  670. NTSTATUS - Completion status.
  671. --***************************************************************************/
  672. NTSTATUS
  673. UlQueryAppPoolInformation(
  674. IN PUL_APP_POOL_PROCESS pProcess,
  675. IN HTTP_APP_POOL_INFORMATION_CLASS InformationClass,
  676. OUT PVOID pAppPoolInformation,
  677. IN ULONG Length,
  678. OUT PULONG pReturnLength OPTIONAL
  679. )
  680. {
  681. NTSTATUS Status = STATUS_SUCCESS;
  682. //
  683. // Sanity check.
  684. //
  685. PAGED_CODE();
  686. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  687. //
  688. // This shouldn't happen, but just in case
  689. //
  690. if (!IS_VALID_AP_PROCESS(pProcess))
  691. {
  692. return STATUS_INVALID_PARAMETER;
  693. }
  694. //
  695. // Do the action
  696. //
  697. switch (InformationClass)
  698. {
  699. case HttpAppPoolDemandStartInformation:
  700. case HttpAppPoolDemandStartFlagInformation:
  701. Status = STATUS_NOT_IMPLEMENTED;
  702. break;
  703. case HttpAppPoolQueueLengthInformation:
  704. if (pAppPoolInformation == NULL)
  705. {
  706. //
  707. // Return the size needed
  708. //
  709. *pReturnLength = sizeof(LONG);
  710. }
  711. //
  712. // check the size of the buffer
  713. //
  714. else if (Length >= sizeof(LONG))
  715. {
  716. //
  717. // Get the request queue length
  718. //
  719. *((PLONG)pAppPoolInformation) = UlpGetAppPoolQueueLength(pProcess);
  720. *pReturnLength = sizeof(LONG);
  721. }
  722. else
  723. {
  724. Status = STATUS_BUFFER_TOO_SMALL;
  725. }
  726. break;
  727. case HttpAppPoolStateInformation:
  728. if (pAppPoolInformation == NULL)
  729. {
  730. //
  731. // Return the size needed
  732. //
  733. *pReturnLength = sizeof(HTTP_ENABLED_STATE);
  734. }
  735. else if (Length < sizeof(HTTP_ENABLED_STATE))
  736. {
  737. Status = STATUS_BUFFER_TOO_SMALL;
  738. }
  739. else
  740. {
  741. PHTTP_ENABLED_STATE pCurrentState =
  742. ((PHTTP_ENABLED_STATE) pAppPoolInformation);
  743. PUL_APP_POOL_OBJECT pAppPool = pProcess->pAppPool;
  744. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  745. *pCurrentState = pAppPool->Enabled;
  746. *pReturnLength = sizeof(HTTP_ENABLED_STATE);
  747. }
  748. break;
  749. default:
  750. // should have been caught in UlQueryAppPoolInformationIoctl
  751. ASSERT(FALSE);
  752. Status = STATUS_INVALID_PARAMETER;
  753. break;
  754. }
  755. return Status;
  756. } // UlQueryAppPoolInformation
  757. /***************************************************************************++
  758. Routine Description:
  759. Arguments:
  760. Return Value:
  761. NTSTATUS - Completion status.
  762. --***************************************************************************/
  763. NTSTATUS
  764. UlSetAppPoolInformation(
  765. IN PUL_APP_POOL_PROCESS pProcess,
  766. IN HTTP_APP_POOL_INFORMATION_CLASS InformationClass,
  767. IN PVOID pAppPoolInformation,
  768. IN ULONG Length
  769. )
  770. {
  771. NTSTATUS Status = STATUS_SUCCESS;
  772. //
  773. // Sanity check.
  774. //
  775. PAGED_CODE();
  776. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  777. //
  778. // check parameters
  779. //
  780. // this shouldn't happen, but just in case
  781. if (!IS_VALID_AP_PROCESS(pProcess)) {
  782. return STATUS_INVALID_PARAMETER;
  783. }
  784. if (!pAppPoolInformation) {
  785. return STATUS_INVALID_PARAMETER;
  786. }
  787. //
  788. // Do the action
  789. //
  790. switch (InformationClass)
  791. {
  792. case HttpAppPoolDemandStartInformation:
  793. case HttpAppPoolDemandStartFlagInformation:
  794. Status = STATUS_NOT_IMPLEMENTED;
  795. break;
  796. case HttpAppPoolQueueLengthInformation:
  797. //
  798. // check the size of the buffer
  799. //
  800. if (Length >= sizeof(LONG))
  801. {
  802. PLONG pQueueLength = (PLONG) pAppPoolInformation;
  803. //
  804. // Set the max incoming request queue length
  805. //
  806. Status = UlpSetAppPoolQueueLength(pProcess, * pQueueLength);
  807. } else {
  808. Status = STATUS_INVALID_PARAMETER;
  809. }
  810. break;
  811. case HttpAppPoolStateInformation:
  812. if (Length < sizeof(HTTP_ENABLED_STATE))
  813. {
  814. Status = STATUS_INVALID_PARAMETER;
  815. }
  816. else
  817. {
  818. HTTP_ENABLED_STATE NewState =
  819. *((PHTTP_ENABLED_STATE) pAppPoolInformation);
  820. if ((NewState != HttpEnabledStateActive)
  821. && (NewState != HttpEnabledStateInactive))
  822. {
  823. Status = STATUS_INVALID_PARAMETER;
  824. }
  825. else
  826. {
  827. UlpSetAppPoolState(pProcess, NewState);
  828. }
  829. }
  830. break;
  831. default:
  832. // should have been caught in UlSetAppPoolInformationIoctl
  833. ASSERT(FALSE);
  834. Status = STATUS_INVALID_PARAMETER;
  835. break;
  836. }
  837. return Status;
  838. } // UlSetAppPoolInformation
  839. /***************************************************************************++
  840. Routine Description:
  841. Marks an app pool as active or inactive. If setting to inactive,
  842. will return immediately 503 on all requests queued to app pool.
  843. Arguments:
  844. pProcess - the app pool process object with which the irp is associated.
  845. Enabled - mark app pool as active or inactive
  846. Return Value:
  847. NTSTATUS
  848. --***************************************************************************/
  849. NTSTATUS
  850. UlpSetAppPoolState(
  851. IN PUL_APP_POOL_PROCESS pProcess,
  852. IN HTTP_ENABLED_STATE Enabled
  853. )
  854. {
  855. NTSTATUS Status = STATUS_SUCCESS;
  856. PUL_APP_POOL_OBJECT pAppPool;
  857. LIST_ENTRY RequestQueueHead;
  858. KLOCK_QUEUE_HANDLE LockHandle;
  859. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  860. pAppPool = pProcess->pAppPool;
  861. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  862. UlTrace(ROUTING, (
  863. "http!UlpSetAppPoolState(AppPool=%p, %lu).\n",
  864. pAppPool, (ULONG) Enabled
  865. ));
  866. InitializeListHead(&RequestQueueHead);
  867. UlAcquireResourceExclusive(&pAppPool->pResource->Resource, TRUE);
  868. pAppPool->Enabled = Enabled;
  869. if (Enabled == HttpEnabledStateInactive)
  870. {
  871. // Make a copy of the app pool's new request queue
  872. if (IsListEmpty(&pAppPool->NewRequestQueue.RequestHead))
  873. {
  874. ASSERT(pAppPool->NewRequestQueue.RequestCount == 0);
  875. }
  876. else
  877. {
  878. RequestQueueHead.Flink
  879. = pAppPool->NewRequestQueue.RequestHead.Flink;
  880. RequestQueueHead.Blink
  881. = pAppPool->NewRequestQueue.RequestHead.Blink;
  882. RequestQueueHead.Blink->Flink = &RequestQueueHead;
  883. RequestQueueHead.Flink->Blink = &RequestQueueHead;
  884. ASSERT(pAppPool->NewRequestQueue.RequestCount > 0);
  885. // Now zap the app pool's new request queue
  886. InitializeListHead(&pAppPool->NewRequestQueue.RequestHead);
  887. pAppPool->NewRequestQueue.RequestCount = 0;
  888. }
  889. }
  890. UlReleaseResource(&pAppPool->pResource->Resource);
  891. // CODEWORK: need to check Enabled flag elsewhere?
  892. // Destroy the list outside of the app pool lock
  893. if (Enabled == HttpEnabledStateInactive)
  894. {
  895. ULONG cRequests = 0;
  896. while (! IsListEmpty(&RequestQueueHead))
  897. {
  898. PUL_INTERNAL_REQUEST pRequest
  899. = CONTAINING_RECORD(
  900. RequestQueueHead.Flink,
  901. UL_INTERNAL_REQUEST,
  902. AppPool.AppPoolEntry
  903. );
  904. PUL_HTTP_CONNECTION pHttpConn = pRequest->pHttpConn;
  905. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  906. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConn));
  907. UlAcquireInStackQueuedSpinLock(
  908. &pAppPool->QueueSpinLock,
  909. &LockHandle
  910. );
  911. RemoveEntryList(&pRequest->AppPool.AppPoolEntry);
  912. pRequest->AppPool.AppPoolEntry.Flink =
  913. pRequest->AppPool.AppPoolEntry.Blink = NULL;
  914. pRequest->AppPool.QueueState = QueueUnlinkedState;
  915. pRequest->ErrorCode = UlErrorUnavailable; // 503
  916. UlReleaseInStackQueuedSpinLock(
  917. &pAppPool->QueueSpinLock,
  918. &LockHandle
  919. );
  920. UlAcquireResourceExclusive(&pHttpConn->Resource, TRUE);
  921. UlSendErrorResponse(pHttpConn);
  922. UlReleaseResource(&pHttpConn->Resource);
  923. // CODEWORK: Need to call UlCancelRequestIo()
  924. // or UlCloseConnection()?
  925. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  926. ++cRequests;
  927. }
  928. UlTrace(ROUTING, (
  929. "%lu unhandled requests 503'd from AppPool %p.\n",
  930. cRequests, pAppPool
  931. ));
  932. }
  933. ASSERT(IsListEmpty(&RequestQueueHead));
  934. return Status;
  935. } // UlpSetAppPoolState
  936. /***************************************************************************++
  937. Routine Description:
  938. associates an irp with the apool that will be completed prior to any
  939. requests being queued.
  940. Arguments:
  941. pProcess - the process object that is queueing this irp
  942. pIrp - the irp to associate.
  943. Return Value:
  944. NTSTATUS - Completion status.
  945. --***************************************************************************/
  946. NTSTATUS
  947. UlWaitForDemandStart(
  948. IN PUL_APP_POOL_PROCESS pProcess,
  949. IN PIRP pIrp
  950. )
  951. {
  952. NTSTATUS Status;
  953. PIO_STACK_LOCATION pIrpSp;
  954. //
  955. // Sanity check.
  956. //
  957. PAGED_CODE();
  958. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  959. ASSERT(IS_VALID_AP_OBJECT(pProcess->pAppPool));
  960. ASSERT(pIrp != NULL);
  961. UlAcquireResourceExclusive(&pProcess->pAppPool->pResource->Resource, TRUE);
  962. //
  963. // Make sure we're not cleaning up the process
  964. //
  965. if (pProcess->InCleanup) {
  966. Status = STATUS_INVALID_HANDLE;
  967. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  968. goto end;
  969. }
  970. //
  971. // already got one?
  972. //
  973. if (pProcess->pAppPool->pDemandStartIrp != NULL)
  974. {
  975. Status = STATUS_OBJECT_NAME_COLLISION;
  976. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  977. goto end;
  978. }
  979. //
  980. // anything waiting in the queue?
  981. //
  982. if (UlpIsRequestQueueEmpty(pProcess))
  983. {
  984. //
  985. // nope, pend the irp
  986. //
  987. IoMarkIrpPending(pIrp);
  988. //
  989. // give the irp a pointer to the app pool
  990. //
  991. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  992. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pProcess->pAppPool;
  993. //
  994. // the cancel routine better not see an irp if it runs immediately
  995. //
  996. ASSERT(pProcess->pAppPool->pDemandStartIrp == NULL);
  997. IoSetCancelRoutine(pIrp, &UlpCancelDemandStart);
  998. //
  999. // cancelled?
  1000. //
  1001. if (pIrp->Cancel)
  1002. {
  1003. //
  1004. // darn it, need to make sure the irp get's completed
  1005. //
  1006. if (IoSetCancelRoutine( pIrp, NULL ) != NULL)
  1007. {
  1008. //
  1009. // we are in charge of completion, IoCancelIrp didn't
  1010. // see our cancel routine (and won't). ioctl wrapper
  1011. // will complete it
  1012. //
  1013. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1014. pIrp->IoStatus.Information = 0;
  1015. UlUnmarkIrpPending( pIrp );
  1016. Status = STATUS_CANCELLED;
  1017. goto end;
  1018. }
  1019. //
  1020. // our cancel routine will run and complete the irp,
  1021. // don't touch it
  1022. //
  1023. //
  1024. // STATUS_PENDING will cause the ioctl wrapper to
  1025. // not complete (or touch in any way) the irp
  1026. //
  1027. Status = STATUS_PENDING;
  1028. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1029. goto end;
  1030. }
  1031. //
  1032. // now we are safe to queue it
  1033. //
  1034. pProcess->pAppPool->pDemandStartIrp = pIrp;
  1035. pProcess->pAppPool->pDemandStartProcess = PsGetCurrentProcess();
  1036. Status = STATUS_PENDING;
  1037. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1038. goto end;
  1039. }
  1040. else
  1041. {
  1042. //
  1043. // something's in the queue, instant demand start
  1044. //
  1045. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1046. IoMarkIrpPending(pIrp);
  1047. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1048. UlCompleteRequest( pIrp, g_UlPriorityBoost );
  1049. Status = STATUS_PENDING;
  1050. goto end;
  1051. }
  1052. end:
  1053. return Status;
  1054. } // UlWaitForDemandStart
  1055. /***************************************************************************++
  1056. Routine Description:
  1057. receives a new http request into pIrp.
  1058. Arguments:
  1059. RequestId - NULL for new requests, non-NULL for a specific request,
  1060. which must be on the special queue.
  1061. Flags - ignored
  1062. pProcess - the process that wants the request
  1063. pIrp - the irp to receive the request
  1064. Return Value:
  1065. NTSTATUS - Completion status.
  1066. --***************************************************************************/
  1067. NTSTATUS
  1068. UlReceiveHttpRequest(
  1069. IN HTTP_REQUEST_ID RequestId,
  1070. IN ULONG Flags,
  1071. IN PUL_APP_POOL_PROCESS pProcess,
  1072. IN PIRP pIrp
  1073. )
  1074. {
  1075. NTSTATUS Status;
  1076. PUL_INTERNAL_REQUEST pRequest = NULL;
  1077. //
  1078. // Sanity check.
  1079. //
  1080. PAGED_CODE();
  1081. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  1082. ASSERT(IS_VALID_AP_OBJECT(pProcess->pAppPool));
  1083. ASSERT(pIrp != NULL);
  1084. UlAcquireResourceShared(&pProcess->pAppPool->pResource->Resource, TRUE);
  1085. //
  1086. // Make sure we're not cleaning up the process
  1087. //
  1088. if (pProcess->InCleanup) {
  1089. Status = STATUS_INVALID_HANDLE;
  1090. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1091. goto end;
  1092. }
  1093. //
  1094. // Is this for a new request?
  1095. //
  1096. if (HTTP_IS_NULL_ID(&RequestId))
  1097. {
  1098. //
  1099. // Do we have a queue'd new request?
  1100. //
  1101. pRequest = UlpDequeueNewRequest(pProcess);
  1102. if (pRequest == NULL)
  1103. {
  1104. PIO_STACK_LOCATION pIrpSp;
  1105. //
  1106. // Nope, queue the irp up.
  1107. //
  1108. IoMarkIrpPending(pIrp);
  1109. //
  1110. // give the irp a pointer to the app pool
  1111. //
  1112. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1113. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pProcess->pAppPool;
  1114. REFERENCE_APP_POOL(pProcess->pAppPool);
  1115. //
  1116. // set to these to null just in case the cancel routine runs
  1117. //
  1118. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  1119. pIrp->Tail.Overlay.ListEntry.Blink = NULL;
  1120. IoSetCancelRoutine(pIrp, &UlpCancelHttpReceive);
  1121. //
  1122. // cancelled?
  1123. //
  1124. if (pIrp->Cancel)
  1125. {
  1126. //
  1127. // darn it, need to make sure the irp get's completed
  1128. //
  1129. if (IoSetCancelRoutine( pIrp, NULL ) != NULL)
  1130. {
  1131. //
  1132. // we are in charge of completion, IoCancelIrp didn't
  1133. // see our cancel routine (and won't). ioctl wrapper
  1134. // will complete it
  1135. //
  1136. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1137. DEREFERENCE_APP_POOL(pProcess->pAppPool);
  1138. pIrp->IoStatus.Information = 0;
  1139. UlUnmarkIrpPending( pIrp );
  1140. Status = STATUS_CANCELLED;
  1141. goto end;
  1142. }
  1143. //
  1144. // our cancel routine will run and complete the irp,
  1145. // don't touch it
  1146. //
  1147. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1148. //
  1149. // STATUS_PENDING will cause the ioctl wrapper to
  1150. // not complete (or touch in any way) the irp
  1151. //
  1152. Status = STATUS_PENDING;
  1153. goto end;
  1154. }
  1155. //
  1156. // now we are safe to queue it
  1157. //
  1158. ExInterlockedInsertTailList(
  1159. &pProcess->NewIrpHead,
  1160. &pIrp->Tail.Overlay.ListEntry,
  1161. KSPIN_LOCK_FROM_UL_SPIN_LOCK(&pProcess->NewIrpSpinLock)
  1162. );
  1163. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1164. Status = STATUS_PENDING;
  1165. goto end;
  1166. }
  1167. else // if (pRequest == NULL)
  1168. {
  1169. //
  1170. // Have a queue'd request, serve it up!
  1171. //
  1172. // UlpDequeueNewRequest gives ourselves a short-lived reference
  1173. //
  1174. //
  1175. // all done with the app pool
  1176. //
  1177. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1178. //
  1179. // Copy it to the irp, the routine will take ownership
  1180. // of pRequest if it is not able to copy it to the irp.
  1181. //
  1182. // it will also complete the irp so don't touch it later.
  1183. //
  1184. IoMarkIrpPending(pIrp);
  1185. UlpCopyRequestToIrp(pRequest, pIrp);
  1186. pIrp = NULL;
  1187. //
  1188. // let go our short-lived reference
  1189. //
  1190. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1191. pRequest = NULL;
  1192. Status = STATUS_PENDING;
  1193. goto end;
  1194. }
  1195. }
  1196. else // if (HTTP_IS_NULL_ID(&RequestId))
  1197. {
  1198. //
  1199. // need to grab the specific request
  1200. //
  1201. //
  1202. // Get the object ptr from id
  1203. //
  1204. pRequest = UlGetRequestFromId(RequestId);
  1205. if (UL_IS_VALID_INTERNAL_REQUEST(pRequest) == FALSE)
  1206. {
  1207. Status = STATUS_INVALID_PARAMETER;
  1208. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1209. goto end;
  1210. }
  1211. //
  1212. // Is this request really queue'd on this process waiting ?
  1213. //
  1214. if ((pRequest->AppPool.QueueState != QueueCopiedState) ||
  1215. (pRequest->AppPool.pProcess != pProcess))
  1216. {
  1217. Status = STATUS_INVALID_PARAMETER;
  1218. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1219. goto end;
  1220. }
  1221. UlTrace(ROUTING, (
  1222. "ul!UlReceiveHttpRequest(ID = %I64x, pProcess = %p)\n"
  1223. " pAppPool = %p (%S)\n"
  1224. " Found pRequest = %p on PendingRequest queue\n",
  1225. RequestId,
  1226. pProcess,
  1227. pProcess->pAppPool,
  1228. pProcess->pAppPool->pName,
  1229. pRequest
  1230. ));
  1231. //
  1232. // let go the lock
  1233. //
  1234. UlReleaseResource(&pProcess->pAppPool->pResource->Resource);
  1235. //
  1236. // Copy it to the irp, the routine will take ownership
  1237. // of pRequest if it is not able to copy it to the irp
  1238. //
  1239. IoMarkIrpPending(pIrp);
  1240. UlpCopyRequestToIrp(pRequest, pIrp);
  1241. //
  1242. // let go our reference
  1243. //
  1244. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1245. pRequest = NULL;
  1246. Status = STATUS_PENDING;
  1247. goto end;
  1248. }
  1249. end:
  1250. if (pRequest != NULL)
  1251. {
  1252. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1253. pRequest = NULL;
  1254. }
  1255. //
  1256. // At this point if Status != PENDING, the ioctl wrapper will
  1257. // complete pIrp
  1258. //
  1259. return Status;
  1260. }
  1261. /***************************************************************************++
  1262. Routine Description:
  1263. called by the http engine to deliver a request to an apool.
  1264. this attemps to find a free irp from any process attached to the apool
  1265. and copies the request to that irp.
  1266. otherwise it queues the request, without taking a refcount on it. the
  1267. request will remove itself from this queue if the connection is dropped.
  1268. Arguments:
  1269. pRequest - the request to deliver
  1270. Return Value:
  1271. NTSTATUS - Completion status.
  1272. --***************************************************************************/
  1273. NTSTATUS
  1274. UlDeliverRequestToProcess(
  1275. IN PUL_APP_POOL_OBJECT pAppPool,
  1276. IN PUL_INTERNAL_REQUEST pRequest
  1277. )
  1278. {
  1279. NTSTATUS Status;
  1280. PIRP pDemandStartIrp;
  1281. PIRP pIrp = NULL;
  1282. PUL_APP_POOL_PROCESS pProcess = NULL;
  1283. //
  1284. // Sanity check.
  1285. //
  1286. PAGED_CODE();
  1287. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1288. ASSERT(IS_VALID_URL_CONFIG_GROUP_INFO(&pRequest->ConfigInfo));
  1289. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  1290. //
  1291. // Has the app pool been disabled?
  1292. //
  1293. if (pAppPool->Enabled == HttpEnabledStateInactive)
  1294. {
  1295. pRequest->ErrorCode = UlErrorUnavailable; // 503
  1296. return STATUS_PORT_DISCONNECTED;
  1297. }
  1298. Status = STATUS_SUCCESS;
  1299. //
  1300. // grab the lock!
  1301. //
  1302. UlAcquireResourceShared(&pAppPool->pResource->Resource, TRUE);
  1303. UlTrace(ROUTING, (
  1304. "ul!UlDeliverRequestToProcess(pRequest = %p)\n"
  1305. " verb + path -> %d %S\n"
  1306. " pAppPool = %p (%S)\n",
  1307. pRequest,
  1308. pRequest->Verb,
  1309. pRequest->CookedUrl.pUrl,
  1310. pAppPool,
  1311. pAppPool->pName
  1312. ));
  1313. TRACE_TIME(
  1314. pRequest->ConnectionId,
  1315. pRequest->RequestId,
  1316. TIME_ACTION_ROUTE_REQUEST
  1317. );
  1318. //
  1319. // hook up request references
  1320. //
  1321. UL_REFERENCE_INTERNAL_REQUEST(pRequest);
  1322. if (pAppPool->NumberActiveProcesses <= 1)
  1323. {
  1324. //
  1325. // bypass process binding if we have only one active process
  1326. //
  1327. pProcess = NULL;
  1328. pIrp = UlpPopNewIrp(pAppPool, &pProcess);
  1329. }
  1330. else
  1331. {
  1332. //
  1333. // check for a process binding
  1334. //
  1335. pProcess = UlQueryProcessBinding(pRequest->pHttpConn, pAppPool);
  1336. if (UlpIsProcessInAppPool(pProcess, pAppPool)) {
  1337. //
  1338. // we're bound to a valid process.
  1339. // Try to get a free irp from that process
  1340. //
  1341. pIrp = UlpPopIrpFromProcess(pProcess);
  1342. } else {
  1343. //
  1344. // we are unbound or bound to a process that went away.
  1345. // Try and get an free irp from any process.
  1346. //
  1347. pProcess = NULL;
  1348. pIrp = UlpPopNewIrp(pAppPool, &pProcess);
  1349. //
  1350. // establish a binding if we got something
  1351. //
  1352. if (pIrp != NULL) {
  1353. ASSERT( IS_VALID_AP_PROCESS( pProcess ) );
  1354. Status = UlBindConnectionToProcess(
  1355. pRequest->pHttpConn,
  1356. pAppPool,
  1357. pProcess
  1358. );
  1359. //
  1360. // Is there anything special we should do on
  1361. // failure? I don't think it should be fatal..
  1362. //
  1363. Status = STATUS_SUCCESS;
  1364. }
  1365. }
  1366. }
  1367. //
  1368. // If we have an IRP, complete it. Otherwise queue the request.
  1369. //
  1370. if (pIrp != NULL)
  1371. {
  1372. ASSERT( pIrp->MdlAddress != NULL );
  1373. ASSERT( pProcess->InCleanup == 0 );
  1374. //
  1375. // attach the request to this process, this grabs the lock
  1376. // we are about to let go of. this allows us to drop the
  1377. // connection if the process dies in the middle of request processing.
  1378. //
  1379. UlpQueuePendingRequest(pProcess, pRequest);
  1380. //
  1381. // we are all done and about to complete the irp, free the lock
  1382. //
  1383. UlReleaseResource(&pAppPool->pResource->Resource);
  1384. //
  1385. // Copy it to the irp, the routine will take ownership
  1386. // of pRequest if it is not able to copy it to the irp
  1387. //
  1388. // it will also complete the irp, don't touch it later
  1389. //
  1390. UlpCopyRequestToIrp(pRequest, pIrp);
  1391. }
  1392. else
  1393. {
  1394. ASSERT(pIrp == NULL);
  1395. //
  1396. // Either didn't find an IRP or there's stuff on the pending request
  1397. // list, so queue this pending request.
  1398. //
  1399. Status = UlpQueueUnboundRequest(pAppPool, pRequest);
  1400. if (!NT_SUCCESS(Status)) {
  1401. //
  1402. // doh! we couldn't queue it, so let go of the request
  1403. //
  1404. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1405. UlReleaseResource(&pAppPool->pResource->Resource);
  1406. return Status;
  1407. }
  1408. //
  1409. // complete the demand start
  1410. //
  1411. pDemandStartIrp = pAppPool->pDemandStartIrp;
  1412. if (pDemandStartIrp != NULL)
  1413. {
  1414. pDemandStartIrp = (PIRP) InterlockedCompareExchangePointer(
  1415. (PVOID *) &pAppPool->pDemandStartIrp,
  1416. NULL,
  1417. pDemandStartIrp
  1418. );
  1419. }
  1420. if (pDemandStartIrp != NULL)
  1421. {
  1422. //
  1423. // pop the cancel routine
  1424. //
  1425. if (IoSetCancelRoutine(pDemandStartIrp, NULL) == NULL)
  1426. {
  1427. //
  1428. // IoCancelIrp pop'd it first
  1429. //
  1430. // ok to just ignore this irp, it's been pop'd off the queue
  1431. // and will be completed in the cancel routine.
  1432. //
  1433. // no need to complete it
  1434. //
  1435. }
  1436. else if (pDemandStartIrp->Cancel)
  1437. {
  1438. //
  1439. // we pop'd it first. but the irp is being cancelled
  1440. // and our cancel routine will never run.
  1441. //
  1442. IoGetCurrentIrpStackLocation(
  1443. pDemandStartIrp
  1444. )->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  1445. pDemandStartIrp->IoStatus.Status = STATUS_CANCELLED;
  1446. pDemandStartIrp->IoStatus.Information = 0;
  1447. pIrp = pDemandStartIrp;
  1448. }
  1449. else
  1450. {
  1451. //
  1452. // free to use the irp
  1453. //
  1454. IoGetCurrentIrpStackLocation(
  1455. pDemandStartIrp
  1456. )->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  1457. pDemandStartIrp->IoStatus.Status = STATUS_SUCCESS;
  1458. pDemandStartIrp->IoStatus.Information = 0;
  1459. pIrp = pDemandStartIrp;
  1460. }
  1461. pAppPool->pDemandStartProcess = NULL;
  1462. }
  1463. //
  1464. // now we finished queue'ing the request, free the lock
  1465. //
  1466. UlReleaseResource(&pAppPool->pResource->Resource);
  1467. //
  1468. // complete any demand start irp (after releasing the resource)
  1469. //
  1470. if (pIrp != NULL)
  1471. {
  1472. UlCompleteRequest(pIrp, g_UlPriorityBoost);
  1473. pIrp = NULL;
  1474. }
  1475. }
  1476. return Status;
  1477. }
  1478. /***************************************************************************++
  1479. Routine Description:
  1480. Removes a request from any app pool lists.
  1481. Arguments:
  1482. pRequest - the request to be unlinked
  1483. --***************************************************************************/
  1484. VOID
  1485. UlUnlinkRequestFromProcess(
  1486. IN PUL_APP_POOL_OBJECT pAppPool,
  1487. IN PUL_INTERNAL_REQUEST pRequest
  1488. )
  1489. {
  1490. KLOCK_QUEUE_HANDLE LockHandle;
  1491. //
  1492. // Sanity check
  1493. //
  1494. PAGED_CODE();
  1495. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1496. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  1497. UlAcquireInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  1498. //
  1499. // remove from whatever queue we're on
  1500. //
  1501. switch (pRequest->AppPool.QueueState)
  1502. {
  1503. case QueueDeliveredState:
  1504. //
  1505. // we're on the apool object new request queue
  1506. //
  1507. UlpRemoveRequest(&pAppPool->NewRequestQueue, pRequest);
  1508. pRequest->AppPool.QueueState = QueueUnlinkedState;
  1509. //
  1510. // clean up the references
  1511. //
  1512. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1513. break;
  1514. case QueueCopiedState:
  1515. //
  1516. // we're on the apool process pending queue
  1517. //
  1518. ASSERT(IS_VALID_AP_PROCESS(pRequest->AppPool.pProcess));
  1519. ASSERT(pRequest->AppPool.pProcess->pAppPool == pAppPool);
  1520. UlpRemoveRequest(
  1521. &pRequest->AppPool.pProcess->PendingRequestQueue,
  1522. pRequest
  1523. );
  1524. pRequest->AppPool.QueueState = QueueUnlinkedState;
  1525. //
  1526. // clean up the references
  1527. //
  1528. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1529. break;
  1530. case QueueUnroutedState:
  1531. case QueueUnlinkedState:
  1532. //
  1533. // It's not on our lists, so we don't do anything
  1534. //
  1535. break;
  1536. default:
  1537. //
  1538. // this shouldn't happen
  1539. //
  1540. ASSERT(FALSE);
  1541. break;
  1542. }
  1543. UlReleaseInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  1544. } // UlUnlinkRequestFromProcess
  1545. /***************************************************************************++
  1546. Routine Description:
  1547. Arguments:
  1548. Return Value:
  1549. NTSTATUS - Completion status.
  1550. --***************************************************************************/
  1551. NTSTATUS
  1552. UlInitializeAP(
  1553. VOID
  1554. )
  1555. {
  1556. NTSTATUS Status = STATUS_SUCCESS;
  1557. ASSERT(!g_InitAPCalled);
  1558. if (!g_InitAPCalled)
  1559. {
  1560. InitializeListHead(&g_AppPoolListHead);
  1561. Status = UlInitializeResource(
  1562. &g_pUlNonpagedData->AppPoolResource,
  1563. "AppPoolResource",
  1564. 0,
  1565. UL_APP_POOL_RESOURCE_TAG
  1566. );
  1567. ASSERT(NT_SUCCESS(Status)); // the call always returns success
  1568. if (NT_SUCCESS(Status)) {
  1569. Status = UlInitializeResource(
  1570. &g_pUlNonpagedData->DisconnectResource,
  1571. "DisconnectResource",
  1572. 0,
  1573. UL_DISCONNECT_RESOURCE_TAG
  1574. );
  1575. if (NT_SUCCESS(Status)) {
  1576. //
  1577. // finished, remember that we're initialized
  1578. //
  1579. g_InitAPCalled = TRUE;
  1580. } else {
  1581. UlDeleteResource(&g_pUlNonpagedData->AppPoolResource);
  1582. }
  1583. }
  1584. }
  1585. return Status;
  1586. }
  1587. /***************************************************************************++
  1588. Routine Description:
  1589. Arguments:
  1590. Return Value:
  1591. NTSTATUS - Completion status.
  1592. --***************************************************************************/
  1593. VOID
  1594. UlTerminateAP(
  1595. VOID
  1596. )
  1597. {
  1598. NTSTATUS Status;
  1599. if (g_InitAPCalled)
  1600. {
  1601. Status = UlDeleteResource(&g_pUlNonpagedData->AppPoolResource);
  1602. ASSERT(NT_SUCCESS(Status));
  1603. Status = UlDeleteResource(&g_pUlNonpagedData->DisconnectResource);
  1604. ASSERT(NT_SUCCESS(Status));
  1605. g_InitAPCalled = FALSE;
  1606. }
  1607. }
  1608. /***************************************************************************++
  1609. Routine Description:
  1610. Allocates and initializes a UL_APP_POOL_PROCESS object
  1611. Arguments:
  1612. None.
  1613. Return Values:
  1614. NULL on failure, process object on success
  1615. --***************************************************************************/
  1616. PUL_APP_POOL_PROCESS
  1617. UlCreateAppPoolProcess(
  1618. PUL_APP_POOL_OBJECT pObject
  1619. )
  1620. {
  1621. PUL_APP_POOL_PROCESS pProcess;
  1622. //
  1623. // Sanity check
  1624. //
  1625. PAGED_CODE();
  1626. pProcess = UL_ALLOCATE_STRUCT(
  1627. NonPagedPool,
  1628. UL_APP_POOL_PROCESS,
  1629. UL_APP_POOL_PROCESS_POOL_TAG
  1630. );
  1631. if (pProcess) {
  1632. NTSTATUS Status;
  1633. RtlZeroMemory(pProcess, sizeof(UL_APP_POOL_PROCESS));
  1634. pProcess->Signature = UL_APP_POOL_PROCESS_POOL_TAG;
  1635. pProcess->pAppPool = pObject;
  1636. InitializeListHead(&pProcess->NewIrpHead);
  1637. Status = UlpInitRequestQueue(
  1638. &pProcess->PendingRequestQueue, // the queue
  1639. -1 // unlimited size
  1640. );
  1641. ASSERT(NT_SUCCESS(Status));
  1642. UlInitializeSpinLock(&pProcess->NewIrpSpinLock, "NewIrpSpinLock");
  1643. //
  1644. // remember current process (for debugging)
  1645. //
  1646. pProcess->pProcess = PsGetCurrentProcess();
  1647. //
  1648. // Init list of WaitForDisconnect IRPs
  1649. //
  1650. UlInitializeNotifyHead(
  1651. &pProcess->WaitForDisconnectHead,
  1652. NULL
  1653. );
  1654. }
  1655. return pProcess;
  1656. }
  1657. /***************************************************************************++
  1658. Routine Description:
  1659. Destroys a UL_APP_POOL_PROCESS object
  1660. Arguments:
  1661. pProcess - object to destory
  1662. --***************************************************************************/
  1663. VOID
  1664. UlFreeAppPoolProcess(
  1665. PUL_APP_POOL_PROCESS pProcess
  1666. )
  1667. {
  1668. //
  1669. // Sanity check
  1670. //
  1671. PAGED_CODE();
  1672. ASSERT( IS_VALID_AP_PROCESS(pProcess) );
  1673. ASSERT( pProcess->InCleanup );
  1674. //
  1675. // free the pool
  1676. //
  1677. UL_FREE_POOL_WITH_SIG(pProcess, UL_APP_POOL_PROCESS_POOL_TAG);
  1678. }
  1679. /***************************************************************************++
  1680. Routine Description:
  1681. cancels the pending user mode irp which was to receive demand start
  1682. notification. this routine ALWAYS results in the irp being completed.
  1683. note: we queue off to cancel in order to process the cancellation at lower
  1684. irql.
  1685. Arguments:
  1686. pDeviceObject - the device object
  1687. pIrp - the irp to cancel
  1688. --***************************************************************************/
  1689. VOID
  1690. UlpCancelDemandStart(
  1691. IN PDEVICE_OBJECT pDeviceObject,
  1692. IN PIRP pIrp
  1693. )
  1694. {
  1695. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1696. ASSERT(pIrp != NULL);
  1697. //
  1698. // release the cancel spinlock. This means the cancel routine
  1699. // must be the one completing the irp (to avoid the race of
  1700. // completion + reuse prior to the cancel routine running).
  1701. //
  1702. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  1703. //
  1704. // queue the cancel to a worker to ensure passive irql.
  1705. //
  1706. UL_CALL_PASSIVE(
  1707. UL_WORK_ITEM_FROM_IRP( pIrp ),
  1708. &UlpCancelDemandStartWorker
  1709. );
  1710. }
  1711. /***************************************************************************++
  1712. Routine Description:
  1713. Actually performs the cancel for the irp.
  1714. Arguments:
  1715. pWorkItem - the work item to process.
  1716. --***************************************************************************/
  1717. VOID
  1718. UlpCancelDemandStartWorker(
  1719. IN PUL_WORK_ITEM pWorkItem
  1720. )
  1721. {
  1722. PIRP pIrp;
  1723. PUL_APP_POOL_OBJECT pAppPool;
  1724. //
  1725. // Sanity check.
  1726. //
  1727. PAGED_CODE();
  1728. //
  1729. // grab the irp off the work item
  1730. //
  1731. pIrp = UL_WORK_ITEM_TO_IRP( pWorkItem );
  1732. ASSERT(IS_VALID_IRP(pIrp));
  1733. //
  1734. // grab the app pool off the irp
  1735. //
  1736. pAppPool = (PUL_APP_POOL_OBJECT)(
  1737. IoGetCurrentIrpStackLocation(pIrp)->Parameters.DeviceIoControl.Type3InputBuffer
  1738. );
  1739. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  1740. //
  1741. // grab the lock protecting the queue'd irp
  1742. //
  1743. UlAcquireResourceExclusive(&pAppPool->pResource->Resource, TRUE);
  1744. //
  1745. // does it need to be dequeue'd ?
  1746. //
  1747. if (pAppPool->pDemandStartIrp != NULL)
  1748. {
  1749. //
  1750. // remove it
  1751. //
  1752. pAppPool->pDemandStartIrp = NULL;
  1753. pAppPool->pDemandStartProcess = NULL;
  1754. }
  1755. //
  1756. // let the lock go
  1757. //
  1758. UlReleaseResource(&pAppPool->pResource->Resource);
  1759. //
  1760. // let our reference go
  1761. //
  1762. IoGetCurrentIrpStackLocation(pIrp)->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  1763. //
  1764. // complete the irp
  1765. //
  1766. pIrp->IoStatus.Status = STATUS_CANCELLED;
  1767. pIrp->IoStatus.Information = 0;
  1768. UlCompleteRequest( pIrp, g_UlPriorityBoost );
  1769. }
  1770. /***************************************************************************++
  1771. Routine Description:
  1772. cancels the pending user mode irp which was to receive the http request.
  1773. this routine ALWAYS results in the irp being completed.
  1774. note: we queue off to cancel in order to process the cancellation at lower
  1775. irql.
  1776. Arguments:
  1777. pDeviceObject - the device object
  1778. pIrp - the irp to cancel
  1779. --***************************************************************************/
  1780. VOID
  1781. UlpCancelHttpReceive(
  1782. IN PDEVICE_OBJECT pDeviceObject,
  1783. IN PIRP pIrp
  1784. )
  1785. {
  1786. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  1787. ASSERT(pIrp != NULL);
  1788. //
  1789. // release the cancel spinlock. This means the cancel routine
  1790. // must be the one completing the irp (to avoid the race of
  1791. // completion + reuse prior to the cancel routine running).
  1792. //
  1793. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  1794. //
  1795. // queue the cancel to a worker to ensure passive irql.
  1796. //
  1797. UL_CALL_PASSIVE(
  1798. UL_WORK_ITEM_FROM_IRP( pIrp ),
  1799. &UlpCancelHttpReceiveWorker
  1800. );
  1801. }
  1802. /***************************************************************************++
  1803. Routine Description:
  1804. Actually performs the cancel for the irp.
  1805. Arguments:
  1806. pWorkItem - the work item to process.
  1807. --***************************************************************************/
  1808. VOID
  1809. UlpCancelHttpReceiveWorker(
  1810. IN PUL_WORK_ITEM pWorkItem
  1811. )
  1812. {
  1813. PUL_APP_POOL_OBJECT pAppPool;
  1814. PIRP pIrp;
  1815. //
  1816. // Sanity check.
  1817. //
  1818. PAGED_CODE();
  1819. ASSERT(pWorkItem != NULL);
  1820. //
  1821. // grab the irp off the work item
  1822. //
  1823. pIrp = UL_WORK_ITEM_TO_IRP( pWorkItem );
  1824. ASSERT(IS_VALID_IRP(pIrp));
  1825. //
  1826. // grab the app pool off the irp
  1827. //
  1828. pAppPool = (PUL_APP_POOL_OBJECT)(
  1829. IoGetCurrentIrpStackLocation(pIrp)->Parameters.DeviceIoControl.Type3InputBuffer
  1830. );
  1831. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  1832. //
  1833. // grab the lock protecting the queue
  1834. //
  1835. UlAcquireResourceExclusive(&pAppPool->pResource->Resource, TRUE);
  1836. //
  1837. // does it need to be de-queue'd ?
  1838. //
  1839. if (pIrp->Tail.Overlay.ListEntry.Flink != NULL)
  1840. {
  1841. //
  1842. // remove it
  1843. //
  1844. RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
  1845. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  1846. pIrp->Tail.Overlay.ListEntry.Blink = NULL;
  1847. }
  1848. //
  1849. // let the lock go
  1850. //
  1851. UlReleaseResource(&pAppPool->pResource->Resource);
  1852. //
  1853. // let our reference go
  1854. //
  1855. IoGetCurrentIrpStackLocation(pIrp)->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  1856. DEREFERENCE_APP_POOL(pAppPool);
  1857. //
  1858. // complete the irp
  1859. //
  1860. pIrp->IoStatus.Status = STATUS_CANCELLED;
  1861. pIrp->IoStatus.Information = 0;
  1862. UlCompleteRequest( pIrp, g_UlPriorityBoost );
  1863. } // UlpCancelHttpReceive
  1864. /******************************************************************************
  1865. Routine Description:
  1866. Copy an HTTP request to a buffer.
  1867. Arguments:
  1868. pRequest - Pointer to this request.
  1869. pBuffer - Pointer to buffer where we'll copy.
  1870. BufferLength - Length of pBuffer.
  1871. pEntityBody - Pointer to entity body of request.
  1872. EntityBodyLength - Length of entity body.
  1873. ******************************************************************************/
  1874. NTSTATUS
  1875. UlpCopyRequestToBuffer(
  1876. PUL_INTERNAL_REQUEST pRequest,
  1877. PUCHAR pKernelBuffer,
  1878. PVOID pUserBuffer,
  1879. ULONG BufferLength,
  1880. PUCHAR pEntityBody,
  1881. ULONG EntityBodyLength
  1882. )
  1883. {
  1884. PHTTP_REQUEST pHttpRequest;
  1885. PHTTP_UNKNOWN_HEADER pUserCurrentUnknownHeader;
  1886. PUCHAR pCurrentBufferPtr;
  1887. ULONG i;
  1888. ULONG BytesCopied;
  1889. ULONG HeaderCount = 0;
  1890. PHTTP_NETWORK_ADDRESS_IPV4 pLocalAddress;
  1891. PHTTP_NETWORK_ADDRESS_IPV4 pRemoteAddress;
  1892. PHTTP_TRANSPORT_ADDRESS pAddress;
  1893. PHTTP_COOKED_URL pCookedUrl;
  1894. PLIST_ENTRY pListEntry;
  1895. NTSTATUS Status;
  1896. //
  1897. // Sanity check.
  1898. //
  1899. PAGED_CODE();
  1900. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1901. ASSERT(pKernelBuffer != NULL);
  1902. ASSERT(pUserBuffer != NULL);
  1903. ASSERT(BufferLength > sizeof(HTTP_REQUEST));
  1904. Status = STATUS_SUCCESS;
  1905. //
  1906. // Set up our pointers to the HTTP_REQUESTS structure, the
  1907. // header arrays we're going to fill in, and the pointer to
  1908. // where we're going to start filling them in.
  1909. //
  1910. // CODEWORK: Make this transport independent.
  1911. //
  1912. pHttpRequest = (PHTTP_REQUEST)pKernelBuffer;
  1913. pLocalAddress = (PHTTP_NETWORK_ADDRESS_IPV4)( pHttpRequest + 1 );
  1914. pRemoteAddress = pLocalAddress + 1;
  1915. pUserCurrentUnknownHeader = (PHTTP_UNKNOWN_HEADER)( pRemoteAddress + 1 );
  1916. pCurrentBufferPtr = (PUCHAR)(pUserCurrentUnknownHeader +
  1917. pRequest->UnknownHeaderCount);
  1918. //
  1919. // Now fill in the HTTP request structure.
  1920. //
  1921. ASSERT(!HTTP_IS_NULL_ID(&pRequest->ConnectionId));
  1922. ASSERT(!HTTP_IS_NULL_ID(&pRequest->RequestIdCopy));
  1923. pHttpRequest->ConnectionId = pRequest->ConnectionId;
  1924. pHttpRequest->RequestId = pRequest->RequestIdCopy;
  1925. pHttpRequest->UrlContext = pRequest->ConfigInfo.UrlContext;
  1926. pHttpRequest->Version = pRequest->Version;
  1927. pHttpRequest->Verb = pRequest->Verb;
  1928. pHttpRequest->Reason = pRequest->Reason;
  1929. pHttpRequest->BytesReceived = pRequest->BytesReceived;
  1930. pAddress = &pHttpRequest->Address;
  1931. pAddress->RemoteAddressLength = sizeof(HTTP_NETWORK_ADDRESS_IPV4);
  1932. pAddress->RemoteAddressType = HTTP_NETWORK_ADDRESS_TYPE_IPV4;
  1933. pAddress->pRemoteAddress = FIXUP_PTR(
  1934. PVOID,
  1935. pUserBuffer,
  1936. pKernelBuffer,
  1937. pRemoteAddress,
  1938. BufferLength
  1939. );
  1940. pRemoteAddress->IpAddress = pRequest->pHttpConn->pConnection->RemoteAddress;
  1941. pRemoteAddress->Port = pRequest->pHttpConn->pConnection->RemotePort;
  1942. pAddress->LocalAddressLength = sizeof(HTTP_NETWORK_ADDRESS_IPV4);
  1943. pAddress->LocalAddressType = HTTP_NETWORK_ADDRESS_TYPE_IPV4;
  1944. pAddress->pLocalAddress = FIXUP_PTR(
  1945. PVOID,
  1946. pUserBuffer,
  1947. pKernelBuffer,
  1948. pLocalAddress,
  1949. BufferLength
  1950. );
  1951. pLocalAddress->IpAddress = pRequest->pHttpConn->pConnection->LocalAddress;
  1952. pLocalAddress->Port = pRequest->pHttpConn->pConnection->LocalPort;
  1953. //
  1954. // and now the cooked url sections
  1955. //
  1956. //
  1957. // Unicode strings must be at 2-byte boundaries. All previous data
  1958. // are structures, so the assertion should be true.
  1959. //
  1960. ASSERT(((ULONG_PTR) pCurrentBufferPtr % sizeof(WCHAR)) == 0);
  1961. //
  1962. // make sure they are valid
  1963. //
  1964. ASSERT(pRequest->CookedUrl.pUrl != NULL);
  1965. ASSERT(pRequest->CookedUrl.pHost != NULL);
  1966. ASSERT(pRequest->CookedUrl.pAbsPath != NULL);
  1967. //
  1968. // do the full url
  1969. //
  1970. ASSERT(pRequest->CookedUrl.Length <= 0xffff);
  1971. pCookedUrl = &pHttpRequest->CookedUrl;
  1972. pCookedUrl->FullUrlLength = (USHORT)(pRequest->CookedUrl.Length);
  1973. pCookedUrl->pFullUrl = FIXUP_PTR(
  1974. PWSTR,
  1975. pUserBuffer,
  1976. pKernelBuffer,
  1977. pCurrentBufferPtr,
  1978. BufferLength
  1979. );
  1980. //
  1981. // and the host
  1982. //
  1983. pCookedUrl->HostLength = DIFF(pRequest->CookedUrl.pAbsPath - pRequest->CookedUrl.pHost)
  1984. * sizeof(WCHAR);
  1985. pCookedUrl->pHost = pCookedUrl->pFullUrl +
  1986. DIFF(pRequest->CookedUrl.pHost - pRequest->CookedUrl.pUrl);
  1987. //
  1988. // is there a query string?
  1989. //
  1990. if (pRequest->CookedUrl.pQueryString != NULL)
  1991. {
  1992. pCookedUrl->AbsPathLength = DIFF(pRequest->CookedUrl.pQueryString -
  1993. pRequest->CookedUrl.pAbsPath) * sizeof(WCHAR);
  1994. pCookedUrl->pAbsPath = pCookedUrl->pHost +
  1995. (pCookedUrl->HostLength / sizeof(WCHAR));
  1996. pCookedUrl->QueryStringLength = (USHORT)(pRequest->CookedUrl.Length) - (
  1997. DIFF(
  1998. pRequest->CookedUrl.pQueryString -
  1999. pRequest->CookedUrl.pUrl
  2000. ) * sizeof(WCHAR)
  2001. );
  2002. pCookedUrl->pQueryString = pCookedUrl->pAbsPath +
  2003. (pCookedUrl->AbsPathLength / sizeof(WCHAR));
  2004. }
  2005. else
  2006. {
  2007. pCookedUrl->AbsPathLength = (USHORT)(pRequest->CookedUrl.Length) - (
  2008. DIFF(
  2009. pRequest->CookedUrl.pAbsPath -
  2010. pRequest->CookedUrl.pUrl
  2011. ) * sizeof(WCHAR)
  2012. );
  2013. pCookedUrl->pAbsPath = pCookedUrl->pHost +
  2014. (pCookedUrl->HostLength / sizeof(WCHAR));
  2015. pCookedUrl->QueryStringLength = 0;
  2016. pCookedUrl->pQueryString = NULL;
  2017. }
  2018. //
  2019. // copy the full url
  2020. //
  2021. RtlCopyMemory(
  2022. pCurrentBufferPtr,
  2023. pRequest->CookedUrl.pUrl,
  2024. pRequest->CookedUrl.Length
  2025. );
  2026. pCurrentBufferPtr += pRequest->CookedUrl.Length;
  2027. //
  2028. // terminate it
  2029. //
  2030. ((PWSTR)pCurrentBufferPtr)[0] = UNICODE_NULL;
  2031. pCurrentBufferPtr += sizeof(WCHAR);
  2032. //
  2033. // any raw verb?
  2034. //
  2035. if (pRequest->Verb == HttpVerbUnknown)
  2036. {
  2037. //
  2038. // Need to copy in the raw verb for the client.
  2039. //
  2040. ASSERT(pRequest->RawVerbLength <= 0x7fff);
  2041. pHttpRequest->UnknownVerbLength = (USHORT)(pRequest->RawVerbLength * sizeof(CHAR));
  2042. pHttpRequest->pUnknownVerb = FIXUP_PTR(
  2043. PSTR,
  2044. pUserBuffer,
  2045. pKernelBuffer,
  2046. pCurrentBufferPtr,
  2047. BufferLength
  2048. );
  2049. RtlCopyMemory(
  2050. pCurrentBufferPtr,
  2051. pRequest->pRawVerb,
  2052. pRequest->RawVerbLength
  2053. );
  2054. BytesCopied = pRequest->RawVerbLength * sizeof(CHAR);
  2055. pCurrentBufferPtr += BytesCopied;
  2056. //
  2057. // terminate it
  2058. //
  2059. ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
  2060. pCurrentBufferPtr += sizeof(CHAR);
  2061. }
  2062. else
  2063. {
  2064. pHttpRequest->UnknownVerbLength = 0;
  2065. pHttpRequest->pUnknownVerb = NULL;
  2066. }
  2067. //
  2068. // copy the raw url
  2069. //
  2070. ASSERT(pRequest->RawUrl.Length <= 0x7fff);
  2071. pHttpRequest->RawUrlLength = (USHORT)(pRequest->RawUrl.Length * sizeof(CHAR));
  2072. pHttpRequest->pRawUrl = FIXUP_PTR(
  2073. PSTR,
  2074. pUserBuffer,
  2075. pKernelBuffer,
  2076. pCurrentBufferPtr,
  2077. BufferLength
  2078. );
  2079. RtlCopyMemory(
  2080. pCurrentBufferPtr,
  2081. pRequest->RawUrl.pUrl,
  2082. pRequest->RawUrl.Length
  2083. );
  2084. BytesCopied = pRequest->RawUrl.Length * sizeof(CHAR);
  2085. pCurrentBufferPtr += BytesCopied;
  2086. //
  2087. // terminate it
  2088. //
  2089. ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
  2090. pCurrentBufferPtr += sizeof(CHAR);
  2091. //
  2092. // no entity body, CODEWORK.
  2093. //
  2094. if (pRequest->ContentLength > 0 || pRequest->Chunked == 1)
  2095. {
  2096. pHttpRequest->MoreEntityBodyExists = 1;
  2097. }
  2098. else
  2099. {
  2100. pHttpRequest->MoreEntityBodyExists = 0;
  2101. }
  2102. pHttpRequest->EntityChunkCount = 0;
  2103. pHttpRequest->pEntityChunks = NULL;
  2104. //
  2105. // Copy in the known headers.
  2106. //
  2107. // Loop through the known header array in the HTTP connection,
  2108. // and copy any that we have.
  2109. //
  2110. RtlZeroMemory(
  2111. pHttpRequest->Headers.pKnownHeaders,
  2112. HttpHeaderRequestMaximum * sizeof(HTTP_KNOWN_HEADER)
  2113. );
  2114. for (i = 0; i < HttpHeaderRequestMaximum; i++)
  2115. {
  2116. HTTP_HEADER_ID HeaderId = (HTTP_HEADER_ID)pRequest->HeaderIndex[i];
  2117. if (HeaderId == HttpHeaderRequestMaximum)
  2118. {
  2119. break;
  2120. }
  2121. //
  2122. // Have a header here we need to copy in.
  2123. //
  2124. ASSERT(pRequest->HeaderValid[HeaderId]);
  2125. ASSERT(pRequest->Headers[HeaderId].HeaderLength <= 0x7fff);
  2126. //
  2127. // ok for HeaderLength to be 0 . we will give usermode a pointer
  2128. // pointing to a NULL string. RawValueLength will be 0.
  2129. //
  2130. pHttpRequest->Headers.pKnownHeaders[HeaderId].RawValueLength =
  2131. (USHORT)(pRequest->Headers[HeaderId].HeaderLength * sizeof(CHAR));
  2132. pHttpRequest->Headers.pKnownHeaders[HeaderId].pRawValue =
  2133. FIXUP_PTR(
  2134. PSTR,
  2135. pUserBuffer,
  2136. pKernelBuffer,
  2137. pCurrentBufferPtr,
  2138. BufferLength
  2139. );
  2140. RtlCopyMemory(
  2141. pCurrentBufferPtr,
  2142. pRequest->Headers[HeaderId].pHeader,
  2143. pRequest->Headers[HeaderId].HeaderLength
  2144. );
  2145. BytesCopied = pRequest->Headers[HeaderId].HeaderLength * sizeof(CHAR);
  2146. pCurrentBufferPtr += BytesCopied;
  2147. //
  2148. // terminate it
  2149. //
  2150. ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
  2151. pCurrentBufferPtr += sizeof(CHAR);
  2152. }
  2153. //
  2154. // Now loop through the unknown headers, and copy them in.
  2155. //
  2156. pHttpRequest->Headers.UnknownHeaderCount = pRequest->UnknownHeaderCount;
  2157. if (pRequest->UnknownHeaderCount == 0)
  2158. {
  2159. pHttpRequest->Headers.pUnknownHeaders = NULL;
  2160. }
  2161. else
  2162. {
  2163. pHttpRequest->Headers.pUnknownHeaders =
  2164. FIXUP_PTR(
  2165. PHTTP_UNKNOWN_HEADER,
  2166. pUserBuffer,
  2167. pKernelBuffer,
  2168. pUserCurrentUnknownHeader,
  2169. BufferLength
  2170. );
  2171. }
  2172. pListEntry = pRequest->UnknownHeaderList.Flink;
  2173. while (pListEntry != &pRequest->UnknownHeaderList)
  2174. {
  2175. PUL_HTTP_UNKNOWN_HEADER pUnknownHeader;
  2176. pUnknownHeader = CONTAINING_RECORD(
  2177. pListEntry,
  2178. UL_HTTP_UNKNOWN_HEADER,
  2179. List
  2180. );
  2181. pListEntry = pListEntry->Flink;
  2182. HeaderCount++;
  2183. ASSERT(HeaderCount <= pRequest->UnknownHeaderCount);
  2184. //
  2185. // First copy in the header name.
  2186. //
  2187. pUserCurrentUnknownHeader->NameLength =
  2188. (USHORT)pUnknownHeader->HeaderNameLength * sizeof(CHAR);
  2189. pUserCurrentUnknownHeader->pName =
  2190. FIXUP_PTR(
  2191. PSTR,
  2192. pUserBuffer,
  2193. pKernelBuffer,
  2194. pCurrentBufferPtr,
  2195. BufferLength
  2196. );
  2197. RtlCopyMemory(
  2198. pCurrentBufferPtr,
  2199. pUnknownHeader->pHeaderName,
  2200. pUnknownHeader->HeaderNameLength
  2201. );
  2202. BytesCopied = pUnknownHeader->HeaderNameLength * sizeof(CHAR);
  2203. pCurrentBufferPtr += BytesCopied;
  2204. //
  2205. // terminate it
  2206. //
  2207. ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
  2208. pCurrentBufferPtr += sizeof(CHAR);
  2209. //
  2210. // Now copy in the header value.
  2211. //
  2212. ASSERT(pUnknownHeader->HeaderValue.HeaderLength <= 0x7fff);
  2213. if (pUnknownHeader->HeaderValue.HeaderLength == 0)
  2214. {
  2215. pUserCurrentUnknownHeader->RawValueLength = 0;
  2216. pUserCurrentUnknownHeader->pRawValue = NULL;
  2217. }
  2218. else
  2219. {
  2220. pUserCurrentUnknownHeader->RawValueLength =
  2221. (USHORT)(pUnknownHeader->HeaderValue.HeaderLength * sizeof(CHAR));
  2222. pUserCurrentUnknownHeader->pRawValue =
  2223. FIXUP_PTR(
  2224. PSTR,
  2225. pUserBuffer,
  2226. pKernelBuffer,
  2227. pCurrentBufferPtr,
  2228. BufferLength
  2229. );
  2230. RtlCopyMemory(
  2231. pCurrentBufferPtr,
  2232. pUnknownHeader->HeaderValue.pHeader,
  2233. pUnknownHeader->HeaderValue.HeaderLength
  2234. );
  2235. BytesCopied = pUnknownHeader->HeaderValue.HeaderLength * sizeof(CHAR);
  2236. pCurrentBufferPtr += BytesCopied;
  2237. //
  2238. // terminate it
  2239. //
  2240. ((PSTR)pCurrentBufferPtr)[0] = ANSI_NULL;
  2241. pCurrentBufferPtr += sizeof(CHAR);
  2242. }
  2243. //
  2244. // skip to the next header
  2245. //
  2246. pUserCurrentUnknownHeader++;
  2247. }
  2248. //
  2249. // Copy raw connection ID.
  2250. //
  2251. pHttpRequest->RawConnectionId = pRequest->RawConnectionId;
  2252. //
  2253. // Copy in SSL information.
  2254. //
  2255. if (pRequest->pHttpConn->SecureConnection == FALSE)
  2256. {
  2257. pHttpRequest->pSslInfo = NULL;
  2258. }
  2259. else
  2260. {
  2261. pCurrentBufferPtr = (PUCHAR)ALIGN_UP_POINTER(pCurrentBufferPtr, PVOID);
  2262. Status = UlGetSslInfo(
  2263. &pRequest->pHttpConn->pConnection->FilterInfo,
  2264. BufferLength - DIFF(pCurrentBufferPtr - pKernelBuffer),
  2265. FIXUP_PTR(
  2266. PUCHAR,
  2267. pUserBuffer,
  2268. pKernelBuffer,
  2269. pCurrentBufferPtr,
  2270. BufferLength
  2271. ),
  2272. pCurrentBufferPtr,
  2273. &BytesCopied
  2274. );
  2275. if (NT_SUCCESS(Status) && BytesCopied)
  2276. {
  2277. pHttpRequest->pSslInfo = FIXUP_PTR(
  2278. PHTTP_SSL_INFO,
  2279. pUserBuffer,
  2280. pKernelBuffer,
  2281. pCurrentBufferPtr,
  2282. BufferLength
  2283. );
  2284. pCurrentBufferPtr += BytesCopied;
  2285. }
  2286. else
  2287. {
  2288. pHttpRequest->pSslInfo = NULL;
  2289. }
  2290. }
  2291. //
  2292. // Make sure we didn't use too much
  2293. //
  2294. ASSERT(DIFF(pCurrentBufferPtr - pKernelBuffer) <= BufferLength);
  2295. TRACE_TIME(
  2296. pRequest->ConnectionId,
  2297. pRequest->RequestId,
  2298. TIME_ACTION_COPY_REQUEST
  2299. );
  2300. return Status;
  2301. } // UlpCopyRequestToBuffer
  2302. /******************************************************************************
  2303. Routine Description:
  2304. Find a pending IRP to deliver a request to. This routine must
  2305. be called with the lock on the apool held.
  2306. Arguments:
  2307. pAppPool - the apool to search for the irp
  2308. ppProcess - the process that we got the irp from
  2309. Return Value:
  2310. A pointer to an IRP if we've found one, or NULL if we didn't.
  2311. ******************************************************************************/
  2312. PIRP
  2313. UlpPopNewIrp(
  2314. IN PUL_APP_POOL_OBJECT pAppPool,
  2315. OUT PUL_APP_POOL_PROCESS * ppProcess
  2316. )
  2317. {
  2318. PUL_APP_POOL_PROCESS pProcess;
  2319. PIRP pIrp = NULL;
  2320. PLIST_ENTRY pEntry;
  2321. //
  2322. // Sanity check.
  2323. //
  2324. PAGED_CODE();
  2325. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  2326. ASSERT(ppProcess != NULL);
  2327. //
  2328. // Start looking for a process with a free IRP. We tend to always go to
  2329. // the first one to try and prevent process thrashing.
  2330. //
  2331. pEntry = pAppPool->ProcessListHead.Flink;
  2332. while (pEntry != &(pAppPool->ProcessListHead))
  2333. {
  2334. pProcess = CONTAINING_RECORD(
  2335. pEntry,
  2336. UL_APP_POOL_PROCESS,
  2337. ListEntry
  2338. );
  2339. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  2340. //
  2341. // get an IRP from this process
  2342. //
  2343. pIrp = UlpPopIrpFromProcess(pProcess);
  2344. //
  2345. // did we find one ?
  2346. //
  2347. if (pIrp != NULL)
  2348. {
  2349. *ppProcess = pProcess;
  2350. break;
  2351. }
  2352. //
  2353. // keep looking - move on to the next process entry
  2354. //
  2355. pEntry = pProcess->ListEntry.Flink;
  2356. }
  2357. return pIrp;
  2358. }
  2359. /***************************************************************************++
  2360. Routine Description:
  2361. Pulls an IRP off the given processes queue if there is one.
  2362. Arguments:
  2363. pProcess - a pointer to the process to search
  2364. Return Value:
  2365. A pointer to an IRP if we've found one, or NULL if we didn't.
  2366. --***************************************************************************/
  2367. PIRP
  2368. UlpPopIrpFromProcess(
  2369. IN PUL_APP_POOL_PROCESS pProcess
  2370. )
  2371. {
  2372. PUL_APP_POOL_OBJECT pProcessAppPool;
  2373. PLIST_ENTRY pEntry;
  2374. PIRP pIrp = NULL;
  2375. //
  2376. // Sanity check.
  2377. //
  2378. PAGED_CODE();
  2379. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  2380. pEntry = ExInterlockedRemoveHeadList(
  2381. &pProcess->NewIrpHead,
  2382. KSPIN_LOCK_FROM_UL_SPIN_LOCK(&pProcess->NewIrpSpinLock)
  2383. );
  2384. if (pEntry != NULL)
  2385. {
  2386. //
  2387. // Found a free irp !
  2388. //
  2389. pEntry->Blink = pEntry->Flink = NULL;
  2390. pIrp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
  2391. //
  2392. // pop the cancel routine
  2393. //
  2394. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  2395. {
  2396. //
  2397. // IoCancelIrp pop'd it first
  2398. //
  2399. // ok to just ignore this irp, it's been pop'd off the queue
  2400. // and will be completed in the cancel routine.
  2401. //
  2402. // keep looking for a irp to use
  2403. //
  2404. pIrp = NULL;
  2405. }
  2406. else if (pIrp->Cancel)
  2407. {
  2408. //
  2409. // we pop'd it first. but the irp is being cancelled
  2410. // and our cancel routine will never run. lets be
  2411. // nice and complete the irp now (vs. using it
  2412. // then completing it - which would also be legal).
  2413. //
  2414. pProcessAppPool = (PUL_APP_POOL_OBJECT)(
  2415. IoGetCurrentIrpStackLocation(pIrp)->
  2416. Parameters.DeviceIoControl.Type3InputBuffer
  2417. );
  2418. ASSERT(pProcessAppPool == pProcess->pAppPool);
  2419. DEREFERENCE_APP_POOL(pProcessAppPool);
  2420. IoGetCurrentIrpStackLocation(pIrp)->
  2421. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2422. pIrp->IoStatus.Status = STATUS_CANCELLED;
  2423. pIrp->IoStatus.Information = 0;
  2424. UlCompleteRequest(pIrp, g_UlPriorityBoost);
  2425. pIrp = NULL;
  2426. }
  2427. else
  2428. {
  2429. //
  2430. // we are free to use this irp !
  2431. //
  2432. pProcessAppPool = (PUL_APP_POOL_OBJECT)(
  2433. IoGetCurrentIrpStackLocation(pIrp)->
  2434. Parameters.DeviceIoControl.Type3InputBuffer
  2435. );
  2436. ASSERT(pProcessAppPool == pProcess->pAppPool);
  2437. DEREFERENCE_APP_POOL(pProcessAppPool);
  2438. IoGetCurrentIrpStackLocation(pIrp)->
  2439. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2440. }
  2441. }
  2442. return pIrp;
  2443. }
  2444. /***************************************************************************++
  2445. Routine Description:
  2446. Loops through an app pool's list of processes, looking for the specified
  2447. process.
  2448. Arguments:
  2449. pProcess - the process to search for
  2450. pAppPool - the app pool to search
  2451. Return Values:
  2452. TRUE if the process was found, FALSE otherwise
  2453. --***************************************************************************/
  2454. BOOLEAN
  2455. UlpIsProcessInAppPool(
  2456. IN PUL_APP_POOL_PROCESS pProcess,
  2457. IN PUL_APP_POOL_OBJECT pAppPool
  2458. )
  2459. {
  2460. BOOLEAN Found = FALSE;
  2461. PLIST_ENTRY pEntry;
  2462. PUL_APP_POOL_PROCESS pCurrentProc;
  2463. //
  2464. // Sanity check.
  2465. //
  2466. PAGED_CODE();
  2467. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  2468. //
  2469. // only look if process isn't NULL.
  2470. //
  2471. if (pProcess != NULL) {
  2472. //
  2473. // Start looking for the process.
  2474. //
  2475. pEntry = pAppPool->ProcessListHead.Flink;
  2476. while (pEntry != &(pAppPool->ProcessListHead))
  2477. {
  2478. pCurrentProc = CONTAINING_RECORD(
  2479. pEntry,
  2480. UL_APP_POOL_PROCESS,
  2481. ListEntry
  2482. );
  2483. ASSERT(IS_VALID_AP_PROCESS(pCurrentProc));
  2484. //
  2485. // did we find it?
  2486. //
  2487. if (pCurrentProc == pProcess) {
  2488. Found = TRUE;
  2489. break;
  2490. }
  2491. //
  2492. // keep looking - move on to the next process entry
  2493. //
  2494. pEntry = pCurrentProc->ListEntry.Flink;
  2495. }
  2496. if (!Found) {
  2497. //
  2498. // process must have gone away.
  2499. //
  2500. UlTrace(ROUTING, (
  2501. "ul!UlpIsProcessInAppPool(\n"
  2502. " pProcess = %p\n"
  2503. " pAppPool = %p (%S) )\n"
  2504. " returning FALSE\n",
  2505. pProcess,
  2506. pAppPool,
  2507. pAppPool->pName
  2508. ));
  2509. }
  2510. }
  2511. return Found;
  2512. }
  2513. /***************************************************************************++
  2514. Routine Description:
  2515. Adds a request to the unbound queue. These requests can be routed to
  2516. any process in the app pool.
  2517. Arguments:
  2518. pAppPool - the pool which is getting the request
  2519. pRequest - the request to queue
  2520. --***************************************************************************/
  2521. NTSTATUS
  2522. UlpQueueUnboundRequest(
  2523. IN PUL_APP_POOL_OBJECT pAppPool,
  2524. IN PUL_INTERNAL_REQUEST pRequest
  2525. )
  2526. {
  2527. NTSTATUS Status;
  2528. KLOCK_QUEUE_HANDLE LockHandle;
  2529. //
  2530. // Sanity check
  2531. //
  2532. PAGED_CODE();
  2533. ASSERT( IS_VALID_AP_OBJECT(pAppPool) );
  2534. ASSERT( UL_IS_VALID_INTERNAL_REQUEST(pRequest) );
  2535. UlAcquireInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  2536. //
  2537. // add it to the queue
  2538. //
  2539. Status = UlpQueueRequest(&pAppPool->NewRequestQueue, pRequest);
  2540. //
  2541. // if it's in, change the queue state
  2542. //
  2543. if (NT_SUCCESS(Status)) {
  2544. pRequest->AppPool.QueueState = QueueDeliveredState;
  2545. } else {
  2546. //
  2547. // the queue is too full, return an error to the client
  2548. //
  2549. UlTrace(ROUTING, (
  2550. "ul!UlpQueueUnboundRequest(pAppPool = %p, pRequest = %p)\n"
  2551. " Rejecting request. AppPool Queue is full (%d items)\n",
  2552. pAppPool,
  2553. pRequest,
  2554. UlpQueryQueueLength(&pAppPool->NewRequestQueue)
  2555. ));
  2556. pRequest->ErrorCode = UlErrorUnavailable; // 503
  2557. }
  2558. UlReleaseInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  2559. return Status;
  2560. } // UlpQueueUnboundRequest
  2561. /***************************************************************************++
  2562. Routine Description:
  2563. Searches request queues for a request available to the specified process.
  2564. If a request is found, it is removed from the queue and returned.
  2565. Arguments:
  2566. pProcess - the process that will get the request
  2567. Return Values:
  2568. Pointer to an HTTP_REQUEST if one is found.
  2569. NULL otherwise.
  2570. --***************************************************************************/
  2571. PUL_INTERNAL_REQUEST
  2572. UlpDequeueNewRequest(
  2573. IN PUL_APP_POOL_PROCESS pProcess
  2574. )
  2575. {
  2576. PLIST_ENTRY pEntry;
  2577. PUL_INTERNAL_REQUEST pRequest = NULL;
  2578. PUL_APP_POOL_OBJECT pAppPool;
  2579. KLOCK_QUEUE_HANDLE LockHandle;
  2580. //
  2581. // Sanity check
  2582. //
  2583. PAGED_CODE();
  2584. ASSERT( IS_VALID_AP_PROCESS(pProcess) );
  2585. pAppPool = pProcess->pAppPool;
  2586. ASSERT( IS_VALID_AP_OBJECT(pAppPool) );
  2587. UlAcquireInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  2588. //
  2589. // find a usable request
  2590. //
  2591. pEntry = pAppPool->NewRequestQueue.RequestHead.Flink;
  2592. while (pEntry != &pAppPool->NewRequestQueue.RequestHead) {
  2593. PUL_APP_POOL_PROCESS pProcBinding;
  2594. pRequest = CONTAINING_RECORD(
  2595. pEntry,
  2596. UL_INTERNAL_REQUEST,
  2597. AppPool.AppPoolEntry
  2598. );
  2599. ASSERT( UL_IS_VALID_INTERNAL_REQUEST(pRequest) );
  2600. if (pAppPool->NumberActiveProcesses <= 1) {
  2601. //
  2602. // done if there is only one active process
  2603. //
  2604. break;
  2605. }
  2606. //
  2607. // check the binding
  2608. //
  2609. pProcBinding = UlQueryProcessBinding(
  2610. pRequest->pHttpConn,
  2611. pAppPool
  2612. );
  2613. if (pProcBinding == pProcess) {
  2614. //
  2615. // found a request bound to the correct process
  2616. //
  2617. break;
  2618. } else if (pProcBinding == NULL) {
  2619. //
  2620. // found an unbound request
  2621. //
  2622. //
  2623. // bind unbound request to this process
  2624. // Note: we're ignoring the return val
  2625. // of UlBindConnectionToProcess because
  2626. // it's probably not a fatal error..
  2627. //
  2628. UlBindConnectionToProcess(
  2629. pRequest->pHttpConn,
  2630. pAppPool,
  2631. pProcess
  2632. );
  2633. break;
  2634. }
  2635. //
  2636. // try the next one
  2637. //
  2638. pEntry = pEntry->Flink;
  2639. }
  2640. //
  2641. // if we found something, remove it from the NewRequestQueue
  2642. // and pend it onto the PendingRequestQuueue
  2643. //
  2644. if (pRequest)
  2645. {
  2646. UlpRemoveRequest(&pAppPool->NewRequestQueue, pRequest);
  2647. //
  2648. // attach the request to this process. this allows us to drop the
  2649. // connection if the process dies in the middle of request
  2650. // processing
  2651. //
  2652. pRequest->AppPool.pProcess = pProcess;
  2653. pRequest->AppPool.QueueState = QueueCopiedState;
  2654. //
  2655. // add a reference to the request so as to allow unlink from
  2656. // process to happen once we let go of the lock
  2657. //
  2658. UL_REFERENCE_INTERNAL_REQUEST(pRequest);
  2659. UlpQueueRequest(
  2660. &pProcess->PendingRequestQueue,
  2661. pRequest
  2662. );
  2663. }
  2664. UlReleaseInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  2665. return pRequest;
  2666. } // UlpDequeueNewRequest
  2667. /***************************************************************************++
  2668. Routine Description:
  2669. Takes all the queued requests bound to the given process and makes them
  2670. available to all processes.
  2671. Arguments:
  2672. pProcess - the process whose requests are to be redistributed
  2673. --***************************************************************************/
  2674. VOID
  2675. UlpUnbindQueuedRequests(
  2676. IN PUL_APP_POOL_PROCESS pProcess
  2677. )
  2678. {
  2679. PLIST_ENTRY pEntry;
  2680. PUL_INTERNAL_REQUEST pRequest = NULL;
  2681. PUL_APP_POOL_OBJECT pAppPool;
  2682. KLOCK_QUEUE_HANDLE LockHandle;
  2683. //
  2684. // Sanity check
  2685. //
  2686. PAGED_CODE();
  2687. ASSERT( IS_VALID_AP_PROCESS(pProcess) );
  2688. pAppPool = pProcess->pAppPool;
  2689. ASSERT( IS_VALID_AP_OBJECT(pAppPool) );
  2690. UlAcquireInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  2691. //
  2692. // find a bound request
  2693. //
  2694. pEntry = pAppPool->NewRequestQueue.RequestHead.Flink;
  2695. while (pEntry != &pAppPool->NewRequestQueue.RequestHead) {
  2696. PUL_APP_POOL_PROCESS pProcBinding;
  2697. pRequest = CONTAINING_RECORD(
  2698. pEntry,
  2699. UL_INTERNAL_REQUEST,
  2700. AppPool.AppPoolEntry
  2701. );
  2702. ASSERT( UL_IS_VALID_INTERNAL_REQUEST(pRequest) );
  2703. //
  2704. // remember the next one
  2705. //
  2706. pEntry = pEntry->Flink;
  2707. //
  2708. // check the binding
  2709. //
  2710. if (pAppPool->NumberActiveProcesses <= 1) {
  2711. pProcBinding = pProcess;
  2712. } else {
  2713. pProcBinding = UlQueryProcessBinding(
  2714. pRequest->pHttpConn,
  2715. pAppPool
  2716. );
  2717. }
  2718. if (pProcBinding == pProcess) {
  2719. //
  2720. // remove from the list
  2721. //
  2722. UlpRemoveRequest(&pAppPool->NewRequestQueue, pRequest);
  2723. //
  2724. // mark it as unrouted
  2725. //
  2726. pRequest->AppPool.QueueState = QueueUnroutedState;
  2727. UlTrace(ROUTING, (
  2728. "STICKY KILL cid %I64x to proc %p\n",
  2729. pRequest->ConnectionId,
  2730. pProcess
  2731. ));
  2732. //
  2733. // kill the binding
  2734. //
  2735. UlBindConnectionToProcess(
  2736. pRequest->pHttpConn,
  2737. pProcess->pAppPool,
  2738. NULL
  2739. );
  2740. //
  2741. // there may be an IRP for this newly unbound
  2742. // request, so redeliver the request outside
  2743. // the locks we're holding.
  2744. //
  2745. UL_QUEUE_WORK_ITEM(
  2746. &pRequest->WorkItem,
  2747. &UlpRedeliverRequestWorker
  2748. );
  2749. }
  2750. }
  2751. UlReleaseInStackQueuedSpinLock(&pAppPool->QueueSpinLock, &LockHandle);
  2752. }
  2753. /***************************************************************************++
  2754. Routine Description:
  2755. Delivers the given request to an App Pool. UlpUnbindQueuedRequests
  2756. uses this routine to call into UlDeliverRequestToProcess outside
  2757. of any locks.
  2758. Arguments:
  2759. pWorkItem - embedded in the request to deliver
  2760. --***************************************************************************/
  2761. VOID
  2762. UlpRedeliverRequestWorker(
  2763. IN PUL_WORK_ITEM pWorkItem
  2764. )
  2765. {
  2766. NTSTATUS Status;
  2767. PUL_INTERNAL_REQUEST pRequest;
  2768. pRequest = CONTAINING_RECORD(
  2769. pWorkItem,
  2770. UL_INTERNAL_REQUEST,
  2771. WorkItem
  2772. );
  2773. //
  2774. // Sanity check
  2775. //
  2776. PAGED_CODE();
  2777. ASSERT( UL_IS_VALID_INTERNAL_REQUEST(pRequest) );
  2778. ASSERT( IS_VALID_URL_CONFIG_GROUP_INFO(&pRequest->ConfigInfo) );
  2779. ASSERT( pRequest->ConfigInfo.pAppPool );
  2780. Status = UlDeliverRequestToProcess(
  2781. pRequest->ConfigInfo.pAppPool,
  2782. pRequest
  2783. );
  2784. //
  2785. // remove the extra reference added in UlpUnbindQueuedRequests
  2786. //
  2787. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  2788. CHECK_STATUS(Status);
  2789. }
  2790. /***************************************************************************++
  2791. Routine Description:
  2792. Checks the request queue to see if there are any requests available
  2793. to the specified process.
  2794. Arguments:
  2795. pProcess - the process doing the check
  2796. Return Values:
  2797. TRUE if there are no requests available, FALSE if there are requests
  2798. --***************************************************************************/
  2799. BOOLEAN
  2800. UlpIsRequestQueueEmpty(
  2801. IN PUL_APP_POOL_PROCESS pProcess
  2802. )
  2803. {
  2804. PUL_APP_POOL_OBJECT pAppPool;
  2805. //
  2806. // Sanity check
  2807. //
  2808. PAGED_CODE();
  2809. ASSERT( IS_VALID_AP_PROCESS(pProcess) );
  2810. pAppPool = pProcess->pAppPool;
  2811. ASSERT( IS_VALID_AP_OBJECT(pAppPool) );
  2812. return (UlpQueryQueueLength(&pAppPool->NewRequestQueue) == 0);
  2813. }
  2814. /***************************************************************************++
  2815. Routine Description:
  2816. Changes the maximum length of the incoming request queue on the app pool.
  2817. Arguments:
  2818. pProcess - App pool process object
  2819. QueueLength - the new max length of the queue
  2820. --***************************************************************************/
  2821. NTSTATUS
  2822. UlpSetAppPoolQueueLength(
  2823. IN PUL_APP_POOL_PROCESS pProcess,
  2824. IN LONG QueueLength
  2825. )
  2826. {
  2827. PUL_APP_POOL_OBJECT pAppPool;
  2828. PLONG pQueueLength;
  2829. NTSTATUS Status;
  2830. pAppPool = pProcess->pAppPool;
  2831. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  2832. //
  2833. // set the new value
  2834. //
  2835. UlAcquireResourceExclusive(&pAppPool->pResource->Resource, TRUE);
  2836. Status = UlpSetMaxQueueLength(&pAppPool->NewRequestQueue, QueueLength);
  2837. UlTrace(ROUTING, (
  2838. "ul!UlpSetAppPoolQueueLength(pProcess = %p, QueueLength = %d)\n"
  2839. " pAppPool = %p (%ws), Status = 0x%08x\n",
  2840. pProcess,
  2841. QueueLength,
  2842. pAppPool,
  2843. pAppPool->pName,
  2844. Status
  2845. ));
  2846. UlReleaseResource(&pAppPool->pResource->Resource);
  2847. RETURN(Status);
  2848. }
  2849. /***************************************************************************++
  2850. Routine Description:
  2851. Gets the maximum length of the incoming request queue on the app pool.
  2852. Arguments:
  2853. pProcess - App pool process object
  2854. return value - max length of the queue
  2855. --***************************************************************************/
  2856. LONG
  2857. UlpGetAppPoolQueueLength(
  2858. IN PUL_APP_POOL_PROCESS pProcess
  2859. )
  2860. {
  2861. PUL_APP_POOL_OBJECT pAppPool;
  2862. NTSTATUS Status;
  2863. LONG QueueLength;
  2864. pAppPool = pProcess->pAppPool;
  2865. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  2866. //
  2867. // Get the max length
  2868. //
  2869. UlAcquireResourceExclusive(&pAppPool->pResource->Resource, TRUE);
  2870. QueueLength = pAppPool->NewRequestQueue.MaxRequests;
  2871. UlReleaseResource(&pAppPool->pResource->Resource);
  2872. return QueueLength;
  2873. }
  2874. /******************************************************************************
  2875. Routine Description:
  2876. this copies a request into a free irp.
  2877. if the request is too large, it queues to request onto the process and
  2878. completes the irp, so that the process can come back later with a larger
  2879. buffer.
  2880. Arguments:
  2881. pRequest - the request to copy
  2882. pProcess - the process that owns pIrp
  2883. pIrp - the irp to copy pRequest to
  2884. Return Value:
  2885. VOID - it always works.
  2886. ******************************************************************************/
  2887. VOID
  2888. UlpCopyRequestToIrp(
  2889. PUL_INTERNAL_REQUEST pRequest,
  2890. PIRP pIrp
  2891. )
  2892. {
  2893. NTSTATUS Status;
  2894. PIO_STACK_LOCATION pIrpSp;
  2895. ULONG BytesNeeded;
  2896. PUCHAR pKernelBuffer;
  2897. PVOID pUserBuffer;
  2898. //
  2899. // Sanity check.
  2900. //
  2901. PAGED_CODE();
  2902. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  2903. ASSERT(pIrp != NULL);
  2904. __try
  2905. {
  2906. //
  2907. // Make sure this is big enough to handle the request, and
  2908. // if so copy it in.
  2909. //
  2910. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  2911. //
  2912. // Calculate the size needed for the request, we'll need it below.
  2913. //
  2914. Status = UlpComputeRequestBytesNeeded(pRequest, &BytesNeeded);
  2915. if (!NT_SUCCESS(Status))
  2916. {
  2917. goto complete;
  2918. }
  2919. //
  2920. // Make sure we've got enough space to handle the whole request.
  2921. //
  2922. if (BytesNeeded <= pIrpSp->Parameters.DeviceIoControl.OutputBufferLength)
  2923. {
  2924. //
  2925. // get the addresses for the buffer
  2926. //
  2927. pKernelBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe(
  2928. pIrp->MdlAddress,
  2929. NormalPagePriority
  2930. );
  2931. if (pKernelBuffer == NULL)
  2932. {
  2933. Status = STATUS_INSUFFICIENT_RESOURCES;
  2934. goto complete;
  2935. }
  2936. //
  2937. // Make sure we are properly aligned.
  2938. //
  2939. if (((ULONG_PTR) pKernelBuffer) & (TYPE_ALIGNMENT(HTTP_REQUEST) - 1))
  2940. {
  2941. UlTrace(ROUTING, (
  2942. "UlpCopyRequestToIrp: pKernelBuffer = %p, Alignment = %p\n"
  2943. " ((ULONG_PTR) pKernelBuffer) & (TYPE_ALIGNMENT(HTTP_REQUEST) - 1) = %p\n",
  2944. pKernelBuffer,
  2945. TYPE_ALIGNMENT(HTTP_REQUEST),
  2946. ((ULONG_PTR) pKernelBuffer) & (TYPE_ALIGNMENT(HTTP_REQUEST) - 1)
  2947. ));
  2948. Status = STATUS_DATATYPE_MISALIGNMENT_ERROR;
  2949. goto complete;
  2950. }
  2951. pUserBuffer = MmGetMdlVirtualAddress( pIrp->MdlAddress );
  2952. ASSERT( pUserBuffer != NULL );
  2953. //
  2954. // This request will fit in this buffer, so copy it.
  2955. //
  2956. Status = UlpCopyRequestToBuffer(
  2957. pRequest,
  2958. pKernelBuffer,
  2959. pUserBuffer,
  2960. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  2961. NULL,
  2962. 0
  2963. );
  2964. if (NT_SUCCESS(Status))
  2965. {
  2966. pIrp->IoStatus.Information = BytesNeeded;
  2967. }
  2968. else
  2969. {
  2970. goto complete;
  2971. }
  2972. }
  2973. else
  2974. {
  2975. //
  2976. // the user buffer is too small
  2977. //
  2978. Status = STATUS_BUFFER_OVERFLOW;
  2979. //
  2980. // is it big enough to hold the basic structure?
  2981. //
  2982. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  2983. sizeof(HTTP_REQUEST))
  2984. {
  2985. PHTTP_REQUEST pUserRequest;
  2986. pUserRequest = (PHTTP_REQUEST)MmGetSystemAddressForMdlSafe(
  2987. pIrp->MdlAddress,
  2988. NormalPagePriority
  2989. );
  2990. if (pUserRequest == NULL)
  2991. {
  2992. Status = STATUS_INSUFFICIENT_RESOURCES;
  2993. goto complete;
  2994. }
  2995. //
  2996. // Copy the request ID into the output buffer. Copy it from the
  2997. // private copy that request holds. Original opaque id may get
  2998. // nulled if connection cleanup happens before we get here.
  2999. //
  3000. ASSERT(!HTTP_IS_NULL_ID(&pRequest->RequestIdCopy));
  3001. pUserRequest->RequestId = pRequest->RequestIdCopy;
  3002. pUserRequest->ConnectionId = pRequest->ConnectionId;
  3003. //
  3004. // and tell how much we actually need
  3005. //
  3006. pIrp->IoStatus.Information = BytesNeeded;
  3007. }
  3008. else
  3009. {
  3010. //
  3011. // Very bad, we can never get here as we check the length in ioctl.cxx
  3012. //
  3013. ASSERT(FALSE);
  3014. pIrp->IoStatus.Information = 0;
  3015. }
  3016. }
  3017. }
  3018. __except( UL_EXCEPTION_FILTER() )
  3019. {
  3020. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  3021. }
  3022. //
  3023. // complete the irp
  3024. //
  3025. complete:
  3026. UlTrace(ROUTING, (
  3027. "ul!UlpCopyRequestToIrp(\n"
  3028. " pRequest = %p,\n"
  3029. " pIrp = %p) Completing Irp\n"
  3030. " pAppPool = %p (%S)\n"
  3031. " pRequest->ConnectionId = %I64x\n"
  3032. " pIrpSp->Parameters.DeviceIoControl.OutputBufferLength = %d\n"
  3033. " pIrp->IoStatus.Status = 0x%x\n"
  3034. " pIrp->IoStatus.Information = %d\n",
  3035. pRequest,
  3036. pIrp,
  3037. pRequest->ConfigInfo.pAppPool,
  3038. pRequest->ConfigInfo.pAppPool->pName,
  3039. pRequest->ConnectionId,
  3040. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  3041. Status,
  3042. pIrp->IoStatus.Information
  3043. ));
  3044. pIrp->IoStatus.Status = Status;
  3045. UlCompleteRequest(pIrp, g_UlPriorityBoost);
  3046. //
  3047. // success. we completed the irp
  3048. //
  3049. } // UlpCopyRequestToIrp
  3050. /******************************************************************************
  3051. Routine Description:
  3052. this will return the apool object reference by this handle, bumping the
  3053. refcount on the apool.
  3054. this is called by UlSetConfigGroupInformation when user mode wants to
  3055. associate an app pool to the config group by handle.
  3056. the config group keeps a pointer to the apool.
  3057. Arguments:
  3058. AppPool - the handle of the apool
  3059. ppAppPool - returns the apool object the handle represented.
  3060. Return Value:
  3061. NTSTATUS
  3062. ******************************************************************************/
  3063. NTSTATUS
  3064. UlGetPoolFromHandle(
  3065. IN HANDLE AppPool,
  3066. OUT PUL_APP_POOL_OBJECT * ppAppPool
  3067. )
  3068. {
  3069. NTSTATUS Status;
  3070. PFILE_OBJECT pFileObject = NULL;
  3071. //
  3072. // Sanity check.
  3073. //
  3074. PAGED_CODE();
  3075. ASSERT(ppAppPool != NULL);
  3076. Status = ObReferenceObjectByHandle(
  3077. AppPool,
  3078. 0, // DesiredAccess
  3079. *IoFileObjectType, // ObjectType
  3080. KernelMode, // AccessMode
  3081. (void**)&pFileObject, // Object
  3082. NULL // HandleInformation
  3083. );
  3084. if (NT_SUCCESS(Status) == FALSE)
  3085. {
  3086. goto end;
  3087. }
  3088. if (IS_APP_POOL(pFileObject) == FALSE ||
  3089. IS_VALID_AP_PROCESS(GET_APP_POOL_PROCESS(pFileObject)) == FALSE)
  3090. {
  3091. Status = STATUS_INVALID_HANDLE;
  3092. goto end;
  3093. }
  3094. *ppAppPool = GET_APP_POOL_PROCESS(pFileObject)->pAppPool;
  3095. ASSERT(IS_VALID_AP_OBJECT(*ppAppPool));
  3096. REFERENCE_APP_POOL(*ppAppPool);
  3097. end:
  3098. if (pFileObject != NULL)
  3099. {
  3100. ObDereferenceObject( pFileObject );
  3101. }
  3102. return Status;
  3103. }
  3104. /******************************************************************************
  3105. Routine Description:
  3106. this routine is called to associate a HTTP_REQUEST with an apool
  3107. process.
  3108. this is basically always done (used to be for 2 [now 3] reasons):
  3109. 1) the process called ReceiveEntityBody and pended an IRP to the
  3110. request. if the process detaches from the apool (CloseHandle,
  3111. ExitProcess) UlDetachProcessFromAppPool will walk the request queue
  3112. and cancel all i/o.
  3113. 2) the request did not fit into a waiting irp, so the request is queued
  3114. for a larger irp to come down and fetch it.
  3115. 3) the response has not been fully sent for the request. the request
  3116. is linked with the process so that the connection can be aborted
  3117. if the process aborts.
  3118. Arguments:
  3119. pProcess - the process to associate the request with.
  3120. pRequest - the request.
  3121. Return Value:
  3122. VOID - it always works.
  3123. ******************************************************************************/
  3124. VOID
  3125. UlpQueuePendingRequest(
  3126. IN PUL_APP_POOL_PROCESS pProcess,
  3127. IN PUL_INTERNAL_REQUEST pRequest
  3128. )
  3129. {
  3130. NTSTATUS Status;
  3131. KLOCK_QUEUE_HANDLE LockHandle;
  3132. //
  3133. // Sanity check.
  3134. //
  3135. PAGED_CODE();
  3136. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  3137. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3138. UlTrace(ROUTING, (
  3139. "ul!UlpQueuePendingRequest(pRequest = %p, pProcess = %p)\n"
  3140. " pAppPool = %p (%S)\n",
  3141. pRequest,
  3142. pProcess,
  3143. pProcess->pAppPool,
  3144. pProcess->pAppPool->pName
  3145. ));
  3146. UlAcquireInStackQueuedSpinLock(
  3147. &pProcess->pAppPool->QueueSpinLock,
  3148. &LockHandle
  3149. );
  3150. //
  3151. // save a pointer to the process in the object so we can confirm
  3152. // that it's on our list.
  3153. //
  3154. pRequest->AppPool.pProcess = pProcess;
  3155. pRequest->AppPool.QueueState = QueueCopiedState;
  3156. //
  3157. // put it on the list
  3158. //
  3159. ASSERT(pRequest->AppPool.AppPoolEntry.Flink == NULL);
  3160. Status = UlpQueueRequest(
  3161. &pProcess->PendingRequestQueue,
  3162. pRequest
  3163. );
  3164. // queue is unlimited
  3165. ASSERT(NT_SUCCESS(Status));
  3166. UlReleaseInStackQueuedSpinLock(
  3167. &pProcess->pAppPool->QueueSpinLock,
  3168. &LockHandle
  3169. );
  3170. } // UlpQueuePendingRequest
  3171. //
  3172. // functions to manipulate a UL_REQUEST_QUEUE
  3173. //
  3174. /***************************************************************************++
  3175. Routine Description:
  3176. Initializes a UL_REQUEST_QUEUE object.
  3177. Arguments:
  3178. pQueue - The queue object to initialize
  3179. MaxRequests - The maximum allowed length of the queue
  3180. --***************************************************************************/
  3181. NTSTATUS
  3182. UlpInitRequestQueue(
  3183. PUL_REQUEST_QUEUE pQueue,
  3184. LONG MaxRequests
  3185. )
  3186. {
  3187. ASSERT(pQueue);
  3188. if ((MaxRequests < 0) && (MaxRequests != -1)) {
  3189. return STATUS_INVALID_PARAMETER;
  3190. }
  3191. pQueue->RequestCount = 0;
  3192. pQueue->MaxRequests = MaxRequests;
  3193. InitializeListHead(&pQueue->RequestHead);
  3194. return STATUS_SUCCESS;
  3195. }
  3196. /***************************************************************************++
  3197. Routine Description:
  3198. Changes the maximum length of a queue.
  3199. Arguments:
  3200. pQueue - The queue object to change
  3201. MaxRequests - The maximum allowed length of the queue
  3202. --***************************************************************************/
  3203. NTSTATUS
  3204. UlpSetMaxQueueLength(
  3205. PUL_REQUEST_QUEUE pQueue,
  3206. LONG MaxRequests
  3207. )
  3208. {
  3209. ASSERT(pQueue);
  3210. if ((MaxRequests < 0) && (MaxRequests != -1)) {
  3211. return STATUS_INVALID_PARAMETER;
  3212. }
  3213. pQueue->MaxRequests = MaxRequests;
  3214. return STATUS_SUCCESS;
  3215. }
  3216. /***************************************************************************++
  3217. Routine Description:
  3218. Queries the current length of a queue.
  3219. Arguments:
  3220. pQueue - The queue object to query
  3221. Return values:
  3222. LONG - the current length of the queue
  3223. --***************************************************************************/
  3224. LONG
  3225. UlpQueryQueueLength(
  3226. PUL_REQUEST_QUEUE pQueue
  3227. )
  3228. {
  3229. ASSERT(pQueue);
  3230. return pQueue->RequestCount;
  3231. }
  3232. /***************************************************************************++
  3233. Routine Description:
  3234. Adds a request to the tail of the queue.
  3235. Arguments:
  3236. pQueue - The queue object
  3237. pRequest - The request to be added
  3238. --***************************************************************************/
  3239. NTSTATUS
  3240. UlpQueueRequest(
  3241. PUL_REQUEST_QUEUE pQueue,
  3242. PUL_INTERNAL_REQUEST pRequest
  3243. )
  3244. {
  3245. ASSERT(pQueue);
  3246. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3247. if ((pQueue->RequestCount < pQueue->MaxRequests) ||
  3248. (pQueue->MaxRequests == -1))
  3249. {
  3250. //
  3251. // add to the end of the queue
  3252. //
  3253. InsertTailList(&pQueue->RequestHead, &pRequest->AppPool.AppPoolEntry);
  3254. pQueue->RequestCount++;
  3255. ASSERT(pQueue->RequestCount >= 1);
  3256. return STATUS_SUCCESS;
  3257. } else {
  3258. //
  3259. // the queue is too full, return an error to the client
  3260. //
  3261. return STATUS_DEVICE_BUSY;
  3262. }
  3263. }
  3264. /***************************************************************************++
  3265. Routine Description:
  3266. Removes a particular request from the queue.
  3267. Arguments:
  3268. pQueue - The queue object
  3269. pRequest - The request to be removed
  3270. --***************************************************************************/
  3271. VOID
  3272. UlpRemoveRequest(
  3273. PUL_REQUEST_QUEUE pQueue,
  3274. PUL_INTERNAL_REQUEST pRequest
  3275. )
  3276. {
  3277. ASSERT(pQueue);
  3278. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3279. ASSERT(NULL != pRequest->AppPool.AppPoolEntry.Flink);
  3280. RemoveEntryList(&pRequest->AppPool.AppPoolEntry);
  3281. pRequest->AppPool.AppPoolEntry.Flink =
  3282. pRequest->AppPool.AppPoolEntry.Blink = NULL;
  3283. pQueue->RequestCount--;
  3284. ASSERT(pQueue->RequestCount >= 0);
  3285. }
  3286. /***************************************************************************++
  3287. Routine Description:
  3288. Removes a request from the head of a queue if there is one.
  3289. App Pool lock must be held.
  3290. Arguments:
  3291. pQueue - The queue object
  3292. Return values:
  3293. Pointer to the request or NULL if the queue is empty.
  3294. --***************************************************************************/
  3295. PUL_INTERNAL_REQUEST
  3296. UlpDequeueRequest(
  3297. PUL_REQUEST_QUEUE pQueue
  3298. )
  3299. {
  3300. PLIST_ENTRY pEntry;
  3301. PUL_INTERNAL_REQUEST pRequest = NULL;
  3302. ASSERT(pQueue);
  3303. if (pQueue->RequestCount)
  3304. {
  3305. pEntry = RemoveHeadList(&pQueue->RequestHead);
  3306. ASSERT(pEntry != NULL);
  3307. pEntry->Flink = pEntry->Blink = NULL;
  3308. pQueue->RequestCount--;
  3309. pRequest = CONTAINING_RECORD(
  3310. pEntry,
  3311. UL_INTERNAL_REQUEST,
  3312. AppPool.AppPoolEntry
  3313. );
  3314. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3315. pRequest->AppPool.QueueState = QueueUnlinkedState;
  3316. }
  3317. else
  3318. ASSERT(IsListEmpty(&pQueue->RequestHead));
  3319. return pRequest;
  3320. }
  3321. /***************************************************************************++
  3322. Routine Description:
  3323. A little utility function to get the app pool pointer out of the
  3324. opaque app pool process object.
  3325. Arguments:
  3326. pProcess - the process object
  3327. --***************************************************************************/
  3328. PUL_APP_POOL_OBJECT
  3329. UlAppPoolObjectFromProcess(
  3330. PUL_APP_POOL_PROCESS pProcess
  3331. )
  3332. {
  3333. PAGED_CODE();
  3334. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  3335. ASSERT(IS_VALID_AP_OBJECT(pProcess->pAppPool));
  3336. return pProcess->pAppPool;
  3337. }
  3338. /***************************************************************************++
  3339. Routine Description:
  3340. Adds a config group to the list of transient registrations associated
  3341. with this app pool.
  3342. Arguments:
  3343. pConfigGroup - the transient group
  3344. pAppPool - the app pool with the registration
  3345. --***************************************************************************/
  3346. VOID
  3347. UlLinkConfigGroupToAppPool(
  3348. IN PUL_CONFIG_GROUP_OBJECT pConfigGroup,
  3349. IN PUL_APP_POOL_OBJECT pAppPool
  3350. )
  3351. {
  3352. //
  3353. // Sanity check
  3354. //
  3355. PAGED_CODE();
  3356. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  3357. ASSERT(IS_VALID_CONFIG_GROUP(pConfigGroup));
  3358. ASSERT(pConfigGroup->AppPoolFlags.Present);
  3359. ASSERT(pConfigGroup->pAppPool == pAppPool);
  3360. UlAddNotifyEntry(
  3361. &pAppPool->TransientHead,
  3362. &pConfigGroup->HandleEntry
  3363. );
  3364. }
  3365. /***************************************************************************++
  3366. Routine Description:
  3367. Determines if the specified connection has been disconnected. If so,
  3368. the IRP is completed immediately, otherwise the IRP is pended.
  3369. Arguments:
  3370. pProcess - the app pool process object with which the irp is associated.
  3371. pHttpConn - Supplies the connection to wait for.
  3372. N.B. Since this connection was retrieved via a opaque ID, it has
  3373. an outstanding reference for this request on the assumption the
  3374. IRP will pend. If this routine does not pend the IRP, the reference
  3375. must be removed.
  3376. pIrp - Supplies the IRP to either complete or pend.
  3377. Return Value:
  3378. NTSTATUS - Completion status.
  3379. --***************************************************************************/
  3380. NTSTATUS
  3381. UlWaitForDisconnect(
  3382. IN PUL_APP_POOL_PROCESS pProcess,
  3383. IN PUL_HTTP_CONNECTION pHttpConn,
  3384. IN PIRP pIrp
  3385. )
  3386. {
  3387. PDRIVER_CANCEL pCancelRoutine;
  3388. NTSTATUS status;
  3389. PIO_STACK_LOCATION pIrpSp;
  3390. PUL_DISCONNECT_OBJECT pDisconnectObj;
  3391. //
  3392. // Allocate an object to associate the IRP with the connection
  3393. // and the app pool
  3394. //
  3395. pDisconnectObj = UlpCreateDisconnectObject(pIrp);
  3396. if (!pDisconnectObj) {
  3397. UL_DEREFERENCE_HTTP_CONNECTION(pHttpConn);
  3398. return STATUS_NO_MEMORY;
  3399. }
  3400. //
  3401. // Acquire the lock protecting the disconnect data and determine
  3402. // if we should queue the IRP or complete it immediately.
  3403. //
  3404. UlAcquireResourceExclusive( &g_pUlNonpagedData->DisconnectResource, TRUE );
  3405. if (pHttpConn->DisconnectFlag)
  3406. {
  3407. //
  3408. // Connection already disconnected, complete the IRP immediately.
  3409. //
  3410. UlReleaseResource( &g_pUlNonpagedData->DisconnectResource );
  3411. UL_DEREFERENCE_HTTP_CONNECTION(pHttpConn);
  3412. UlpFreeDisconnectObject(pDisconnectObj);
  3413. IoMarkIrpPending(pIrp);
  3414. pIrp->IoStatus.Status = STATUS_SUCCESS;
  3415. UlCompleteRequest( pIrp, g_UlPriorityBoost );
  3416. return STATUS_PENDING;
  3417. }
  3418. //
  3419. // Save a pointer to the disconnect object in the IRP so we
  3420. // can find it inside our cancel routine.
  3421. //
  3422. pIrpSp = IoGetCurrentIrpStackLocation( pIrp );
  3423. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pDisconnectObj;
  3424. //
  3425. // Make the IRP cancellable.
  3426. //
  3427. IoMarkIrpPending( pIrp );
  3428. IoSetCancelRoutine( pIrp, &UlpCancelWaitForDisconnect );
  3429. if (pIrp->Cancel)
  3430. {
  3431. //
  3432. // The IRP has either already been cancelled IRP is in the
  3433. // process of being cancelled.
  3434. //
  3435. pCancelRoutine = IoSetCancelRoutine( pIrp, NULL );
  3436. if (pCancelRoutine == NULL)
  3437. {
  3438. //
  3439. // The previous cancel routine was already NULL, meaning that
  3440. // it has either already run or will run Real Soon Now, so
  3441. // we can just ignore it. Returning STATUS_PENDING causes
  3442. // the IOCTL wrapper to not attempt to complete the IRP.
  3443. //
  3444. status = STATUS_PENDING;
  3445. goto dont_queue;
  3446. }
  3447. else
  3448. {
  3449. //
  3450. // We have to cancel it ourselves, so we'll just complete
  3451. // the IRP immediately with STATUS_CANCELLED.
  3452. //
  3453. status = STATUS_CANCELLED;
  3454. goto dont_queue;
  3455. }
  3456. }
  3457. //
  3458. // The IRP has not been cancelled yet. Queue it on the connection
  3459. // and return with the connection still referenced. The reference
  3460. // is removed when the IRP is dequeued & completed or cancelled.
  3461. //
  3462. // Also queue it on the app pool process in case the pool handle
  3463. // gets closed before the connection does.
  3464. //
  3465. UlAddNotifyEntry(
  3466. &pHttpConn->WaitForDisconnectHead,
  3467. &pDisconnectObj->ConnectionEntry
  3468. );
  3469. UlAddNotifyEntry(
  3470. &pProcess->WaitForDisconnectHead,
  3471. &pDisconnectObj->ProcessEntry
  3472. );
  3473. UlReleaseResource( &g_pUlNonpagedData->DisconnectResource );
  3474. //
  3475. // now that we're on the lists we don't need the reference to
  3476. // the HTTP_CONNECTION.
  3477. //
  3478. UL_DEREFERENCE_HTTP_CONNECTION( pHttpConn );
  3479. return STATUS_PENDING;
  3480. dont_queue:
  3481. UL_DEREFERENCE_HTTP_CONNECTION( pHttpConn );
  3482. UlUnmarkIrpPending( pIrp );
  3483. UlReleaseResource( &g_pUlNonpagedData->DisconnectResource );
  3484. UlpFreeDisconnectObject(pDisconnectObj);
  3485. return status;
  3486. } // UlWaitForDisconnect
  3487. /***************************************************************************++
  3488. Routine Description:
  3489. Cancels the pending "wait for disconnect" IRP.
  3490. Arguments:
  3491. pDeviceObject - Supplies the device object for the request.
  3492. pIrp - Supplies the IRP to cancel.
  3493. --***************************************************************************/
  3494. VOID
  3495. UlpCancelWaitForDisconnect(
  3496. IN PDEVICE_OBJECT pDeviceObject,
  3497. IN PIRP pIrp
  3498. )
  3499. {
  3500. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  3501. ASSERT(pIrp != NULL);
  3502. //
  3503. // release the cancel spinlock. This means the cancel routine
  3504. // must be the one completing the irp (to avoid the race of
  3505. // completion + reuse prior to the cancel routine running).
  3506. //
  3507. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  3508. //
  3509. // queue the cancel to a worker to ensure passive irql.
  3510. //
  3511. UL_CALL_PASSIVE(
  3512. UL_WORK_ITEM_FROM_IRP( pIrp ),
  3513. &UlpCancelWaitForDisconnectWorker
  3514. );
  3515. }
  3516. /***************************************************************************++
  3517. Routine Description:
  3518. Actually performs the cancel for the irp.
  3519. Arguments:
  3520. pWorkItem - the work item to process.
  3521. --***************************************************************************/
  3522. VOID
  3523. UlpCancelWaitForDisconnectWorker(
  3524. IN PUL_WORK_ITEM pWorkItem
  3525. )
  3526. {
  3527. PIRP pIrp;
  3528. PIO_STACK_LOCATION pIrpSp;
  3529. PUL_DISCONNECT_OBJECT pDisconnectObj;
  3530. //
  3531. // Sanity check.
  3532. //
  3533. PAGED_CODE();
  3534. //
  3535. // grab the irp off the work item
  3536. //
  3537. pIrp = UL_WORK_ITEM_TO_IRP( pWorkItem );
  3538. ASSERT(IS_VALID_IRP(pIrp));
  3539. //
  3540. // grab the disconnect object off the irp
  3541. //
  3542. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  3543. pDisconnectObj = (PUL_DISCONNECT_OBJECT)(
  3544. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer
  3545. );
  3546. ASSERT(IS_VALID_DISCONNECT_OBJECT(pDisconnectObj));
  3547. //
  3548. // Acquire the lock protecting the disconnect data, and remove the
  3549. // IRP if necessary.
  3550. //
  3551. UlAcquireResourceExclusive( &g_pUlNonpagedData->DisconnectResource, TRUE );
  3552. UlRemoveNotifyEntry(&pDisconnectObj->ConnectionEntry);
  3553. UlRemoveNotifyEntry(&pDisconnectObj->ProcessEntry);
  3554. UlReleaseResource( &g_pUlNonpagedData->DisconnectResource );
  3555. //
  3556. // Free the disconnect object and complete the IRP.
  3557. //
  3558. UlpFreeDisconnectObject(pDisconnectObj);
  3559. pIrp->IoStatus.Status = STATUS_CANCELLED;
  3560. pIrp->IoStatus.Information = 0;
  3561. UlCompleteRequest( pIrp, g_UlPriorityBoost );
  3562. } // UlpCancelWaitForDisconnectWorker
  3563. /***************************************************************************++
  3564. Routine Description:
  3565. Completes all WaitForDisconnect IRPs attached to an http connection
  3566. has been disconnected.
  3567. Arguments:
  3568. pHttpConnection - the connection that's disconnected
  3569. --***************************************************************************/
  3570. VOID
  3571. UlCompleteAllWaitForDisconnect(
  3572. IN PUL_HTTP_CONNECTION pHttpConnection
  3573. )
  3574. {
  3575. PLIST_ENTRY pListEntry;
  3576. PIRP pIrp;
  3577. NTSTATUS Success = STATUS_SUCCESS;
  3578. //
  3579. // Sanity check
  3580. //
  3581. PAGED_CODE();
  3582. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConnection));
  3583. UlAcquireResourceExclusive( &g_pUlNonpagedData->DisconnectResource, TRUE);
  3584. //
  3585. // prevent new IRPs from getting attached to the connection,
  3586. // by setting the DisconnectFlag.
  3587. //
  3588. ASSERT(!pHttpConnection->DisconnectFlag);
  3589. pHttpConnection->DisconnectFlag = TRUE;
  3590. //
  3591. // Complete any pending "wait for disconnect" IRPs.
  3592. //
  3593. UlNotifyAllEntries(
  3594. &UlpNotifyCompleteWaitForDisconnect,
  3595. &pHttpConnection->WaitForDisconnectHead,
  3596. &Success
  3597. );
  3598. UlReleaseResource( &g_pUlNonpagedData->DisconnectResource );
  3599. }
  3600. /***************************************************************************++
  3601. Routine Description:
  3602. Removes a UL_DISCONNECT_OBJECT from its lists and completes the IRP.
  3603. Arguments:
  3604. pEntry - the notify list entry
  3605. pHost - the UL_DISCONNECT_OBJECT
  3606. pv - pointer to an NTSTATUS to be returned
  3607. --***************************************************************************/
  3608. BOOLEAN
  3609. UlpNotifyCompleteWaitForDisconnect(
  3610. IN PUL_NOTIFY_ENTRY pEntry,
  3611. IN PVOID pHost,
  3612. IN PVOID pv
  3613. )
  3614. {
  3615. PUL_DISCONNECT_OBJECT pDisconnectObj;
  3616. PIRP pIrp;
  3617. PDRIVER_CANCEL pCancelRoutine;
  3618. PNTSTATUS pStatus;
  3619. //
  3620. // Sanity check
  3621. //
  3622. PAGED_CODE();
  3623. ASSERT(pEntry);
  3624. ASSERT(pHost);
  3625. ASSERT(pv);
  3626. pStatus = (PNTSTATUS) pv;
  3627. pDisconnectObj = (PUL_DISCONNECT_OBJECT) pHost;
  3628. ASSERT(IS_VALID_DISCONNECT_OBJECT(pDisconnectObj));
  3629. //
  3630. // remove object from lists
  3631. //
  3632. UlRemoveNotifyEntry(&pDisconnectObj->ConnectionEntry);
  3633. UlRemoveNotifyEntry(&pDisconnectObj->ProcessEntry);
  3634. //
  3635. // complete the IRP
  3636. //
  3637. pIrp = pDisconnectObj->pIrp;
  3638. //
  3639. // We'll be completing the IRP real soon, so make it
  3640. // non-cancellable.
  3641. //
  3642. pCancelRoutine = IoSetCancelRoutine( pIrp, NULL );
  3643. if (pCancelRoutine == NULL)
  3644. {
  3645. //
  3646. // The cancel routine is already NULL, meaning that the
  3647. // cancel routine will run Real Soon Now, so we can
  3648. // just drop this IRP on the floor.
  3649. //
  3650. }
  3651. else
  3652. {
  3653. //
  3654. // Complete the IRP, then free the disconnect object
  3655. //
  3656. pIrp->IoStatus.Status = *pStatus;
  3657. pIrp->IoStatus.Information = 0;
  3658. UlCompleteRequest( pIrp, g_UlPriorityBoost );
  3659. UlpFreeDisconnectObject(pDisconnectObj);
  3660. }
  3661. return TRUE;
  3662. }
  3663. /***************************************************************************++
  3664. Routine Description:
  3665. Allocates and initializes a disconnect object.
  3666. Arguments:
  3667. pIrp - a UlWaitForDisconnect IRP
  3668. --***************************************************************************/
  3669. PUL_DISCONNECT_OBJECT
  3670. UlpCreateDisconnectObject(
  3671. IN PIRP pIrp
  3672. )
  3673. {
  3674. PUL_DISCONNECT_OBJECT pObject;
  3675. pObject = UL_ALLOCATE_STRUCT(
  3676. PagedPool,
  3677. UL_DISCONNECT_OBJECT,
  3678. UL_DISCONNECT_OBJECT_POOL_TAG
  3679. );
  3680. if (pObject) {
  3681. pObject->Signature = UL_DISCONNECT_OBJECT_POOL_TAG;
  3682. pObject->pIrp = pIrp;
  3683. UlInitializeNotifyEntry(&pObject->ProcessEntry, pObject);
  3684. UlInitializeNotifyEntry(&pObject->ConnectionEntry, pObject);
  3685. }
  3686. return pObject;
  3687. }
  3688. /***************************************************************************++
  3689. Routine Description:
  3690. Gets rid of a disconnect object
  3691. Arguments:
  3692. pObject - the disconnect object to free
  3693. --***************************************************************************/
  3694. VOID
  3695. UlpFreeDisconnectObject(
  3696. IN PUL_DISCONNECT_OBJECT pObject
  3697. )
  3698. {
  3699. UL_FREE_POOL_WITH_SIG(pObject, UL_DISCONNECT_OBJECT_POOL_TAG);
  3700. }