Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5963 lines
154 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name:
  4. apool.c
  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"
  13. #include "apoolp.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text( INIT, UlInitializeAP )
  16. #pragma alloc_text( PAGE, UlTerminateAP )
  17. #pragma alloc_text( PAGE, UlGetPoolFromHandle )
  18. #pragma alloc_text( PAGE, UlQueryAppPoolInformation )
  19. #pragma alloc_text( PAGE, UlSetAppPoolInformation )
  20. #pragma alloc_text( PAGE, UlCloseAppPoolProcess )
  21. #pragma alloc_text( PAGE, UlCopyRequestToBuffer )
  22. #pragma alloc_text( PAGE, UlCopyRequestToIrp )
  23. #pragma alloc_text( PAGE, UlpCopyEntityBodyToBuffer )
  24. #pragma alloc_text( PAGE, UlpRedeliverRequestWorker )
  25. #endif // ALLOC_PRAGMA
  26. #if 0
  27. #if REFERENCE_DEBUG
  28. NOT PAGEABLE -- UlDereferenceAppPool
  29. NOT PAGEABLE -- UlReferenceAppPool
  30. #endif
  31. NOT PAGEABLE -- UlAttachProcessToAppPool
  32. NOT PAGEABLE -- UlDetachProcessFromAppPool
  33. NOT PAGEABLE -- UlShutdownAppPoolProcess
  34. NOT PAGEABLE -- UlReceiveHttpRequest
  35. NOT PAGEABLE -- UlDeliverRequestToProcess
  36. NOT PAGEABLE -- UlUnlinkRequestFromProcess
  37. NOT PAGEABLE -- UlWaitForDisconnect
  38. NOT PAGEABLE -- UlDequeueNewRequest
  39. NOT PAGEABLE -- UlRequeuePendingRequest
  40. NOT PAGEABLE -- UlpSetAppPoolState
  41. NOT PAGEABLE -- UlpPopIrpFromProcess
  42. NOT PAGEABLE -- UlpQueuePendingRequest
  43. NOT PAGEABLE -- UlpQueueUnboundRequest
  44. NOT PAGEABLE -- UlpUnbindQueuedRequests
  45. NOT PAGEABLE -- UlDeleteAppPool
  46. NOT PAGEABLE -- UlpPopNewIrp
  47. NOT PAGEABLE -- UlpIsProcessInAppPool
  48. NOT PAGEABLE -- UlpQueueRequest
  49. NOT PAGEABLE -- UlpRemoveRequest
  50. NOT PAGEABLE -- UlpDequeueRequest
  51. NOT PAGEABLE -- UlpSetAppPoolControlChannelHelper
  52. NOT PAGEABLE -- UlWaitForDemandStart
  53. NOT PAGEABLE -- UlCompleteAllWaitForDisconnect
  54. NOT PAGEABLE -- UlpCancelDemandStart
  55. NOT PAGEABLE -- UlpCancelHttpReceive
  56. NOT PAGEABLE -- UlpCancelWaitForDisconnect
  57. NOT PAGEABLE -- UlpCancelWaitForDisconnectWorker
  58. NOT PAGEABLE -- UlReferenceAppPoolProcess
  59. NOT PAGEABLE -- UlDereferenceAppPoolProcess
  60. NOT PAGEABLE -- UlpSetAppPoolQueueLength
  61. #endif
  62. //
  63. // Globals
  64. //
  65. LIST_ENTRY g_AppPoolListHead = {NULL, NULL};
  66. BOOLEAN g_InitAPCalled = FALSE;
  67. LONG g_RequestsQueued = 0;
  68. /***************************************************************************++
  69. Routine Description:
  70. Creates a new process object and attaches it to an apool.
  71. Called by handle create and returns the process object to attach to the
  72. handle.
  73. Arguments:
  74. pName - the name of the apool to attach to
  75. N.B. Since pName comes from IoMgr (tag IoNm),
  76. we can safely reference it without extra playing.
  77. NameLength - the byte count of pName
  78. Create - whether or not a new apool should be created if pName
  79. does not exist
  80. pAccessState - the state of an access-in-progress
  81. DesiredAccess - the desired access mask
  82. RequestorMode - UserMode or KernelMode
  83. ppProcess - returns the newly created PROCESS object
  84. Return Value:
  85. NTSTATUS - Completion status.
  86. --***************************************************************************/
  87. NTSTATUS
  88. UlAttachProcessToAppPool(
  89. IN PWCHAR pName OPTIONAL,
  90. IN USHORT NameLength,
  91. IN BOOLEAN Create,
  92. IN PACCESS_STATE pAccessState,
  93. IN ACCESS_MASK DesiredAccess,
  94. IN KPROCESSOR_MODE RequestorMode,
  95. OUT PUL_APP_POOL_PROCESS * ppProcess
  96. )
  97. {
  98. NTSTATUS Status;
  99. PUL_APP_POOL_OBJECT pObject = NULL;
  100. PUL_APP_POOL_PROCESS pProcess = NULL;
  101. LIST_ENTRY * pEntry;
  102. KLOCK_QUEUE_HANDLE LockHandle;
  103. BOOLEAN SecurityAssigned = FALSE;
  104. ULONG Index;
  105. //
  106. // Sanity check.
  107. //
  108. PAGED_CODE();
  109. ASSERT(ppProcess != NULL);
  110. Status = STATUS_SUCCESS;
  111. *ppProcess = NULL;
  112. ASSERT(NameLength < UL_MAX_APP_POOL_NAME_SIZE);
  113. //
  114. // WAS-type controller process can only be created not opened.
  115. //
  116. if (!Create && (DesiredAccess & WRITE_OWNER))
  117. {
  118. return STATUS_NOT_SUPPORTED;
  119. }
  120. //
  121. // Make sure the AppPool name if passed in doesn't contain '/' since
  122. // it is used as a deliminator of a fragment name.
  123. //
  124. for (Index = 0; Index < NameLength/sizeof(WCHAR); Index++)
  125. {
  126. if (L'/' == pName[Index])
  127. {
  128. return STATUS_OBJECT_NAME_INVALID;
  129. }
  130. }
  131. //
  132. // Try and find an existing app pool of this name; also potentially
  133. // pre-allocate the memory.
  134. //
  135. UlAcquireResourceExclusive(&g_pUlNonpagedData->AppPoolResource, TRUE);
  136. if (pName != NULL)
  137. {
  138. pEntry = g_AppPoolListHead.Flink;
  139. //
  140. // CODEWORK: use something faster than a linear search.
  141. // This won't scale well to hundreds of app pools.
  142. // On the other hand, this isn't something we'll be doing thousands
  143. // of times a second.
  144. //
  145. while (pEntry != &g_AppPoolListHead)
  146. {
  147. pObject = CONTAINING_RECORD(
  148. pEntry,
  149. UL_APP_POOL_OBJECT,
  150. ListEntry
  151. );
  152. if (pObject->NameLength == NameLength &&
  153. _wcsnicmp(pObject->pName, pName, NameLength/sizeof(WCHAR)) == 0)
  154. {
  155. //
  156. // Match.
  157. //
  158. break;
  159. }
  160. pEntry = pEntry->Flink;
  161. }
  162. //
  163. // Found 1?
  164. //
  165. if (pEntry == &g_AppPoolListHead)
  166. {
  167. pObject = NULL;
  168. }
  169. }
  170. //
  171. // Found 1?
  172. //
  173. if (pObject == NULL)
  174. {
  175. //
  176. // Nope, allowed to create?
  177. //
  178. if (!Create)
  179. {
  180. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  181. goto end;
  182. }
  183. //
  184. // Create it. Allocate the object memory.
  185. //
  186. pObject = UL_ALLOCATE_STRUCT_WITH_SPACE(
  187. NonPagedPool,
  188. UL_APP_POOL_OBJECT,
  189. NameLength + sizeof(WCHAR),
  190. UL_APP_POOL_OBJECT_POOL_TAG
  191. );
  192. if (pObject == NULL)
  193. {
  194. Status = STATUS_NO_MEMORY;
  195. goto end;
  196. }
  197. RtlZeroMemory(
  198. pObject,
  199. NameLength + sizeof(WCHAR) +
  200. sizeof(UL_APP_POOL_OBJECT)
  201. );
  202. pObject->Signature = UL_APP_POOL_OBJECT_POOL_TAG;
  203. pObject->RefCount = 1;
  204. pObject->NameLength = NameLength;
  205. pObject->State = HttpAppPoolDisabled_ByAdministrator;
  206. pObject->LoadBalancerCapability = HttpLoadBalancerBasicCapability;
  207. pObject->pControlChannel = NULL;
  208. InitializeListHead(&pObject->ProcessListHead);
  209. InitializeListHead(&pObject->NewRequestHead);
  210. pObject->RequestCount = 0;
  211. pObject->MaxRequests = DEFAULT_APP_POOL_QUEUE_MAX;
  212. UlInitializeSpinLock(&pObject->SpinLock, "AppPoolSpinLock");
  213. if (pName != NULL)
  214. {
  215. RtlCopyMemory(
  216. pObject->pName,
  217. pName,
  218. NameLength + sizeof(WCHAR)
  219. );
  220. }
  221. //
  222. // Set the security descriptor.
  223. //
  224. Status = UlAssignSecurity(
  225. &pObject->pSecurityDescriptor,
  226. pAccessState
  227. );
  228. if (!NT_SUCCESS(Status))
  229. {
  230. goto end;
  231. }
  232. SecurityAssigned = TRUE;
  233. WRITE_APP_POOL_TIME_TRACE_LOG(
  234. pObject,
  235. NULL,
  236. APP_POOL_TIME_ACTION_CREATE_APPOOL
  237. );
  238. UlTrace(REFCOUNT, (
  239. "http!UlAttachProcessToAppPool ap=%p refcount=%d\n",
  240. pObject,
  241. pObject->RefCount
  242. ));
  243. }
  244. else // if (pObject != NULL)
  245. {
  246. //
  247. // We found the named AppPool object in the list. Reference it.
  248. //
  249. REFERENCE_APP_POOL(pObject);
  250. //
  251. // We found one. Were we trying to create?
  252. //
  253. if (Create)
  254. {
  255. Status = STATUS_OBJECT_NAME_COLLISION;
  256. goto end;
  257. }
  258. //
  259. // Perform an access check against the app pool.
  260. //
  261. Status = UlAccessCheck(
  262. pObject->pSecurityDescriptor,
  263. pAccessState,
  264. DesiredAccess,
  265. RequestorMode,
  266. pName
  267. );
  268. if (!NT_SUCCESS(Status))
  269. {
  270. goto end;
  271. }
  272. }
  273. //
  274. // Create a process entry for it.
  275. //
  276. pProcess = UlCreateAppPoolProcess(pObject);
  277. if (pProcess == NULL)
  278. {
  279. Status = STATUS_NO_MEMORY;
  280. goto end;
  281. }
  282. REFERENCE_APP_POOL_PROCESS(pProcess);
  283. //
  284. // Put the process in the app pool list.
  285. //
  286. UlAcquireInStackQueuedSpinLock(&pObject->SpinLock, &LockHandle);
  287. if (DesiredAccess & WRITE_OWNER)
  288. {
  289. pProcess->Controller = 1;
  290. }
  291. else
  292. {
  293. pObject->NumberActiveProcesses++;
  294. if (pObject->pControlChannel)
  295. {
  296. InterlockedIncrement(
  297. (PLONG)&pObject->pControlChannel->AppPoolProcessCount
  298. );
  299. }
  300. }
  301. InsertHeadList(&pObject->ProcessListHead, &pProcess->ListEntry);
  302. UlReleaseInStackQueuedSpinLock(&pObject->SpinLock, &LockHandle);
  303. WRITE_APP_POOL_TIME_TRACE_LOG(
  304. pObject,
  305. pProcess,
  306. APP_POOL_TIME_ACTION_CREATE_PROCESS
  307. );
  308. //
  309. // Insert AppPool into the global list if it has been created.
  310. //
  311. if (Create)
  312. {
  313. InsertHeadList(&g_AppPoolListHead, &pObject->ListEntry);
  314. }
  315. //
  316. // Return it.
  317. //
  318. *ppProcess = pProcess;
  319. end:
  320. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  321. if (NT_SUCCESS(Status) == FALSE)
  322. {
  323. if (pObject != NULL)
  324. {
  325. if (SecurityAssigned)
  326. {
  327. UlDeassignSecurity(&pObject->pSecurityDescriptor);
  328. }
  329. DEREFERENCE_APP_POOL(pObject);
  330. }
  331. if (pProcess != NULL)
  332. {
  333. UL_FREE_POOL_WITH_SIG(pProcess, UL_APP_POOL_PROCESS_POOL_TAG);
  334. }
  335. }
  336. return Status;
  337. } // UlAttachProcessToAppPool
  338. /***************************************************************************++
  339. Routine Description:
  340. This is called by UlCleanup when the handle count goes to 0. It removes
  341. the PROCESS object from the apool, cancelling all i/o .
  342. Arguments:
  343. pCleanupIrp - the cleanup irp
  344. pCleanupIrpSp - the current stack location of the cleanup irp
  345. Return Value:
  346. NTSTATUS - Completion status.
  347. --***************************************************************************/
  348. NTSTATUS
  349. UlDetachProcessFromAppPool(
  350. IN PIRP pCleanupIrp,
  351. IN PIO_STACK_LOCATION pCleanupIrpSp
  352. )
  353. {
  354. LIST_ENTRY PendingRequestHead;
  355. PUL_APP_POOL_OBJECT pAppPool;
  356. NTSTATUS CancelStatus = STATUS_CANCELLED;
  357. PUL_INTERNAL_REQUEST pRequest;
  358. KLOCK_QUEUE_HANDLE LockHandle;
  359. PUL_APP_POOL_PROCESS pProcess;
  360. BOOLEAN ListEmpty;
  361. PLIST_ENTRY pEntry;
  362. //
  363. // Sanity check.
  364. //
  365. PAGED_CODE();
  366. pProcess = GET_APP_POOL_PROCESS(pCleanupIrpSp->FileObject);
  367. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  368. UlTrace(ROUTING, (
  369. "http!UlDetachProcessFromAppPool(%p, %S)\n",
  370. pProcess,
  371. pProcess->pAppPool->pName
  372. ));
  373. pAppPool = pProcess->pAppPool;
  374. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  375. WRITE_APP_POOL_TIME_TRACE_LOG(
  376. pAppPool,
  377. pProcess,
  378. APP_POOL_TIME_ACTION_DETACH_PROCESS
  379. );
  380. //
  381. // Mark that this appool process is invalid for further
  382. // ioctls.
  383. //
  384. MARK_INVALID_APP_POOL(pCleanupIrpSp->FileObject);
  385. //
  386. // Shut down I/O on the handle.
  387. //
  388. UlShutdownAppPoolProcess(pProcess);
  389. //
  390. // Do final cleanup for the process.
  391. //
  392. UlAcquireResourceExclusive(&g_pUlNonpagedData->AppPoolResource, TRUE);
  393. //
  394. // Unlink from the App Pool list.
  395. //
  396. UlAcquireInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  397. RemoveEntryList(&pProcess->ListEntry);
  398. pProcess->ListEntry.Flink = pProcess->ListEntry.Blink = NULL;
  399. //
  400. // Move requests that have been passed up to the process to
  401. // a local list so their connections can be closed.
  402. //
  403. InitializeListHead(&PendingRequestHead);
  404. while (NULL != (pRequest = UlpDequeueRequest(
  405. pAppPool,
  406. &pProcess->PendingRequestHead
  407. )))
  408. {
  409. //
  410. // Move the entry to local list so we can close its
  411. // connection outside the app pool lock.
  412. //
  413. InsertTailList(&PendingRequestHead, &pRequest->AppPool.AppPoolEntry);
  414. }
  415. //
  416. // Adjust number of active processes.
  417. //
  418. if (!pProcess->Controller)
  419. {
  420. pAppPool->NumberActiveProcesses--;
  421. if (pAppPool->pControlChannel)
  422. {
  423. InterlockedDecrement(
  424. (PLONG)&pAppPool->pControlChannel->AppPoolProcessCount
  425. );
  426. }
  427. }
  428. ListEmpty = (BOOLEAN) IsListEmpty(&pAppPool->ProcessListHead);
  429. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  430. //
  431. // Remove the AppPool from the global list if this is the last process
  432. //
  433. if (ListEmpty)
  434. {
  435. RemoveEntryList(&pAppPool->ListEntry);
  436. pAppPool->ListEntry.Flink = pAppPool->ListEntry.Blink = NULL;
  437. //
  438. // Cleanup any security descriptor on the object.
  439. //
  440. UlDeassignSecurity(&pAppPool->pSecurityDescriptor);
  441. }
  442. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  443. //
  444. // Disable the AppPool to clean up the NewRequestQueue if we are the
  445. // last process on the AppPool.
  446. //
  447. if (ListEmpty)
  448. {
  449. UlpSetAppPoolState(pProcess, HttpAppPoolDisabled_ByAdministrator);
  450. }
  451. //
  452. // Close connections associated with the requests that
  453. // the process was handling.
  454. //
  455. while (!IsListEmpty(&PendingRequestHead))
  456. {
  457. pEntry = RemoveHeadList(&PendingRequestHead);
  458. pEntry->Flink = pEntry->Blink = NULL;
  459. pRequest = CONTAINING_RECORD(
  460. pEntry,
  461. UL_INTERNAL_REQUEST,
  462. AppPool.AppPoolEntry
  463. );
  464. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  465. UlTrace(ROUTING, (
  466. "http!UlDetachProcessFromAppPool(%p, %S): tanking pending req=%p\n",
  467. pProcess,
  468. pAppPool->pName,
  469. pRequest
  470. ));
  471. //
  472. // Cancel any pending I/O related to this request.
  473. //
  474. UlAcquirePushLockExclusive(&pRequest->pHttpConn->PushLock);
  475. UlCancelRequestIo(pRequest);
  476. //
  477. // Try to log an entry to the error log file.
  478. // pHttpConn's request pointer could be null, (unlinked)
  479. // need to pass the pRequest separetely.
  480. //
  481. UlErrorLog( pRequest->pHttpConn,
  482. pRequest,
  483. ERROR_LOG_INFO_FOR_APP_POOL_DETACH,
  484. ERROR_LOG_INFO_FOR_APP_POOL_DETACH_SIZE,
  485. TRUE
  486. );
  487. UlReleasePushLockExclusive(&pRequest->pHttpConn->PushLock);
  488. //
  489. // Abort the connection this request is associated with.
  490. //
  491. (VOID) UlCloseConnection(
  492. pRequest->pHttpConn->pConnection,
  493. TRUE,
  494. NULL,
  495. NULL
  496. );
  497. //
  498. // Drop our list's reference.
  499. //
  500. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  501. }
  502. ASSERT(IsListEmpty(&PendingRequestHead));
  503. //
  504. // Purge all zombie connections that belong to this process.
  505. //
  506. UlPurgeZombieConnections(
  507. &UlPurgeAppPoolProcess,
  508. (PVOID) pProcess
  509. );
  510. //
  511. // Cancel any remaining WaitForDisconnect IRPs.
  512. //
  513. UlAcquireResourceExclusive(&g_pUlNonpagedData->DisconnectResource, TRUE);
  514. UlNotifyAllEntries(
  515. UlpNotifyCompleteWaitForDisconnect,
  516. &pProcess->WaitForDisconnectHead,
  517. &CancelStatus
  518. );
  519. UlReleaseResource(&g_pUlNonpagedData->DisconnectResource);
  520. //
  521. // Kill any cache entries related to this process.
  522. //
  523. UlFlushCacheByProcess(pProcess);
  524. //
  525. // Mark the original cleanup irp pending and then deref and return.
  526. // When the refcount on pProcess reaches to zero it will complete
  527. // the cleanup irp.
  528. //
  529. IoMarkIrpPending(pCleanupIrp);
  530. pCleanupIrp->IoStatus.Status = STATUS_PENDING;
  531. //
  532. // Tell the process which Irp to complete once it's ready
  533. // to go away.
  534. //
  535. pProcess->pCleanupIrp = pCleanupIrp;
  536. //
  537. // Release our refcount on the pProcess.
  538. //
  539. DEREFERENCE_APP_POOL_PROCESS(pProcess);
  540. return STATUS_PENDING;
  541. } // UlDetachProcessFromAppPool
  542. /***************************************************************************++
  543. Routine Description:
  544. Cleans up outstanding I/O on an app pool process. This function
  545. cancels all calls to HttpReceiveHttpRequest, and routes queued
  546. requests to other worker processes. Outstanding send i/o is not
  547. affected.
  548. Arguments:
  549. pProcess - the process object to shut down
  550. Return Value:
  551. None
  552. --***************************************************************************/
  553. VOID
  554. UlShutdownAppPoolProcess(
  555. IN PUL_APP_POOL_PROCESS pProcess
  556. )
  557. {
  558. PUL_APP_POOL_OBJECT pAppPool;
  559. PUL_APP_POOL_OBJECT pDemandStartAppPool;
  560. KLOCK_QUEUE_HANDLE LockHandle;
  561. LIST_ENTRY RequestList;
  562. PUL_INTERNAL_REQUEST pRequest;
  563. PLIST_ENTRY pEntry;
  564. PIRP pIrp;
  565. PUL_APP_POOL_PROCESS pAppPoolProcess;
  566. //
  567. // Sanity check.
  568. //
  569. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  570. pAppPool = pProcess->pAppPool;
  571. UlAcquireResourceExclusive(&g_pUlNonpagedData->AppPoolResource, TRUE);
  572. UlAcquireInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  573. if (pProcess->InCleanup)
  574. {
  575. //
  576. // If we've already done this, get out.
  577. //
  578. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  579. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  580. return;
  581. }
  582. //
  583. // Mark the process as InCleanup so new I/O won't be attached,
  584. // and so we won't try to clean it up again.
  585. //
  586. pProcess->InCleanup = 1;
  587. //
  588. // Cancel demand start IRP.
  589. //
  590. if (pProcess->Controller && pAppPool->pDemandStartIrp != NULL)
  591. {
  592. if (IoSetCancelRoutine(pAppPool->pDemandStartIrp, NULL) == NULL)
  593. {
  594. //
  595. // IoCancelIrp pop'd it first, ok to just ignore this irp,
  596. // it's been pop'd off the queue and will be completed in the
  597. // cancel routine. No need to complete it.
  598. //
  599. }
  600. else
  601. {
  602. pDemandStartAppPool = (PUL_APP_POOL_OBJECT)
  603. IoGetCurrentIrpStackLocation(pAppPool->pDemandStartIrp)->
  604. Parameters.DeviceIoControl.Type3InputBuffer;
  605. ASSERT(pDemandStartAppPool == pAppPool);
  606. DEREFERENCE_APP_POOL(pAppPool);
  607. IoGetCurrentIrpStackLocation(pAppPool->pDemandStartIrp)->
  608. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  609. pAppPool->pDemandStartIrp->IoStatus.Status = STATUS_CANCELLED;
  610. pAppPool->pDemandStartIrp->IoStatus.Information = 0;
  611. UlCompleteRequest(pAppPool->pDemandStartIrp, IO_NO_INCREMENT);
  612. }
  613. pAppPool->pDemandStartIrp = NULL;
  614. pAppPool->pDemandStartProcess = NULL;
  615. }
  616. //
  617. // Cancel pending HttpReceiveHttpRequest IRPs.
  618. //
  619. while (!IsListEmpty(&pProcess->NewIrpHead))
  620. {
  621. //
  622. // Pop it off the list.
  623. //
  624. pEntry = RemoveHeadList(&pProcess->NewIrpHead);
  625. pEntry->Blink = pEntry->Flink = NULL;
  626. pIrp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
  627. ASSERT(IS_VALID_IRP(pIrp));
  628. //
  629. // Pop the cancel routine.
  630. //
  631. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  632. {
  633. //
  634. // IoCancelIrp pop'd it first, ok to just ignore this irp,
  635. // it's been pop'd off the queue and will be completed in the
  636. // cancel routine. Keep looping.
  637. //
  638. pIrp = NULL;
  639. }
  640. else
  641. {
  642. //
  643. // Cancel it. Even if pIrp->Cancel == TRUE we are supposed to
  644. // complete it, our cancel routine will never run.
  645. //
  646. pAppPoolProcess = (PUL_APP_POOL_PROCESS)
  647. IoGetCurrentIrpStackLocation(pIrp)->
  648. Parameters.DeviceIoControl.Type3InputBuffer;
  649. ASSERT(pAppPoolProcess == pProcess);
  650. DEREFERENCE_APP_POOL_PROCESS(pAppPoolProcess);
  651. IoGetCurrentIrpStackLocation(pIrp)->
  652. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  653. pIrp->IoStatus.Status = STATUS_CANCELLED;
  654. pIrp->IoStatus.Information = 0;
  655. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  656. pIrp = NULL;
  657. }
  658. }
  659. //
  660. // Move requests that have been passed up to the process to a local list
  661. // so their pending HttpReceiveEntityBody IRPs can be canceled.
  662. //
  663. InitializeListHead(&RequestList);
  664. pEntry = pProcess->PendingRequestHead.Flink;
  665. while (pEntry != &pProcess->PendingRequestHead)
  666. {
  667. pRequest = CONTAINING_RECORD(
  668. pEntry,
  669. UL_INTERNAL_REQUEST,
  670. AppPool.AppPoolEntry
  671. );
  672. pEntry = pEntry->Flink;
  673. //
  674. // Take a short lived reference for the request so we can traverse
  675. // the list outside the AppPool lock.
  676. //
  677. UL_REFERENCE_INTERNAL_REQUEST(pRequest);
  678. InsertTailList(&RequestList, &pRequest->AppPool.ProcessEntry);
  679. }
  680. //
  681. // Unbind requests that haven't been passed up to this process so
  682. // they can be handled by other processes in the app pool.
  683. //
  684. UlpUnbindQueuedRequests(pProcess);
  685. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  686. UlReleaseResource(&g_pUlNonpagedData->AppPoolResource);
  687. //
  688. // Cancel pending HttpReceiveEntityBody IRPs.
  689. //
  690. while (!IsListEmpty(&RequestList))
  691. {
  692. pEntry = RemoveHeadList(&RequestList);
  693. pEntry->Flink = pEntry->Blink = NULL;
  694. pRequest = CONTAINING_RECORD(
  695. pEntry,
  696. UL_INTERNAL_REQUEST,
  697. AppPool.ProcessEntry
  698. );
  699. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  700. //
  701. // Cancel any pending I/O related to this request.
  702. //
  703. UlAcquirePushLockExclusive(&pRequest->pHttpConn->PushLock);
  704. UlCancelRequestIo(pRequest);
  705. UlReleasePushLockExclusive(&pRequest->pHttpConn->PushLock);
  706. //
  707. // Drop the extra short lived reference we just added.
  708. //
  709. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  710. }
  711. } // UlShutdownAppPoolProcess
  712. #if REFERENCE_DEBUG
  713. /***************************************************************************++
  714. Routine Description:
  715. Increments the refcount.
  716. Arguments:
  717. pAppPool - the object to increment.
  718. Return Value:
  719. None
  720. --***************************************************************************/
  721. VOID
  722. UlReferenceAppPool(
  723. IN PUL_APP_POOL_OBJECT pAppPool
  724. REFERENCE_DEBUG_FORMAL_PARAMS
  725. )
  726. {
  727. LONG RefCount;
  728. //
  729. // Sanity check.
  730. //
  731. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  732. RefCount = InterlockedIncrement(&pAppPool->RefCount);
  733. ASSERT(RefCount > 0);
  734. WRITE_REF_TRACE_LOG(
  735. g_pAppPoolTraceLog,
  736. REF_ACTION_REFERENCE_APP_POOL,
  737. RefCount,
  738. pAppPool,
  739. pFileName,
  740. LineNumber
  741. );
  742. UlTrace(REFCOUNT, (
  743. "http!UlReferenceAppPool ap=%p refcount=%d\n",
  744. pAppPool,
  745. RefCount
  746. ));
  747. } // UlReferenceAppPool
  748. /***************************************************************************++
  749. Routine Description:
  750. Decrements the refcount. If it hits 0, destruct's the apool, cancelling
  751. all i/o and dumping all queued requests.
  752. Arguments:
  753. pAppPool - the object to decrement.
  754. Return Value:
  755. None
  756. --***************************************************************************/
  757. VOID
  758. UlDereferenceAppPool(
  759. IN PUL_APP_POOL_OBJECT pAppPool
  760. REFERENCE_DEBUG_FORMAL_PARAMS
  761. )
  762. {
  763. LONG RefCount;
  764. //
  765. // Sanity check.
  766. //
  767. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  768. RefCount = InterlockedDecrement(&pAppPool->RefCount);
  769. ASSERT(RefCount >= 0);
  770. //
  771. // Tracing.
  772. //
  773. WRITE_REF_TRACE_LOG(
  774. g_pAppPoolTraceLog,
  775. REF_ACTION_DEREFERENCE_APP_POOL,
  776. RefCount,
  777. pAppPool,
  778. pFileName,
  779. LineNumber
  780. );
  781. UlTrace(REFCOUNT, (
  782. "http!UlDereferenceAppPool ap=%p refcount=%d\n",
  783. pAppPool,
  784. RefCount
  785. ));
  786. //
  787. // Clean up if necessary.
  788. //
  789. if (RefCount == 0)
  790. {
  791. DELETE_APP_POOL(pAppPool);
  792. }
  793. } // UlDereferenceAppPool
  794. /***************************************************************************++
  795. Routine Description:
  796. Increments the refcount on appool process.
  797. Arguments:
  798. pAppPoolProcess - the object to increment
  799. Return Value:
  800. None
  801. --***************************************************************************/
  802. VOID
  803. UlReferenceAppPoolProcess(
  804. IN PUL_APP_POOL_PROCESS pAppPoolProcess
  805. REFERENCE_DEBUG_FORMAL_PARAMS
  806. )
  807. {
  808. LONG RefCount;
  809. //
  810. // Sanity check.
  811. //
  812. ASSERT(IS_VALID_AP_PROCESS(pAppPoolProcess));
  813. RefCount = InterlockedIncrement(&pAppPoolProcess->RefCount);
  814. WRITE_REF_TRACE_LOG(
  815. g_pAppPoolProcessTraceLog,
  816. REF_ACTION_REFERENCE_APP_POOL_PROCESS,
  817. RefCount,
  818. pAppPoolProcess,
  819. pFileName,
  820. LineNumber
  821. );
  822. UlTrace(ROUTING,(
  823. "http!UlReferenceAppPoolProcess app=%p refcount=%d\n",
  824. pAppPoolProcess,
  825. RefCount
  826. ));
  827. } // UlReferenceAppPoolProcess
  828. /***************************************************************************++
  829. Routine Description:
  830. Decrements the refcount. If it hits 0, it completes the pending cleanup
  831. irp for the process. But does not free up the process structure itself.
  832. The structure get cleaned up when close on the process handle happens.
  833. FastIo path may call us at dispacth level, luckily pAppPoolProcess is
  834. from nonpaged pool and we queue a work item.
  835. Arguments:
  836. pAppPoolProcess - the object to decrement
  837. Return Value:
  838. None
  839. --***************************************************************************/
  840. VOID
  841. UlDereferenceAppPoolProcess(
  842. IN PUL_APP_POOL_PROCESS pAppPoolProcess
  843. REFERENCE_DEBUG_FORMAL_PARAMS
  844. )
  845. {
  846. LONG RefCount;
  847. //
  848. // Sanity check.
  849. //
  850. ASSERT(IS_VALID_AP_PROCESS(pAppPoolProcess));
  851. RefCount = InterlockedDecrement(&pAppPoolProcess->RefCount);
  852. //
  853. // Tracing.
  854. //
  855. WRITE_REF_TRACE_LOG(
  856. g_pAppPoolProcessTraceLog,
  857. REF_ACTION_DEREFERENCE_APP_POOL_PROCESS,
  858. RefCount,
  859. pAppPoolProcess,
  860. pFileName,
  861. LineNumber
  862. );
  863. UlTrace(ROUTING, (
  864. "http!UlDereferenceAppPoolProcess app=%p refcount=%d\n",
  865. pAppPoolProcess,
  866. RefCount
  867. ));
  868. if (RefCount == 0)
  869. {
  870. ASSERT(pAppPoolProcess->pCleanupIrp);
  871. UlpCleanUpAppoolProcess(pAppPoolProcess);
  872. }
  873. } // UlDereferenceAppPoolProcess
  874. #endif // REFERENCE_DEBUG
  875. /***************************************************************************++
  876. Routine Description:
  877. The actual cleanup routine to do the original cleanup Irp completion
  878. once the refcount on the process reaches to zero.
  879. Arguments:
  880. pAppPoolProcess - the appool process
  881. Return Value:
  882. None
  883. --***************************************************************************/
  884. VOID
  885. UlpCleanUpAppoolProcess(
  886. IN PUL_APP_POOL_PROCESS pAppPoolProcess
  887. )
  888. {
  889. PIRP pIrp;
  890. //
  891. // Sanity check.
  892. //
  893. ASSERT(IS_VALID_AP_PROCESS(pAppPoolProcess));
  894. ASSERT(pAppPoolProcess->RefCount == 0);
  895. pIrp = pAppPoolProcess->pCleanupIrp;
  896. ASSERT(pIrp);
  897. WRITE_APP_POOL_TIME_TRACE_LOG(
  898. pAppPoolProcess->pAppPool,
  899. pAppPoolProcess,
  900. APP_POOL_TIME_ACTION_DETACH_PROCESS_COMPLETE
  901. );
  902. pAppPoolProcess->pCleanupIrp = NULL;
  903. UlTrace(ROUTING,(
  904. "http!UlpCleanUpAppoolProcess: pAppPoolProcess %p pIrp %p\n",
  905. pAppPoolProcess,
  906. pIrp
  907. ));
  908. pIrp->IoStatus.Status = STATUS_SUCCESS;
  909. UlCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  910. } // UlpCleanUpAppoolProcess
  911. /***************************************************************************++
  912. Routine Description:
  913. Destructs the apool object.
  914. Arguments:
  915. pAppPool - the object to destruct
  916. Return Value:
  917. None
  918. --***************************************************************************/
  919. VOID
  920. UlDeleteAppPool(
  921. IN PUL_APP_POOL_OBJECT pAppPool
  922. REFERENCE_DEBUG_FORMAL_PARAMS
  923. )
  924. {
  925. #if REFERENCE_DEBUG
  926. UNREFERENCED_PARAMETER(pFileName);
  927. UNREFERENCED_PARAMETER(LineNumber);
  928. #endif
  929. ASSERT(0 == pAppPool->RefCount);
  930. //
  931. // There better not be any process objects hanging around.
  932. //
  933. ASSERT(IsListEmpty(&pAppPool->ProcessListHead));
  934. //
  935. // There better not be any pending requests hanging around.
  936. //
  937. ASSERT(IsListEmpty(&pAppPool->NewRequestHead));
  938. //
  939. // If we're holding a ref on a control channel, release it.
  940. //
  941. if (pAppPool->pControlChannel)
  942. {
  943. DEREFERENCE_CONTROL_CHANNEL(pAppPool->pControlChannel);
  944. }
  945. WRITE_APP_POOL_TIME_TRACE_LOG(
  946. pAppPool,
  947. NULL,
  948. APP_POOL_TIME_ACTION_DESTROY_APPOOL
  949. );
  950. UL_FREE_POOL_WITH_SIG(pAppPool, UL_APP_POOL_OBJECT_POOL_TAG);
  951. } // UlDeleteAppPool
  952. /***************************************************************************++
  953. Routine Description:
  954. Queries the app-pool queue length.
  955. Arguments:
  956. pProcess - the appool process
  957. InformationClass - tells which information we want to query
  958. pAppPoolInformation - pointer to the buffer to return information
  959. Length - length of the buffer to return information
  960. pReturnLength - tells how many bytes we have returned
  961. Return Value:
  962. NTSTATUS - Completion status.
  963. --***************************************************************************/
  964. NTSTATUS
  965. UlQueryAppPoolInformation(
  966. IN PUL_APP_POOL_PROCESS pProcess,
  967. IN HTTP_APP_POOL_INFORMATION_CLASS InformationClass,
  968. OUT PVOID pAppPoolInformation,
  969. IN ULONG Length,
  970. OUT PULONG pReturnLength
  971. )
  972. {
  973. NTSTATUS Status = STATUS_SUCCESS;
  974. UNREFERENCED_PARAMETER(Length);
  975. //
  976. // Sanity check.
  977. //
  978. PAGED_CODE();
  979. ASSERT(pReturnLength);
  980. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  981. ASSERT(IS_VALID_AP_OBJECT(pProcess->pAppPool));
  982. //
  983. // Do the action.
  984. //
  985. switch (InformationClass)
  986. {
  987. case HttpAppPoolQueueLengthInformation:
  988. *((PULONG) pAppPoolInformation) = pProcess->pAppPool->MaxRequests;
  989. *pReturnLength = sizeof(ULONG);
  990. break;
  991. case HttpAppPoolStateInformation:
  992. *((PHTTP_APP_POOL_ENABLED_STATE) pAppPoolInformation) =
  993. pProcess->pAppPool->State;
  994. *pReturnLength = sizeof(HTTP_APP_POOL_ENABLED_STATE);
  995. break;
  996. case HttpAppPoolLoadBalancerInformation:
  997. *((PHTTP_LOAD_BALANCER_CAPABILITIES) pAppPoolInformation) =
  998. pProcess->pAppPool->LoadBalancerCapability;
  999. *pReturnLength = sizeof(HTTP_LOAD_BALANCER_CAPABILITIES);
  1000. break;
  1001. default:
  1002. //
  1003. // Should have been caught in UlQueryAppPoolInformationIoctl.
  1004. //
  1005. ASSERT(FALSE);
  1006. Status = STATUS_INVALID_PARAMETER;
  1007. break;
  1008. }
  1009. return Status;
  1010. } // UlQueryAppPoolInformation
  1011. /***************************************************************************++
  1012. Routine Description:
  1013. Sets the app-pool queue length etc.
  1014. Arguments:
  1015. pProcess - the appool process
  1016. InformationClass - tells which information we want to set
  1017. pAppPoolInformation - pointer to the buffer for the input information
  1018. Length - length of the buffer for the input information
  1019. Return Value:
  1020. NTSTATUS - Completion status.
  1021. --***************************************************************************/
  1022. NTSTATUS
  1023. UlSetAppPoolInformation(
  1024. IN PUL_APP_POOL_PROCESS pProcess,
  1025. IN HTTP_APP_POOL_INFORMATION_CLASS InformationClass,
  1026. IN PVOID pAppPoolInformation,
  1027. IN ULONG Length
  1028. )
  1029. {
  1030. NTSTATUS Status = STATUS_SUCCESS;
  1031. ULONG QueueLength;
  1032. HTTP_APP_POOL_ENABLED_STATE State;
  1033. HTTP_LOAD_BALANCER_CAPABILITIES Capabilities;
  1034. UNREFERENCED_PARAMETER(Length);
  1035. //
  1036. // Sanity check.
  1037. //
  1038. PAGED_CODE();
  1039. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  1040. ASSERT(pAppPoolInformation);
  1041. //
  1042. // Do the action.
  1043. //
  1044. switch (InformationClass)
  1045. {
  1046. case HttpAppPoolQueueLengthInformation:
  1047. QueueLength = *((PULONG) pAppPoolInformation);
  1048. if (QueueLength > UL_MAX_REQUESTS_QUEUED ||
  1049. QueueLength < UL_MIN_REQUESTS_QUEUED)
  1050. {
  1051. return STATUS_NOT_SUPPORTED;
  1052. }
  1053. else
  1054. {
  1055. Status = UlpSetAppPoolQueueLength(pProcess, QueueLength);
  1056. }
  1057. break;
  1058. case HttpAppPoolStateInformation:
  1059. State = *((PHTTP_APP_POOL_ENABLED_STATE) pAppPoolInformation);
  1060. if (State < HttpAppPoolEnabled ||
  1061. State >= HttpAppPoolEnabledMaximum)
  1062. {
  1063. Status = STATUS_NOT_SUPPORTED;
  1064. }
  1065. else
  1066. {
  1067. UlpSetAppPoolState(pProcess, State);
  1068. }
  1069. break;
  1070. case HttpAppPoolLoadBalancerInformation:
  1071. Capabilities =
  1072. *((PHTTP_LOAD_BALANCER_CAPABILITIES) pAppPoolInformation);
  1073. if (Capabilities != HttpLoadBalancerBasicCapability &&
  1074. Capabilities != HttpLoadBalancerSophisticatedCapability)
  1075. {
  1076. Status = STATUS_NOT_SUPPORTED;
  1077. }
  1078. else
  1079. {
  1080. UlpSetAppPoolLoadBalancerCapability(pProcess, Capabilities);
  1081. }
  1082. break;
  1083. case HttpAppPoolControlChannelInformation:
  1084. {
  1085. PHTTP_APP_POOL_CONTROL_CHANNEL pControlChannelInfo;
  1086. PUL_CONTROL_CHANNEL pControlChannel;
  1087. if (Length < sizeof(HTTP_APP_POOL_CONTROL_CHANNEL))
  1088. {
  1089. Status = STATUS_INVALID_PARAMETER;
  1090. }
  1091. else
  1092. {
  1093. pControlChannelInfo =
  1094. (PHTTP_APP_POOL_CONTROL_CHANNEL) pAppPoolInformation;
  1095. if (pControlChannelInfo->Flags.Present)
  1096. {
  1097. Status = UlGetControlChannelFromHandle(
  1098. pControlChannelInfo->ControlChannel,
  1099. UserMode,
  1100. &pControlChannel
  1101. );
  1102. if (NT_SUCCESS(Status))
  1103. {
  1104. UlpSetAppPoolControlChannelHelper(
  1105. pProcess,
  1106. pControlChannel
  1107. );
  1108. }
  1109. }
  1110. }
  1111. }
  1112. break;
  1113. default:
  1114. //
  1115. // Should have been caught in UlSetAppPoolInformationIoctl.
  1116. //
  1117. ASSERT(FALSE);
  1118. Status = STATUS_INVALID_PARAMETER;
  1119. break;
  1120. }
  1121. return Status;
  1122. } // UlSetAppPoolInformation
  1123. /*++
  1124. Routine Description:
  1125. Sets the app-pool control channel property. Must be non-pageable
  1126. because we need to take the app pool spin lock.
  1127. Arguments:
  1128. pProcess - the appool process
  1129. pControlChannel - the new control channel to set on the app pool
  1130. --*/
  1131. VOID
  1132. UlpSetAppPoolControlChannelHelper(
  1133. IN PUL_APP_POOL_PROCESS pProcess,
  1134. IN PUL_CONTROL_CHANNEL pControlChannel
  1135. )
  1136. {
  1137. PUL_CONTROL_CHANNEL pOldControlChannel;
  1138. PUL_APP_POOL_OBJECT pAppPool;
  1139. KLOCK_QUEUE_HANDLE LockHandle;
  1140. // NOT_PAGEABLE
  1141. pAppPool = pProcess->pAppPool;
  1142. UlAcquireInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  1143. //
  1144. // Get the old control channle (if any)
  1145. //
  1146. pOldControlChannel = pAppPool->pControlChannel;
  1147. //
  1148. // Set new control channel on app pool
  1149. //
  1150. pProcess->pAppPool->pControlChannel = pControlChannel;
  1151. //
  1152. // If we already have a control channel on the app pool,
  1153. // remove this app pool's count & deref old control channel.
  1154. //
  1155. if (pOldControlChannel)
  1156. {
  1157. InterlockedExchangeAdd(
  1158. (PLONG)&pOldControlChannel->AppPoolProcessCount,
  1159. -((LONG)pProcess->pAppPool->NumberActiveProcesses)
  1160. );
  1161. DEREFERENCE_CONTROL_CHANNEL(pOldControlChannel);
  1162. }
  1163. //
  1164. // add this AppPool's active process count to control channel.
  1165. //
  1166. InterlockedExchangeAdd(
  1167. (PLONG)&pControlChannel->AppPoolProcessCount,
  1168. pProcess->pAppPool->NumberActiveProcesses
  1169. );
  1170. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  1171. return;
  1172. }
  1173. /***************************************************************************++
  1174. Routine Description:
  1175. Convert AppPoolEnabledState to ErrorCode.
  1176. Arguments:
  1177. State - AppPoolEnabledState
  1178. Return Value:
  1179. ErrorCode
  1180. --***************************************************************************/
  1181. UL_HTTP_ERROR
  1182. UlpConvertAppPoolEnabledStateToErrorCode(
  1183. IN HTTP_APP_POOL_ENABLED_STATE State
  1184. )
  1185. {
  1186. UL_HTTP_ERROR ErrorCode;
  1187. ASSERT(State != HttpAppPoolEnabled);
  1188. switch (State)
  1189. {
  1190. case HttpAppPoolDisabled_RapidFailProtection:
  1191. ErrorCode = UlErrorRapidFailProtection;
  1192. break;
  1193. case HttpAppPoolDisabled_AppPoolQueueFull:
  1194. ErrorCode = UlErrorAppPoolQueueFull;
  1195. break;
  1196. case HttpAppPoolDisabled_ByAdministrator:
  1197. ErrorCode = UlErrorDisabledByAdmin;
  1198. break;
  1199. case HttpAppPoolDisabled_JobObjectFired:
  1200. ErrorCode = UlErrorJobObjectFired;
  1201. break;
  1202. case HttpAppPoolEnabled:
  1203. default:
  1204. ASSERT(!"Invalid HTTP_APP_POOL_ENABLED_STATE");
  1205. ErrorCode = UlErrorUnavailable; // generic 503
  1206. break;
  1207. }
  1208. return ErrorCode;
  1209. } // UlpConvertAppPoolEnabledStateToErrorCode
  1210. /***************************************************************************++
  1211. Routine Description:
  1212. Marks an app pool as active or inactive. If setting to inactive,
  1213. will return immediately 503 on all requests queued to app pool.
  1214. Arguments:
  1215. pProcess - the app pool process object with which the irp is associated
  1216. State - mark app pool as active or inactive
  1217. Return Value:
  1218. NTSTATUS - Completion status.
  1219. --***************************************************************************/
  1220. NTSTATUS
  1221. UlpSetAppPoolState(
  1222. IN PUL_APP_POOL_PROCESS pProcess,
  1223. IN HTTP_APP_POOL_ENABLED_STATE State
  1224. )
  1225. {
  1226. PUL_APP_POOL_OBJECT pAppPool;
  1227. KLOCK_QUEUE_HANDLE LockHandle;
  1228. PUL_INTERNAL_REQUEST pRequest;
  1229. PUL_HTTP_CONNECTION pHttpConn;
  1230. ULONG Requests = 0;
  1231. UL_HTTP_ERROR ErrorCode = UlErrorUnavailable;
  1232. LIST_ENTRY NewRequestHead;
  1233. PLIST_ENTRY pEntry;
  1234. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  1235. pAppPool = pProcess->pAppPool;
  1236. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  1237. UlTrace(ROUTING, (
  1238. "http!UlpSetAppPoolState(AppPool=%p, %lu).\n",
  1239. pAppPool, (ULONG) State
  1240. ));
  1241. InitializeListHead(&NewRequestHead);
  1242. UlAcquireInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  1243. pAppPool->State = State;
  1244. if (State != HttpAppPoolEnabled)
  1245. {
  1246. ErrorCode = UlpConvertAppPoolEnabledStateToErrorCode(State);
  1247. WRITE_APP_POOL_TIME_TRACE_LOG(
  1248. pAppPool,
  1249. (PVOID) (ULONG_PTR) State,
  1250. APP_POOL_TIME_ACTION_MARK_APPOOL_INACTIVE
  1251. );
  1252. while (NULL != (pRequest = UlpDequeueRequest(
  1253. pAppPool,
  1254. &pAppPool->NewRequestHead
  1255. )))
  1256. {
  1257. //
  1258. // Move the entry to a local list so we can process them
  1259. // outside the app pool lock.
  1260. //
  1261. InsertTailList(&NewRequestHead, &pRequest->AppPool.AppPoolEntry);
  1262. }
  1263. }
  1264. else
  1265. {
  1266. WRITE_APP_POOL_TIME_TRACE_LOG(
  1267. pAppPool,
  1268. NULL,
  1269. APP_POOL_TIME_ACTION_MARK_APPOOL_ACTIVE
  1270. );
  1271. }
  1272. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  1273. //
  1274. // Send 503 to all the requests we have removed from the queue.
  1275. //
  1276. while (!IsListEmpty(&NewRequestHead))
  1277. {
  1278. pEntry = RemoveHeadList(&NewRequestHead);
  1279. pEntry->Flink = pEntry->Blink = NULL;
  1280. pRequest = CONTAINING_RECORD(
  1281. pEntry,
  1282. UL_INTERNAL_REQUEST,
  1283. AppPool.AppPoolEntry
  1284. );
  1285. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1286. pHttpConn = pRequest->pHttpConn;
  1287. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConn));
  1288. UlAcquirePushLockExclusive(&pHttpConn->PushLock);
  1289. if (pHttpConn->UlconnDestroyed)
  1290. {
  1291. ASSERT(NULL == pHttpConn->pRequest);
  1292. }
  1293. else
  1294. {
  1295. UlSetErrorCode(pRequest, ErrorCode, pAppPool);
  1296. UlSendErrorResponse(pHttpConn);
  1297. }
  1298. UlReleasePushLockExclusive(&pHttpConn->PushLock);
  1299. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1300. ++Requests;
  1301. }
  1302. if (State != HttpAppPoolEnabled)
  1303. {
  1304. UlTrace(ROUTING, (
  1305. "%lu unhandled requests 503'd from AppPool %p.\n",
  1306. Requests, pAppPool
  1307. ));
  1308. }
  1309. return STATUS_SUCCESS;
  1310. } // UlpSetAppPoolState
  1311. /***************************************************************************++
  1312. Routine Description:
  1313. Sets the load balancer capabilities of an app pool to Basic
  1314. or Sophisticated.
  1315. Arguments:
  1316. pProcess - the app pool process object with which the irp
  1317. is associated.
  1318. LoadBalancerCapability - new capability
  1319. Return Value:
  1320. NTSTATUS - Completion status.
  1321. --***************************************************************************/
  1322. NTSTATUS
  1323. UlpSetAppPoolLoadBalancerCapability(
  1324. IN PUL_APP_POOL_PROCESS pProcess,
  1325. IN HTTP_LOAD_BALANCER_CAPABILITIES LoadBalancerCapability
  1326. )
  1327. {
  1328. PUL_APP_POOL_OBJECT pAppPool;
  1329. KLOCK_QUEUE_HANDLE LockHandle;
  1330. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  1331. pAppPool = pProcess->pAppPool;
  1332. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  1333. UlTrace(ROUTING, (
  1334. "http!UlpSetAppPoolLoadBalancerCapability(AppPool=%p, %lu).\n",
  1335. pAppPool, (ULONG) LoadBalancerCapability
  1336. ));
  1337. UlAcquireInStackQueuedSpinLock(&pProcess->pAppPool->SpinLock, &LockHandle);
  1338. pAppPool->LoadBalancerCapability = LoadBalancerCapability;
  1339. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  1340. WRITE_APP_POOL_TIME_TRACE_LOG(
  1341. pAppPool,
  1342. (PVOID) (ULONG_PTR) LoadBalancerCapability,
  1343. APP_POOL_TIME_ACTION_LOAD_BAL_CAPABILITY
  1344. );
  1345. return STATUS_SUCCESS;
  1346. } // UlpSetAppPoolLoadBalancerCapability
  1347. /***************************************************************************++
  1348. Routine Description:
  1349. Associates an irp with the apool that will be completed prior to any
  1350. requests being queued.
  1351. Arguments:
  1352. pProcess - the process object that is queueing this irp
  1353. pIrp - the irp to associate.
  1354. Return Value:
  1355. NTSTATUS - Completion status.
  1356. --***************************************************************************/
  1357. NTSTATUS
  1358. UlWaitForDemandStart(
  1359. IN PUL_APP_POOL_PROCESS pProcess,
  1360. IN PIRP pIrp
  1361. )
  1362. {
  1363. NTSTATUS Status;
  1364. PIO_STACK_LOCATION pIrpSp;
  1365. KLOCK_QUEUE_HANDLE LockHandle;
  1366. PEPROCESS CurrentProcess = PsGetCurrentProcess();
  1367. //
  1368. // Sanity check.
  1369. //
  1370. PAGED_CODE();
  1371. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  1372. ASSERT(IS_VALID_AP_OBJECT(pProcess->pAppPool));
  1373. ASSERT(pIrp != NULL);
  1374. //
  1375. // DemandStart IRPs can only come from controller processes.
  1376. //
  1377. if (!pProcess->Controller)
  1378. {
  1379. return STATUS_INVALID_ID_AUTHORITY;
  1380. }
  1381. UlAcquireInStackQueuedSpinLock(&pProcess->pAppPool->SpinLock, &LockHandle);
  1382. //
  1383. // Make sure we're not cleaning up the process
  1384. //
  1385. if (pProcess->InCleanup)
  1386. {
  1387. Status = STATUS_INVALID_HANDLE;
  1388. goto end;
  1389. }
  1390. //
  1391. // Already got one?
  1392. //
  1393. if (pProcess->pAppPool->pDemandStartIrp != NULL)
  1394. {
  1395. Status = STATUS_OBJECT_NAME_COLLISION;
  1396. goto end;
  1397. }
  1398. //
  1399. // Anything waiting in the queue?
  1400. //
  1401. if (IsListEmpty(&pProcess->pAppPool->NewRequestHead))
  1402. {
  1403. //
  1404. // Nope, pend the irp.
  1405. //
  1406. IoMarkIrpPending(pIrp);
  1407. //
  1408. // Give the irp a pointer to the app pool.
  1409. //
  1410. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1411. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer =
  1412. pProcess->pAppPool;
  1413. REFERENCE_APP_POOL(pProcess->pAppPool);
  1414. //
  1415. // The cancel routine better not see an irp if it runs immediately.
  1416. //
  1417. ASSERT(pProcess->pAppPool->pDemandStartIrp == NULL);
  1418. IoSetCancelRoutine(pIrp, &UlpCancelDemandStart);
  1419. //
  1420. // Cancelled?
  1421. //
  1422. if (pIrp->Cancel)
  1423. {
  1424. //
  1425. // Darn it, need to make sure the irp get's completed.
  1426. //
  1427. if (IoSetCancelRoutine(pIrp, NULL) != NULL)
  1428. {
  1429. //
  1430. // We are in charge of completion, IoCancelIrp didn't
  1431. // see our cancel routine (and won't). Ioctl wrapper
  1432. // will complete it.
  1433. //
  1434. DEREFERENCE_APP_POOL(pProcess->pAppPool);
  1435. pIrp->IoStatus.Information = 0;
  1436. UlUnmarkIrpPending(pIrp);
  1437. Status = STATUS_CANCELLED;
  1438. goto end;
  1439. }
  1440. //
  1441. // Our cancel routine will run and complete the irp,
  1442. // don't touch it.
  1443. //
  1444. //
  1445. // STATUS_PENDING will cause the ioctl wrapper to
  1446. // not complete (or touch in any way) the irp.
  1447. //
  1448. Status = STATUS_PENDING;
  1449. goto end;
  1450. }
  1451. //
  1452. // Now we are safe to queue it.
  1453. //
  1454. pProcess->pAppPool->pDemandStartIrp = pIrp;
  1455. pProcess->pAppPool->pDemandStartProcess = CurrentProcess;
  1456. Status = STATUS_PENDING;
  1457. goto end;
  1458. }
  1459. else
  1460. {
  1461. //
  1462. // Something's in the queue, instant demand start.
  1463. //
  1464. IoMarkIrpPending(pIrp);
  1465. pIrp->IoStatus.Status = STATUS_SUCCESS;
  1466. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  1467. Status = STATUS_PENDING;
  1468. goto end;
  1469. }
  1470. end:
  1471. UlReleaseInStackQueuedSpinLock(&pProcess->pAppPool->SpinLock, &LockHandle);
  1472. return Status;
  1473. } // UlWaitForDemandStart
  1474. /***************************************************************************++
  1475. Routine Description:
  1476. Receives a new http request into pIrp or pend the irp if no request
  1477. is available.
  1478. Arguments:
  1479. RequestId - NULL for new requests, non-NULL for a specific request,
  1480. which must be on the special queue
  1481. Flags - ignored
  1482. pProcess - the process that wants the request
  1483. pIrp - the irp to receive the request
  1484. Return Value:
  1485. NTSTATUS - Completion status.
  1486. --***************************************************************************/
  1487. NTSTATUS
  1488. UlReceiveHttpRequest(
  1489. IN HTTP_REQUEST_ID RequestId,
  1490. IN ULONG Flags,
  1491. IN PUL_APP_POOL_PROCESS pProcess,
  1492. IN PIRP pIrp
  1493. )
  1494. {
  1495. NTSTATUS Status;
  1496. PUL_INTERNAL_REQUEST pRequest = NULL;
  1497. KLOCK_QUEUE_HANDLE LockHandle;
  1498. PIO_STACK_LOCATION pIrpSp;
  1499. UNREFERENCED_PARAMETER(Flags);
  1500. //
  1501. // Sanity check.
  1502. //
  1503. PAGED_CODE();
  1504. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  1505. ASSERT(IS_VALID_AP_OBJECT(pProcess->pAppPool));
  1506. ASSERT(pIrp);
  1507. ASSERT(pIrp->MdlAddress);
  1508. UlAcquireInStackQueuedSpinLock(&pProcess->pAppPool->SpinLock, &LockHandle);
  1509. //
  1510. // Make sure we're not cleaning up the process.
  1511. //
  1512. if (pProcess->InCleanup)
  1513. {
  1514. Status = STATUS_INVALID_HANDLE;
  1515. UlReleaseInStackQueuedSpinLock(
  1516. &pProcess->pAppPool->SpinLock,
  1517. &LockHandle
  1518. );
  1519. goto end;
  1520. }
  1521. //
  1522. // Is this for a new request?
  1523. //
  1524. if (HTTP_IS_NULL_ID(&RequestId))
  1525. {
  1526. //
  1527. // Do we have a queue'd new request?
  1528. //
  1529. Status = UlDequeueNewRequest(pProcess, 0, &pRequest);
  1530. if (!NT_SUCCESS(Status) && STATUS_NOT_FOUND != Status)
  1531. {
  1532. UlReleaseInStackQueuedSpinLock(
  1533. &pProcess->pAppPool->SpinLock,
  1534. &LockHandle
  1535. );
  1536. goto end;
  1537. }
  1538. if (pRequest == NULL)
  1539. {
  1540. //
  1541. // Nope, queue the irp up.
  1542. //
  1543. IoMarkIrpPending(pIrp);
  1544. //
  1545. // Give the irp a pointer to the app pool process.
  1546. //
  1547. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1548. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pProcess;
  1549. REFERENCE_APP_POOL_PROCESS(pProcess);
  1550. //
  1551. // Set to these to null just in case the cancel routine runs.
  1552. //
  1553. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  1554. pIrp->Tail.Overlay.ListEntry.Blink = NULL;
  1555. IoSetCancelRoutine(pIrp, &UlpCancelHttpReceive);
  1556. //
  1557. // Cancelled?
  1558. //
  1559. if (pIrp->Cancel)
  1560. {
  1561. //
  1562. // Darn it, need to make sure the irp get's completed.
  1563. //
  1564. if (IoSetCancelRoutine(pIrp, NULL) != NULL)
  1565. {
  1566. //
  1567. // We are in charge of completion, IoCancelIrp didn't
  1568. // see our cancel routine (and won't). Ioctl wrapper
  1569. // will complete it.
  1570. //
  1571. UlReleaseInStackQueuedSpinLock(
  1572. &pProcess->pAppPool->SpinLock,
  1573. &LockHandle
  1574. );
  1575. REFERENCE_APP_POOL_PROCESS(pProcess);
  1576. pIrp->IoStatus.Information = 0;
  1577. UlUnmarkIrpPending(pIrp);
  1578. Status = STATUS_CANCELLED;
  1579. goto end;
  1580. }
  1581. //
  1582. // Our cancel routine will run and complete the irp,
  1583. // don't touch it.
  1584. //
  1585. UlReleaseInStackQueuedSpinLock(
  1586. &pProcess->pAppPool->SpinLock,
  1587. &LockHandle
  1588. );
  1589. //
  1590. // STATUS_PENDING will cause the ioctl wrapper to
  1591. // not complete (or touch in any way) the irp.
  1592. //
  1593. Status = STATUS_PENDING;
  1594. goto end;
  1595. }
  1596. //
  1597. // Now we are safe to queue it.
  1598. //
  1599. InsertTailList(
  1600. &pProcess->NewIrpHead,
  1601. &pIrp->Tail.Overlay.ListEntry
  1602. );
  1603. UlReleaseInStackQueuedSpinLock(
  1604. &pProcess->pAppPool->SpinLock,
  1605. &LockHandle
  1606. );
  1607. Status = STATUS_PENDING;
  1608. goto end;
  1609. }
  1610. else // if (pRequest == NULL)
  1611. {
  1612. //
  1613. // Have a queue'd request, serve it up!
  1614. //
  1615. // UlDequeueNewRequest gives ourselves a short-lived reference.
  1616. //
  1617. UlReleaseInStackQueuedSpinLock(
  1618. &pProcess->pAppPool->SpinLock,
  1619. &LockHandle
  1620. );
  1621. //
  1622. // Copy it to the irp, the routine will take ownership
  1623. // of pRequest if it is not able to copy it to the irp.
  1624. //
  1625. // It will also complete the irp so don't touch it later.
  1626. //
  1627. IoMarkIrpPending(pIrp);
  1628. UlCopyRequestToIrp(pRequest, pIrp, TRUE, FALSE);
  1629. pIrp = NULL;
  1630. //
  1631. // Let go our short-lived reference.
  1632. //
  1633. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1634. pRequest = NULL;
  1635. Status = STATUS_PENDING;
  1636. goto end;
  1637. }
  1638. }
  1639. else // if (HTTP_IS_NULL_ID(&RequestId))
  1640. {
  1641. //
  1642. // Need to grab the specific request from id.
  1643. //
  1644. pRequest = UlGetRequestFromId(RequestId, pProcess);
  1645. if (!pRequest)
  1646. {
  1647. Status = STATUS_CONNECTION_INVALID;
  1648. UlReleaseInStackQueuedSpinLock(
  1649. &pProcess->pAppPool->SpinLock,
  1650. &LockHandle
  1651. );
  1652. goto end;
  1653. }
  1654. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1655. //
  1656. // Let go the lock.
  1657. //
  1658. UlReleaseInStackQueuedSpinLock(
  1659. &pProcess->pAppPool->SpinLock,
  1660. &LockHandle
  1661. );
  1662. UlTrace(ROUTING, (
  1663. "http!UlReceiveHttpRequest(ID = %I64x, pProcess = %p)\n"
  1664. " pAppPool = %p (%S)\n"
  1665. " Found pRequest = %p on PendingRequest queue\n",
  1666. RequestId,
  1667. pProcess,
  1668. pProcess->pAppPool,
  1669. pProcess->pAppPool->pName,
  1670. pRequest
  1671. ));
  1672. //
  1673. // Copy it to the irp, the routine will take ownership
  1674. // of pRequest if it is not able to copy it to the irp.
  1675. //
  1676. IoMarkIrpPending(pIrp);
  1677. UlCopyRequestToIrp(pRequest, pIrp, TRUE, FALSE);
  1678. //
  1679. // Let go our reference.
  1680. //
  1681. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1682. pRequest = NULL;
  1683. Status = STATUS_PENDING;
  1684. goto end;
  1685. }
  1686. end:
  1687. if (pRequest != NULL)
  1688. {
  1689. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  1690. pRequest = NULL;
  1691. }
  1692. //
  1693. // At this point if Status != STATUS_PENDING, the ioctl wrapper will
  1694. // complete pIrp.
  1695. //
  1696. return Status;
  1697. } // UlReceiveHttpRequest
  1698. /***************************************************************************++
  1699. Routine Description:
  1700. Called by the http engine to deliver a request to an apool.
  1701. This attempts to find a free irp from any process attached to the apool
  1702. and copies the request to that irp.
  1703. Otherwise it queues the request, without taking a refcount on it. The
  1704. request will remove itself from this queue if the connection is dropped.
  1705. Arguments:
  1706. pAppPool - the AppPool
  1707. pRequest - the request to deliver
  1708. pIrpToComplete - optionally provides a pointer of the irp to complete
  1709. Return Value:
  1710. NTSTATUS - Completion status.
  1711. --***************************************************************************/
  1712. NTSTATUS
  1713. UlDeliverRequestToProcess(
  1714. IN PUL_APP_POOL_OBJECT pAppPool,
  1715. IN PUL_INTERNAL_REQUEST pRequest,
  1716. OUT PIRP * pIrpToComplete OPTIONAL
  1717. )
  1718. {
  1719. NTSTATUS Status;
  1720. PUL_APP_POOL_OBJECT pDemandStartAppPool;
  1721. PIRP pDemandStartIrp;
  1722. PIRP pIrp = NULL;
  1723. PUL_APP_POOL_PROCESS pProcess = NULL;
  1724. KLOCK_QUEUE_HANDLE LockHandle;
  1725. PVOID pUrl;
  1726. ULONG UrlLength;
  1727. PUL_CONTROL_CHANNEL pControlChannel;
  1728. BOOLEAN FailedDemandStart = FALSE;
  1729. //
  1730. // Sanity check.
  1731. //
  1732. PAGED_CODE();
  1733. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1734. ASSERT(IS_VALID_URL_CONFIG_GROUP_INFO(&pRequest->ConfigInfo));
  1735. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  1736. ASSERT(!pIrpToComplete || !(*pIrpToComplete));
  1737. UlTrace(ROUTING, (
  1738. "http!UlDeliverRequestToProcess(pRequest = %p)\n"
  1739. " verb + path -> %d %S\n"
  1740. " pAppPool = %p (%S)\n",
  1741. pRequest,
  1742. pRequest->Verb,
  1743. pRequest->CookedUrl.pUrl,
  1744. pAppPool,
  1745. pAppPool->pName
  1746. ));
  1747. //
  1748. // Grab the lock!
  1749. //
  1750. UlAcquireInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  1751. TRACE_TIME(
  1752. pRequest->ConnectionId,
  1753. pRequest->RequestId,
  1754. TIME_ACTION_ROUTE_REQUEST
  1755. );
  1756. //
  1757. // Was the app pool enabled yet?
  1758. //
  1759. if (pAppPool->State != HttpAppPoolEnabled)
  1760. {
  1761. UlSetErrorCode(
  1762. pRequest,
  1763. UlpConvertAppPoolEnabledStateToErrorCode(pAppPool->State),
  1764. pAppPool
  1765. );
  1766. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  1767. return STATUS_PORT_DISCONNECTED;
  1768. }
  1769. Status = STATUS_SUCCESS;
  1770. //
  1771. // Complete the demand start if this is the very first request so we can
  1772. // do load balancing for web gardens, or if there is no worker process
  1773. // being started in which case we have no choice.
  1774. //
  1775. if (pAppPool->pDemandStartIrp &&
  1776. (pRequest->FirstRequest || !pAppPool->NumberActiveProcesses))
  1777. {
  1778. pControlChannel = pAppPool->pControlChannel;
  1779. if (pControlChannel &&
  1780. (pControlChannel->AppPoolProcessCount >= pControlChannel->DemandStartThreshold))
  1781. {
  1782. //
  1783. // If we currently exceed our demand start threshold, do
  1784. // not complete the demand start Irp AND fail the queuing of the
  1785. // request (send back a 503).
  1786. //
  1787. ASSERT(IS_VALID_CONTROL_CHANNEL(pControlChannel));
  1788. FailedDemandStart = TRUE;
  1789. }
  1790. else
  1791. {
  1792. // Do the Irp Dance
  1793. pDemandStartIrp = pAppPool->pDemandStartIrp;
  1794. //
  1795. // Pop the cancel routine.
  1796. //
  1797. if (IoSetCancelRoutine(pDemandStartIrp, NULL) == NULL)
  1798. {
  1799. //
  1800. // IoCancelIrp pop'd it first.
  1801. //
  1802. // Ok to just ignore this irp, it's been pop'd off the queue
  1803. // and will be completed in the cancel routine.
  1804. //
  1805. // No need to complete it.
  1806. //
  1807. }
  1808. else
  1809. if (pDemandStartIrp->Cancel)
  1810. {
  1811. //
  1812. // We pop'd it first, but the irp is being cancelled
  1813. // and our cancel routine will never run.
  1814. //
  1815. pDemandStartAppPool = (PUL_APP_POOL_OBJECT)
  1816. IoGetCurrentIrpStackLocation(pDemandStartIrp)->
  1817. Parameters.DeviceIoControl.Type3InputBuffer;
  1818. ASSERT(pDemandStartAppPool == pAppPool);
  1819. DEREFERENCE_APP_POOL(pDemandStartAppPool);
  1820. IoGetCurrentIrpStackLocation(pDemandStartIrp)->
  1821. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  1822. pDemandStartIrp->IoStatus.Status = STATUS_CANCELLED;
  1823. pDemandStartIrp->IoStatus.Information = 0;
  1824. UlCompleteRequest(pDemandStartIrp, IO_NO_INCREMENT);
  1825. }
  1826. else
  1827. {
  1828. //
  1829. // Free to use the irp.
  1830. //
  1831. pDemandStartAppPool = (PUL_APP_POOL_OBJECT)
  1832. IoGetCurrentIrpStackLocation(pDemandStartIrp)->
  1833. Parameters.DeviceIoControl.Type3InputBuffer;
  1834. ASSERT(pDemandStartAppPool == pAppPool);
  1835. DEREFERENCE_APP_POOL(pDemandStartAppPool);
  1836. IoGetCurrentIrpStackLocation(pDemandStartIrp)->
  1837. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  1838. pDemandStartIrp->IoStatus.Status = STATUS_SUCCESS;
  1839. pDemandStartIrp->IoStatus.Information = 0;
  1840. UlCompleteRequest(pDemandStartIrp, IO_NETWORK_INCREMENT);
  1841. }
  1842. pAppPool->pDemandStartProcess = NULL;
  1843. pAppPool->pDemandStartIrp = NULL;
  1844. }
  1845. }
  1846. //
  1847. // Hook up request references.
  1848. //
  1849. UL_REFERENCE_INTERNAL_REQUEST(pRequest);
  1850. if (pAppPool->NumberActiveProcesses <= 1)
  1851. {
  1852. //
  1853. // Bypass process binding if we have only one active process.
  1854. //
  1855. pProcess = NULL;
  1856. pIrp = UlpPopNewIrp(pAppPool, pRequest, &pProcess);
  1857. }
  1858. else
  1859. {
  1860. //
  1861. // Check for a process binding.
  1862. //
  1863. pProcess = UlQueryProcessBinding(pRequest->pHttpConn, pAppPool);
  1864. if (UlpIsProcessInAppPool(pProcess, pAppPool))
  1865. {
  1866. //
  1867. // We're bound to a valid process.
  1868. // Try to get a free irp from that process.
  1869. //
  1870. pIrp = UlpPopIrpFromProcess(pProcess, pRequest);
  1871. }
  1872. else
  1873. {
  1874. //
  1875. // Remove the binding if we were previously bound to a process.
  1876. //
  1877. if (pProcess)
  1878. {
  1879. UlBindConnectionToProcess(
  1880. pRequest->pHttpConn,
  1881. pAppPool,
  1882. NULL
  1883. );
  1884. }
  1885. //
  1886. // We are unbound or bound to a process that went away.
  1887. // Try and get an free irp from any process.
  1888. //
  1889. pProcess = NULL;
  1890. pIrp = UlpPopNewIrp(pAppPool, pRequest, &pProcess);
  1891. //
  1892. // Establish a binding if we got something.
  1893. //
  1894. if (pIrp != NULL)
  1895. {
  1896. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  1897. Status = UlBindConnectionToProcess(
  1898. pRequest->pHttpConn,
  1899. pAppPool,
  1900. pProcess
  1901. );
  1902. //
  1903. // Is there anything special we should do on
  1904. // failure? I don't think it should be fatal.
  1905. //
  1906. Status = STATUS_SUCCESS;
  1907. }
  1908. }
  1909. }
  1910. if (ETW_LOG_MIN())
  1911. {
  1912. pUrl = NULL;
  1913. UrlLength = 0;
  1914. //
  1915. // Trace the URL optionally here in case we turned off ParseHook.
  1916. //
  1917. if (ETW_LOG_URL())
  1918. {
  1919. pUrl = pRequest->CookedUrl.pUrl;
  1920. UrlLength = pRequest->CookedUrl.Length;
  1921. }
  1922. UlEtwTraceEvent(
  1923. &UlTransGuid,
  1924. ETW_TYPE_ULDELIVER,
  1925. (PVOID) &pRequest,
  1926. sizeof(PVOID),
  1927. &pRequest->RequestIdCopy,
  1928. sizeof(HTTP_REQUEST_ID),
  1929. &pRequest->ConfigInfo.SiteId,
  1930. sizeof(ULONG),
  1931. pRequest->ConfigInfo.pAppPool->pName,
  1932. pRequest->ConfigInfo.pAppPool->NameLength,
  1933. pUrl,
  1934. UrlLength,
  1935. NULL,
  1936. 0
  1937. );
  1938. }
  1939. //
  1940. // If we have an IRP, complete it. Otherwise queue the request.
  1941. //
  1942. if (pIrp != NULL)
  1943. {
  1944. ASSERT(pIrp->MdlAddress != NULL);
  1945. ASSERT(pProcess->InCleanup == 0);
  1946. //
  1947. // We are all done and about to complete the irp, free the lock.
  1948. //
  1949. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  1950. UlTrace(ROUTING, (
  1951. "http!UlDeliverRequestToProcess(pRequest = %p, pProcess = %p)\n"
  1952. " queued pending request. pAppPool = %p (%S)\n",
  1953. pRequest,
  1954. pProcess,
  1955. pProcess->pAppPool,
  1956. pProcess->pAppPool->pName
  1957. ));
  1958. //
  1959. // Copy it to the irp, the routine will take ownership
  1960. // of pRequest if it is not able to copy it to the irp.
  1961. //
  1962. // It will also complete the irp, don't touch it later.
  1963. //
  1964. if (pIrpToComplete)
  1965. {
  1966. UlCopyRequestToIrp(pRequest, pIrp, FALSE, TRUE);
  1967. *pIrpToComplete = pIrp;
  1968. }
  1969. else
  1970. {
  1971. UlCopyRequestToIrp(pRequest, pIrp, TRUE, TRUE);
  1972. }
  1973. }
  1974. else
  1975. {
  1976. ASSERT(pIrp == NULL);
  1977. if (FailedDemandStart)
  1978. {
  1979. UlTrace(ROUTING, (
  1980. "http!UlDeliverRequestToProcess(pRequest = %p, pAppPool = %p)\n"
  1981. " Failing request because Demand Start Threshold exceeded.\n",
  1982. pRequest,
  1983. pAppPool
  1984. ));
  1985. UlSetErrorCode( pRequest, UlErrorUnavailable, pAppPool);
  1986. Status = STATUS_PORT_DISCONNECTED;
  1987. }
  1988. else
  1989. {
  1990. //
  1991. // Either didn't find an IRP or there's stuff on the pending request
  1992. // list, so queue this pending request.
  1993. //
  1994. Status = UlpQueueUnboundRequest(pAppPool, pRequest);
  1995. }
  1996. if (!NT_SUCCESS(Status))
  1997. {
  1998. //
  1999. // Doh! We couldn't queue it, so let go of the request.
  2000. //
  2001. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  2002. }
  2003. //
  2004. // Now we finished queue'ing the request, free the lock.
  2005. //
  2006. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  2007. }
  2008. return Status;
  2009. } // UlDeliverRequestToProcess
  2010. /***************************************************************************++
  2011. Routine Description:
  2012. Removes a request from any app pool lists.
  2013. Arguments:
  2014. pAppPool - the appool to unlink the request from
  2015. pRequest - the request to be unlinked
  2016. Return Value:
  2017. None
  2018. --***************************************************************************/
  2019. VOID
  2020. UlUnlinkRequestFromProcess(
  2021. IN PUL_APP_POOL_OBJECT pAppPool,
  2022. IN PUL_INTERNAL_REQUEST pRequest
  2023. )
  2024. {
  2025. KLOCK_QUEUE_HANDLE LockHandle;
  2026. BOOLEAN NeedDeref = FALSE;
  2027. //
  2028. // Sanity check.
  2029. //
  2030. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  2031. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  2032. UlAcquireInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  2033. //
  2034. // Remove from whatever queue we're on.
  2035. //
  2036. switch (pRequest->AppPool.QueueState)
  2037. {
  2038. case QueueDeliveredState:
  2039. //
  2040. // We're on the apool object new request queue.
  2041. //
  2042. UlpRemoveRequest(pAppPool, pRequest);
  2043. pRequest->AppPool.QueueState = QueueUnlinkedState;
  2044. NeedDeref = TRUE;
  2045. break;
  2046. case QueueCopiedState:
  2047. //
  2048. // We're on the apool process pending queue.
  2049. //
  2050. ASSERT(IS_VALID_AP_PROCESS(pRequest->AppPool.pProcess));
  2051. ASSERT(pRequest->AppPool.pProcess->pAppPool == pAppPool);
  2052. UlpRemoveRequest(pAppPool, pRequest);
  2053. pRequest->AppPool.QueueState = QueueUnlinkedState;
  2054. NeedDeref = TRUE;
  2055. break;
  2056. case QueueUnroutedState:
  2057. case QueueUnlinkedState:
  2058. //
  2059. // It's not on our lists, so we don't do anything.
  2060. //
  2061. break;
  2062. default:
  2063. //
  2064. // This shouldn't happen.
  2065. //
  2066. ASSERT(!"Invalid app pool queue state");
  2067. break;
  2068. }
  2069. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  2070. //
  2071. // Clean up the references.
  2072. //
  2073. if (NeedDeref)
  2074. {
  2075. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  2076. }
  2077. } // UlUnlinkRequestFromProcess
  2078. /***************************************************************************++
  2079. Routine Description:
  2080. Initializes the AppPool module.
  2081. Arguments:
  2082. None
  2083. Return Value:
  2084. NTSTATUS - Completion status.
  2085. --***************************************************************************/
  2086. NTSTATUS
  2087. UlInitializeAP(
  2088. VOID
  2089. )
  2090. {
  2091. NTSTATUS Status = STATUS_SUCCESS;
  2092. ASSERT(!g_InitAPCalled);
  2093. if (!g_InitAPCalled)
  2094. {
  2095. InitializeListHead(&g_AppPoolListHead);
  2096. g_RequestsQueued = 0;
  2097. Status = UlInitializeResource(
  2098. &g_pUlNonpagedData->AppPoolResource,
  2099. "AppPoolResource",
  2100. 0,
  2101. UL_APP_POOL_RESOURCE_TAG
  2102. );
  2103. if (NT_SUCCESS(Status))
  2104. {
  2105. Status = UlInitializeResource(
  2106. &g_pUlNonpagedData->DisconnectResource,
  2107. "DisconnectResource",
  2108. 0,
  2109. UL_DISCONNECT_RESOURCE_TAG
  2110. );
  2111. if (NT_SUCCESS(Status))
  2112. {
  2113. //
  2114. // Finished, remember that we're initialized.
  2115. //
  2116. g_InitAPCalled = TRUE;
  2117. }
  2118. else
  2119. {
  2120. UlDeleteResource(&g_pUlNonpagedData->AppPoolResource);
  2121. }
  2122. }
  2123. }
  2124. return Status;
  2125. } // UlInitializeAP
  2126. /***************************************************************************++
  2127. Routine Description:
  2128. Terminates the AppPool module.
  2129. Arguments:
  2130. None
  2131. Return Value:
  2132. None
  2133. --***************************************************************************/
  2134. VOID
  2135. UlTerminateAP(
  2136. VOID
  2137. )
  2138. {
  2139. if (g_InitAPCalled)
  2140. {
  2141. (VOID) UlDeleteResource(&g_pUlNonpagedData->AppPoolResource);
  2142. (VOID) UlDeleteResource(&g_pUlNonpagedData->DisconnectResource);
  2143. g_InitAPCalled = FALSE;
  2144. }
  2145. } // UlTerminateAP
  2146. /***************************************************************************++
  2147. Routine Description:
  2148. Allocates and initializes a UL_APP_POOL_PROCESS object.
  2149. Arguments:
  2150. None
  2151. Return Value:
  2152. NULL on failure, process object on success
  2153. --***************************************************************************/
  2154. PUL_APP_POOL_PROCESS
  2155. UlCreateAppPoolProcess(
  2156. PUL_APP_POOL_OBJECT pObject
  2157. )
  2158. {
  2159. PUL_APP_POOL_PROCESS pProcess;
  2160. //
  2161. // Sanity check.
  2162. //
  2163. PAGED_CODE();
  2164. pProcess = UL_ALLOCATE_STRUCT(
  2165. NonPagedPool,
  2166. UL_APP_POOL_PROCESS,
  2167. UL_APP_POOL_PROCESS_POOL_TAG
  2168. );
  2169. if (pProcess)
  2170. {
  2171. RtlZeroMemory(pProcess, sizeof(UL_APP_POOL_PROCESS));
  2172. pProcess->Signature = UL_APP_POOL_PROCESS_POOL_TAG;
  2173. pProcess->pAppPool = pObject;
  2174. InitializeListHead(&pProcess->NewIrpHead);
  2175. InitializeListHead(&pProcess->PendingRequestHead);
  2176. //
  2177. // Remember the current process (WP).
  2178. //
  2179. pProcess->pProcess = PsGetCurrentProcess();
  2180. //
  2181. // Initialize list of WaitForDisconnect IRPs.
  2182. //
  2183. UlInitializeNotifyHead(&pProcess->WaitForDisconnectHead, NULL);
  2184. }
  2185. return pProcess;
  2186. } // UlCreateAppPoolProcess
  2187. /***************************************************************************++
  2188. Routine Description:
  2189. Destroys a UL_APP_POOL_PROCESS object.
  2190. Arguments:
  2191. pProcess - object to destory
  2192. Return Value:
  2193. None
  2194. --***************************************************************************/
  2195. VOID
  2196. UlCloseAppPoolProcess(
  2197. PUL_APP_POOL_PROCESS pProcess
  2198. )
  2199. {
  2200. //
  2201. // Sanity check.
  2202. //
  2203. PAGED_CODE();
  2204. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  2205. ASSERT(pProcess->InCleanup);
  2206. ASSERT(IS_VALID_AP_OBJECT(pProcess->pAppPool));
  2207. WRITE_APP_POOL_TIME_TRACE_LOG(
  2208. pProcess->pAppPool,
  2209. pProcess,
  2210. APP_POOL_TIME_ACTION_DESTROY_APPOOL_PROCESS
  2211. );
  2212. //
  2213. // Drop the AppPool reference.
  2214. //
  2215. DEREFERENCE_APP_POOL(pProcess->pAppPool);
  2216. //
  2217. // Free the pool.
  2218. //
  2219. UL_FREE_POOL_WITH_SIG(pProcess, UL_APP_POOL_PROCESS_POOL_TAG);
  2220. } // UlCloseAppPoolProcess
  2221. /***************************************************************************++
  2222. Routine Description:
  2223. Cancels the pending user mode irp which was to receive demand start
  2224. notification. This routine ALWAYS results in the irp being completed.
  2225. Arguments:
  2226. pDeviceObject - the device object
  2227. pIrp - the irp to cancel
  2228. Return Value:
  2229. None
  2230. --***************************************************************************/
  2231. VOID
  2232. UlpCancelDemandStart(
  2233. IN PDEVICE_OBJECT pDeviceObject,
  2234. IN PIRP pIrp
  2235. )
  2236. {
  2237. PUL_APP_POOL_OBJECT pAppPool;
  2238. PIO_STACK_LOCATION pIrpSp;
  2239. KLOCK_QUEUE_HANDLE LockHandle;
  2240. UNREFERENCED_PARAMETER(pDeviceObject);
  2241. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  2242. ASSERT(pIrp != NULL);
  2243. //
  2244. // Release the cancel spinlock. This means the cancel routine
  2245. // must be the one completing the irp (to avoid the race of
  2246. // completion + reuse prior to the cancel routine running).
  2247. //
  2248. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  2249. //
  2250. // Grab the app pool off the irp.
  2251. //
  2252. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  2253. pAppPool = (PUL_APP_POOL_OBJECT)
  2254. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  2255. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  2256. //
  2257. // Grab the lock protecting the queue'd irp.
  2258. //
  2259. UlAcquireInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  2260. //
  2261. // Does it need to be dequeue'd?
  2262. //
  2263. if (pAppPool->pDemandStartIrp != NULL)
  2264. {
  2265. //
  2266. // Remove it.
  2267. //
  2268. pAppPool->pDemandStartIrp = NULL;
  2269. pAppPool->pDemandStartProcess = NULL;
  2270. }
  2271. //
  2272. // Let the lock go.
  2273. //
  2274. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  2275. //
  2276. // Let our reference go.
  2277. //
  2278. DEREFERENCE_APP_POOL(pAppPool);
  2279. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2280. //
  2281. // Complete the irp.
  2282. //
  2283. pIrp->IoStatus.Status = STATUS_CANCELLED;
  2284. pIrp->IoStatus.Information = 0;
  2285. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  2286. } // UlpCancelDemandStart
  2287. /***************************************************************************++
  2288. Routine Description:
  2289. Cancels the pending user mode irp which was to receive the http request.
  2290. this routine ALWAYS results in the irp being completed.
  2291. Arguments:
  2292. pDeviceObject - the device object
  2293. pIrp - the irp to cancel
  2294. Return Value:
  2295. None
  2296. --***************************************************************************/
  2297. VOID
  2298. UlpCancelHttpReceive(
  2299. IN PDEVICE_OBJECT pDeviceObject,
  2300. IN PIRP pIrp
  2301. )
  2302. {
  2303. PUL_APP_POOL_PROCESS pProcess;
  2304. PIO_STACK_LOCATION pIrpSp;
  2305. KLOCK_QUEUE_HANDLE LockHandle;
  2306. UNREFERENCED_PARAMETER(pDeviceObject);
  2307. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  2308. ASSERT(pIrp != NULL);
  2309. //
  2310. // Release the cancel spinlock. This means the cancel routine
  2311. // must be the one completing the irp (to avoid the race of
  2312. // completion + reuse prior to the cancel routine running).
  2313. //
  2314. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  2315. //
  2316. // Grab the app pool off the irp.
  2317. //
  2318. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  2319. pProcess = (PUL_APP_POOL_PROCESS)
  2320. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  2321. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  2322. //
  2323. // Grab the lock protecting the queue.
  2324. //
  2325. UlAcquireInStackQueuedSpinLock(&pProcess->pAppPool->SpinLock, &LockHandle);
  2326. //
  2327. // Does it need to be de-queue'd?
  2328. //
  2329. if (pIrp->Tail.Overlay.ListEntry.Flink != NULL)
  2330. {
  2331. //
  2332. // Remove it.
  2333. //
  2334. RemoveEntryList(&pIrp->Tail.Overlay.ListEntry);
  2335. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  2336. pIrp->Tail.Overlay.ListEntry.Blink = NULL;
  2337. }
  2338. //
  2339. // Let the lock go.
  2340. //
  2341. UlReleaseInStackQueuedSpinLock(&pProcess->pAppPool->SpinLock, &LockHandle);
  2342. //
  2343. // Let our reference go.
  2344. //
  2345. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2346. DEREFERENCE_APP_POOL_PROCESS(pProcess);
  2347. //
  2348. // Complete the irp.
  2349. //
  2350. pIrp->IoStatus.Status = STATUS_CANCELLED;
  2351. pIrp->IoStatus.Information = 0;
  2352. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  2353. } // UlpCancelHttpReceive
  2354. /******************************************************************************
  2355. Routine Description:
  2356. Copy an HTTP request to a buffer.
  2357. Arguments:
  2358. pRequest - pointer to this request
  2359. pBuffer - pointer to buffer where we'll copy
  2360. BufferLength - length of pBuffer
  2361. Flags - flags for HttpReceiveHttpRequest
  2362. LockAcquired - either called from UlDeliverRequestToProcess (TRUE)
  2363. or UlReceiveHttpRequest/UlpFastReceiveHttpRequest
  2364. pBytesCopied - actual bytes copied
  2365. Return Value:
  2366. NTSTATUS - Completion status.
  2367. ******************************************************************************/
  2368. NTSTATUS
  2369. UlCopyRequestToBuffer(
  2370. IN PUL_INTERNAL_REQUEST pRequest,
  2371. IN PUCHAR pKernelBuffer,
  2372. IN PVOID pUserBuffer,
  2373. IN ULONG BufferLength,
  2374. IN ULONG Flags,
  2375. IN BOOLEAN LockAcquired,
  2376. OUT PULONG pBytesCopied
  2377. )
  2378. {
  2379. PHTTP_REQUEST pHttpRequest;
  2380. PHTTP_UNKNOWN_HEADER pUserCurrentUnknownHeader;
  2381. HTTP_HEADER_ID HeaderId;
  2382. PUL_HTTP_UNKNOWN_HEADER pUnknownHeader;
  2383. PUCHAR pCurrentBufferPtr;
  2384. ULONG Index;
  2385. ULONG BytesCopied;
  2386. ULONG HeaderCount = 0;
  2387. PUCHAR pLocalAddress;
  2388. PUCHAR pRemoteAddress;
  2389. USHORT AddressType;
  2390. USHORT AddressLength;
  2391. USHORT AlignedAddressLength;
  2392. PHTTP_TRANSPORT_ADDRESS pAddress;
  2393. PHTTP_COOKED_URL pCookedUrl;
  2394. PHTTP_DATA_CHUNK pDataChunk;
  2395. PLIST_ENTRY pListEntry;
  2396. PEPROCESS pProcess;
  2397. NTSTATUS Status;
  2398. PUCHAR pEntityBody;
  2399. LONG EntityBodyLength;
  2400. PCWSTR pFullUrl;
  2401. PCWSTR pHost;
  2402. PCWSTR pAbsPath;
  2403. USHORT HostLength;
  2404. USHORT AbsPathLength;
  2405. HANDLE MappedToken = NULL;
  2406. //
  2407. // Sanity check.
  2408. //
  2409. PAGED_CODE();
  2410. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  2411. ASSERT(pKernelBuffer != NULL);
  2412. ASSERT(pUserBuffer != NULL);
  2413. ASSERT(BufferLength > sizeof(HTTP_REQUEST));
  2414. Status = STATUS_SUCCESS;
  2415. *pBytesCopied = 0;
  2416. __try
  2417. {
  2418. //
  2419. // Set up our pointers to the HTTP_REQUEST structure, the
  2420. // header arrays we're going to fill in, and the pointer to
  2421. // where we're going to start filling them in.
  2422. //
  2423. pHttpRequest = (PHTTP_REQUEST) pKernelBuffer;
  2424. AddressType = pRequest->pHttpConn->pConnection->AddressType;
  2425. if (TDI_ADDRESS_TYPE_IP == AddressType)
  2426. {
  2427. AddressLength = SOCKADDR_ADDRESS_LENGTH_IP;
  2428. }
  2429. else
  2430. if (TDI_ADDRESS_TYPE_IP6 == AddressType)
  2431. {
  2432. AddressLength = SOCKADDR_ADDRESS_LENGTH_IP6;
  2433. }
  2434. else
  2435. {
  2436. ASSERT(!"Invalid AddressType");
  2437. AddressLength = 0;
  2438. }
  2439. //
  2440. // We've allocated enough space for two SOCKADDR_IN6s, so use that.
  2441. //
  2442. AlignedAddressLength =
  2443. (USHORT) ALIGN_UP(SOCKADDR_ADDRESS_LENGTH_IP6, PVOID);
  2444. pLocalAddress = (PUCHAR) (pHttpRequest + 1);
  2445. pRemoteAddress = pLocalAddress + AlignedAddressLength;
  2446. pUserCurrentUnknownHeader =
  2447. (PHTTP_UNKNOWN_HEADER) (pRemoteAddress + AlignedAddressLength);
  2448. ASSERT((((ULONG_PTR) pUserCurrentUnknownHeader)
  2449. & (TYPE_ALIGNMENT(PVOID) - 1)) == 0);
  2450. pCurrentBufferPtr = (PUCHAR) (pUserCurrentUnknownHeader +
  2451. pRequest->UnknownHeaderCount);
  2452. //
  2453. // Now fill in the HTTP request structure.
  2454. //
  2455. ASSERT(!HTTP_IS_NULL_ID(&pRequest->ConnectionId));
  2456. ASSERT(!HTTP_IS_NULL_ID(&pRequest->RequestIdCopy));
  2457. pHttpRequest->ConnectionId = pRequest->ConnectionId;
  2458. pHttpRequest->RequestId = pRequest->RequestIdCopy;
  2459. pHttpRequest->UrlContext = pRequest->ConfigInfo.UrlContext;
  2460. pHttpRequest->Version = pRequest->Version;
  2461. pHttpRequest->Verb = pRequest->Verb;
  2462. pHttpRequest->BytesReceived = pRequest->BytesReceived;
  2463. pAddress = &pHttpRequest->Address;
  2464. pAddress->pRemoteAddress = FIXUP_PTR(
  2465. PVOID,
  2466. pUserBuffer,
  2467. pKernelBuffer,
  2468. pRemoteAddress,
  2469. BufferLength
  2470. );
  2471. CopyTdiAddrToSockAddr(
  2472. AddressType,
  2473. pRequest->pHttpConn->pConnection->RemoteAddress,
  2474. (struct sockaddr *) pRemoteAddress
  2475. );
  2476. pAddress->pLocalAddress = FIXUP_PTR(
  2477. PVOID,
  2478. pUserBuffer,
  2479. pKernelBuffer,
  2480. pLocalAddress,
  2481. BufferLength
  2482. );
  2483. CopyTdiAddrToSockAddr(
  2484. AddressType,
  2485. pRequest->pHttpConn->pConnection->LocalAddress,
  2486. (struct sockaddr *) pLocalAddress
  2487. );
  2488. //
  2489. // And now the cooked url sections.
  2490. //
  2491. //
  2492. // Unicode strings must be at 2-byte boundaries. All previous data
  2493. // are structures, so the assertion should be true.
  2494. //
  2495. ASSERT(((ULONG_PTR) pCurrentBufferPtr % sizeof(WCHAR)) == 0);
  2496. //
  2497. // Make sure they are valid.
  2498. //
  2499. ASSERT(pRequest->CookedUrl.pUrl != NULL);
  2500. ASSERT(pRequest->CookedUrl.pHost != NULL);
  2501. ASSERT(pRequest->CookedUrl.pAbsPath != NULL);
  2502. //
  2503. // Do the full url. Must be careful to put any computed values
  2504. // that are subsequently needed on the RHS of expressions into
  2505. // local stack variables before putting them into pCookedUrl.
  2506. // In other words, we must not commit the cardinal sin of reading
  2507. // from pCookedUrl after writing to it, because this is a buffer
  2508. // that the user can overwrite at any instant.
  2509. //
  2510. pCookedUrl = &pHttpRequest->CookedUrl;
  2511. pCookedUrl->FullUrlLength = (USHORT)(pRequest->CookedUrl.Length);
  2512. pFullUrl = FIXUP_PTR(
  2513. PCWSTR,
  2514. pUserBuffer,
  2515. pKernelBuffer,
  2516. pCurrentBufferPtr,
  2517. BufferLength
  2518. );
  2519. pCookedUrl->pFullUrl = pFullUrl;
  2520. //
  2521. // And the host.
  2522. //
  2523. HostLength = DIFF_USHORT(
  2524. (PUCHAR) pRequest->CookedUrl.pAbsPath -
  2525. (PUCHAR) pRequest->CookedUrl.pHost
  2526. );
  2527. pCookedUrl->HostLength = HostLength;
  2528. pHost = pFullUrl +
  2529. DIFF_USHORT(pRequest->CookedUrl.pHost - pRequest->CookedUrl.pUrl);
  2530. pCookedUrl->pHost = pHost;
  2531. //
  2532. // Is there a query string?
  2533. //
  2534. if (pRequest->CookedUrl.pQueryString != NULL)
  2535. {
  2536. AbsPathLength = DIFF_USHORT(
  2537. (PUCHAR) pRequest->CookedUrl.pQueryString -
  2538. (PUCHAR) pRequest->CookedUrl.pAbsPath
  2539. );
  2540. pCookedUrl->AbsPathLength = AbsPathLength;
  2541. pAbsPath = pHost + (HostLength / sizeof(WCHAR));
  2542. pCookedUrl->pAbsPath = pAbsPath;
  2543. pCookedUrl->QueryStringLength =
  2544. (USHORT) (pRequest->CookedUrl.Length) -
  2545. DIFF_USHORT(
  2546. (PUCHAR) pRequest->CookedUrl.pQueryString -
  2547. (PUCHAR) pRequest->CookedUrl.pUrl
  2548. );
  2549. pCookedUrl->pQueryString =
  2550. pAbsPath + (AbsPathLength / sizeof(WCHAR));
  2551. }
  2552. else
  2553. {
  2554. pCookedUrl->AbsPathLength =
  2555. (USHORT) (pRequest->CookedUrl.Length) -
  2556. DIFF_USHORT(
  2557. (PUCHAR) pRequest->CookedUrl.pAbsPath -
  2558. (PUCHAR) pRequest->CookedUrl.pUrl
  2559. );
  2560. pCookedUrl->pAbsPath = pHost + (HostLength / sizeof(WCHAR));
  2561. pCookedUrl->QueryStringLength = 0;
  2562. pCookedUrl->pQueryString = NULL;
  2563. }
  2564. //
  2565. // Copy the full url.
  2566. //
  2567. RtlCopyMemory(
  2568. pCurrentBufferPtr,
  2569. pRequest->CookedUrl.pUrl,
  2570. pRequest->CookedUrl.Length
  2571. );
  2572. pCurrentBufferPtr += pRequest->CookedUrl.Length;
  2573. //
  2574. // Terminate it.
  2575. //
  2576. ((PWSTR) pCurrentBufferPtr)[0] = UNICODE_NULL;
  2577. pCurrentBufferPtr += sizeof(WCHAR);
  2578. //
  2579. // Any raw verb?
  2580. //
  2581. if (pRequest->Verb == HttpVerbUnknown)
  2582. {
  2583. //
  2584. // Need to copy in the raw verb for the client.
  2585. //
  2586. ASSERT(pRequest->RawVerbLength <= ANSI_STRING_MAX_CHAR_LEN);
  2587. pHttpRequest->UnknownVerbLength =
  2588. (pRequest->RawVerbLength * sizeof(CHAR));
  2589. pHttpRequest->pUnknownVerb = FIXUP_PTR(
  2590. PSTR,
  2591. pUserBuffer,
  2592. pKernelBuffer,
  2593. pCurrentBufferPtr,
  2594. BufferLength
  2595. );
  2596. RtlCopyMemory(
  2597. pCurrentBufferPtr,
  2598. pRequest->pRawVerb,
  2599. pRequest->RawVerbLength
  2600. );
  2601. BytesCopied = pRequest->RawVerbLength * sizeof(CHAR);
  2602. pCurrentBufferPtr += BytesCopied;
  2603. //
  2604. // Terminate it.
  2605. //
  2606. ((PSTR) pCurrentBufferPtr)[0] = ANSI_NULL;
  2607. pCurrentBufferPtr += sizeof(CHAR);
  2608. }
  2609. else
  2610. {
  2611. pHttpRequest->UnknownVerbLength = 0;
  2612. pHttpRequest->pUnknownVerb = NULL;
  2613. }
  2614. //
  2615. // Copy the raw url.
  2616. //
  2617. ASSERT(pRequest->RawUrl.Length <= ANSI_STRING_MAX_CHAR_LEN);
  2618. pHttpRequest->RawUrlLength = (USHORT) pRequest->RawUrl.Length;
  2619. pHttpRequest->pRawUrl = FIXUP_PTR(
  2620. PSTR,
  2621. pUserBuffer,
  2622. pKernelBuffer,
  2623. pCurrentBufferPtr,
  2624. BufferLength
  2625. );
  2626. RtlCopyMemory(
  2627. pCurrentBufferPtr,
  2628. pRequest->RawUrl.pUrl,
  2629. pRequest->RawUrl.Length
  2630. );
  2631. BytesCopied = pRequest->RawUrl.Length;
  2632. pCurrentBufferPtr += BytesCopied;
  2633. //
  2634. // Terminate it.
  2635. //
  2636. ((PSTR) pCurrentBufferPtr)[0] = ANSI_NULL;
  2637. pCurrentBufferPtr += sizeof(CHAR);
  2638. //
  2639. // Copy in the known headers.
  2640. //
  2641. // Loop through the known header array in the HTTP connection,
  2642. // and copy any that we have.
  2643. //
  2644. RtlZeroMemory(
  2645. pHttpRequest->Headers.KnownHeaders,
  2646. HttpHeaderRequestMaximum * sizeof(HTTP_KNOWN_HEADER)
  2647. );
  2648. for (Index = 0; Index < HttpHeaderRequestMaximum; Index++)
  2649. {
  2650. HeaderId = (HTTP_HEADER_ID) pRequest->HeaderIndex[Index];
  2651. if (HeaderId == HttpHeaderRequestMaximum)
  2652. {
  2653. break;
  2654. }
  2655. //
  2656. // Have a header here we need to copy in.
  2657. //
  2658. ASSERT(pRequest->HeaderValid[HeaderId]);
  2659. ASSERT(pRequest->Headers[HeaderId].HeaderLength
  2660. <= ANSI_STRING_MAX_CHAR_LEN);
  2661. //
  2662. // Ok for HeaderLength to be 0, we will give usermode a pointer
  2663. // pointing to a NULL string. RawValueLength will be 0.
  2664. //
  2665. pHttpRequest->Headers.KnownHeaders[HeaderId].RawValueLength =
  2666. (USHORT) (pRequest->Headers[HeaderId].HeaderLength * sizeof(CHAR));
  2667. pHttpRequest->Headers.KnownHeaders[HeaderId].pRawValue =
  2668. FIXUP_PTR(
  2669. PSTR,
  2670. pUserBuffer,
  2671. pKernelBuffer,
  2672. pCurrentBufferPtr,
  2673. BufferLength
  2674. );
  2675. RtlCopyMemory(
  2676. pCurrentBufferPtr,
  2677. pRequest->Headers[HeaderId].pHeader,
  2678. pRequest->Headers[HeaderId].HeaderLength
  2679. );
  2680. BytesCopied =
  2681. pRequest->Headers[HeaderId].HeaderLength * sizeof(CHAR);
  2682. pCurrentBufferPtr += BytesCopied;
  2683. //
  2684. // Terminate it.
  2685. //
  2686. ((PSTR) pCurrentBufferPtr)[0] = ANSI_NULL;
  2687. pCurrentBufferPtr += sizeof(CHAR);
  2688. }
  2689. //
  2690. // Now loop through the unknown headers, and copy them in.
  2691. //
  2692. pHttpRequest->Headers.UnknownHeaderCount = pRequest->UnknownHeaderCount;
  2693. if (pRequest->UnknownHeaderCount == 0)
  2694. {
  2695. pHttpRequest->Headers.pUnknownHeaders = NULL;
  2696. }
  2697. else
  2698. {
  2699. pHttpRequest->Headers.pUnknownHeaders =
  2700. FIXUP_PTR(
  2701. PHTTP_UNKNOWN_HEADER,
  2702. pUserBuffer,
  2703. pKernelBuffer,
  2704. pUserCurrentUnknownHeader,
  2705. BufferLength
  2706. );
  2707. }
  2708. pListEntry = pRequest->UnknownHeaderList.Flink;
  2709. while (pListEntry != &pRequest->UnknownHeaderList)
  2710. {
  2711. pUnknownHeader = CONTAINING_RECORD(
  2712. pListEntry,
  2713. UL_HTTP_UNKNOWN_HEADER,
  2714. List
  2715. );
  2716. pListEntry = pListEntry->Flink;
  2717. HeaderCount++;
  2718. ASSERT(HeaderCount <= pRequest->UnknownHeaderCount);
  2719. //
  2720. // First copy in the header name.
  2721. //
  2722. pUserCurrentUnknownHeader->NameLength =
  2723. pUnknownHeader->HeaderNameLength * sizeof(CHAR);
  2724. pUserCurrentUnknownHeader->pName =
  2725. FIXUP_PTR(
  2726. PSTR,
  2727. pUserBuffer,
  2728. pKernelBuffer,
  2729. pCurrentBufferPtr,
  2730. BufferLength
  2731. );
  2732. RtlCopyMemory(
  2733. pCurrentBufferPtr,
  2734. pUnknownHeader->pHeaderName,
  2735. pUnknownHeader->HeaderNameLength
  2736. );
  2737. BytesCopied = pUnknownHeader->HeaderNameLength * sizeof(CHAR);
  2738. pCurrentBufferPtr += BytesCopied;
  2739. //
  2740. // Terminate it.
  2741. //
  2742. ((PSTR) pCurrentBufferPtr)[0] = ANSI_NULL;
  2743. pCurrentBufferPtr += sizeof(CHAR);
  2744. //
  2745. // Now copy in the header value.
  2746. //
  2747. ASSERT(pUnknownHeader->HeaderValue.HeaderLength <= 0x7fff);
  2748. if (pUnknownHeader->HeaderValue.HeaderLength == 0)
  2749. {
  2750. pUserCurrentUnknownHeader->RawValueLength = 0;
  2751. pUserCurrentUnknownHeader->pRawValue = NULL;
  2752. }
  2753. else
  2754. {
  2755. pUserCurrentUnknownHeader->RawValueLength = (USHORT)
  2756. (pUnknownHeader->HeaderValue.HeaderLength * sizeof(CHAR));
  2757. pUserCurrentUnknownHeader->pRawValue =
  2758. FIXUP_PTR(
  2759. PSTR,
  2760. pUserBuffer,
  2761. pKernelBuffer,
  2762. pCurrentBufferPtr,
  2763. BufferLength
  2764. );
  2765. RtlCopyMemory(
  2766. pCurrentBufferPtr,
  2767. pUnknownHeader->HeaderValue.pHeader,
  2768. pUnknownHeader->HeaderValue.HeaderLength
  2769. );
  2770. BytesCopied =
  2771. pUnknownHeader->HeaderValue.HeaderLength * sizeof(CHAR);
  2772. pCurrentBufferPtr += BytesCopied;
  2773. //
  2774. // Terminate it.
  2775. //
  2776. ((PSTR) pCurrentBufferPtr)[0] = ANSI_NULL;
  2777. pCurrentBufferPtr += sizeof(CHAR);
  2778. }
  2779. //
  2780. // Skip to the next header.
  2781. //
  2782. pUserCurrentUnknownHeader++;
  2783. }
  2784. //
  2785. // Copy raw connection ID.
  2786. //
  2787. pHttpRequest->RawConnectionId = pRequest->RawConnectionId;
  2788. //
  2789. // Copy in SSL information.
  2790. //
  2791. if (pRequest->pHttpConn->SecureConnection == FALSE)
  2792. {
  2793. pHttpRequest->pSslInfo = NULL;
  2794. }
  2795. else
  2796. {
  2797. pCurrentBufferPtr =
  2798. (PUCHAR) ALIGN_UP_POINTER(pCurrentBufferPtr, PVOID);
  2799. //
  2800. // When a handling a request on a keepalive connection, it's
  2801. // possible that we might be running on system process's context.
  2802. // Therefore if we are copying over the user credentials we have
  2803. // to duplicate the token on target worker process but not on the
  2804. // system process again.
  2805. //
  2806. pProcess = pRequest->AppPool.pProcess->pProcess;
  2807. Status = UlGetSslInfo(
  2808. &pRequest->pHttpConn->pConnection->FilterInfo,
  2809. BufferLength - DIFF(pCurrentBufferPtr - pKernelBuffer),
  2810. FIXUP_PTR(
  2811. PUCHAR,
  2812. pUserBuffer,
  2813. pKernelBuffer,
  2814. pCurrentBufferPtr,
  2815. BufferLength
  2816. ),
  2817. pProcess,
  2818. pCurrentBufferPtr,
  2819. &MappedToken,
  2820. &BytesCopied
  2821. );
  2822. if (NT_SUCCESS(Status) && 0 != BytesCopied)
  2823. {
  2824. pHttpRequest->pSslInfo = FIXUP_PTR(
  2825. PHTTP_SSL_INFO,
  2826. pUserBuffer,
  2827. pKernelBuffer,
  2828. pCurrentBufferPtr,
  2829. BufferLength
  2830. );
  2831. pCurrentBufferPtr += BytesCopied;
  2832. }
  2833. else
  2834. {
  2835. pHttpRequest->pSslInfo = NULL;
  2836. }
  2837. }
  2838. //
  2839. // Copy entity body.
  2840. //
  2841. if (pRequest->ContentLength > 0 || pRequest->Chunked == 1)
  2842. {
  2843. pEntityBody = (PUCHAR)ALIGN_UP_POINTER(pCurrentBufferPtr, PVOID);
  2844. EntityBodyLength = BufferLength - DIFF(pEntityBody - pKernelBuffer);
  2845. if ((Flags & HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY) &&
  2846. EntityBodyLength > 0 &&
  2847. EntityBodyLength > sizeof(HTTP_DATA_CHUNK) &&
  2848. pRequest->ChunkBytesToRead > 0 &&
  2849. pRequest->ChunkBytesRead < pRequest->ChunkBytesParsed)
  2850. {
  2851. pCurrentBufferPtr = pEntityBody;
  2852. //
  2853. // We at least have 1 byte space for entity body so copy it.
  2854. //
  2855. pHttpRequest->EntityChunkCount = 1;
  2856. pHttpRequest->pEntityChunks = FIXUP_PTR(
  2857. PHTTP_DATA_CHUNK,
  2858. pUserBuffer,
  2859. pKernelBuffer,
  2860. pCurrentBufferPtr,
  2861. BufferLength
  2862. );
  2863. pDataChunk = (PHTTP_DATA_CHUNK)pCurrentBufferPtr;
  2864. pCurrentBufferPtr += sizeof(HTTP_DATA_CHUNK);
  2865. pDataChunk->DataChunkType = HttpDataChunkFromMemory;
  2866. pDataChunk->FromMemory.pBuffer = FIXUP_PTR(
  2867. PVOID,
  2868. pUserBuffer,
  2869. pKernelBuffer,
  2870. pCurrentBufferPtr,
  2871. BufferLength
  2872. );
  2873. //
  2874. // Need to take the HttpConnection lock if this is called
  2875. // from the receive I/O path, either fast or slow. The lock is
  2876. // already taken on the delivery path.
  2877. //
  2878. if (!LockAcquired)
  2879. {
  2880. UlAcquirePushLockExclusive(&pRequest->pHttpConn->PushLock);
  2881. }
  2882. BytesCopied = UlpCopyEntityBodyToBuffer(
  2883. pRequest,
  2884. pCurrentBufferPtr,
  2885. EntityBodyLength - sizeof(HTTP_DATA_CHUNK),
  2886. &pHttpRequest->Flags
  2887. );
  2888. if (!LockAcquired)
  2889. {
  2890. UlReleasePushLockExclusive(&pRequest->pHttpConn->PushLock);
  2891. }
  2892. if (BytesCopied)
  2893. {
  2894. pDataChunk->FromMemory.BufferLength = BytesCopied;
  2895. pCurrentBufferPtr += BytesCopied;
  2896. }
  2897. else
  2898. {
  2899. //
  2900. // Be nice and reset EntityChunkCount and pEntityChunks if
  2901. // UlpCopyEntityBodyToBuffer doesn't copy anything, usually
  2902. // indicating an error has been hit.
  2903. //
  2904. pHttpRequest->EntityChunkCount = 0;
  2905. pHttpRequest->pEntityChunks = NULL;
  2906. pHttpRequest->Flags =
  2907. HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS;
  2908. }
  2909. }
  2910. else
  2911. {
  2912. //
  2913. // Either the app doesn't ask for entity body or we have nothing
  2914. // or can't copy. Let ReceiveEntityBody handle this.
  2915. //
  2916. pHttpRequest->EntityChunkCount = 0;
  2917. pHttpRequest->pEntityChunks = NULL;
  2918. pHttpRequest->Flags = HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS;
  2919. }
  2920. }
  2921. else
  2922. {
  2923. //
  2924. // This request doesn't have entity bodies.
  2925. //
  2926. pHttpRequest->EntityChunkCount = 0;
  2927. pHttpRequest->pEntityChunks = NULL;
  2928. pHttpRequest->Flags = 0;
  2929. }
  2930. //
  2931. // Make sure we didn't use too much.
  2932. //
  2933. ASSERT(DIFF(pCurrentBufferPtr - pKernelBuffer) <= BufferLength);
  2934. *pBytesCopied = DIFF(pCurrentBufferPtr - pKernelBuffer);
  2935. }
  2936. __except( UL_EXCEPTION_FILTER() )
  2937. {
  2938. Status = UL_CONVERT_EXCEPTION_CODE( GetExceptionCode() );
  2939. }
  2940. TRACE_TIME(
  2941. pRequest->ConnectionId,
  2942. pRequest->RequestId,
  2943. TIME_ACTION_COPY_REQUEST
  2944. );
  2945. if (!NT_SUCCESS(Status) && MappedToken)
  2946. {
  2947. //
  2948. // The only reason we can fail after getting a MappedToken is because
  2949. // the code after that throws an exception, which is only possible
  2950. // if UlCopyRequestToBuffer is called from the fast I/O path, which
  2951. // guarantees we are the user's context.
  2952. //
  2953. ASSERT(g_pUlSystemProcess != (PKPROCESS)IoGetCurrentProcess());
  2954. ZwClose(MappedToken);
  2955. }
  2956. return Status;
  2957. } // UlCopyRequestToBuffer
  2958. /******************************************************************************
  2959. Routine Description:
  2960. Copy as much as entity body as possible to the buffer provided.
  2961. Arguments:
  2962. pRequest - the request to copy the entity body from
  2963. pBuffer - the buffer to copy the entity body
  2964. BufferLength - the length of the buffer for the maximum we can copy
  2965. pFlags - tells if there are still more entity bodies
  2966. Return Value:
  2967. Total number of bytes of entity body being copied
  2968. ******************************************************************************/
  2969. ULONG
  2970. UlpCopyEntityBodyToBuffer(
  2971. IN PUL_INTERNAL_REQUEST pRequest,
  2972. IN PUCHAR pEntityBody,
  2973. IN ULONG EntityBodyLength,
  2974. OUT PULONG pFlags
  2975. )
  2976. {
  2977. ULONGLONG ChunkBytesRead = pRequest->ChunkBytesRead;
  2978. ULONG TotalBytesRead;
  2979. NTSTATUS Status;
  2980. //
  2981. // Sanity check.
  2982. //
  2983. PAGED_CODE();
  2984. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  2985. ASSERT(NULL != pEntityBody);
  2986. ASSERT(EntityBodyLength > 0);
  2987. ASSERT(NULL != pFlags);
  2988. ASSERT(UlDbgPushLockOwnedExclusive(&pRequest->pHttpConn->PushLock));
  2989. UlTrace(ROUTING, (
  2990. "http!UlpCopyEntityBodyToBuffer"
  2991. " pRequest = %p, pEntityBody = %p, EntityBodyLength = %d\n",
  2992. pRequest,
  2993. pEntityBody,
  2994. EntityBodyLength
  2995. ));
  2996. //
  2997. // UlProcessBufferQueue needs to be called in a try/except because
  2998. // pEntityBody can be user mode memory address when called from the
  2999. // fast receive path.
  3000. //
  3001. __try
  3002. {
  3003. UlProcessBufferQueue(pRequest, pEntityBody, EntityBodyLength);
  3004. }
  3005. __except(UL_EXCEPTION_FILTER())
  3006. {
  3007. Status = UL_CONVERT_EXCEPTION_CODE(GetExceptionCode());
  3008. return 0;
  3009. }
  3010. if (pRequest->ParseState > ParseEntityBodyState &&
  3011. pRequest->ChunkBytesRead == pRequest->ChunkBytesParsed)
  3012. {
  3013. *pFlags = 0;
  3014. }
  3015. else
  3016. {
  3017. *pFlags = HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS;
  3018. }
  3019. TotalBytesRead = (ULONG)(pRequest->ChunkBytesRead - ChunkBytesRead);
  3020. ASSERT(TotalBytesRead <= EntityBodyLength);
  3021. return TotalBytesRead;
  3022. } // UlpCopyEntityBodyToBuffer
  3023. /******************************************************************************
  3024. Routine Description:
  3025. Find a pending IRP to deliver a request to. This routine must
  3026. be called with the lock on the apool held.
  3027. Arguments:
  3028. pAppPool - the apool to search for the irp
  3029. pRequest - the request that needs to pop the irp
  3030. ppProcess - the process that we got the irp from
  3031. Return Value:
  3032. A pointer to an IRP if we've found one, or NULL if we didn't
  3033. ******************************************************************************/
  3034. PIRP
  3035. UlpPopNewIrp(
  3036. IN PUL_APP_POOL_OBJECT pAppPool,
  3037. IN PUL_INTERNAL_REQUEST pRequest,
  3038. OUT PUL_APP_POOL_PROCESS * ppProcess
  3039. )
  3040. {
  3041. PUL_APP_POOL_PROCESS pProcess;
  3042. PIRP pIrp = NULL;
  3043. PLIST_ENTRY pEntry;
  3044. //
  3045. // Sanity check.
  3046. //
  3047. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  3048. ASSERT(UlDbgSpinLockOwned(&pAppPool->SpinLock));
  3049. ASSERT(ppProcess != NULL);
  3050. //
  3051. // Start looking for a process with a free IRP. We tend to always go to
  3052. // the first one to try and prevent process thrashing.
  3053. //
  3054. pEntry = pAppPool->ProcessListHead.Flink;
  3055. while (pEntry != &(pAppPool->ProcessListHead))
  3056. {
  3057. pProcess = CONTAINING_RECORD(
  3058. pEntry,
  3059. UL_APP_POOL_PROCESS,
  3060. ListEntry
  3061. );
  3062. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  3063. //
  3064. // Get an IRP from this process.
  3065. //
  3066. pIrp = UlpPopIrpFromProcess(pProcess, pRequest);
  3067. //
  3068. // Did we find one?
  3069. //
  3070. if (pIrp != NULL)
  3071. {
  3072. //
  3073. // Save a pointer to the process.
  3074. //
  3075. *ppProcess = pProcess;
  3076. //
  3077. // Move the process to the end of the line
  3078. // so that other processes get a chance
  3079. // to process requests.
  3080. //
  3081. RemoveEntryList(pEntry);
  3082. InsertTailList(&(pAppPool->ProcessListHead), pEntry);
  3083. break;
  3084. }
  3085. //
  3086. // Keep looking - move on to the next process entry.
  3087. //
  3088. pEntry = pProcess->ListEntry.Flink;
  3089. }
  3090. return pIrp;
  3091. } // UlpPopNewIrp
  3092. /***************************************************************************++
  3093. Routine Description:
  3094. Pulls an IRP off the given processes queue if there is one.
  3095. Arguments:
  3096. pProcess - a pointer to the process to search
  3097. pRequest - the request to pop the irp for
  3098. Return Value:
  3099. A pointer to an IRP if we've found one, or NULL if we didn't
  3100. --***************************************************************************/
  3101. PIRP
  3102. UlpPopIrpFromProcess(
  3103. IN PUL_APP_POOL_PROCESS pProcess,
  3104. IN PUL_INTERNAL_REQUEST pRequest
  3105. )
  3106. {
  3107. PUL_APP_POOL_PROCESS pAppPoolProcess;
  3108. PLIST_ENTRY pEntry;
  3109. PIRP pIrp = NULL;
  3110. NTSTATUS Status;
  3111. //
  3112. // Sanity check.
  3113. //
  3114. ASSERT(UlDbgSpinLockOwned(&pProcess->pAppPool->SpinLock));
  3115. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  3116. if (!IsListEmpty(&pProcess->NewIrpHead))
  3117. {
  3118. pEntry = RemoveHeadList(&pProcess->NewIrpHead);
  3119. //
  3120. // Found a free irp!
  3121. //
  3122. pEntry->Blink = pEntry->Flink = NULL;
  3123. pIrp = CONTAINING_RECORD(
  3124. pEntry,
  3125. IRP,
  3126. Tail.Overlay.ListEntry
  3127. );
  3128. //
  3129. // Pop the cancel routine.
  3130. //
  3131. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  3132. {
  3133. //
  3134. // IoCancelIrp pop'd it first.
  3135. //
  3136. // Ok to just ignore this irp, it's been pop'd off the queue
  3137. // and will be completed in the cancel routine.
  3138. //
  3139. // Keep looking for a irp to use.
  3140. //
  3141. pIrp = NULL;
  3142. }
  3143. else
  3144. if (pIrp->Cancel)
  3145. {
  3146. //
  3147. // We pop'd it first, but the irp is being cancelled
  3148. // and our cancel routine will never run. Lets be
  3149. // nice and complete the irp now (vs. using it
  3150. // then completing it - which would also be legal).
  3151. //
  3152. pAppPoolProcess = (PUL_APP_POOL_PROCESS)
  3153. IoGetCurrentIrpStackLocation(pIrp)->
  3154. Parameters.DeviceIoControl.Type3InputBuffer;
  3155. ASSERT(pAppPoolProcess == pProcess);
  3156. DEREFERENCE_APP_POOL_PROCESS(pAppPoolProcess);
  3157. IoGetCurrentIrpStackLocation(pIrp)->
  3158. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  3159. pIrp->IoStatus.Status = STATUS_CANCELLED;
  3160. pIrp->IoStatus.Information = 0;
  3161. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3162. pIrp = NULL;
  3163. }
  3164. else
  3165. {
  3166. //
  3167. // We are free to use this irp!
  3168. //
  3169. pAppPoolProcess = (PUL_APP_POOL_PROCESS)
  3170. IoGetCurrentIrpStackLocation(pIrp)->
  3171. Parameters.DeviceIoControl.Type3InputBuffer;
  3172. ASSERT(pAppPoolProcess == pProcess);
  3173. DEREFERENCE_APP_POOL_PROCESS(pAppPoolProcess);
  3174. IoGetCurrentIrpStackLocation(pIrp)->
  3175. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  3176. //
  3177. // Queue the request to the process's pending queue, and if we
  3178. // can't, complete the IRP with error status.
  3179. //
  3180. Status = UlpQueuePendingRequest(pProcess, pRequest);
  3181. if (!NT_SUCCESS(Status))
  3182. {
  3183. pIrp->IoStatus.Status = Status;
  3184. pIrp->IoStatus.Information = 0;
  3185. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3186. pIrp = NULL;
  3187. }
  3188. }
  3189. }
  3190. return pIrp;
  3191. } // UlpPopIrpFromProcess
  3192. /***************************************************************************++
  3193. Routine Description:
  3194. Loops through an app pool's list of processes, looking for the specified
  3195. process.
  3196. Arguments:
  3197. pProcess - the process to search for
  3198. pAppPool - the app pool to search
  3199. Return Value:
  3200. TRUE if the process was found, FALSE otherwise
  3201. --***************************************************************************/
  3202. BOOLEAN
  3203. UlpIsProcessInAppPool(
  3204. IN PUL_APP_POOL_PROCESS pProcess,
  3205. IN PUL_APP_POOL_OBJECT pAppPool
  3206. )
  3207. {
  3208. BOOLEAN Found = FALSE;
  3209. PLIST_ENTRY pEntry;
  3210. PUL_APP_POOL_PROCESS pCurrentProc;
  3211. //
  3212. // Sanity check.
  3213. //
  3214. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  3215. ASSERT(UlDbgSpinLockOwned(&pAppPool->SpinLock));
  3216. //
  3217. // Only look if process isn't NULL.
  3218. //
  3219. if (pProcess != NULL)
  3220. {
  3221. //
  3222. // Start looking for the process.
  3223. //
  3224. pEntry = pAppPool->ProcessListHead.Flink;
  3225. while (pEntry != &(pAppPool->ProcessListHead))
  3226. {
  3227. pCurrentProc = CONTAINING_RECORD(
  3228. pEntry,
  3229. UL_APP_POOL_PROCESS,
  3230. ListEntry
  3231. );
  3232. ASSERT(IS_VALID_AP_PROCESS(pCurrentProc));
  3233. //
  3234. // Did we find it?
  3235. //
  3236. if (pCurrentProc == pProcess)
  3237. {
  3238. Found = TRUE;
  3239. break;
  3240. }
  3241. //
  3242. // Keep looking - move on to the next process entry.
  3243. //
  3244. pEntry = pCurrentProc->ListEntry.Flink;
  3245. }
  3246. }
  3247. return Found;
  3248. } // UlpIsProcessInAppPool
  3249. /***************************************************************************++
  3250. Routine Description:
  3251. Adds a request to the unbound queue. These requests can be routed to
  3252. any process in the app pool.
  3253. Arguments:
  3254. pAppPool - the pool which is getting the request
  3255. pRequest - the request to queue
  3256. Return Value:
  3257. NTSTATUS - Completion status.
  3258. --***************************************************************************/
  3259. NTSTATUS
  3260. UlpQueueUnboundRequest(
  3261. IN PUL_APP_POOL_OBJECT pAppPool,
  3262. IN PUL_INTERNAL_REQUEST pRequest
  3263. )
  3264. {
  3265. NTSTATUS Status;
  3266. PUL_TIMEOUT_INFO_ENTRY pTimeoutInfo;
  3267. //
  3268. // Sanity check.
  3269. //
  3270. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  3271. ASSERT(UlDbgSpinLockOwned(&pAppPool->SpinLock));
  3272. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3273. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  3274. //
  3275. // Add the request to the NewRequestQueue.
  3276. //
  3277. Status = UlpQueueRequest(pAppPool, &pAppPool->NewRequestHead, pRequest);
  3278. //
  3279. // If it's in, change the queue state.
  3280. //
  3281. if (NT_SUCCESS(Status))
  3282. {
  3283. pRequest->AppPool.QueueState = QueueDeliveredState;
  3284. //
  3285. // Turn the connection idle timer back on so that it won't stay
  3286. // on the queue forever and will also get purged under low
  3287. // resource conditions.
  3288. //
  3289. pTimeoutInfo = &pRequest->pHttpConn->TimeoutInfo;
  3290. UlAcquireSpinLockAtDpcLevel(&pTimeoutInfo->Lock);
  3291. if (UlIsConnectionTimerOff(pTimeoutInfo, TimerAppPool))
  3292. {
  3293. UlSetConnectionTimer(pTimeoutInfo, TimerAppPool);
  3294. }
  3295. UlReleaseSpinLockFromDpcLevel(&pTimeoutInfo->Lock);
  3296. UlEvaluateTimerState(pTimeoutInfo);
  3297. }
  3298. else
  3299. {
  3300. //
  3301. // The queue is too full, return an error to the client.
  3302. //
  3303. UlTrace(ROUTING, (
  3304. "http!UlpQueueUnboundRequest(pAppPool = %p, pRequest = %p)\n"
  3305. " Rejecting request. AppPool Queue is full (%d items)\n",
  3306. pAppPool,
  3307. pRequest,
  3308. pAppPool->RequestCount
  3309. ));
  3310. UlSetErrorCode( pRequest, UlErrorAppPoolQueueFull, pAppPool); // 503
  3311. }
  3312. return Status;
  3313. } // UlpQueueUnboundRequest
  3314. /***************************************************************************++
  3315. Routine Description:
  3316. Searches request queues for a request available to the specified process.
  3317. If a request is found, it is removed from the queue and returned.
  3318. Arguments:
  3319. pProcess - the process that will get the request
  3320. RequestBufferLength - the optional buffer length for the request
  3321. pRequest - the request pointer to receive the request
  3322. Return Value:
  3323. Pointer to an HTTP_REQUEST if one is found or NULL otherwise
  3324. --***************************************************************************/
  3325. NTSTATUS
  3326. UlDequeueNewRequest(
  3327. IN PUL_APP_POOL_PROCESS pProcess,
  3328. IN ULONG RequestBufferLength,
  3329. OUT PUL_INTERNAL_REQUEST * pNewRequest
  3330. )
  3331. {
  3332. PLIST_ENTRY pEntry;
  3333. PUL_INTERNAL_REQUEST pRequest = NULL;
  3334. PUL_APP_POOL_OBJECT pAppPool;
  3335. PUL_TIMEOUT_INFO_ENTRY pTimeoutInfo;
  3336. NTSTATUS Status = STATUS_NOT_FOUND;
  3337. PUL_APP_POOL_PROCESS pProcBinding;
  3338. ULONG BytesNeeded;
  3339. //
  3340. // Sanity check.
  3341. //
  3342. ASSERT(UlDbgSpinLockOwned(&pProcess->pAppPool->SpinLock));
  3343. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  3344. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  3345. *pNewRequest = NULL;
  3346. pAppPool = pProcess->pAppPool;
  3347. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  3348. //
  3349. // Find a usable request.
  3350. //
  3351. pEntry = pAppPool->NewRequestHead.Flink;
  3352. while (pEntry != &pAppPool->NewRequestHead)
  3353. {
  3354. pRequest = CONTAINING_RECORD(
  3355. pEntry,
  3356. UL_INTERNAL_REQUEST,
  3357. AppPool.AppPoolEntry
  3358. );
  3359. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3360. if (pAppPool->NumberActiveProcesses <= 1)
  3361. {
  3362. //
  3363. // Done if there is only one active process.
  3364. //
  3365. break;
  3366. }
  3367. //
  3368. // Check the binding.
  3369. //
  3370. pProcBinding = UlQueryProcessBinding(
  3371. pRequest->pHttpConn,
  3372. pAppPool
  3373. );
  3374. if (pProcBinding == pProcess)
  3375. {
  3376. //
  3377. // Found a request bound to the correct process.
  3378. //
  3379. break;
  3380. }
  3381. else
  3382. if (pProcBinding == NULL)
  3383. {
  3384. //
  3385. // Found an unbound request.
  3386. // Bind unbound request to this process.
  3387. // Note: we're ignoring the return value of
  3388. // UlBindConnectionToProcess because it's probably not a fatal
  3389. // error.
  3390. //
  3391. UlBindConnectionToProcess(
  3392. pRequest->pHttpConn,
  3393. pAppPool,
  3394. pProcess
  3395. );
  3396. break;
  3397. }
  3398. //
  3399. // Try the next one.
  3400. //
  3401. pEntry = pEntry->Flink;
  3402. }
  3403. //
  3404. // If we found something, remove it from the NewRequestQueue
  3405. // and pend it onto the PendingRequestQuueue.
  3406. //
  3407. if (pRequest)
  3408. {
  3409. //
  3410. // Let us check if this request can fit into a buffer with
  3411. // RequestBufferLength. Only check this if requested.
  3412. //
  3413. if (RequestBufferLength)
  3414. {
  3415. Status = UlComputeRequestBytesNeeded(pRequest, &BytesNeeded);
  3416. if (!NT_SUCCESS(Status))
  3417. {
  3418. return Status;
  3419. }
  3420. else
  3421. if (BytesNeeded > RequestBufferLength)
  3422. {
  3423. return STATUS_BUFFER_TOO_SMALL;
  3424. }
  3425. }
  3426. //
  3427. // We will return STATUS_SUCCESS from here on.
  3428. //
  3429. Status = STATUS_SUCCESS;
  3430. //
  3431. // Remove the request from the AppPool's NewRequestQueue and insert
  3432. // it to the process's PendingRequestQueue. There is no change in
  3433. // the queue limit.
  3434. //
  3435. RemoveEntryList(&pRequest->AppPool.AppPoolEntry);
  3436. InsertTailList(
  3437. &pProcess->PendingRequestHead,
  3438. &pRequest->AppPool.AppPoolEntry
  3439. );
  3440. //
  3441. // Attach the request to this process. This allows us to drop the
  3442. // connection if the process dies in the middle of request
  3443. // processing.
  3444. //
  3445. pRequest->AppPool.pProcess = pProcess;
  3446. pRequest->AppPool.QueueState = QueueCopiedState;
  3447. //
  3448. // Add a reference to the process to ensure it stays around during
  3449. // the send for the memory we lock.
  3450. //
  3451. REFERENCE_APP_POOL_PROCESS(pProcess);
  3452. //
  3453. // Add a reference to the request so as to allow unlink from
  3454. // process to happen once we let go of the lock.
  3455. //
  3456. UL_REFERENCE_INTERNAL_REQUEST(pRequest);
  3457. //
  3458. // Stop the connection idle timer after the request is delivered.
  3459. //
  3460. pTimeoutInfo = &pRequest->pHttpConn->TimeoutInfo;
  3461. UlAcquireSpinLockAtDpcLevel(&pTimeoutInfo->Lock);
  3462. UlResetConnectionTimer(pTimeoutInfo, TimerAppPool);
  3463. UlReleaseSpinLockFromDpcLevel(&pTimeoutInfo->Lock);
  3464. UlEvaluateTimerState(pTimeoutInfo);
  3465. }
  3466. *pNewRequest = pRequest;
  3467. return Status;
  3468. } // UlDequeueNewRequest
  3469. /***************************************************************************++
  3470. Routine Description:
  3471. Put the request back from the process's pending request queue to the
  3472. AppPool's new request queue.
  3473. Arguments:
  3474. pProcess - the process that will dequeue the request
  3475. pRequest - the request to dequeue
  3476. Return Value:
  3477. None
  3478. --***************************************************************************/
  3479. VOID
  3480. UlRequeuePendingRequest(
  3481. IN PUL_APP_POOL_PROCESS pProcess,
  3482. IN PUL_INTERNAL_REQUEST pRequest
  3483. )
  3484. {
  3485. KLOCK_QUEUE_HANDLE LockHandle;
  3486. PUL_TIMEOUT_INFO_ENTRY pTimeoutInfo;
  3487. UlAcquireInStackQueuedSpinLock(
  3488. &pProcess->pAppPool->SpinLock,
  3489. &LockHandle
  3490. );
  3491. if (!pProcess->InCleanup &&
  3492. QueueCopiedState == pRequest->AppPool.QueueState)
  3493. {
  3494. //
  3495. // Unset the request's AppPool info.
  3496. //
  3497. ASSERT( pRequest->AppPool.pProcess == pProcess );
  3498. DEREFERENCE_APP_POOL_PROCESS(pProcess);
  3499. pRequest->AppPool.pProcess = NULL;
  3500. pRequest->AppPool.QueueState = QueueDeliveredState;
  3501. //
  3502. // Move the request back from the process's pending queue to the
  3503. // AppPool's new request queue. This doesn't affect queue count.
  3504. //
  3505. RemoveEntryList(&pRequest->AppPool.AppPoolEntry);
  3506. InsertHeadList(
  3507. &pProcess->pAppPool->NewRequestHead,
  3508. &pRequest->AppPool.AppPoolEntry
  3509. );
  3510. //
  3511. // Lastly, we have to turn back on the idle timer.
  3512. //
  3513. pTimeoutInfo = &pRequest->pHttpConn->TimeoutInfo;
  3514. UlAcquireSpinLockAtDpcLevel(&pTimeoutInfo->Lock);
  3515. if (UlIsConnectionTimerOff(pTimeoutInfo, TimerConnectionIdle))
  3516. {
  3517. UlSetConnectionTimer(pTimeoutInfo, TimerConnectionIdle);
  3518. }
  3519. UlReleaseSpinLockFromDpcLevel(&pTimeoutInfo->Lock);
  3520. UlEvaluateTimerState(pTimeoutInfo);
  3521. }
  3522. UlReleaseInStackQueuedSpinLock(
  3523. &pProcess->pAppPool->SpinLock,
  3524. &LockHandle
  3525. );
  3526. } // UlRequeuePendingRequest
  3527. /***************************************************************************++
  3528. Routine Description:
  3529. Takes all the queued requests bound to the given process and makes them
  3530. available to all processes.
  3531. Arguments:
  3532. pProcess - the process whose requests are to be redistributed
  3533. Return Value:
  3534. None
  3535. --***************************************************************************/
  3536. VOID
  3537. UlpUnbindQueuedRequests(
  3538. IN PUL_APP_POOL_PROCESS pProcess
  3539. )
  3540. {
  3541. PLIST_ENTRY pEntry;
  3542. PUL_INTERNAL_REQUEST pRequest = NULL;
  3543. PUL_APP_POOL_OBJECT pAppPool;
  3544. PUL_APP_POOL_PROCESS pProcBinding;
  3545. //
  3546. // Sanity check.
  3547. //
  3548. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  3549. ASSERT(UlDbgSpinLockOwned(&pProcess->pAppPool->SpinLock));
  3550. pAppPool = pProcess->pAppPool;
  3551. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  3552. //
  3553. // Find a bound request.
  3554. //
  3555. pEntry = pAppPool->NewRequestHead.Flink;
  3556. while (pEntry != &pAppPool->NewRequestHead)
  3557. {
  3558. pRequest = CONTAINING_RECORD(
  3559. pEntry,
  3560. UL_INTERNAL_REQUEST,
  3561. AppPool.AppPoolEntry
  3562. );
  3563. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3564. //
  3565. // Remember the next one.
  3566. //
  3567. pEntry = pEntry->Flink;
  3568. //
  3569. // Check the binding.
  3570. //
  3571. if (pAppPool->NumberActiveProcesses <= 1)
  3572. {
  3573. pProcBinding = pProcess;
  3574. }
  3575. else
  3576. {
  3577. pProcBinding = UlQueryProcessBinding(
  3578. pRequest->pHttpConn,
  3579. pAppPool
  3580. );
  3581. }
  3582. if (pProcBinding == pProcess)
  3583. {
  3584. //
  3585. // Remove from the list.
  3586. //
  3587. UlpRemoveRequest(pAppPool, pRequest);
  3588. //
  3589. // Mark it as unrouted.
  3590. //
  3591. pRequest->AppPool.QueueState = QueueUnroutedState;
  3592. UlTrace(ROUTING, (
  3593. "STICKY KILL cid %I64x to proc %p\n",
  3594. pRequest->ConnectionId,
  3595. pProcess
  3596. ));
  3597. //
  3598. // Kill the binding.
  3599. //
  3600. UlBindConnectionToProcess(
  3601. pRequest->pHttpConn,
  3602. pProcess->pAppPool,
  3603. NULL
  3604. );
  3605. //
  3606. // There may be an IRP for this newly unbound
  3607. // request, so redeliver the request outside
  3608. // the locks we're holding.
  3609. //
  3610. UL_QUEUE_WORK_ITEM(
  3611. &pRequest->WorkItem,
  3612. &UlpRedeliverRequestWorker
  3613. );
  3614. }
  3615. }
  3616. } // UlpUnbindQueuedRequests
  3617. /***************************************************************************++
  3618. Routine Description:
  3619. Delivers the given request to an App Pool. UlpUnbindQueuedRequests
  3620. uses this routine to call into UlDeliverRequestToProcess outside
  3621. of any locks.
  3622. Arguments:
  3623. pWorkItem - embedded in the request to deliver
  3624. Return Value:
  3625. None
  3626. --***************************************************************************/
  3627. VOID
  3628. UlpRedeliverRequestWorker(
  3629. IN PUL_WORK_ITEM pWorkItem
  3630. )
  3631. {
  3632. NTSTATUS Status;
  3633. PUL_INTERNAL_REQUEST pRequest;
  3634. pRequest = CONTAINING_RECORD(
  3635. pWorkItem,
  3636. UL_INTERNAL_REQUEST,
  3637. WorkItem
  3638. );
  3639. //
  3640. // Sanity check.
  3641. //
  3642. PAGED_CODE();
  3643. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3644. ASSERT(IS_VALID_URL_CONFIG_GROUP_INFO(&pRequest->ConfigInfo));
  3645. ASSERT(pRequest->ConfigInfo.pAppPool);
  3646. Status = UlDeliverRequestToProcess(
  3647. pRequest->ConfigInfo.pAppPool,
  3648. pRequest,
  3649. NULL
  3650. );
  3651. //
  3652. // Remove the extra reference added in UlpUnbindQueuedRequests.
  3653. //
  3654. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  3655. } // UlpRedeliverRequestWorker
  3656. /***************************************************************************++
  3657. Routine Description:
  3658. Changes the maximum length of the incoming request queue on the app pool.
  3659. Arguments:
  3660. pProcess - App pool process object
  3661. QueueLength - the new max length of the queue
  3662. Return Value:
  3663. NTSTATUS - Completion status.
  3664. --***************************************************************************/
  3665. NTSTATUS
  3666. UlpSetAppPoolQueueLength(
  3667. IN PUL_APP_POOL_PROCESS pProcess,
  3668. IN ULONG QueueLength
  3669. )
  3670. {
  3671. PUL_APP_POOL_OBJECT pAppPool;
  3672. KLOCK_QUEUE_HANDLE LockHandle;
  3673. pAppPool = pProcess->pAppPool;
  3674. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  3675. //
  3676. // Set the new value.
  3677. //
  3678. UlAcquireInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  3679. pAppPool->MaxRequests = QueueLength;
  3680. UlReleaseInStackQueuedSpinLock(&pAppPool->SpinLock, &LockHandle);
  3681. UlTrace(ROUTING, (
  3682. "http!UlpSetAppPoolQueueLength(pProcess = %p, QueueLength = %ld)\n"
  3683. " pAppPool = %p (%ws), Status = 0x%08x\n",
  3684. pProcess,
  3685. QueueLength,
  3686. pAppPool,
  3687. pAppPool->pName,
  3688. STATUS_SUCCESS
  3689. ));
  3690. return STATUS_SUCCESS;
  3691. } // UlpSetAppPoolQueueLength
  3692. /******************************************************************************
  3693. Routine Description:
  3694. This copies a request into a free irp.
  3695. If the request is too large, it queues to request onto the process and
  3696. completes the irp, so that the process can come back later with a larger
  3697. buffer.
  3698. Arguments:
  3699. pRequest - the request to copy
  3700. pProcess - the process that owns pIrp
  3701. pIrp - the irp to copy pRequest to
  3702. Return Value:
  3703. None
  3704. ******************************************************************************/
  3705. VOID
  3706. UlCopyRequestToIrp(
  3707. IN PUL_INTERNAL_REQUEST pRequest,
  3708. IN PIRP pIrp,
  3709. IN BOOLEAN CompleteIrp,
  3710. IN BOOLEAN LockAcquired
  3711. )
  3712. {
  3713. NTSTATUS Status;
  3714. PIO_STACK_LOCATION pIrpSp = NULL;
  3715. ULONG BytesNeeded;
  3716. ULONG BytesCopied;
  3717. PUCHAR pKernelBuffer;
  3718. PVOID pUserBuffer;
  3719. PHTTP_RECEIVE_REQUEST_INFO pRequestInfo;
  3720. PHTTP_REQUEST pUserRequest;
  3721. //
  3722. // Sanity check.
  3723. //
  3724. PAGED_CODE();
  3725. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3726. ASSERT(pIrp != NULL);
  3727. ASSERT(NULL != pIrp->MdlAddress);
  3728. //
  3729. // Make sure this is big enough to handle the request, and
  3730. // if so copy it in.
  3731. //
  3732. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  3733. //
  3734. // Calculate the size needed for the request, we'll need it below.
  3735. //
  3736. Status = UlComputeRequestBytesNeeded(pRequest, &BytesNeeded);
  3737. if (!NT_SUCCESS(Status))
  3738. {
  3739. goto complete;
  3740. }
  3741. //
  3742. // Make sure we've got enough space to handle the whole request.
  3743. //
  3744. if (BytesNeeded <=
  3745. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength)
  3746. {
  3747. //
  3748. // Get the addresses for the buffer.
  3749. //
  3750. pKernelBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe(
  3751. pIrp->MdlAddress,
  3752. NormalPagePriority
  3753. );
  3754. if (pKernelBuffer == NULL)
  3755. {
  3756. Status = STATUS_INSUFFICIENT_RESOURCES;
  3757. goto complete;
  3758. }
  3759. //
  3760. // Make sure we are properly aligned.
  3761. //
  3762. ASSERT(!(((ULONG_PTR) pKernelBuffer) & (TYPE_ALIGNMENT(PVOID) - 1)));
  3763. pUserBuffer = MmGetMdlVirtualAddress(pIrp->MdlAddress);
  3764. ASSERT(pUserBuffer != NULL);
  3765. pRequestInfo =
  3766. (PHTTP_RECEIVE_REQUEST_INFO)pIrp->AssociatedIrp.SystemBuffer;
  3767. //
  3768. // This request will fit in this buffer, so copy it.
  3769. //
  3770. Status = UlCopyRequestToBuffer(
  3771. pRequest,
  3772. pKernelBuffer,
  3773. pUserBuffer,
  3774. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength,
  3775. pRequestInfo->Flags,
  3776. LockAcquired,
  3777. &BytesCopied
  3778. );
  3779. if (NT_SUCCESS(Status))
  3780. {
  3781. pIrp->IoStatus.Information = BytesCopied;
  3782. }
  3783. else
  3784. {
  3785. goto complete;
  3786. }
  3787. }
  3788. else
  3789. {
  3790. //
  3791. // The user buffer is too small.
  3792. //
  3793. Status = STATUS_BUFFER_OVERFLOW;
  3794. //
  3795. // Is it big enough to hold the basic structure?
  3796. //
  3797. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength >=
  3798. sizeof(HTTP_REQUEST))
  3799. {
  3800. pUserRequest = (PHTTP_REQUEST)MmGetSystemAddressForMdlSafe(
  3801. pIrp->MdlAddress,
  3802. NormalPagePriority
  3803. );
  3804. if (pUserRequest == NULL)
  3805. {
  3806. Status = STATUS_INSUFFICIENT_RESOURCES;
  3807. goto complete;
  3808. }
  3809. //
  3810. // Copy the request id into the output buffer. Copy it from
  3811. // the private copy that request holds. Original opaque id
  3812. // may get nulled if connection cleanup happens before we get
  3813. // here.
  3814. //
  3815. ASSERT(!HTTP_IS_NULL_ID(&pRequest->RequestIdCopy));
  3816. pUserRequest->RequestId = pRequest->RequestIdCopy;
  3817. pUserRequest->ConnectionId = pRequest->ConnectionId;
  3818. //
  3819. // And tell how much we actually need.
  3820. //
  3821. pIrp->IoStatus.Information = BytesNeeded;
  3822. }
  3823. else
  3824. {
  3825. //
  3826. // Very bad, we can never get here as we check the length in
  3827. // ioctl.c.
  3828. //
  3829. ASSERT(FALSE);
  3830. pIrp->IoStatus.Information = 0;
  3831. }
  3832. }
  3833. complete:
  3834. UlTrace(ROUTING, (
  3835. "http!UlCopyRequestToIrp(\n"
  3836. " pRequest = %p,\n"
  3837. " pIrp = %p) Completing Irp\n"
  3838. " pAppPool = %p (%S)\n"
  3839. " pRequest->ConnectionId = %I64x\n"
  3840. " pIrpSp->Parameters.DeviceIoControl.OutputBufferLength = %d\n"
  3841. " pIrp->IoStatus.Status = 0x%x\n"
  3842. " pIrp->IoStatus.Information = %Iu\n",
  3843. pRequest,
  3844. pIrp,
  3845. pRequest->ConfigInfo.pAppPool,
  3846. pRequest->ConfigInfo.pAppPool->pName,
  3847. pRequest->ConnectionId,
  3848. pIrpSp ? pIrpSp->Parameters.DeviceIoControl.OutputBufferLength : 0,
  3849. Status,
  3850. pIrp->IoStatus.Information
  3851. ));
  3852. pIrp->IoStatus.Status = Status;
  3853. //
  3854. // Complete the irp.
  3855. //
  3856. if (CompleteIrp)
  3857. {
  3858. //
  3859. // Use IO_NO_INCREMENT to avoid the work thread being rescheduled.
  3860. //
  3861. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  3862. }
  3863. } // UlCopyRequestToIrp
  3864. /******************************************************************************
  3865. Routine Description:
  3866. This will return the apool object reference by this handle, bumping the
  3867. refcount on the apool.
  3868. This is called by UlSetConfigGroupInformation when user mode wants to
  3869. associate an app pool to the config group by handle.
  3870. The config group keeps a pointer to the apool.
  3871. Arguments:
  3872. AppPool - the handle of the apool
  3873. AccessMode - KernelMode or UserMode
  3874. ppAppPool - returns the apool object the handle represented.
  3875. Return Value:
  3876. NTSTATUS - Completion status.
  3877. ******************************************************************************/
  3878. NTSTATUS
  3879. UlGetPoolFromHandle(
  3880. IN HANDLE AppPool,
  3881. IN KPROCESSOR_MODE AccessMode,
  3882. OUT PUL_APP_POOL_OBJECT * ppAppPool
  3883. )
  3884. {
  3885. NTSTATUS Status;
  3886. PFILE_OBJECT pFileObject = NULL;
  3887. //
  3888. // Sanity check.
  3889. //
  3890. PAGED_CODE();
  3891. ASSERT(ppAppPool != NULL);
  3892. Status = ObReferenceObjectByHandle(
  3893. AppPool,
  3894. FILE_READ_ACCESS, // DesiredAccess
  3895. *IoFileObjectType, // ObjectType
  3896. AccessMode, // AccessMode
  3897. (PVOID *) &pFileObject, // Object
  3898. NULL // HandleInformation
  3899. );
  3900. if (NT_SUCCESS(Status) == FALSE)
  3901. {
  3902. goto end;
  3903. }
  3904. if (IS_APP_POOL_FO(pFileObject) == FALSE ||
  3905. IS_VALID_AP_PROCESS(GET_APP_POOL_PROCESS(pFileObject)) == FALSE)
  3906. {
  3907. Status = STATUS_INVALID_HANDLE;
  3908. goto end;
  3909. }
  3910. *ppAppPool = GET_APP_POOL_PROCESS(pFileObject)->pAppPool;
  3911. ASSERT(IS_VALID_AP_OBJECT(*ppAppPool));
  3912. REFERENCE_APP_POOL(*ppAppPool);
  3913. end:
  3914. if (pFileObject != NULL)
  3915. {
  3916. ObDereferenceObject(pFileObject);
  3917. }
  3918. return Status;
  3919. } // UlGetPoolFromHandle
  3920. /******************************************************************************
  3921. Routine Description:
  3922. This routine is called to associate a HTTP_REQUEST with an apool
  3923. process.
  3924. This is basically always done (used to be for 2 [now 3] reasons):
  3925. 1) The process called ReceiveEntityBody and pended an IRP to the
  3926. request. If the process detaches from the apool (CloseHandle,
  3927. ExitProcess) UlDetachProcessFromAppPool will walk the request queue
  3928. and cancel all i/o.
  3929. 2) The request did not fit into a waiting irp, so the request is queued
  3930. for a larger irp to come down and fetch it.
  3931. 3) The response has not been fully sent for the request. The request
  3932. is linked with the process so that the connection can be aborted
  3933. if the process aborts.
  3934. Arguments:
  3935. pProcess - the process to associate the request with
  3936. pRequest - the request
  3937. Return Value:
  3938. NTSTATUS - Completion status.
  3939. ******************************************************************************/
  3940. NTSTATUS
  3941. UlpQueuePendingRequest(
  3942. IN PUL_APP_POOL_PROCESS pProcess,
  3943. IN PUL_INTERNAL_REQUEST pRequest
  3944. )
  3945. {
  3946. NTSTATUS Status;
  3947. //
  3948. // Sanity check.
  3949. //
  3950. ASSERT(IS_VALID_AP_PROCESS(pProcess));
  3951. ASSERT(UlDbgSpinLockOwned(&pProcess->pAppPool->SpinLock));
  3952. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3953. //
  3954. // Put it on the list.
  3955. //
  3956. ASSERT(pRequest->AppPool.AppPoolEntry.Flink == NULL);
  3957. Status = UlpQueueRequest(
  3958. pProcess->pAppPool,
  3959. &pProcess->PendingRequestHead,
  3960. pRequest
  3961. );
  3962. if (NT_SUCCESS(Status))
  3963. {
  3964. //
  3965. // Save a pointer to the process in the object so we can confirm
  3966. // that it's on our list.
  3967. //
  3968. pRequest->AppPool.pProcess = pProcess;
  3969. pRequest->AppPool.QueueState = QueueCopiedState;
  3970. //
  3971. // Add a reference to the process to ensure it stays around during
  3972. // the send for the memory we lock.
  3973. //
  3974. REFERENCE_APP_POOL_PROCESS(pProcess);
  3975. }
  3976. return Status;
  3977. } // UlpQueuePendingRequest
  3978. /***************************************************************************++
  3979. Routine Description:
  3980. Adds a request to the tail of the queue.
  3981. App Pool queue lock must be held.
  3982. Arguments:
  3983. pAppPool - the AppPool to add
  3984. pQueueList - the queue list
  3985. pRequest - the request to be added
  3986. Return Value:
  3987. NTSTATUS - Completion status.
  3988. --***************************************************************************/
  3989. NTSTATUS
  3990. UlpQueueRequest(
  3991. IN PUL_APP_POOL_OBJECT pAppPool,
  3992. IN PLIST_ENTRY pQueueList,
  3993. IN PUL_INTERNAL_REQUEST pRequest
  3994. )
  3995. {
  3996. LONG GlobalRequests;
  3997. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  3998. ASSERT(UlDbgSpinLockOwned(&pAppPool->SpinLock));
  3999. ASSERT(pQueueList);
  4000. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  4001. //
  4002. // See if we've exceeded the global limit on requests queued and
  4003. // the queue's limits.
  4004. //
  4005. GlobalRequests = InterlockedIncrement(&g_RequestsQueued);
  4006. ASSERT(GlobalRequests > 0);
  4007. if ((ULONG) GlobalRequests > g_UlMaxRequestsQueued ||
  4008. pAppPool->RequestCount >= pAppPool->MaxRequests)
  4009. {
  4010. InterlockedDecrement(&g_RequestsQueued);
  4011. return STATUS_INVALID_DEVICE_STATE;
  4012. }
  4013. //
  4014. // Add to the end of the queue.
  4015. //
  4016. InsertTailList(pQueueList, &pRequest->AppPool.AppPoolEntry);
  4017. pAppPool->RequestCount++;
  4018. ASSERT(pAppPool->RequestCount >= 1);
  4019. return STATUS_SUCCESS;
  4020. } // UlpQueueRequest
  4021. /***************************************************************************++
  4022. Routine Description:
  4023. Removes a particular request from the queue.
  4024. App Pool queue lock must be held.
  4025. Arguments:
  4026. pAppPool - the AppPool to remove the request from
  4027. pRequest - the request to be removed
  4028. Return Value:
  4029. None
  4030. --***************************************************************************/
  4031. VOID
  4032. UlpRemoveRequest(
  4033. IN PUL_APP_POOL_OBJECT pAppPool,
  4034. IN PUL_INTERNAL_REQUEST pRequest
  4035. )
  4036. {
  4037. LONG GlobalRequests;
  4038. ASSERT(UlDbgSpinLockOwned(&pAppPool->SpinLock));
  4039. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  4040. ASSERT(NULL != pRequest->AppPool.AppPoolEntry.Flink);
  4041. ASSERT(pAppPool->RequestCount > 0);
  4042. RemoveEntryList(&pRequest->AppPool.AppPoolEntry);
  4043. pRequest->AppPool.AppPoolEntry.Flink = NULL;
  4044. pRequest->AppPool.AppPoolEntry.Blink = NULL;
  4045. pAppPool->RequestCount--;
  4046. GlobalRequests = InterlockedDecrement(&g_RequestsQueued);
  4047. ASSERT(GlobalRequests >= 0);
  4048. } // UlpRemoveRequest
  4049. /***************************************************************************++
  4050. Routine Description:
  4051. Removes a request from the head of a queue if there is one.
  4052. App Pool queue lock must be held.
  4053. Arguments:
  4054. pAppPool - the AppPool to dequeue the request from
  4055. pQueueList - the queue list
  4056. Return values:
  4057. Pointer to the request or NULL if the queue is empty.
  4058. --***************************************************************************/
  4059. PUL_INTERNAL_REQUEST
  4060. UlpDequeueRequest(
  4061. IN PUL_APP_POOL_OBJECT pAppPool,
  4062. IN PLIST_ENTRY pQueueList
  4063. )
  4064. {
  4065. PLIST_ENTRY pEntry;
  4066. PUL_INTERNAL_REQUEST pRequest = NULL;
  4067. LONG GlobalRequests;
  4068. ASSERT(IS_VALID_AP_OBJECT(pAppPool));
  4069. ASSERT(UlDbgSpinLockOwned(&pAppPool->SpinLock));
  4070. ASSERT(pQueueList);
  4071. if (!IsListEmpty(pQueueList))
  4072. {
  4073. pEntry = RemoveHeadList(pQueueList);
  4074. pEntry->Flink = pEntry->Blink = NULL;
  4075. pAppPool->RequestCount--;
  4076. pRequest = CONTAINING_RECORD(
  4077. pEntry,
  4078. UL_INTERNAL_REQUEST,
  4079. AppPool.AppPoolEntry
  4080. );
  4081. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  4082. pRequest->AppPool.QueueState = QueueUnlinkedState;
  4083. GlobalRequests = InterlockedDecrement(&g_RequestsQueued);
  4084. ASSERT(GlobalRequests >= 0);
  4085. }
  4086. return pRequest;
  4087. } // UlpDequeueRequest
  4088. /***************************************************************************++
  4089. Routine Description:
  4090. Determines if the specified connection has been disconnected. If so,
  4091. the IRP is completed immediately, otherwise the IRP is pended.
  4092. Arguments:
  4093. pProcess - the app pool process object with which the irp is associated
  4094. pHttpConn - supplies the connection to wait for
  4095. N.B. Since this connection was retrieved via a opaque ID, it has
  4096. an outstanding reference for this request on the assumption the
  4097. IRP will pend. If this routine does not pend the IRP, the reference
  4098. must be removed.
  4099. pIrp - supplies the IRP to either complete or pend
  4100. Return Value:
  4101. NTSTATUS - Completion status.
  4102. --***************************************************************************/
  4103. NTSTATUS
  4104. UlWaitForDisconnect(
  4105. IN PUL_APP_POOL_PROCESS pProcess,
  4106. IN PUL_HTTP_CONNECTION pHttpConn,
  4107. IN PIRP pIrp
  4108. )
  4109. {
  4110. PDRIVER_CANCEL pCancelRoutine;
  4111. NTSTATUS Status;
  4112. PIO_STACK_LOCATION pIrpSp;
  4113. PUL_DISCONNECT_OBJECT pDisconnectObj;
  4114. //
  4115. // Acquire the lock protecting the disconnect data and determine
  4116. // if we should queue the IRP or complete it immediately.
  4117. //
  4118. UlAcquirePushLockExclusive(&pHttpConn->PushLock);
  4119. //
  4120. // WaitForDisconnect is allowed only for the process that picked up
  4121. // the current request.
  4122. //
  4123. if (!pHttpConn->pRequest ||
  4124. pHttpConn->pRequest->AppPool.pProcess != pProcess)
  4125. {
  4126. UlReleasePushLockExclusive(&pHttpConn->PushLock);
  4127. return STATUS_INVALID_ID_AUTHORITY;
  4128. }
  4129. if (pHttpConn->DisconnectFlag)
  4130. {
  4131. //
  4132. // Connection already disconnected, complete the IRP immediately.
  4133. //
  4134. UlReleasePushLockExclusive(&pHttpConn->PushLock);
  4135. IoMarkIrpPending(pIrp);
  4136. pIrp->IoStatus.Status = STATUS_SUCCESS;
  4137. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  4138. return STATUS_PENDING;
  4139. }
  4140. //
  4141. // Allocate an object to associate the IRP with the connection
  4142. // and the app pool.
  4143. //
  4144. pDisconnectObj = UlpCreateDisconnectObject(pIrp);
  4145. if (!pDisconnectObj)
  4146. {
  4147. UlReleasePushLockExclusive(&pHttpConn->PushLock);
  4148. return STATUS_NO_MEMORY;
  4149. }
  4150. UlAcquireResourceExclusive(&g_pUlNonpagedData->DisconnectResource, TRUE);
  4151. //
  4152. // Save a pointer to the disconnect object in the IRP so we
  4153. // can find it inside our cancel routine.
  4154. //
  4155. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  4156. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pDisconnectObj;
  4157. //
  4158. // Make the IRP cancellable.
  4159. //
  4160. IoMarkIrpPending(pIrp);
  4161. IoSetCancelRoutine(pIrp, &UlpCancelWaitForDisconnect);
  4162. if (pIrp->Cancel)
  4163. {
  4164. //
  4165. // The IRP has either already been cancelled IRP is in the
  4166. // process of being cancelled.
  4167. //
  4168. pCancelRoutine = IoSetCancelRoutine(pIrp, NULL);
  4169. if (pCancelRoutine == NULL)
  4170. {
  4171. //
  4172. // The previous cancel routine was already NULL, meaning that
  4173. // it has either already run or will run Real Soon Now, so
  4174. // we can just ignore it. Returning STATUS_PENDING causes
  4175. // the IOCTL wrapper to not attempt to complete the IRP.
  4176. //
  4177. Status = STATUS_PENDING;
  4178. goto end;
  4179. }
  4180. else
  4181. {
  4182. //
  4183. // We have to cancel it ourselves, so we'll just complete
  4184. // the IRP immediately with STATUS_CANCELLED.
  4185. //
  4186. Status = STATUS_CANCELLED;
  4187. goto end;
  4188. }
  4189. }
  4190. //
  4191. // We have queued at least one WaitForDisconnect IRP.
  4192. //
  4193. pHttpConn->WaitForDisconnectFlag = 1;
  4194. //
  4195. // The IRP has not been cancelled yet. Queue it on the connection
  4196. // and return with the connection still referenced. The reference
  4197. // is removed when the IRP is dequeued & completed or cancelled.
  4198. //
  4199. // Also queue it on the app pool process in case the pool handle
  4200. // gets closed before the connection does.
  4201. //
  4202. UlAddNotifyEntry(
  4203. &pHttpConn->WaitForDisconnectHead,
  4204. &pDisconnectObj->ConnectionEntry
  4205. );
  4206. UlAddNotifyEntry(
  4207. &pProcess->WaitForDisconnectHead,
  4208. &pDisconnectObj->ProcessEntry
  4209. );
  4210. UlReleaseResource(&g_pUlNonpagedData->DisconnectResource);
  4211. UlReleasePushLockExclusive(&pHttpConn->PushLock);
  4212. return STATUS_PENDING;
  4213. end:
  4214. UlUnmarkIrpPending(pIrp);
  4215. UlReleaseResource(&g_pUlNonpagedData->DisconnectResource);
  4216. UlReleasePushLockExclusive(&pHttpConn->PushLock);
  4217. UlpFreeDisconnectObject(pDisconnectObj);
  4218. return Status;
  4219. } // UlWaitForDisconnect
  4220. /***************************************************************************++
  4221. Routine Description:
  4222. Cancels the pending "wait for disconnect" IRP.
  4223. Arguments:
  4224. pDeviceObject - supplies the device object for the request
  4225. pIrp - supplies the IRP to cancel
  4226. Return Value:
  4227. None
  4228. --***************************************************************************/
  4229. VOID
  4230. UlpCancelWaitForDisconnect(
  4231. IN PDEVICE_OBJECT pDeviceObject,
  4232. IN PIRP pIrp
  4233. )
  4234. {
  4235. ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
  4236. UNREFERENCED_PARAMETER(pDeviceObject);
  4237. ASSERT(pIrp != NULL);
  4238. //
  4239. // Release the cancel spinlock. This means the cancel routine
  4240. // must be the one completing the irp (to avoid the race of
  4241. // completion + reuse prior to the cancel routine running).
  4242. //
  4243. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  4244. //
  4245. // Queue the cancel to a worker to ensure passive irql.
  4246. //
  4247. UL_CALL_PASSIVE(
  4248. UL_WORK_ITEM_FROM_IRP(pIrp),
  4249. &UlpCancelWaitForDisconnectWorker
  4250. );
  4251. } // UlpCancelWaitForDisconnect
  4252. /***************************************************************************++
  4253. Routine Description:
  4254. Actually performs the cancel for the irp.
  4255. Arguments:
  4256. pWorkItem - the work item to process
  4257. Return Value:
  4258. None
  4259. --***************************************************************************/
  4260. VOID
  4261. UlpCancelWaitForDisconnectWorker(
  4262. IN PUL_WORK_ITEM pWorkItem
  4263. )
  4264. {
  4265. PIRP pIrp;
  4266. PIO_STACK_LOCATION pIrpSp;
  4267. PUL_DISCONNECT_OBJECT pDisconnectObj;
  4268. //
  4269. // Sanity check.
  4270. //
  4271. PAGED_CODE();
  4272. //
  4273. // Grab the irp off the work item.
  4274. //
  4275. pIrp = UL_WORK_ITEM_TO_IRP(pWorkItem);
  4276. ASSERT(IS_VALID_IRP(pIrp));
  4277. //
  4278. // Grab the disconnect object off the irp.
  4279. //
  4280. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  4281. pDisconnectObj = (PUL_DISCONNECT_OBJECT)
  4282. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  4283. ASSERT(IS_VALID_DISCONNECT_OBJECT(pDisconnectObj));
  4284. //
  4285. // Acquire the lock protecting the disconnect data, and remove the
  4286. // IRP if necessary.
  4287. //
  4288. UlAcquireResourceExclusive(&g_pUlNonpagedData->DisconnectResource, TRUE);
  4289. UlRemoveNotifyEntry(&pDisconnectObj->ConnectionEntry);
  4290. UlRemoveNotifyEntry(&pDisconnectObj->ProcessEntry);
  4291. UlReleaseResource(&g_pUlNonpagedData->DisconnectResource);
  4292. //
  4293. // Free the disconnect object and complete the IRP.
  4294. //
  4295. UlpFreeDisconnectObject(pDisconnectObj);
  4296. pIrp->IoStatus.Status = STATUS_CANCELLED;
  4297. pIrp->IoStatus.Information = 0;
  4298. UlCompleteRequest(pIrp, IO_NO_INCREMENT);
  4299. } // UlpCancelWaitForDisconnectWorker
  4300. /***************************************************************************++
  4301. Routine Description:
  4302. Completes all WaitForDisconnect IRPs attached to an http connection
  4303. has been disconnected.
  4304. Arguments:
  4305. pHttpConnection - the connection that's disconnected
  4306. Return Value:
  4307. None
  4308. --***************************************************************************/
  4309. VOID
  4310. UlCompleteAllWaitForDisconnect(
  4311. IN PUL_HTTP_CONNECTION pHttpConnection
  4312. )
  4313. {
  4314. NTSTATUS Status = STATUS_SUCCESS;
  4315. //
  4316. // Sanity check.
  4317. //
  4318. PAGED_CODE();
  4319. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConnection));
  4320. UlAcquireResourceExclusive(&g_pUlNonpagedData->DisconnectResource, TRUE);
  4321. //
  4322. // Complete any pending "wait for disconnect" IRPs.
  4323. //
  4324. UlNotifyAllEntries(
  4325. &UlpNotifyCompleteWaitForDisconnect,
  4326. &pHttpConnection->WaitForDisconnectHead,
  4327. &Status
  4328. );
  4329. UlReleaseResource(&g_pUlNonpagedData->DisconnectResource);
  4330. } // UlCompleteAllWaitForDisconnect
  4331. /***************************************************************************++
  4332. Routine Description:
  4333. Removes a UL_DISCONNECT_OBJECT from its lists and completes the IRP.
  4334. Arguments:
  4335. pEntry - the notify list entry
  4336. pHost - the UL_DISCONNECT_OBJECT
  4337. pStatus - pointer to an NTSTATUS to be returned
  4338. Return Value:
  4339. None
  4340. --***************************************************************************/
  4341. BOOLEAN
  4342. UlpNotifyCompleteWaitForDisconnect(
  4343. IN PUL_NOTIFY_ENTRY pEntry,
  4344. IN PVOID pHost,
  4345. IN PVOID pStatus
  4346. )
  4347. {
  4348. PUL_DISCONNECT_OBJECT pDisconnectObj;
  4349. PIRP pIrp;
  4350. PDRIVER_CANCEL pCancelRoutine;
  4351. //
  4352. // Sanity check.
  4353. //
  4354. PAGED_CODE();
  4355. ASSERT(pEntry);
  4356. ASSERT(pHost);
  4357. ASSERT(pStatus);
  4358. ASSERT(UlDbgResourceOwnedExclusive(&g_pUlNonpagedData->DisconnectResource));
  4359. UNREFERENCED_PARAMETER(pEntry);
  4360. pDisconnectObj = (PUL_DISCONNECT_OBJECT) pHost;
  4361. ASSERT(IS_VALID_DISCONNECT_OBJECT(pDisconnectObj));
  4362. //
  4363. // Locate and try to complete the IRP.
  4364. //
  4365. pIrp = pDisconnectObj->pIrp;
  4366. //
  4367. // We'll be completing the IRP real soon, so make it
  4368. // non-cancellable.
  4369. //
  4370. pCancelRoutine = IoSetCancelRoutine(pIrp, NULL);
  4371. if (pCancelRoutine == NULL)
  4372. {
  4373. //
  4374. // The cancel routine is already NULL, meaning that the
  4375. // cancel routine will run Real Soon Now, so we can
  4376. // just drop this IRP on the floor.
  4377. //
  4378. }
  4379. else
  4380. {
  4381. //
  4382. // Remove object from lists.
  4383. //
  4384. UlRemoveNotifyEntry(&pDisconnectObj->ConnectionEntry);
  4385. UlRemoveNotifyEntry(&pDisconnectObj->ProcessEntry);
  4386. //
  4387. // Complete the IRP, then free the disconnect object.
  4388. //
  4389. pIrp->IoStatus.Status = *((PNTSTATUS) pStatus);
  4390. pIrp->IoStatus.Information = 0;
  4391. UlCompleteRequest(pIrp, IO_NETWORK_INCREMENT);
  4392. UlpFreeDisconnectObject(pDisconnectObj);
  4393. }
  4394. return TRUE;
  4395. } // UlpNotifyCompleteWaitForDisconnect
  4396. /***************************************************************************++
  4397. Routine Description:
  4398. Allocates and initializes a disconnect object.
  4399. Arguments:
  4400. pIrp - a UlWaitForDisconnect IRP
  4401. Return Value:
  4402. PUL_DISCONNECT_OBJECT
  4403. --***************************************************************************/
  4404. PUL_DISCONNECT_OBJECT
  4405. UlpCreateDisconnectObject(
  4406. IN PIRP pIrp
  4407. )
  4408. {
  4409. PUL_DISCONNECT_OBJECT pObject;
  4410. pObject = UL_ALLOCATE_STRUCT(
  4411. PagedPool,
  4412. UL_DISCONNECT_OBJECT,
  4413. UL_DISCONNECT_OBJECT_POOL_TAG
  4414. );
  4415. if (pObject)
  4416. {
  4417. pObject->Signature = UL_DISCONNECT_OBJECT_POOL_TAG;
  4418. pObject->pIrp = pIrp;
  4419. UlInitializeNotifyEntry(&pObject->ProcessEntry, pObject);
  4420. UlInitializeNotifyEntry(&pObject->ConnectionEntry, pObject);
  4421. }
  4422. return pObject;
  4423. } // UlpCreateDisconnectObject
  4424. /***************************************************************************++
  4425. Routine Description:
  4426. Gets rid of a disconnect object.
  4427. Arguments:
  4428. pObject - the disconnect object to free
  4429. Return Value:
  4430. None
  4431. --***************************************************************************/
  4432. VOID
  4433. UlpFreeDisconnectObject(
  4434. IN PUL_DISCONNECT_OBJECT pObject
  4435. )
  4436. {
  4437. UL_FREE_POOL_WITH_SIG(pObject, UL_DISCONNECT_OBJECT_POOL_TAG);
  4438. } // UlpFreeDisconnectObject