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

5222 lines
138 KiB

  1. /*++
  2. Copyright (c) 1998-2001 Microsoft Corporation
  3. Module Name:
  4. httprcv.cxx
  5. Abstract:
  6. Contains core HTTP receive code.
  7. Author:
  8. Henry Sanders (henrysa) 10-Jun-1998
  9. Revision History:
  10. Paul McDaniel (paulmcd) 01-Mar-1999
  11. massively rewrote it to handle request spanning tdi packets.
  12. moved all http parsing to PASSIVE irql (from DISPATCH).
  13. also merged tditest into this module.
  14. Eric Stenson (EricSten) 11-Sep-2000
  15. Added support for sending "100 Continue" responses to PUT
  16. and POST requests. Added #pragma's for PAGED -vs- Non-PAGED
  17. functions.
  18. --*/
  19. #include "precomp.h"
  20. #include "httprcvp.h"
  21. //
  22. // Declare pageable and non-pageable functions
  23. //
  24. #ifdef ALLOC_PRAGMA
  25. // Init
  26. #pragma alloc_text( INIT, UlInitializeHttpRcv )
  27. #pragma alloc_text( PAGE, UlTerminateHttpRcv )
  28. // Public
  29. #pragma alloc_text( PAGE, UlResumeParsing )
  30. #pragma alloc_text( PAGE, UlGetCGroupForRequest )
  31. #pragma alloc_text( PAGE, UlSendSimpleStatus )
  32. #pragma alloc_text( PAGE, UlSendErrorResponse )
  33. // Private
  34. #pragma alloc_text( PAGE, UlpDeliverHttpRequest )
  35. #pragma alloc_text( PAGE, UlpProcessBufferQueue )
  36. #pragma alloc_text( PAGE, UlpCancelEntityBodyWorker )
  37. #if DBG
  38. #pragma alloc_text( PAGE, UlpIsValidRequestBufferList )
  39. #endif // DBG
  40. #endif // ALLOC_PRAGMA
  41. #if 0 // Non-Pageable Functions
  42. // Public
  43. NOT PAGEABLE -- UlHttpReceive
  44. NOT PAGEABLE -- UlConnectionRequest
  45. NOT PAGEABLE -- UlConnectionComplete
  46. NOT PAGEABLE -- UlConnectionDisconnect
  47. NOT PAGEABLE -- UlConnectionDestroyed
  48. NOT PAGEABLE -- UlReceiveEntityBody
  49. // Private
  50. NOT PAGEABLE -- UlpHandleRequest
  51. NOT PAGEABLE -- UlpParseNextRequest
  52. NOT PAGEABLE -- UlpInsertBuffer
  53. NOT PAGEABLE -- UlpMergeBuffers
  54. NOT PAGEABLE -- UlpAdjustBuffers
  55. NOT PAGEABLE -- UlpConsumeBytesFromConnection
  56. NOT PAGEABLE -- UlpCancelEntityBody
  57. NOT PAGEABLE -- UlpCompleteSendResponse
  58. NOT PAGEABLE -- UlpRestartSendSimpleResponse
  59. NOT PAGEABLE -- UlpSendSimpleCleanupWorker
  60. #endif // Non-Pageable Functions
  61. /*++
  62. Paul McDaniel (paulmcd) 26-May-1999
  63. here is a brief description of the data structures used by this module:
  64. the connection keeps track of all buffers received by TDI into a list anchored
  65. by HTTP_CONNECTION::BufferHead. this list is sequenced and sorted. the
  66. buffers are refcounted.
  67. HTTP_REQUEST(s) keep pointers into these buffers for the parts they consume.
  68. HTTP_REQUEST::pHeaderBuffer and HTTP_REQUEST::pChunkBuffer.
  69. the buffers fall off the list as they are no longer needed. the connection
  70. only keeps a reference at HTTP_CONNECTION::pCurrentBuffer. so as it completes
  71. the processing of a buffer, if no other objects kept that buffer, it will be
  72. released.
  73. here is a brief description of the functions in this module, and how they
  74. are used:
  75. UlHttpReceive - the TDI data indication handler. copies buffers and queues to
  76. UlpHandleRequest.
  77. UlpHandleRequest - the main processing function for connections.
  78. UlCreateHttpConnectionId - creates the connections opaque id.
  79. UlpInsertBuffer - inserts the buffer into pConnection->BufferHead - sorted.
  80. UlpAdjustBuffers - determines where in BufferHead the current connection
  81. should be parsing. handle buffer merging and copying if a protocol
  82. token spans buffers
  83. UlParseHttp - the main http parser. expects that no protocol tokens span
  84. a buffer. will return a status code if it does.
  85. UlpProcessBufferQueue - handles entity body buffer processing.
  86. synchronizes access to BufferHead at pRequest->pChunkBuffer with
  87. UlReceiveEntityBody.
  88. UlConnectionRequest - called when a new connection comes in. allocates a new
  89. HTTP_CONNECTION. does not create the opaque id.
  90. UlConnectionComplete - called if the client is happy with our accept.
  91. closes the connection if error status.
  92. UlConnectionDisconnect - called when the client disconnects. it calls tdi to
  93. close the server end. always a graceful close.
  94. UlConnectionDestroyed - called when the connection is dropped. both sides have
  95. closed it. deletes all opaque ids . removes the tdi reference on the
  96. HTTP_CONNECTION (and hopefully vice versa) .
  97. UlReceiveEntityBody - called by user mode to read entity body. pends the irp
  98. to pRequest->IrpHead and calls UlpProcessBufferQueue .
  99. --*/
  100. /*++
  101. Routine Description:
  102. The main http receive routine.
  103. Arguments:
  104. pHttpConn - Pointer to HTTP connection on which data was received.
  105. pBuffer - Pointer to data received.
  106. BufferLength - Length of data pointed to by pBuffer.
  107. UnreceivedLength- Bytes that the transport has, but aren't in pBuffer
  108. pBytesTaken - Pointer to where to return bytes taken.
  109. Return Value:
  110. Status of receive.
  111. --*/
  112. NTSTATUS
  113. UlHttpReceive(
  114. IN PVOID pListeningContext,
  115. IN PVOID pConnectionContext,
  116. IN PVOID pVoidBuffer,
  117. IN ULONG BufferLength,
  118. IN ULONG UnreceivedLength,
  119. OUT PULONG pBytesTaken
  120. )
  121. {
  122. PUL_REQUEST_BUFFER pRequestBuffer;
  123. PUL_HTTP_CONNECTION pConnection;
  124. BOOLEAN DrainAfterDisconnect = FALSE;
  125. ULONG SpaceAvailable;
  126. KIRQL OldIrql;
  127. ASSERT(BufferLength != 0);
  128. ASSERT(pConnectionContext != NULL);
  129. pConnection = (PUL_HTTP_CONNECTION)pConnectionContext;
  130. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  131. //
  132. // Make sure we are not buffering too much data.
  133. // Need to adjust the BufferLength to be no more
  134. // than the number of bytes we can accept at this time.
  135. //
  136. //
  137. // PerfBug: need to get rid of this lock
  138. //
  139. UlAcquireSpinLock(
  140. &pConnection->BufferingInfo.BufferingSpinLock,
  141. &OldIrql
  142. );
  143. DrainAfterDisconnect = pConnection->BufferingInfo.DrainAfterDisconnect;
  144. if (DrainAfterDisconnect)
  145. {
  146. pConnection->BufferingInfo.TransportBytesNotTaken += UnreceivedLength;
  147. }
  148. else
  149. {
  150. if ((pConnection->BufferingInfo.BytesBuffered + BufferLength) > g_UlMaxBufferedBytes)
  151. {
  152. SpaceAvailable = g_UlMaxBufferedBytes - pConnection->BufferingInfo.BytesBuffered;
  153. pConnection->BufferingInfo.TransportBytesNotTaken += (BufferLength - SpaceAvailable);
  154. BufferLength = SpaceAvailable;
  155. }
  156. pConnection->BufferingInfo.BytesBuffered += BufferLength;
  157. pConnection->BufferingInfo.TransportBytesNotTaken += UnreceivedLength;
  158. }
  159. UlReleaseSpinLock(
  160. &pConnection->BufferingInfo.BufferingSpinLock,
  161. OldIrql
  162. );
  163. if (BufferLength && DrainAfterDisconnect == FALSE)
  164. {
  165. //
  166. // get a new request buffer
  167. //
  168. pRequestBuffer = UlCreateRequestBuffer(
  169. BufferLength,
  170. pConnection->NextBufferNumber
  171. );
  172. if (pRequestBuffer == NULL)
  173. {
  174. return STATUS_NO_MEMORY;
  175. }
  176. //
  177. // increment our buffer number counter
  178. //
  179. pConnection->NextBufferNumber += 1;
  180. //
  181. // copy the tdi buffer
  182. //
  183. RtlCopyMemory(pRequestBuffer->pBuffer, pVoidBuffer, BufferLength);
  184. pRequestBuffer->UsedBytes = BufferLength;
  185. //
  186. // Add backpointer to connection.
  187. //
  188. pRequestBuffer->pConnection = pConnection;
  189. UlTrace( PARSER, (
  190. "*** Request Buffer %p has connection %p\n",
  191. pRequestBuffer,
  192. pConnection
  193. ));
  194. IF_DEBUG2(HTTP_IO, VERBOSE)
  195. {
  196. UlTraceVerbose( HTTP_IO, (
  197. "<<<< Request(%p), "
  198. "RequestBuffer[%d] %p, %d bytes, "
  199. "Conn %p.\n",
  200. pConnection->pRequest,
  201. pRequestBuffer->BufferNumber, pRequestBuffer, BufferLength,
  202. pConnection
  203. ));
  204. UlDbgPrettyPrintBuffer(pRequestBuffer->pBuffer, BufferLength);
  205. UlTraceVerbose( HTTP_IO, (">>>>\n"));
  206. }
  207. //
  208. // Queue a work item to handle the data.
  209. //
  210. // Reference the connection so it doesn't go
  211. // away while we're waiting for our work item
  212. // to run. UlpHandleRequest will release the ref.
  213. //
  214. UL_REFERENCE_HTTP_CONNECTION(pConnection);
  215. UL_QUEUE_WORK_ITEM(
  216. &(pRequestBuffer->WorkItem),
  217. &UlpHandleRequest
  218. );
  219. }
  220. else if ( DrainAfterDisconnect && UnreceivedLength != 0 )
  221. {
  222. // Handle the case where we are in drain state and there's
  223. // unreceived data indicated but not available by the tdi.
  224. UlpDiscardBytesFromConnection( pConnection );
  225. }
  226. //
  227. // Tell the caller how many bytes we consumed.
  228. //
  229. *pBytesTaken = BufferLength;
  230. return STATUS_SUCCESS;
  231. } // UlHttpReceive
  232. /***************************************************************************++
  233. Routine Description:
  234. links the buffer into the connection and processes the list.
  235. starts http request parsing.
  236. Arguments:
  237. pWorkItem - points to a UL_REQUEST_BUFFER
  238. --***************************************************************************/
  239. VOID
  240. UlpHandleRequest(
  241. IN PUL_WORK_ITEM pWorkItem
  242. )
  243. {
  244. NTSTATUS Status;
  245. PUL_REQUEST_BUFFER pRequestBuffer;
  246. PUL_HTTP_CONNECTION pConnection;
  247. KIRQL OldIrql;
  248. //
  249. // Sanity check.
  250. //
  251. PAGED_CODE();
  252. pRequestBuffer = CONTAINING_RECORD(
  253. pWorkItem,
  254. UL_REQUEST_BUFFER,
  255. WorkItem
  256. );
  257. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pRequestBuffer) );
  258. pConnection = pRequestBuffer->pConnection;
  259. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  260. //
  261. // grab the lock
  262. //
  263. UlAcquireResourceExclusive(&(pConnection->Resource), TRUE);
  264. //
  265. // if the connection is going down, just bail out.
  266. //
  267. if (pConnection->UlconnDestroyed) {
  268. UlFreeRequestBuffer(pRequestBuffer);
  269. Status = STATUS_SUCCESS;
  270. goto end;
  271. }
  272. //
  273. // stop the Connection Timeout timer
  274. // and start the Header Wait timer
  275. //
  276. UlLockTimeoutInfo(
  277. &pConnection->TimeoutInfo,
  278. &OldIrql
  279. );
  280. UlResetConnectionTimer(
  281. &pConnection->TimeoutInfo,
  282. TimerConnectionIdle
  283. );
  284. UlSetConnectionTimer(
  285. &pConnection->TimeoutInfo,
  286. TimerHeaderWait
  287. );
  288. UlUnlockTimeoutInfo(
  289. &pConnection->TimeoutInfo,
  290. OldIrql
  291. );
  292. UlEvaluateTimerState(
  293. &pConnection->TimeoutInfo
  294. );
  295. //
  296. // Make sure it has an id already created.
  297. //
  298. // This is done here because the opaqueid stuff likes to run
  299. // at PASSIVE_LEVEL.
  300. //
  301. if (HTTP_IS_NULL_ID(&(pConnection->ConnectionId)))
  302. {
  303. Status = UlCreateHttpConnectionId(pConnection);
  304. if (!NT_SUCCESS(Status))
  305. {
  306. UlFreeRequestBuffer(pRequestBuffer);
  307. goto end;
  308. }
  309. }
  310. //
  311. // insert it into the list
  312. //
  313. ASSERT( 0 != pRequestBuffer->UsedBytes );
  314. UlTraceVerbose( PARSER, (
  315. "http!UlpHandleRequest: conn = %p, Req = %p: "
  316. "about to insert buffer %p\n",
  317. pConnection,
  318. pConnection->pRequest,
  319. pRequestBuffer
  320. ));
  321. UlpInsertBuffer(pConnection, pRequestBuffer);
  322. //
  323. // Kick off the parser
  324. //
  325. UlTraceVerbose( PARSER, (
  326. "http!UlpHandleRequest: conn = %p, Req = %p: "
  327. "about to parse next request\n",
  328. pConnection,
  329. pConnection->pRequest
  330. ));
  331. Status = UlpParseNextRequest(pConnection);
  332. end:
  333. UlTraceVerbose( PARSER, (
  334. "http!UlpHandleRequest: status %08lx, pConnection %p, pRequest %p\n",
  335. Status,
  336. pConnection,
  337. pConnection->pRequest
  338. ));
  339. if (!NT_SUCCESS(Status) && pConnection->pRequest != NULL)
  340. {
  341. UlTrace( PARSER, (
  342. "*** status %08lx, pConnection %p, pRequest %p\n",
  343. Status,
  344. pConnection,
  345. pConnection->pRequest
  346. ));
  347. //
  348. // An error happened, most propably during parsing.
  349. // Send an error back if user hasn't send one yet.
  350. // E.g. We have received a request,then delivered
  351. // it to the WP, therefore WaitingForResponse is
  352. // set. And then encountered an error when dealing
  353. // with entity body.
  354. //
  355. UlSendErrorResponse( pConnection );
  356. }
  357. //
  358. // done with the lock
  359. //
  360. UlReleaseResource(&(pConnection->Resource));
  361. //
  362. // and release the connection
  363. //
  364. UL_DEREFERENCE_HTTP_CONNECTION(pConnection);
  365. CHECK_STATUS(Status);
  366. } // UlpHandleRequest
  367. /***************************************************************************++
  368. Routine Description:
  369. When we finish sending a response we call into this function to
  370. kick the parser back into action.
  371. Arguments:
  372. pConnection - the connection on which to resume
  373. --***************************************************************************/
  374. VOID
  375. UlResumeParsing(
  376. IN PUL_HTTP_CONNECTION pConnection
  377. )
  378. {
  379. NTSTATUS Status = STATUS_SUCCESS;
  380. PLIST_ENTRY pEntry;
  381. //
  382. // Sanity check.
  383. //
  384. PAGED_CODE();
  385. ASSERT( UL_IS_VALID_HTTP_CONNECTION( pConnection ) );
  386. UlTrace(HTTP_IO, (
  387. "http!UlResumeParsing(pHttpConn = %p)\n",
  388. pConnection
  389. ));
  390. //
  391. // grab the lock
  392. //
  393. UlAcquireResourceExclusive(&(pConnection->Resource), TRUE);
  394. //
  395. // if the connection is going down, just bail out.
  396. //
  397. if (!pConnection->UlconnDestroyed)
  398. {
  399. //
  400. // Forget about the old request.
  401. //
  402. UlCleanupHttpConnection( pConnection );
  403. //
  404. // Kick off the parser
  405. //
  406. Status = UlpParseNextRequest(pConnection);
  407. if (!NT_SUCCESS(Status) && pConnection->pRequest != NULL)
  408. {
  409. //
  410. // Uh oh, something bad happened, send back an error
  411. //
  412. UlSendErrorResponse( pConnection );
  413. }
  414. }
  415. //
  416. // done with the lock
  417. //
  418. UlReleaseResource(&(pConnection->Resource));
  419. CHECK_STATUS(Status);
  420. } // UlResumeParsing
  421. /***************************************************************************++
  422. Routine Description:
  423. Tries to parse data attached to the connection into a request. If
  424. a complete request header is parsed, the request will be dispatched
  425. to an Application Pool.
  426. This function assumes the caller is holding the connection resource!
  427. Arguments:
  428. pConnection - the HTTP_CONNECTION with data to parse.
  429. --***************************************************************************/
  430. NTSTATUS
  431. UlpParseNextRequest(
  432. IN PUL_HTTP_CONNECTION pConnection
  433. )
  434. {
  435. NTSTATUS Status;
  436. PUL_INTERNAL_REQUEST pRequest = NULL;
  437. ULONG BytesTaken;
  438. ULONG BufferLength;
  439. BOOLEAN ResponseSent;
  440. KIRQL OldIrql;
  441. //
  442. // Sanity check.
  443. //
  444. PAGED_CODE();
  445. ASSERT( UL_IS_VALID_HTTP_CONNECTION( pConnection ) );
  446. Status = STATUS_SUCCESS;
  447. UlTrace(HTTP_IO, ("http!UlpParseNextRequest(httpconn = %p)\n", pConnection));
  448. //
  449. // Only parse the next request if
  450. //
  451. // We haven't dispatched the current request yet
  452. // OR
  453. // The current request has unparsed entity body or trailers.
  454. //
  455. if ((pConnection->pRequest == NULL)
  456. || ( !pConnection->WaitingForResponse )
  457. || (pConnection->pRequest->ParseState == ParseEntityBodyState)
  458. || (pConnection->pRequest->ParseState == ParseTrailerState))
  459. {
  460. //
  461. // loop consuming the buffer, we will make multiple iterations
  462. // if a single request spans multiple buffers.
  463. //
  464. for (;;)
  465. {
  466. ASSERT( UlpIsValidRequestBufferList( pConnection ) );
  467. Status = UlpAdjustBuffers(pConnection);
  468. if (!NT_SUCCESS(Status))
  469. {
  470. if (Status == STATUS_MORE_PROCESSING_REQUIRED)
  471. {
  472. Status = STATUS_SUCCESS;
  473. }
  474. break;
  475. }
  476. //
  477. // Since BufferLength is a ULONG, it can never be negative.
  478. // So, if UsedBytes is greater than ParsedBytes, BufferLength
  479. // will be very large, and non-zero.
  480. //
  481. ASSERT( pConnection->pCurrentBuffer->UsedBytes >
  482. pConnection->pCurrentBuffer->ParsedBytes );
  483. BufferLength = pConnection->pCurrentBuffer->UsedBytes -
  484. pConnection->pCurrentBuffer->ParsedBytes;
  485. //
  486. // do we need to create a request object?
  487. //
  488. if (pConnection->pRequest == NULL)
  489. {
  490. //
  491. // First shot at reading a request, allocate a request object
  492. //
  493. Status = UlpCreateHttpRequest(pConnection, &pConnection->pRequest);
  494. if (NT_SUCCESS(Status) == FALSE)
  495. goto end;
  496. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pConnection->pRequest));
  497. UlTrace(HTTP_IO, (
  498. "http!UlpParseNextRequest created pRequest = %p for httpconn = %p\n",
  499. pConnection->pRequest,
  500. pConnection
  501. ));
  502. //
  503. // To be exact precise about the life-time of this
  504. // request, copy the starting TIMESTAMP from connection
  505. // pointer. But that won't work since we may get hit by
  506. // multiple requests to the same connection. So we won't
  507. // be that much precise.
  508. //
  509. KeQuerySystemTime( &(pConnection->pRequest->TimeStamp) );
  510. TRACE_TIME(
  511. pConnection->ConnectionId,
  512. pConnection->pRequest->RequestId,
  513. TIME_ACTION_CREATE_REQUEST
  514. );
  515. WRITE_REF_TRACE_LOG2(
  516. g_pHttpConnectionTraceLog,
  517. pConnection->pTraceLog,
  518. REF_ACTION_INSERT_REQUEST,
  519. pConnection->RefCount,
  520. pConnection->pRequest,
  521. __FILE__,
  522. __LINE__
  523. );
  524. }
  525. UlTrace( PARSER, (
  526. "*** pConn %p, pReq %p, ParseState %lu\n",
  527. pConnection,
  528. pConnection->pRequest,
  529. pConnection->pRequest->ParseState
  530. ));
  531. PARSE_STATE OldState = pConnection->pRequest->ParseState;
  532. switch (pConnection->pRequest->ParseState)
  533. {
  534. case ParseVerbState:
  535. case ParseUrlState:
  536. case ParseVersionState:
  537. case ParseHeadersState:
  538. case ParseCookState:
  539. pRequest = pConnection->pRequest;
  540. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  541. //
  542. // parse it !
  543. //
  544. Status = UlParseHttp(
  545. pRequest,
  546. GET_REQUEST_BUFFER_POS(pConnection->pCurrentBuffer),
  547. BufferLength,
  548. &BytesTaken
  549. );
  550. ASSERT(BytesTaken <= BufferLength);
  551. UlTraceVerbose(PARSER, (
  552. "UlpParseNextRequest(pRequest = %p) "
  553. "UlParseHttp: states (Vb/U/Ver/Hd/Ck) "
  554. "%d -> %d, %d bytes taken\n",
  555. pRequest, OldState, pConnection->pRequest->ParseState,
  556. BytesTaken
  557. ));
  558. pConnection->pCurrentBuffer->ParsedBytes += BytesTaken;
  559. BufferLength -= BytesTaken;
  560. //
  561. // Need some accounting for Logging
  562. //
  563. pRequest->BytesReceived += BytesTaken;
  564. //
  565. // did we consume any of the data? if so, give the request
  566. // a pointer to the buffer
  567. //
  568. if (BytesTaken > 0)
  569. {
  570. if (pRequest->pHeaderBuffer == NULL)
  571. {
  572. //
  573. // store its location, for later release
  574. //
  575. pRequest->pHeaderBuffer = pConnection->pCurrentBuffer;
  576. }
  577. pRequest->pLastHeaderBuffer = pConnection->pCurrentBuffer;
  578. if (!UlpReferenceBuffers(
  579. pRequest,
  580. pConnection->pCurrentBuffer
  581. ))
  582. {
  583. Status = STATUS_NO_MEMORY;
  584. goto end;
  585. }
  586. //
  587. // Tell the connection how many bytes we consumed.
  588. // HTTP header bytes are "consumed" as soon as we
  589. // parse them.
  590. //
  591. UlpConsumeBytesFromConnection(
  592. pConnection,
  593. BytesTaken
  594. );
  595. }
  596. //
  597. // did everything work out ok?
  598. //
  599. if (!NT_SUCCESS(Status))
  600. {
  601. if (Status == STATUS_MORE_PROCESSING_REQUIRED)
  602. {
  603. ULONG FullBytesReceived;
  604. FullBytesReceived = (ULONG)(
  605. (pRequest->BytesReceived + BufferLength));
  606. if (FullBytesReceived < g_UlMaxRequestBytes)
  607. {
  608. //
  609. // we need more transport data
  610. //
  611. pConnection->NeedMoreData = 1;
  612. Status = STATUS_SUCCESS;
  613. continue;
  614. }
  615. else
  616. {
  617. //
  618. // The request has grown too large. Send back
  619. // an error.
  620. //
  621. if (pRequest->ParseState == ParseUrlState)
  622. {
  623. pRequest->ErrorCode = UlErrorUrlLength;
  624. UlTrace(PARSER, (
  625. "UlpParseNextRequest(pRequest = %p)"
  626. " ERROR: URL is too big\n",
  627. pRequest
  628. ));
  629. }
  630. else
  631. {
  632. pRequest->ErrorCode = UlErrorRequestLength;
  633. UlTrace(PARSER, (
  634. "UlpParseNextRequest(pRequest = %p)"
  635. " ERROR: request is too big\n",
  636. pRequest
  637. ));
  638. }
  639. pRequest->ParseState = ParseErrorState;
  640. Status = STATUS_SECTION_TOO_BIG;
  641. goto end;
  642. }
  643. }
  644. else
  645. {
  646. //
  647. // some other bad error!
  648. //
  649. goto end;
  650. }
  651. }
  652. //
  653. // if we're not done parsing the request, we need more data.
  654. // it's not bad enough to set NeedMoreData as nothing important
  655. // spanned buffer boundaries (header values, etc..) . it was
  656. // a clean split. no buffer merging is necessary. simply skip
  657. // to the next buffer.
  658. //
  659. if (pRequest->ParseState <= ParseCookState)
  660. {
  661. continue;
  662. }
  663. //
  664. // all done, mark the sequence number on this request
  665. //
  666. pRequest->RecvNumber = pConnection->NextRecvNumber;
  667. pConnection->NextRecvNumber += 1;
  668. UlTrace(HTTP_IO, (
  669. "http!UlpParseNextRequest(httpconn = %p) built request %p\n",
  670. pConnection,
  671. pRequest
  672. ));
  673. //
  674. // Stop the Header Wait timer
  675. //
  676. UlLockTimeoutInfo(
  677. &pConnection->TimeoutInfo,
  678. &OldIrql
  679. );
  680. UlResetConnectionTimer(
  681. &pConnection->TimeoutInfo,
  682. TimerHeaderWait
  683. );
  684. UlUnlockTimeoutInfo(
  685. &pConnection->TimeoutInfo,
  686. OldIrql
  687. );
  688. UlEvaluateTimerState(
  689. &pConnection->TimeoutInfo
  690. );
  691. //
  692. // check protocol compliance
  693. //
  694. Status = UlCheckProtocolCompliance(pConnection, pRequest);
  695. if (!NT_SUCCESS(Status))
  696. {
  697. //
  698. // This request is bad. Send a 400.
  699. //
  700. pRequest->ParseState = ParseErrorState;
  701. goto end;
  702. }
  703. Status = UlpDeliverHttpRequest( pConnection, &ResponseSent );
  704. if (!NT_SUCCESS(Status)) {
  705. goto end;
  706. }
  707. if (ResponseSent)
  708. {
  709. //
  710. // We have hit the cache entry and sent the response.
  711. // There is no more use for the request anymore so
  712. // unlink it from the connection and try parsing the
  713. // next request immediately.
  714. //
  715. UlCleanupHttpConnection(pConnection);
  716. continue;
  717. }
  718. //
  719. // if we're done parsing the request break out
  720. // of the loop. Otherwise keep going around
  721. // so we can pick up the entity body.
  722. //
  723. if (pRequest->ParseState == ParseDoneState)
  724. {
  725. goto end;
  726. }
  727. //
  728. // done with protocol parsing. keep looping.
  729. //
  730. break;
  731. case ParseEntityBodyState:
  732. case ParseTrailerState:
  733. pRequest = pConnection->pRequest;
  734. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  735. //
  736. // is there anything for us to parse?
  737. //
  738. UlTraceVerbose(PARSER, (
  739. "UlpParseNextRequest(pRequest=%p, httpconn=%p): "
  740. "ChunkBytesToParse = %d.\n",
  741. pRequest, pConnection, pRequest->ChunkBytesToParse
  742. ));
  743. if (pRequest->ChunkBytesToParse > 0)
  744. {
  745. ULONG BytesToSkip;
  746. //
  747. // Set/bump the Entity Body Receive timer
  748. //
  749. UlLockTimeoutInfo(
  750. &pConnection->TimeoutInfo,
  751. &OldIrql
  752. );
  753. UlSetConnectionTimer(
  754. &pConnection->TimeoutInfo,
  755. TimerEntityBody
  756. );
  757. UlUnlockTimeoutInfo(
  758. &pConnection->TimeoutInfo,
  759. OldIrql
  760. );
  761. UlEvaluateTimerState(
  762. &pConnection->TimeoutInfo
  763. );
  764. //
  765. // is this the first chunk we've parsed?
  766. //
  767. if (pRequest->pChunkBuffer == NULL)
  768. {
  769. //
  770. // store its location, this is where to start reading
  771. //
  772. pRequest->pChunkBuffer = pConnection->pCurrentBuffer;
  773. pRequest->pChunkLocation = GET_REQUEST_BUFFER_POS(
  774. pConnection->pCurrentBuffer
  775. );
  776. }
  777. //
  778. // how much should we parse?
  779. //
  780. BytesToSkip = (ULONG)(
  781. MIN(
  782. pRequest->ChunkBytesToParse,
  783. BufferLength
  784. )
  785. );
  786. //
  787. // update that we parsed this piece
  788. //
  789. pRequest->ChunkBytesToParse -= BytesToSkip;
  790. pRequest->ChunkBytesParsed += BytesToSkip;
  791. pConnection->pCurrentBuffer->ParsedBytes += BytesToSkip;
  792. BufferLength -= BytesToSkip;
  793. //
  794. // Need some accounting info for Logging
  795. // ??? I'm not sure about this well enough
  796. //
  797. pRequest->BytesReceived += BytesToSkip;
  798. }
  799. //
  800. // process any irp's waiting for entity body
  801. //
  802. //
  803. // CODEWORK. this doesn't need to be called after each chunk.
  804. //
  805. UlTraceVerbose(PARSER, (
  806. "UlpParseNextRequest(pRequest=%p, httpconn=%p): "
  807. "about to process buffer queue\n",
  808. pRequest, pConnection
  809. ));
  810. UlpProcessBufferQueue(pRequest);
  811. //
  812. // check to see there is another chunk
  813. //
  814. UlTraceVerbose(PARSER, (
  815. "UlpParseNextRequest(pRequest=%p, httpconn=%p): "
  816. "checking to see if another chunk.\n",
  817. pRequest, pConnection
  818. ));
  819. Status = UlParseHttp(
  820. pRequest,
  821. GET_REQUEST_BUFFER_POS(pConnection->pCurrentBuffer),
  822. BufferLength,
  823. &BytesTaken
  824. );
  825. UlTraceVerbose(PARSER, (
  826. "UlpParseNextRequest(pRequest = %p)"
  827. " UlParseHttp: states (EB/T) %d -> %d, %d bytes taken\n",
  828. pRequest, OldState, pConnection->pRequest->ParseState,
  829. BytesTaken
  830. ));
  831. pConnection->pCurrentBuffer->ParsedBytes += BytesTaken;
  832. BufferLength -= BytesTaken;
  833. //
  834. // Need some accounting info for Logging
  835. //
  836. pRequest->BytesReceived += BytesTaken;
  837. //
  838. // was there enough in the buffer to please?
  839. //
  840. if (NT_SUCCESS(Status) == FALSE)
  841. {
  842. if (Status == STATUS_MORE_PROCESSING_REQUIRED)
  843. {
  844. //
  845. // we need more transport data
  846. //
  847. pConnection->NeedMoreData = 1;
  848. Status = STATUS_SUCCESS;
  849. continue;
  850. }
  851. else
  852. {
  853. //
  854. // some other bad error !
  855. //
  856. goto end;
  857. }
  858. }
  859. //
  860. // are we all done parsing it ?
  861. //
  862. if (pRequest->ParseState == ParseDoneState)
  863. {
  864. ASSERT( pConnection->WaitingForResponse == 1 );
  865. //
  866. // Once more, with feeling. Check to see if there
  867. // are any remaining buffers to be processed or irps
  868. // to be completed (e.g., catch a solo zero-length
  869. // chunk)
  870. //
  871. UlpProcessBufferQueue(pRequest);
  872. //
  873. // Stop entity body receive timer
  874. //
  875. UlLockTimeoutInfo(
  876. &pConnection->TimeoutInfo,
  877. &OldIrql
  878. );
  879. UlResetConnectionTimer(
  880. &pConnection->TimeoutInfo,
  881. TimerEntityBody
  882. );
  883. UlUnlockTimeoutInfo(
  884. &pConnection->TimeoutInfo,
  885. OldIrql
  886. );
  887. UlEvaluateTimerState(
  888. &pConnection->TimeoutInfo
  889. );
  890. UlTraceVerbose(PARSER, (
  891. "UlpParseNextRequest(pRequest = %p) all done\n",
  892. pRequest
  893. ));
  894. goto end;
  895. }
  896. //
  897. // keep looping.
  898. //
  899. break;
  900. case ParseErrorState:
  901. //
  902. // ignore this buffer
  903. //
  904. Status = STATUS_SUCCESS;
  905. goto end;
  906. case ParseDoneState:
  907. default:
  908. //
  909. // this should never happen
  910. //
  911. Status = STATUS_INVALID_DEVICE_STATE;
  912. goto end;
  913. } // switch (pConnection->pRequest->ParseState)
  914. } // for(;;)
  915. }
  916. end:
  917. return Status;
  918. } // UlpParseNextRequest
  919. /***************************************************************************++
  920. Routine Description:
  921. DeliverHttpRequest may want to get the cgroup info for the request if it's
  922. not a cache hit. Similarly sendresponse may want to get this info - later-
  923. even if it's cache hit, when logging is enabled on the hit. Therefore we
  924. have created a new function for this to easily maintain the functionality.
  925. Arguments:
  926. pConnection - The connection whose request we are to deliver.
  927. --***************************************************************************/
  928. NTSTATUS
  929. UlGetCGroupForRequest(
  930. IN PUL_INTERNAL_REQUEST pRequest
  931. )
  932. {
  933. NTSTATUS Status;
  934. BOOLEAN OptionsStar;
  935. //
  936. // Sanity check
  937. //
  938. PAGED_CODE();
  939. Status = STATUS_SUCCESS;
  940. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  941. //
  942. // Lookup the config group information for this url .
  943. //
  944. // don't include the query string in the lookup.
  945. // route OPTIONS * as though it were OPTIONS /
  946. //
  947. if (pRequest->CookedUrl.pQueryString != NULL)
  948. {
  949. pRequest->CookedUrl.pQueryString[0] = UNICODE_NULL;
  950. }
  951. if ((pRequest->Verb == HttpVerbOPTIONS)
  952. && (pRequest->CookedUrl.pAbsPath[0] == '*')
  953. && (pRequest->CookedUrl.pAbsPath[1] == UNICODE_NULL))
  954. {
  955. pRequest->CookedUrl.pAbsPath[0] = '/';
  956. OptionsStar = TRUE;
  957. } else {
  958. OptionsStar = FALSE;
  959. }
  960. //
  961. // Get the Url Config Info
  962. //
  963. Status = UlGetConfigGroupInfoForUrl(
  964. pRequest->CookedUrl.pUrl,
  965. pRequest->pHttpConn,
  966. &pRequest->ConfigInfo
  967. );
  968. if (pRequest->CookedUrl.pQueryString != NULL)
  969. {
  970. pRequest->CookedUrl.pQueryString[0] = L'?';
  971. }
  972. //
  973. // restore the * in the path
  974. //
  975. if (OptionsStar) {
  976. pRequest->CookedUrl.pAbsPath[0] = '*';
  977. }
  978. return Status;
  979. } // UlGetCGroupForRequest
  980. /***************************************************************************++
  981. Routine Description:
  982. Takes a parsed http request and tries to deliver it to something
  983. that can send a response.
  984. First we try the cache. If there is no cache entry we try to route
  985. to an app pool.
  986. We send back an auto response if the control channel
  987. or config group is inactive. If we can't do any of those things we
  988. set an error code in the HTTP_REQUEST and return a failure status.
  989. The caller will take care of sending the error.
  990. Arguments:
  991. pConnection - The connection whose request we are to deliver.
  992. --***************************************************************************/
  993. NTSTATUS
  994. UlpDeliverHttpRequest(
  995. IN PUL_HTTP_CONNECTION pConnection,
  996. OUT PBOOLEAN pResponseSent
  997. )
  998. {
  999. NTSTATUS Status;
  1000. PUL_INTERNAL_REQUEST pRequest;
  1001. BOOLEAN ServedFromCache;
  1002. BOOLEAN OptionsStar;
  1003. BOOLEAN ConnectionRefused;
  1004. HTTP_ENABLED_STATE CurrentState;
  1005. PUL_INTERNAL_RESPONSE pAutoResponse;
  1006. ULONG Connections;
  1007. PUL_SITE_COUNTER_ENTRY pCtr;
  1008. PUL_CONFIG_GROUP_OBJECT pMaxBandwidth;
  1009. //
  1010. // Sanity check
  1011. //
  1012. PAGED_CODE();
  1013. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  1014. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pConnection->pRequest));
  1015. pRequest = pConnection->pRequest;
  1016. *pResponseSent = FALSE;
  1017. ConnectionRefused = FALSE;
  1018. pMaxBandwidth = NULL;
  1019. //
  1020. // Do we have a cache hit?
  1021. // Set WaitingForResponse to 1 before calling UlSendCachedResponse
  1022. // because the send may be completed before we return.
  1023. //
  1024. pConnection->WaitingForResponse = 1;
  1025. UlTrace( PARSER, (
  1026. "***3 pConnection %p->WaitingForResponse = 1\n",
  1027. pConnection
  1028. ));
  1029. pRequest->CachePreconditions = UlCheckCachePreconditions(
  1030. pRequest,
  1031. pConnection
  1032. );
  1033. if (pRequest->CachePreconditions)
  1034. {
  1035. Status = UlSendCachedResponse(
  1036. pConnection,
  1037. &ServedFromCache,
  1038. &ConnectionRefused
  1039. );
  1040. if (NT_SUCCESS(Status) && ServedFromCache && !ConnectionRefused)
  1041. {
  1042. //
  1043. // All done with this request. Wait for response
  1044. // before going on.
  1045. //
  1046. *pResponseSent = TRUE;
  1047. goto end;
  1048. }
  1049. //
  1050. // If a cache precondition failed during SendCacheResponse,
  1051. // then bail out.
  1052. //
  1053. if ( UlErrorPreconditionFailed == pRequest->ErrorCode )
  1054. {
  1055. ASSERT( STATUS_INVALID_DEVICE_STATE == Status );
  1056. pConnection->WaitingForResponse = 0;
  1057. UlTrace( PARSER, (
  1058. "***3 pConnection %p->WaitingForResponse = 0\n",
  1059. pConnection
  1060. ));
  1061. goto end;
  1062. }
  1063. }
  1064. //
  1065. // We didn't do a send from the cache, so we are not
  1066. // yet WaitingForResponse.
  1067. //
  1068. pConnection->WaitingForResponse = 0;
  1069. UlTrace( PARSER, (
  1070. "***3 pConnection %p->WaitingForResponse = 0\n",
  1071. pConnection
  1072. ));
  1073. //
  1074. // If connection refused during SendCacheResponse because of a connection
  1075. // limit then refuse the request.
  1076. //
  1077. if (ConnectionRefused)
  1078. {
  1079. pRequest->ParseState = ParseErrorState;
  1080. pRequest->ErrorCode = UlErrorConnectionLimit;
  1081. Status = STATUS_INVALID_DEVICE_STATE;
  1082. goto end;
  1083. }
  1084. //
  1085. // Allocate request ID here since we didn't do it in UlCreateHttpRequest.
  1086. //
  1087. Status = UlAllocateRequestId(pRequest);
  1088. if (!NT_SUCCESS(Status))
  1089. {
  1090. pRequest->ParseState = ParseErrorState;
  1091. pRequest->ErrorCode = UlErrorInternalServer;
  1092. goto end;
  1093. }
  1094. UL_REFERENCE_INTERNAL_REQUEST( pRequest );
  1095. pRequest->RequestIdCopy = pRequest->RequestId;
  1096. //
  1097. // Previous code fragment here to get the cgroup info
  1098. // has been moved to a seperate function, as logging
  1099. // related code in sendresponse requires this info
  1100. // as well.
  1101. //
  1102. Status = UlGetCGroupForRequest( pRequest );
  1103. //
  1104. // CODEWORK+BUGBUG: need to check the port's actually matched
  1105. //
  1106. //
  1107. // check that the config group tree lookup matched
  1108. //
  1109. if (!NT_SUCCESS(Status) || pRequest->ConfigInfo.pAppPool == NULL)
  1110. {
  1111. //
  1112. // Could not route to a listening url, send
  1113. // back an http error. Always return error 400
  1114. // to show that host not found. This will also
  1115. // make us to be compliant with HTTP1.1 / 5.2
  1116. //
  1117. // REVIEW: What do we do about the site counter(s)
  1118. // REVIEW: when we can't route to a site? i.e., Connection Attempts?
  1119. pRequest->ParseState = ParseErrorState;
  1120. pRequest->ErrorCode = UlErrorHost;
  1121. Status = STATUS_INVALID_DEVICE_STATE;
  1122. goto end;
  1123. }
  1124. //
  1125. // Check to see if there's a connection timeout value override
  1126. //
  1127. if (0L != pRequest->ConfigInfo.ConnectionTimeout)
  1128. {
  1129. UlSetPerSiteConnectionTimeoutValue(
  1130. &pRequest->pHttpConn->TimeoutInfo,
  1131. pRequest->ConfigInfo.ConnectionTimeout
  1132. );
  1133. }
  1134. //
  1135. // Check the connection limit of the site.
  1136. //
  1137. if (UlCheckSiteConnectionLimit(pConnection, &pRequest->ConfigInfo) == FALSE)
  1138. {
  1139. // If exceeding the site limit, send back 403 error and disconnect.
  1140. // NOTE: This code depend on the fact that UlSendErrorResponse always
  1141. // NOTE: disconnect. Otherwise we need a force disconnect here.
  1142. pRequest->ParseState = ParseErrorState;
  1143. pRequest->ErrorCode = UlErrorConnectionLimit;
  1144. Status = STATUS_INVALID_DEVICE_STATE;
  1145. goto end;
  1146. }
  1147. //
  1148. // Perf Counters (non-cached)
  1149. //
  1150. pCtr = pRequest->ConfigInfo.pSiteCounters;
  1151. if (pCtr)
  1152. {
  1153. // NOTE: pCtr may be NULL if the SiteId was never set on the root-level
  1154. // NOTE: Config Group for the site. BVTs may need to be updated.
  1155. ASSERT(IS_VALID_SITE_COUNTER_ENTRY(pCtr));
  1156. UlIncSiteNonCriticalCounterUlong(pCtr, HttpSiteCounterConnAttempts);
  1157. UlIncSiteNonCriticalCounterUlong(pCtr, HttpSiteCounterAllReqs);
  1158. if (pCtr != pConnection->pPrevSiteCounters)
  1159. {
  1160. if (pConnection->pPrevSiteCounters)
  1161. {
  1162. // Decrement old site's counters & release ref count
  1163. UlDecSiteCounter(
  1164. pConnection->pPrevSiteCounters,
  1165. HttpSiteCounterCurrentConns
  1166. );
  1167. DEREFERENCE_SITE_COUNTER_ENTRY(pConnection->pPrevSiteCounters);
  1168. }
  1169. Connections = (ULONG) UlIncSiteCounter(pCtr, HttpSiteCounterCurrentConns);
  1170. UlMaxSiteCounter(
  1171. pCtr,
  1172. HttpSiteCounterMaxConnections,
  1173. Connections
  1174. );
  1175. // add ref for new site counters
  1176. REFERENCE_SITE_COUNTER_ENTRY(pCtr);
  1177. pConnection->pPrevSiteCounters = pCtr;
  1178. }
  1179. }
  1180. // Try to get the corresponding cgroup for the bw settings
  1181. pMaxBandwidth = pRequest->ConfigInfo.pMaxBandwidth;
  1182. //
  1183. // Install a filter if BWT is enabled for this request's site.
  1184. //
  1185. if (pMaxBandwidth != NULL &&
  1186. pMaxBandwidth->MaxBandwidth.Flags.Present != 0 &&
  1187. pMaxBandwidth->MaxBandwidth.MaxBandwidth != HTTP_LIMIT_INFINITE)
  1188. {
  1189. // Call TCI to do the filter addition
  1190. UlTcAddFilter( pConnection, pMaxBandwidth );
  1191. }
  1192. else
  1193. {
  1194. // Attempt to add the filter to the global flow
  1195. if (UlTcGlobalThrottlingEnabled())
  1196. {
  1197. UlTcAddFilter( pConnection, NULL );
  1198. }
  1199. }
  1200. //
  1201. // the routing matched, let's check and see if we are active.
  1202. //
  1203. //
  1204. // first check the control channel.
  1205. //
  1206. if (pRequest->ConfigInfo.pControlChannel->State != HttpEnabledStateActive)
  1207. {
  1208. UlTrace(HTTP_IO, ("http!UlpDeliverHttpRequest Control Channel is inactive\n"));
  1209. CurrentState = HttpEnabledStateInactive;
  1210. pAutoResponse =
  1211. pRequest->ConfigInfo.pControlChannel->pAutoResponse;
  1212. }
  1213. // now check the cgroup
  1214. else if (pRequest->ConfigInfo.CurrentState != HttpEnabledStateActive)
  1215. {
  1216. UlTrace(HTTP_IO, ("http!UlpDeliverHttpRequest Config Group is inactive\n"));
  1217. CurrentState = HttpEnabledStateInactive;
  1218. pAutoResponse = pRequest->ConfigInfo.pAutoResponse;
  1219. }
  1220. else
  1221. {
  1222. CurrentState = HttpEnabledStateActive;
  1223. pAutoResponse = NULL;
  1224. }
  1225. //
  1226. // well, are we active?
  1227. //
  1228. if (CurrentState == HttpEnabledStateActive)
  1229. {
  1230. //
  1231. // it's a normal request. Deliver to
  1232. // app pool (aka client)
  1233. //
  1234. Status = UlDeliverRequestToProcess(
  1235. pRequest->ConfigInfo.pAppPool,
  1236. pRequest
  1237. );
  1238. if (NT_SUCCESS(Status)) {
  1239. //
  1240. // All done with this request. Wait for response
  1241. // before going on.
  1242. //
  1243. pConnection->WaitingForResponse = 1;
  1244. UlTrace( PARSER, (
  1245. "***4 pConnection %p->WaitingForResponse = 1\n",
  1246. pConnection
  1247. ));
  1248. }
  1249. } else {
  1250. //
  1251. // we are not active. Send an autoresponse if we have one.
  1252. //
  1253. if (pAutoResponse != NULL)
  1254. {
  1255. //
  1256. // send it and return
  1257. //
  1258. Status = UlSendHttpResponse(
  1259. pRequest,
  1260. pAutoResponse,
  1261. 0,
  1262. NULL,
  1263. NULL
  1264. );
  1265. }
  1266. else
  1267. {
  1268. //
  1269. // We have to fall back to a hardcoded response
  1270. //
  1271. pRequest->ParseState = ParseErrorState;
  1272. pRequest->ErrorCode = UlErrorUnavailable;
  1273. Status = STATUS_INVALID_DEVICE_STATE;
  1274. }
  1275. }
  1276. end:
  1277. return Status;
  1278. } // UlpDeliverHttpRequest
  1279. /***************************************************************************++
  1280. Routine Description:
  1281. links the buffer into the sorted connection list.
  1282. Arguments:
  1283. pConnection - the connection to insert into
  1284. pRequestBuffer - the buffer to link in
  1285. --***************************************************************************/
  1286. VOID
  1287. UlpInsertBuffer(
  1288. PUL_HTTP_CONNECTION pConnection,
  1289. PUL_REQUEST_BUFFER pRequestBuffer
  1290. )
  1291. {
  1292. PLIST_ENTRY pEntry;
  1293. PUL_REQUEST_BUFFER pListBuffer = NULL;
  1294. ASSERT( UL_IS_VALID_HTTP_CONNECTION(pConnection) );
  1295. ASSERT( UlDbgResourceOwnedExclusive( &pConnection->Resource ) );
  1296. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pRequestBuffer) );
  1297. ASSERT( pRequestBuffer->UsedBytes != 0 );
  1298. //
  1299. // figure out where to insert the buffer into our
  1300. // sorted queue (we need to enforce FIFO by number -
  1301. // head is the first in). optimize for ordered inserts by
  1302. // searching tail to head.
  1303. //
  1304. pEntry = pConnection->BufferHead.Blink;
  1305. while (pEntry != &(pConnection->BufferHead))
  1306. {
  1307. pListBuffer = CONTAINING_RECORD(
  1308. pEntry,
  1309. UL_REQUEST_BUFFER,
  1310. ListEntry
  1311. );
  1312. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pListBuffer) );
  1313. //
  1314. // if the number is less than, put it here, we are
  1315. // searching in reverse sort order
  1316. //
  1317. if (pListBuffer->BufferNumber < pRequestBuffer->BufferNumber)
  1318. {
  1319. break;
  1320. }
  1321. //
  1322. // go on to the next one
  1323. //
  1324. pEntry = pEntry->Blink;
  1325. }
  1326. UlTrace(
  1327. HTTP_IO, (
  1328. "http!UlpInsertBuffer(conn=%p): inserting %p(%d) after %p(%d)\n",
  1329. pConnection,
  1330. pRequestBuffer,
  1331. pRequestBuffer->BufferNumber,
  1332. pListBuffer,
  1333. (pEntry == &(pConnection->BufferHead)) ?
  1334. -1 : pListBuffer->BufferNumber
  1335. )
  1336. );
  1337. //
  1338. // and insert it
  1339. //
  1340. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  1341. InsertHeadList(
  1342. pEntry,
  1343. &(pRequestBuffer->ListEntry)
  1344. );
  1345. WRITE_REF_TRACE_LOG2(
  1346. g_pHttpConnectionTraceLog,
  1347. pConnection->pTraceLog,
  1348. REF_ACTION_INSERT_BUFFER,
  1349. pConnection->RefCount,
  1350. pRequestBuffer,
  1351. __FILE__,
  1352. __LINE__
  1353. );
  1354. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  1355. } // UlpInsertBuffer
  1356. /***************************************************************************++
  1357. Routine Description:
  1358. Merges the unparsed bytes on a source buffer to a destination buffer.
  1359. Assumes that there is space in the buffer.
  1360. Arguments:
  1361. pDest - the buffer the gets the bytes
  1362. pSrc - the buffer that gives the bytes
  1363. --***************************************************************************/
  1364. VOID
  1365. UlpMergeBuffers(
  1366. PUL_REQUEST_BUFFER pDest,
  1367. PUL_REQUEST_BUFFER pSrc
  1368. )
  1369. {
  1370. ASSERT( UL_IS_VALID_REQUEST_BUFFER( pDest ) );
  1371. ASSERT( UL_IS_VALID_REQUEST_BUFFER( pSrc ) );
  1372. ASSERT( pDest->AllocBytes - pDest->UsedBytes >= UNPARSED_BUFFER_BYTES( pSrc ) );
  1373. ASSERT( UlpIsValidRequestBufferList( pSrc->pConnection ) );
  1374. UlTrace(HTTP_IO, (
  1375. "http!UlpMergeBuffers(pDest = %p(#%d), pSrc = %p(#%d))\n"
  1376. " Copying %d bytes from pSrc.\n"
  1377. " pDest->AllocBytes (%d) - pDest->UsedBytes(%d) = %d available\n",
  1378. pDest,
  1379. pDest->BufferNumber,
  1380. pSrc,
  1381. pSrc->BufferNumber,
  1382. UNPARSED_BUFFER_BYTES( pSrc ),
  1383. pDest->AllocBytes,
  1384. pDest->UsedBytes,
  1385. pDest->AllocBytes - pDest->UsedBytes
  1386. ));
  1387. //
  1388. // copy the unparsed bytes
  1389. //
  1390. RtlCopyMemory(
  1391. pDest->pBuffer + pDest->UsedBytes,
  1392. GET_REQUEST_BUFFER_POS( pSrc ),
  1393. UNPARSED_BUFFER_BYTES( pSrc )
  1394. );
  1395. //
  1396. // adjust buffer byte counters to match the transfer
  1397. //
  1398. pDest->UsedBytes += UNPARSED_BUFFER_BYTES( pSrc );
  1399. pSrc->UsedBytes = pSrc->ParsedBytes;
  1400. ASSERT( pDest->UsedBytes != 0 );
  1401. ASSERT( pDest->UsedBytes <= pDest->AllocBytes );
  1402. } // UlpMergeBuffers
  1403. /***************************************************************************++
  1404. Routine Description:
  1405. sets up pCurrentBuffer to the proper location, merging any blocks
  1406. as needed.
  1407. Arguments:
  1408. pConnection - the connection to adjust buffers for
  1409. --***************************************************************************/
  1410. NTSTATUS
  1411. UlpAdjustBuffers(
  1412. PUL_HTTP_CONNECTION pConnection
  1413. )
  1414. {
  1415. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  1416. ASSERT(UlDbgResourceOwnedExclusive(&pConnection->Resource));
  1417. //
  1418. // do we have a starting buffer?
  1419. //
  1420. if (pConnection->pCurrentBuffer == NULL)
  1421. {
  1422. //
  1423. // the list can't be empty, this is the FIRST time in
  1424. // pCurrentBuffer is NULL
  1425. //
  1426. ASSERT(IsListEmpty(&(pConnection->BufferHead)) == FALSE);
  1427. ASSERT(pConnection->NextBufferToParse == 0);
  1428. //
  1429. // pop from the head
  1430. //
  1431. pConnection->pCurrentBuffer = CONTAINING_RECORD(
  1432. pConnection->BufferHead.Flink,
  1433. UL_REQUEST_BUFFER,
  1434. ListEntry
  1435. );
  1436. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pConnection->pCurrentBuffer) );
  1437. //
  1438. // is this the right number?
  1439. //
  1440. if (pConnection->pCurrentBuffer->BufferNumber !=
  1441. pConnection->NextBufferToParse)
  1442. {
  1443. pConnection->pCurrentBuffer = NULL;
  1444. return STATUS_MORE_PROCESSING_REQUIRED;
  1445. }
  1446. pConnection->NextBufferToParse += 1;
  1447. pConnection->NeedMoreData = 0;
  1448. }
  1449. //
  1450. // did we need more transport data?
  1451. //
  1452. if (pConnection->NeedMoreData == 1)
  1453. {
  1454. PUL_REQUEST_BUFFER pNextBuffer;
  1455. UlTrace(HTTP_IO, (
  1456. "http!UlpAdjustBuffers(pHttpConn %p) NeedMoreData == 1\n",
  1457. pConnection
  1458. ));
  1459. //
  1460. // is it there?
  1461. //
  1462. if (pConnection->pCurrentBuffer->ListEntry.Flink ==
  1463. &(pConnection->BufferHead))
  1464. {
  1465. //
  1466. // need to wait for more
  1467. //
  1468. UlTrace(HTTP_IO, (
  1469. "http!UlpAdjustBuffers(pHttpConn %p) NeedMoreData == 1\n"
  1470. " No new buffer available yet\n",
  1471. pConnection
  1472. ));
  1473. return STATUS_MORE_PROCESSING_REQUIRED;
  1474. }
  1475. pNextBuffer = CONTAINING_RECORD(
  1476. pConnection->pCurrentBuffer->ListEntry.Flink,
  1477. UL_REQUEST_BUFFER,
  1478. ListEntry
  1479. );
  1480. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pNextBuffer) );
  1481. //
  1482. // is the next buffer really the 'next' buffer?
  1483. //
  1484. if (pNextBuffer->BufferNumber != pConnection->NextBufferToParse)
  1485. {
  1486. UlTrace(HTTP_IO, (
  1487. "http!UlpAdjustBuffers(pHttpConn %p) NeedMoreData == 1\n"
  1488. " Buffer %d available, but we're waiting for %d\n",
  1489. pConnection,
  1490. pNextBuffer->BufferNumber,
  1491. pConnection->NextBufferToParse
  1492. ));
  1493. return STATUS_MORE_PROCESSING_REQUIRED;
  1494. }
  1495. //
  1496. // is there space to merge the blocks?
  1497. //
  1498. if (pNextBuffer->UsedBytes <
  1499. (pConnection->pCurrentBuffer->AllocBytes -
  1500. pConnection->pCurrentBuffer->UsedBytes))
  1501. {
  1502. //
  1503. // merge 'em .. copy the next buffer into this buffer
  1504. //
  1505. UlpMergeBuffers(
  1506. pConnection->pCurrentBuffer, // dest
  1507. pNextBuffer // src
  1508. );
  1509. //
  1510. // remove the next (now empty) buffer
  1511. //
  1512. ASSERT( pNextBuffer->UsedBytes == 0 );
  1513. UlFreeRequestBuffer(pNextBuffer);
  1514. ASSERT( UlpIsValidRequestBufferList( pConnection ) );
  1515. //
  1516. // skip the buffer sequence number as we deleted that next buffer
  1517. // placing the data in the current buffer. the "new" next buffer
  1518. // will have a 1 higher sequence number.
  1519. //
  1520. pConnection->NextBufferToParse += 1;
  1521. //
  1522. // reset the signal for more data needed
  1523. //
  1524. pConnection->NeedMoreData = 0;
  1525. }
  1526. else
  1527. {
  1528. PUL_REQUEST_BUFFER pNewBuffer;
  1529. //
  1530. // allocate a new buffer with space for the remaining stuff
  1531. // from the old buffer, and everything in the new buffer.
  1532. //
  1533. // this new buffer is replacing pNextBuffer so gets its
  1534. // BufferNumber.
  1535. //
  1536. pNewBuffer = UlCreateRequestBuffer(
  1537. (pConnection->pCurrentBuffer->UsedBytes -
  1538. pConnection->pCurrentBuffer->ParsedBytes) +
  1539. pNextBuffer->UsedBytes,
  1540. pNextBuffer->BufferNumber
  1541. );
  1542. if (pNewBuffer == NULL)
  1543. {
  1544. return STATUS_INSUFFICIENT_RESOURCES;
  1545. }
  1546. pNewBuffer->pConnection = pConnection;
  1547. UlTrace( PARSER, (
  1548. "*** Request Buffer %p has connection %p\n",
  1549. pNewBuffer,
  1550. pConnection
  1551. ));
  1552. //
  1553. // copy the unused portion into the start of this
  1554. // buffer
  1555. //
  1556. UlpMergeBuffers(
  1557. pNewBuffer, // dest
  1558. pConnection->pCurrentBuffer // src
  1559. );
  1560. if ( 0 == pConnection->pCurrentBuffer->UsedBytes )
  1561. {
  1562. //
  1563. // Whoops! Accidently ate everything...zap this buffer!
  1564. // This happens when we're ahead of the parser and there
  1565. // are 0 ParsedBytes.
  1566. //
  1567. ASSERT( 0 == pConnection->pCurrentBuffer->ParsedBytes );
  1568. UlTrace(HTTP_IO, (
  1569. "http!UlpAdjustBuffers: Zapping pConnection->pCurrentBuffer (%p)\n",
  1570. pConnection->pCurrentBuffer
  1571. ));
  1572. UlFreeRequestBuffer( pConnection->pCurrentBuffer );
  1573. pConnection->pCurrentBuffer = NULL;
  1574. }
  1575. //
  1576. // merge the next block into this one
  1577. //
  1578. UlpMergeBuffers(
  1579. pNewBuffer, // dest
  1580. pNextBuffer // src
  1581. );
  1582. //
  1583. // Dispose of the now empty next buffer
  1584. //
  1585. ASSERT(pNextBuffer->UsedBytes == 0);
  1586. UlFreeRequestBuffer(pNextBuffer);
  1587. pNextBuffer = NULL;
  1588. //
  1589. // link in the new buffer
  1590. //
  1591. ASSERT(pNewBuffer->UsedBytes != 0 );
  1592. UlpInsertBuffer(pConnection, pNewBuffer);
  1593. ASSERT( UlpIsValidRequestBufferList( pConnection ) );
  1594. //
  1595. // this newly created (larger) buffer is still the next
  1596. // buffer to parse
  1597. //
  1598. ASSERT(pNewBuffer->BufferNumber == pConnection->NextBufferToParse);
  1599. //
  1600. // so make it the current buffer now
  1601. //
  1602. pConnection->pCurrentBuffer = pNewBuffer;
  1603. //
  1604. // and advance the sequence checker
  1605. //
  1606. pConnection->NextBufferToParse += 1;
  1607. //
  1608. // now reset the signal for more data needed
  1609. //
  1610. pConnection->NeedMoreData = 0;
  1611. }
  1612. }
  1613. else
  1614. {
  1615. //
  1616. // is this buffer drained?
  1617. //
  1618. if (pConnection->pCurrentBuffer->UsedBytes ==
  1619. pConnection->pCurrentBuffer->ParsedBytes)
  1620. {
  1621. PUL_REQUEST_BUFFER pOldBuffer;
  1622. //
  1623. // are there any more buffers?
  1624. //
  1625. if (pConnection->pCurrentBuffer->ListEntry.Flink ==
  1626. &(pConnection->BufferHead))
  1627. {
  1628. //
  1629. // need to wait for more.
  1630. //
  1631. // we leave this empty buffer around refcount'd
  1632. // in pCurrentBuffer until a new buffer shows up,
  1633. // or the connection is dropped.
  1634. //
  1635. // this is so we don't lose our place
  1636. // and have to search the sorted queue
  1637. //
  1638. UlTrace(HTTP_IO, (
  1639. "http!UlpAdjustBuffers(pHttpConn = %p) NeedMoreData == 0\n"
  1640. " buffer %p(%d) is drained, more required\n",
  1641. pConnection,
  1642. pConnection->pCurrentBuffer,
  1643. pConnection->pCurrentBuffer->BufferNumber
  1644. ));
  1645. return STATUS_MORE_PROCESSING_REQUIRED;
  1646. }
  1647. // else
  1648. //
  1649. // grab the next buffer
  1650. //
  1651. pOldBuffer = pConnection->pCurrentBuffer;
  1652. pConnection->
  1653. pCurrentBuffer = CONTAINING_RECORD(
  1654. pConnection->
  1655. pCurrentBuffer->ListEntry.Flink,
  1656. UL_REQUEST_BUFFER,
  1657. ListEntry
  1658. );
  1659. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pConnection->pCurrentBuffer) );
  1660. //
  1661. // is it the 'next' buffer?
  1662. //
  1663. if (pConnection->pCurrentBuffer->BufferNumber !=
  1664. pConnection->NextBufferToParse)
  1665. {
  1666. UlTrace(HTTP_IO, (
  1667. "http!UlpAdjustBuffers(pHttpConn %p) NeedMoreData == 0\n"
  1668. " Buffer %d available, but we're waiting for %d\n",
  1669. pConnection,
  1670. pConnection->pCurrentBuffer->BufferNumber,
  1671. pConnection->NextBufferToParse
  1672. ));
  1673. pConnection->pCurrentBuffer = pOldBuffer;
  1674. return STATUS_MORE_PROCESSING_REQUIRED;
  1675. }
  1676. //
  1677. // bump up the buffer number
  1678. //
  1679. pConnection->NextBufferToParse += 1;
  1680. pConnection->NeedMoreData = 0;
  1681. }
  1682. }
  1683. return STATUS_SUCCESS;
  1684. } // UlpAdjustBuffers
  1685. /***************************************************************************++
  1686. Routine Description:
  1687. Routine invoked after an incoming TCP/MUX connection has been
  1688. received (but not yet accepted).
  1689. Arguments:
  1690. pListeningContext - Supplies an uninterpreted context value as
  1691. passed to the UlCreateListeningEndpoint() API.
  1692. pConnection - Supplies the connection being established.
  1693. pRemoteAddress - Supplies the remote (client-side) address
  1694. requesting the connection.
  1695. RemoteAddressLength - Supplies the total byte length of the
  1696. pRemoteAddress structure.
  1697. ppConnectionContext - Receives a pointer to an uninterpreted
  1698. context value to be associated with the new connection if
  1699. accepted. If the new connection is not accepted, this
  1700. parameter is ignored.
  1701. Return Value:
  1702. BOOLEAN - TRUE if the connection was accepted, FALSE if not.
  1703. --***************************************************************************/
  1704. BOOLEAN
  1705. UlConnectionRequest(
  1706. IN PVOID pListeningContext,
  1707. IN PUL_CONNECTION pConnection,
  1708. IN PTRANSPORT_ADDRESS pRemoteAddress,
  1709. IN ULONG RemoteAddressLength,
  1710. OUT PVOID *ppConnectionContext
  1711. )
  1712. {
  1713. PUL_HTTP_CONNECTION pHttpConnection;
  1714. NTSTATUS status;
  1715. //
  1716. // Sanity check.
  1717. //
  1718. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1719. UlTrace(HTTP_IO,("UlConnectionRequest: conn %p\n",pConnection));
  1720. //
  1721. // Check the global connection limit. If it's reached then
  1722. // enforce it by refusing the connection request. The TDI will
  1723. // return STATUS_CONNECTION_REFUSED when we return FALSE here
  1724. //
  1725. if (UlAcceptGlobalConnection() == FALSE)
  1726. {
  1727. UlTrace(LIMITS,
  1728. ("UlConnectionRequest: conn %p refused global limit is reached.\n",
  1729. pConnection
  1730. ));
  1731. return FALSE;
  1732. }
  1733. //
  1734. // Create a new HTTP connection.
  1735. //
  1736. status = UlCreateHttpConnection( &pHttpConnection, pConnection );
  1737. if (NT_SUCCESS(status))
  1738. {
  1739. //
  1740. // We the HTTP_CONNECTION pointer as our connection context,
  1741. // ULTDI now owns a reference (from the create).
  1742. //
  1743. *ppConnectionContext = pHttpConnection;
  1744. return TRUE;
  1745. }
  1746. //
  1747. // Failed to create new connection.
  1748. //
  1749. UlTrace(HTTP_IO,
  1750. ("UlpTestConnectionRequest: cannot create new conn, error %08lx\n",
  1751. status
  1752. ));
  1753. return FALSE;
  1754. } // UlConnectionRequest
  1755. /***************************************************************************++
  1756. Routine Description:
  1757. Routine invoked after an incoming TCP/MUX connection has been
  1758. fully accepted.
  1759. This routine is also invoked if an incoming connection was not
  1760. accepted *after* PUL_CONNECTION_REQUEST returned TRUE. In other
  1761. words, if PUL_CONNECTION_REQUEST indicated that the connection
  1762. should be accepted but a fatal error occurred later, then
  1763. PUL_CONNECTION_COMPLETE is invoked.
  1764. Arguments:
  1765. pListeningContext - Supplies an uninterpreted context value
  1766. as passed to the UlCreateListeningEndpoint() API.
  1767. pConnectionContext - Supplies the uninterpreted context value
  1768. as returned by PUL_CONNECTION_REQUEST.
  1769. Status - Supplies the completion status. If this value is
  1770. STATUS_SUCCESS, then the connection is now fully accepted.
  1771. Otherwise, the connection has been aborted.
  1772. --***************************************************************************/
  1773. VOID
  1774. UlConnectionComplete(
  1775. IN PVOID pListeningContext,
  1776. IN PVOID pConnectionContext,
  1777. IN NTSTATUS Status
  1778. )
  1779. {
  1780. PUL_CONNECTION pConnection;
  1781. PUL_HTTP_CONNECTION pHttpConnection;
  1782. //
  1783. // Sanity check.
  1784. //
  1785. pHttpConnection = (PUL_HTTP_CONNECTION)pConnectionContext;
  1786. pConnection = pHttpConnection->pConnection;
  1787. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1788. UlTrace(HTTP_IO,("UlConnectionComplete: http %p conn %p status %08lx\n",
  1789. pHttpConnection,
  1790. pConnection,
  1791. Status
  1792. ));
  1793. //
  1794. // Blow away our HTTP connection if the connect failed.
  1795. //
  1796. if (!NT_SUCCESS(Status))
  1797. {
  1798. UL_DEREFERENCE_HTTP_CONNECTION( pHttpConnection );
  1799. }
  1800. } // UlConnectionComplete
  1801. /***************************************************************************++
  1802. Routine Description:
  1803. Routine invoked after an established TCP/MUX connection has been
  1804. disconnected by the remote (client) side.
  1805. This indication is now obsolete no longer get called from TDI.
  1806. Arguments:
  1807. pListeningContext - Supplies an uninterpreted context value
  1808. as passed to the UlCreateListeningEndpoint() API.
  1809. pConnectionContext - Supplies the uninterpreted context value
  1810. as returned by PUL_CONNECTION_REQUEST.
  1811. Status - Supplies the termination status.
  1812. --***************************************************************************/
  1813. VOID
  1814. UlConnectionDisconnect(
  1815. IN PVOID pListeningContext,
  1816. IN PVOID pConnectionContext,
  1817. IN NTSTATUS Status
  1818. )
  1819. {
  1820. PUL_CONNECTION pConnection;
  1821. PUL_HTTP_CONNECTION pHttpConnection;
  1822. //
  1823. // Sanity check.
  1824. //
  1825. pHttpConnection = (PUL_HTTP_CONNECTION)pConnectionContext;
  1826. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pHttpConnection));
  1827. pConnection = pHttpConnection->pConnection;
  1828. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1829. UlTrace(HTTP_IO,("UlConnectionDisconnect: http %p conn %p\n",
  1830. pHttpConnection,
  1831. pConnection
  1832. ));
  1833. //
  1834. // We are responsible for closing the server side of the tcp connection.
  1835. // No reason to do an abortive disconnect. this indication is that the
  1836. // client has ALREADY disconnected.
  1837. //
  1838. Status = UlCloseConnection(pConnection, FALSE, NULL, NULL);
  1839. #if DBG
  1840. if (!NT_SUCCESS(Status))
  1841. {
  1842. DbgPrint(
  1843. "UlConnectionDisconnect: cannot close, error %08lx\n",
  1844. Status
  1845. );
  1846. }
  1847. #endif
  1848. } // UlConnectionDisconnect
  1849. /***************************************************************************++
  1850. Routine Description:
  1851. Worker function to do cleanup work that shouldn't happen above DPC level.
  1852. Arguments:
  1853. pWorkItem -- a pointer to a UL_WORK_ITEM DisconnectWorkItem
  1854. --***************************************************************************/
  1855. VOID
  1856. UlConnectionDisconnectCompleteWorker(
  1857. IN PUL_WORK_ITEM pWorkItem
  1858. )
  1859. {
  1860. PUL_HTTP_CONNECTION pConnection;
  1861. PAGED_CODE();
  1862. ASSERT(pWorkItem);
  1863. pConnection = CONTAINING_RECORD(
  1864. pWorkItem,
  1865. UL_HTTP_CONNECTION,
  1866. DisconnectWorkItem
  1867. );
  1868. UlTrace(HTTP_IO, (
  1869. "http!UlConnectionDisconnectCompleteWorker (%p) pConnection (%p)\n",
  1870. pWorkItem,
  1871. pConnection
  1872. ));
  1873. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  1874. //
  1875. // If connection is already get destroyed just bail out !
  1876. //
  1877. WRITE_REF_TRACE_LOG2(
  1878. g_pTdiTraceLog,
  1879. pConnection->pConnection->pTraceLog,
  1880. REF_ACTION_DRAIN_UL_CONNECTION_DISCONNECT_COMPLETE,
  1881. pConnection->pConnection->ReferenceCount,
  1882. pConnection->pConnection,
  1883. __FILE__,
  1884. __LINE__
  1885. );
  1886. //
  1887. // Check to see if we have to draine out or not.
  1888. //
  1889. UlpDiscardBytesFromConnection( pConnection );
  1890. //
  1891. // Deref the http connection
  1892. //
  1893. UL_DEREFERENCE_HTTP_CONNECTION( pConnection );
  1894. } // UlConnectionDisconnectCompleteWorker
  1895. /***************************************************************************++
  1896. Routine Description:
  1897. Routine invoked after an established TCP/MUX connection has been
  1898. disconnected by us (server side) we make a final check here to see
  1899. if we have to drain the connection or not.
  1900. Arguments:
  1901. pListeningContext - Supplies an uninterpreted context value
  1902. as passed to the UlCreateListeningEndpoint() API.
  1903. pConnectionContext - Supplies the uninterpreted context value
  1904. as returned by PUL_CONNECTION_REQUEST.
  1905. --***************************************************************************/
  1906. VOID
  1907. UlConnectionDisconnectComplete(
  1908. IN PVOID pListeningContext,
  1909. IN PVOID pConnectionContext
  1910. )
  1911. {
  1912. PUL_HTTP_CONNECTION pConnection;
  1913. //
  1914. // Sanity check.
  1915. //
  1916. pConnection = (PUL_HTTP_CONNECTION)pConnectionContext;
  1917. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  1918. UlTrace( HTTP_IO,("UlConnectionDisconnectComplete: pConnection %p \n",
  1919. pConnection
  1920. ));
  1921. UL_REFERENCE_HTTP_CONNECTION( pConnection );
  1922. UL_QUEUE_WORK_ITEM(
  1923. &pConnection->DisconnectWorkItem,
  1924. &UlConnectionDisconnectCompleteWorker
  1925. );
  1926. } // UlConnectionDisconnectComplete
  1927. /***************************************************************************++
  1928. Routine Description:
  1929. Routine invoked after an established TCP/MUX connection has been
  1930. destroyed.
  1931. Arguments:
  1932. pListeningContext - Supplies an uninterpreted context value
  1933. as passed to the UlCreateListeningEndpoint() API.
  1934. pConnectionContext - Supplies the uninterpreted context value
  1935. as returned by PUL_CONNECTION_REQUEST.
  1936. --***************************************************************************/
  1937. VOID
  1938. UlConnectionDestroyed(
  1939. IN PVOID pListeningContext,
  1940. IN PVOID pConnectionContext
  1941. )
  1942. {
  1943. PUL_CONNECTION pConnection;
  1944. PUL_HTTP_CONNECTION pHttpConnection;
  1945. NTSTATUS status;
  1946. //
  1947. // Sanity check.
  1948. //
  1949. pHttpConnection = (PUL_HTTP_CONNECTION)pConnectionContext;
  1950. pConnection = pHttpConnection->pConnection;
  1951. ASSERT( IS_VALID_CONNECTION( pConnection ) );
  1952. UlTrace(
  1953. HTTP_IO, (
  1954. "http!UlConnectionDestroyed: http %p conn %p\n",
  1955. pHttpConnection,
  1956. pConnection
  1957. )
  1958. );
  1959. //
  1960. // Remove the CONNECTION and REQUEST opaque id entries and the ULTDI
  1961. // reference
  1962. //
  1963. UL_QUEUE_WORK_ITEM(
  1964. &pHttpConnection->WorkItem,
  1965. UlConnectionDestroyedWorker
  1966. );
  1967. } // UlConnectionDestroyed
  1968. /***************************************************************************++
  1969. Routine Description:
  1970. handles retrieving entity body from the http request and placing into
  1971. user mode buffers.
  1972. Arguments:
  1973. pRequest - the request to receive from.
  1974. pIrp - the user irp to copy it into. this will be pended, always.
  1975. --***************************************************************************/
  1976. NTSTATUS
  1977. UlReceiveEntityBody(
  1978. IN PUL_APP_POOL_PROCESS pProcess,
  1979. IN PUL_INTERNAL_REQUEST pRequest,
  1980. IN PIRP pIrp
  1981. )
  1982. {
  1983. NTSTATUS Status;
  1984. PIO_STACK_LOCATION pIrpSp;
  1985. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  1986. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pRequest->pHttpConn));
  1987. //
  1988. // get the current stack location (a macro)
  1989. //
  1990. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  1991. UlTraceVerbose(HTTP_IO, (
  1992. "http!UlReceiveEntityBody: process=%p, req=%p, irp=%p, irpsp=%p\n",
  1993. pProcess, pRequest, pIrp, pIrpSp
  1994. ));
  1995. //
  1996. // is there any recv buffer?
  1997. //
  1998. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength == 0)
  1999. {
  2000. //
  2001. // nope, shortcircuit this
  2002. //
  2003. Status = STATUS_PENDING;
  2004. pIrp->IoStatus.Information = 0;
  2005. goto end;
  2006. }
  2007. //
  2008. // grab our lock
  2009. //
  2010. UlAcquireResourceExclusive(&(pRequest->pHttpConn->Resource), TRUE);
  2011. //
  2012. // Make sure we're not cleaning up the request before queuing an
  2013. // IRP on it.
  2014. //
  2015. if (pRequest->InCleanup)
  2016. {
  2017. Status = STATUS_CONNECTION_DISCONNECTED;
  2018. UlReleaseResource(&(pRequest->pHttpConn->Resource));
  2019. UlTraceVerbose(HTTP_IO, (
  2020. "http!UlReceiveEntityBody(%p): Cleaning up request, status=0x%x\n",
  2021. pRequest, Status
  2022. ));
  2023. goto end;
  2024. }
  2025. //
  2026. // is there any data to read? either
  2027. //
  2028. // 1) there were no entity chunks OR
  2029. //
  2030. // 2) there were and :
  2031. //
  2032. // 2b) we've are done parsing all of them AND
  2033. //
  2034. // 2c) we've read all we parsed
  2035. //
  2036. // 3) we have encountered an error when parsing
  2037. // the entity body. Therefore parser was in the
  2038. // error state.
  2039. //
  2040. if ((pRequest->ContentLength == 0 && pRequest->Chunked == 0) ||
  2041. (pRequest->ParseState > ParseEntityBodyState &&
  2042. pRequest->ChunkBytesRead == pRequest->ChunkBytesParsed) ||
  2043. (pRequest->ParseState == ParseErrorState)
  2044. )
  2045. {
  2046. if ( pRequest->ParseState == ParseErrorState )
  2047. {
  2048. //
  2049. // Do not route up the entity body if we have
  2050. // encountered an error when parsing it.
  2051. //
  2052. Status = STATUS_INVALID_DEVICE_REQUEST;
  2053. }
  2054. else
  2055. {
  2056. //
  2057. // nope, complete right away
  2058. //
  2059. Status = STATUS_END_OF_FILE;
  2060. }
  2061. UlReleaseResource(&(pRequest->pHttpConn->Resource));
  2062. UlTraceVerbose(HTTP_IO, (
  2063. "http!UlReceiveEntityBody(%p): No data to read, status=0x%x\n",
  2064. pRequest, Status
  2065. ));
  2066. goto end;
  2067. }
  2068. //
  2069. // queue the irp
  2070. //
  2071. IoMarkIrpPending(pIrp);
  2072. //
  2073. // handle 100 continue message reponses
  2074. //
  2075. if ( HTTP_GREATER_EQUAL_VERSION(pRequest->Version, 1, 1) )
  2076. {
  2077. //
  2078. // if this is a HTTP/1.1 PUT or POST request,
  2079. // send "100 Continue" response.
  2080. //
  2081. if ( (HttpVerbPUT == pRequest->Verb) ||
  2082. (HttpVerbPOST == pRequest->Verb) )
  2083. {
  2084. //
  2085. // Only send continue once...
  2086. //
  2087. if ( (0 == pRequest->SentContinue) &&
  2088. (0 == pRequest->SentResponse) )
  2089. {
  2090. ULONG BytesSent;
  2091. BytesSent = UlSendSimpleStatus(pRequest, UlStatusContinue);
  2092. pRequest->SentContinue = 1;
  2093. // Update the server to client bytes sent.
  2094. // The logging & perf counters will use it.
  2095. pRequest->BytesSent += BytesSent;
  2096. UlTraceVerbose(HTTP_IO, (
  2097. "http!UlReceiveEntityBody(%p): sent \"100 Continue\", "
  2098. "bytes sent = %d\n",
  2099. pRequest, pRequest->BytesSent
  2100. ));
  2101. }
  2102. }
  2103. }
  2104. //
  2105. // give it a pointer to the request object
  2106. //
  2107. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = pRequest;
  2108. UL_REFERENCE_INTERNAL_REQUEST(pRequest);
  2109. //
  2110. // set to these to null just in case the cancel routine runs
  2111. //
  2112. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  2113. pIrp->Tail.Overlay.ListEntry.Blink = NULL;
  2114. IoSetCancelRoutine(pIrp, &UlpCancelEntityBody);
  2115. //
  2116. // cancelled?
  2117. //
  2118. if (pIrp->Cancel)
  2119. {
  2120. //
  2121. // darn it, need to make sure the irp get's completed
  2122. //
  2123. if (IoSetCancelRoutine( pIrp, NULL ) != NULL)
  2124. {
  2125. //
  2126. // we are in charge of completion, IoCancelIrp didn't
  2127. // see our cancel routine (and won't). ioctl wrapper
  2128. // will complete it
  2129. //
  2130. UlReleaseResource(&(pRequest->pHttpConn->Resource));
  2131. //
  2132. // let go of the request reference
  2133. //
  2134. UL_DEREFERENCE_INTERNAL_REQUEST(
  2135. (PUL_INTERNAL_REQUEST)(pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer)
  2136. );
  2137. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2138. pIrp->IoStatus.Information = 0;
  2139. UlUnmarkIrpPending( pIrp );
  2140. Status = STATUS_CANCELLED;
  2141. goto end;
  2142. }
  2143. //
  2144. // our cancel routine will run and complete the irp,
  2145. // don't touch it
  2146. //
  2147. //
  2148. // STATUS_PENDING will cause the ioctl wrapper to
  2149. // not complete (or touch in any way) the irp
  2150. //
  2151. Status = STATUS_PENDING;
  2152. UlReleaseResource(&(pRequest->pHttpConn->Resource));
  2153. goto end;
  2154. }
  2155. //
  2156. // now we are safe to queue it
  2157. //
  2158. //
  2159. // queue the irp on the request
  2160. //
  2161. InsertHeadList(&(pRequest->IrpHead), &(pIrp->Tail.Overlay.ListEntry));
  2162. //
  2163. // Remember IrpHead has been touched so we need to call UlCancelRequestIo.
  2164. //
  2165. pRequest->IrpsPending = TRUE;
  2166. //
  2167. // all done
  2168. //
  2169. Status = STATUS_PENDING;
  2170. //
  2171. // Process the buffer queue (which might process the irp we just queued)
  2172. //
  2173. ASSERT( UlpIsValidRequestBufferList( pRequest->pHttpConn ) );
  2174. UlpProcessBufferQueue(pRequest);
  2175. UlReleaseResource(&(pRequest->pHttpConn->Resource));
  2176. //
  2177. // all done
  2178. //
  2179. end:
  2180. UlTraceVerbose(HTTP_IO, (
  2181. "http!UlReceiveEntityBody(%p): returning status=0x%x\n",
  2182. pRequest, Status
  2183. ));
  2184. RETURN(Status);
  2185. } // UlReceiveEntityBody
  2186. /***************************************************************************++
  2187. Routine Description:
  2188. processes the pending irp queue and buffered body. copying data from the
  2189. buffers into the irps, releasing the buffers and completing the irps
  2190. you must already have the resource locked exclusive on the request prior
  2191. to calling this procedure.
  2192. Arguments:
  2193. pRequest - the request which we should process.
  2194. --***************************************************************************/
  2195. VOID
  2196. UlpProcessBufferQueue(
  2197. PUL_INTERNAL_REQUEST pRequest
  2198. )
  2199. {
  2200. ULONG OutputBufferLength;
  2201. PUCHAR pOutputBuffer;
  2202. PIRP pIrp;
  2203. PIO_STACK_LOCATION pIrpSp;
  2204. PLIST_ENTRY pEntry;
  2205. ULONG BytesToCopy;
  2206. ULONG BufferLength;
  2207. ULONG TotalBytesConsumed;
  2208. //
  2209. // Sanity check.
  2210. //
  2211. PAGED_CODE();
  2212. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  2213. ASSERT(UlDbgResourceOwnedExclusive(&pRequest->pHttpConn->Resource));
  2214. //
  2215. // now let's pop some buffers off the list
  2216. //
  2217. OutputBufferLength = 0;
  2218. TotalBytesConsumed = 0;
  2219. pIrp = NULL;
  2220. while (TRUE)
  2221. {
  2222. //
  2223. // is there any more entity body to read?
  2224. //
  2225. UlTraceVerbose(HTTP_IO, (
  2226. "http!UlpProcessBufferQueue(req=%p): "
  2227. "ParseState=%d, ChunkBytesRead=%d, ChunkBytesParsed=%d, "
  2228. "ChunkBuffer=%p\n",
  2229. pRequest, pRequest->ParseState,
  2230. pRequest->ChunkBytesRead, pRequest->ChunkBytesParsed,
  2231. pRequest->pChunkBuffer
  2232. ));
  2233. if (pRequest->ParseState > ParseEntityBodyState &&
  2234. pRequest->ChunkBytesRead == pRequest->ChunkBytesParsed)
  2235. {
  2236. //
  2237. // nope, let's loop through all of the irp's, completing 'em
  2238. //
  2239. UlTraceVerbose(HTTP_IO, (
  2240. "http!UlpProcessBufferQueue(req=%p): no more EntityBody\n",
  2241. pRequest
  2242. ));
  2243. BufferLength = 0;
  2244. }
  2245. //
  2246. // Do we have data ready to be read ?
  2247. //
  2248. // we have not recieved the first chunk from the parser? OR
  2249. // the parser has not parsed any more data, we've read it all so far
  2250. //
  2251. else if (pRequest->pChunkBuffer == NULL ||
  2252. pRequest->ChunkBytesRead == pRequest->ChunkBytesParsed)
  2253. {
  2254. //
  2255. // Wait for the parser .... UlpParseNextRequest will call
  2256. // this function when it has seen more .
  2257. //
  2258. UlTraceVerbose(HTTP_IO, (
  2259. "http!UlpProcessBufferQueue(req=%p): pChunkBuffer=%p, "
  2260. "ChunkBytesRead=0x%I64x, ChunkBytesParsed=0x%I64x.\n",
  2261. pRequest, pRequest->pChunkBuffer,
  2262. pRequest->ChunkBytesRead, pRequest->ChunkBytesParsed
  2263. ));
  2264. break;
  2265. }
  2266. //
  2267. // We are ready to process !
  2268. //
  2269. else
  2270. {
  2271. BufferLength = pRequest->pChunkBuffer->UsedBytes -
  2272. DIFF(pRequest->pChunkLocation -
  2273. pRequest->pChunkBuffer->pBuffer);
  2274. UlTraceVerbose(HTTP_IO, (
  2275. "http!UlpProcessBufferQueue(req=%p): BufferLength=0x%x\n",
  2276. pRequest, BufferLength
  2277. ));
  2278. }
  2279. //
  2280. // do we need a fresh irp?
  2281. //
  2282. if (OutputBufferLength == 0)
  2283. {
  2284. //
  2285. // need to complete the current in-used irp first
  2286. //
  2287. if (pIrp != NULL)
  2288. {
  2289. //
  2290. // let go of the request reference
  2291. //
  2292. UL_DEREFERENCE_INTERNAL_REQUEST(
  2293. (PUL_INTERNAL_REQUEST)pIrpSp->Parameters.
  2294. DeviceIoControl.Type3InputBuffer
  2295. );
  2296. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2297. //
  2298. // complete the used irp
  2299. //
  2300. UlTraceVerbose(HTTP_IO, (
  2301. "http!UlpProcessBufferQueue(req=%p): "
  2302. "completing Irp %p, Status=0x%x\n",
  2303. pRequest, pIrp,
  2304. pIrp->IoStatus.Status
  2305. ));
  2306. UlCompleteRequest(pIrp, g_UlPriorityBoost);
  2307. pIrp = NULL;
  2308. }
  2309. //
  2310. // dequeue an irp
  2311. //
  2312. while (IsListEmpty(&(pRequest->IrpHead)) == FALSE)
  2313. {
  2314. pEntry = RemoveTailList(&(pRequest->IrpHead));
  2315. pEntry->Blink = pEntry->Flink = NULL;
  2316. pIrp = CONTAINING_RECORD(pEntry, IRP, Tail.Overlay.ListEntry);
  2317. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  2318. //
  2319. // pop the cancel routine
  2320. //
  2321. if (IoSetCancelRoutine(pIrp, NULL) == NULL)
  2322. {
  2323. //
  2324. // IoCancelIrp pop'd it first
  2325. //
  2326. // ok to just ignore this irp, it's been pop'd off the
  2327. // queue and will be completed in the cancel routine.
  2328. //
  2329. // keep looking for a irp to use
  2330. //
  2331. }
  2332. else if (pIrp->Cancel)
  2333. {
  2334. //
  2335. // we pop'd it first. but the irp is being cancelled
  2336. // and our cancel routine will never run. lets be
  2337. // nice and complete the irp now (vs. using it
  2338. // then completing it - which would also be legal).
  2339. //
  2340. //
  2341. // let go of the request reference
  2342. //
  2343. UL_DEREFERENCE_INTERNAL_REQUEST(
  2344. (PUL_INTERNAL_REQUEST)pIrpSp->Parameters.
  2345. DeviceIoControl.Type3InputBuffer
  2346. );
  2347. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2348. //
  2349. // complete the irp
  2350. //
  2351. pIrp->IoStatus.Status = STATUS_CANCELLED;
  2352. pIrp->IoStatus.Information = 0;
  2353. UlTraceVerbose(HTTP_IO, (
  2354. "http!UlpProcessBufferQueue(req=%p): "
  2355. "completing cancelled Irp %p, Status=0x%x\n",
  2356. pRequest, pIrp,
  2357. pIrp->IoStatus.Status
  2358. ));
  2359. UlCompleteRequest(pIrp, g_UlPriorityBoost);
  2360. pIrp = NULL;
  2361. }
  2362. else
  2363. {
  2364. //
  2365. // we are free to use this irp !
  2366. //
  2367. break;
  2368. }
  2369. } // while (IsListEmpty(&(pRequest->IrpHead)) == FALSE)
  2370. //
  2371. // did we get an irp?
  2372. //
  2373. if (pIrp == NULL)
  2374. {
  2375. //
  2376. // stop looping
  2377. //
  2378. break;
  2379. }
  2380. UlTraceVerbose(HTTP_IO, (
  2381. "http!UlpProcessBufferQueue(req=%p): found Irp %p\n",
  2382. pRequest, pIrp
  2383. ));
  2384. //
  2385. // CODEWORK: we could release the request now.
  2386. //
  2387. OutputBufferLength =
  2388. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength;
  2389. pOutputBuffer = (PUCHAR) MmGetSystemAddressForMdlSafe(
  2390. pIrp->MdlAddress,
  2391. NormalPagePriority
  2392. );
  2393. if ( pOutputBuffer == NULL )
  2394. {
  2395. pIrp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
  2396. pIrp->IoStatus.Information = 0;
  2397. break;
  2398. }
  2399. //
  2400. // fill in the IO_STATUS_BLOCK
  2401. //
  2402. pIrp->IoStatus.Status = STATUS_SUCCESS;
  2403. pIrp->IoStatus.Information = 0;
  2404. } // if (OutputBufferLength == 0)
  2405. UlTrace(
  2406. HTTP_IO, (
  2407. "http!UlpProcessBufferQueue(req=%p): pChunkBuffer=%p(%d)\n",
  2408. pRequest,
  2409. pRequest->pChunkBuffer,
  2410. pRequest->pChunkBuffer == NULL ?
  2411. -1 :
  2412. pRequest->pChunkBuffer->BufferNumber
  2413. )
  2414. );
  2415. //
  2416. // how much of it can we copy? min of both buffer sizes
  2417. // and the chunk size
  2418. //
  2419. BytesToCopy = MIN(BufferLength, OutputBufferLength);
  2420. BytesToCopy = (ULONG)(MIN(
  2421. (ULONGLONG)(BytesToCopy),
  2422. pRequest->ChunkBytesToRead
  2423. ));
  2424. if (BytesToCopy > 0)
  2425. {
  2426. ASSERT(pRequest->pChunkBuffer != NULL) ;
  2427. //
  2428. // copy the buffer
  2429. //
  2430. RtlCopyMemory(
  2431. pOutputBuffer,
  2432. pRequest->pChunkLocation,
  2433. BytesToCopy
  2434. );
  2435. IF_DEBUG2(HTTP_IO, VERBOSE)
  2436. {
  2437. UlTraceVerbose( HTTP_IO, (
  2438. ">>>> http!UlpProcessBufferQueue(req=%p): %d bytes\n",
  2439. pRequest, BytesToCopy
  2440. ));
  2441. UlDbgPrettyPrintBuffer(pOutputBuffer, BytesToCopy);
  2442. UlTraceVerbose( HTTP_IO, ("<<<<\n"));
  2443. }
  2444. pRequest->pChunkLocation += BytesToCopy;
  2445. BufferLength -= BytesToCopy;
  2446. pRequest->ChunkBytesToRead -= BytesToCopy;
  2447. pRequest->ChunkBytesRead += BytesToCopy;
  2448. pOutputBuffer += BytesToCopy;
  2449. OutputBufferLength -= BytesToCopy;
  2450. pIrp->IoStatus.Information += BytesToCopy;
  2451. TotalBytesConsumed += BytesToCopy;
  2452. }
  2453. else
  2454. {
  2455. UlTraceVerbose(HTTP_IO, (
  2456. "http!UlpProcessBufferQueue(req=%p): BytesToCopy=0\n",
  2457. pRequest
  2458. ));
  2459. }
  2460. //
  2461. // are we all done with body?
  2462. //
  2463. // when the parser is all done, and we caught up with the parser
  2464. // we are all done.
  2465. //
  2466. UlTraceVerbose(HTTP_IO, (
  2467. "http!UlpProcessBufferQueue(req=%p): "
  2468. "ParseState=%d, ChunkBytesRead=%d, BytesParsed=%d, "
  2469. "BytesToRead=%d, BufferLength=%d\n",
  2470. pRequest, pRequest->ParseState,
  2471. pRequest->ChunkBytesRead, pRequest->ChunkBytesParsed,
  2472. pRequest->ChunkBytesToRead, BufferLength
  2473. ));
  2474. if (pRequest->ParseState > ParseEntityBodyState &&
  2475. pRequest->ChunkBytesRead == pRequest->ChunkBytesParsed)
  2476. {
  2477. //
  2478. // we are done buffering, mark this irp's return status
  2479. // if we didn't copy any data into it
  2480. //
  2481. if (pIrp->IoStatus.Information == 0)
  2482. {
  2483. pIrp->IoStatus.Status = STATUS_END_OF_FILE;
  2484. }
  2485. //
  2486. // force it to complete at the top of the loop
  2487. //
  2488. OutputBufferLength = 0;
  2489. UlTraceVerbose(HTTP_IO, (
  2490. "http!UlpProcessBufferQueue(req=%p): "
  2491. "set Irp %p status to EOF\n",
  2492. pRequest, pIrp
  2493. ));
  2494. }
  2495. //
  2496. // need to do buffer management? three cases to worry about:
  2497. //
  2498. // 1) consumed the buffer, but more chunk bytes exist
  2499. //
  2500. // 2) consumed the buffer, and no more chunk bytes exist
  2501. //
  2502. // 3) did not consume the buffer, but no more chunk bytes exist
  2503. //
  2504. else if (BufferLength == 0)
  2505. {
  2506. PUL_REQUEST_BUFFER pNewBuffer;
  2507. PLIST_ENTRY pNextEntry;
  2508. //
  2509. // consumed the buffer, has the parser already seen another?
  2510. //
  2511. //
  2512. // end of the list?
  2513. //
  2514. if (pRequest->pChunkBuffer->ListEntry.Flink !=
  2515. &(pRequest->pHttpConn->BufferHead))
  2516. {
  2517. pNewBuffer = CONTAINING_RECORD(
  2518. pRequest->pChunkBuffer->ListEntry.Flink,
  2519. UL_REQUEST_BUFFER,
  2520. ListEntry
  2521. );
  2522. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pNewBuffer) );
  2523. //
  2524. // There had better be some bytes in this buffer
  2525. //
  2526. ASSERT( 0 != pNewBuffer->UsedBytes );
  2527. }
  2528. else
  2529. {
  2530. pNewBuffer = NULL;
  2531. }
  2532. UlTraceVerbose(HTTP_IO, (
  2533. "http!UlpProcessBufferQueue(req=%p): "
  2534. "pNewBuffer = %p, %d parsed bytes\n",
  2535. pRequest, pNewBuffer, (pNewBuffer ? pNewBuffer->ParsedBytes : 0)
  2536. ));
  2537. //
  2538. // the flink buffer is a "next buffer" (the list is circular)
  2539. // AND that buffer has been consumed by the parser,
  2540. //
  2541. // then we too can move on to it and start consuming.
  2542. //
  2543. if (pNewBuffer != NULL && pNewBuffer->ParsedBytes > 0)
  2544. {
  2545. PUL_REQUEST_BUFFER pOldBuffer;
  2546. //
  2547. // remember the old buffer
  2548. //
  2549. pOldBuffer = pRequest->pChunkBuffer;
  2550. ASSERT(pNewBuffer->BufferNumber > pOldBuffer->BufferNumber);
  2551. //
  2552. // use it the new one
  2553. //
  2554. pRequest->pChunkBuffer = pNewBuffer;
  2555. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pRequest->pChunkBuffer) );
  2556. //
  2557. // update our current location in the buffer and record
  2558. // its length
  2559. //
  2560. pRequest->pChunkLocation = pRequest->pChunkBuffer->pBuffer;
  2561. BufferLength = pRequest->pChunkBuffer->UsedBytes;
  2562. //
  2563. // did the chunk end on that buffer boundary and there are
  2564. // more chunks ?
  2565. //
  2566. if (pRequest->ChunkBytesToRead == 0)
  2567. {
  2568. NTSTATUS Status;
  2569. ULONG BytesTaken = 0L;
  2570. //
  2571. // we know there are more chunk buffers,
  2572. // thus we must be chunk encoded
  2573. //
  2574. ASSERT(pRequest->Chunked == 1);
  2575. //
  2576. // the chunk length is not allowed to span buffers,
  2577. // let's parse it
  2578. //
  2579. Status = UlParseChunkLength(
  2580. pRequest,
  2581. pRequest->pChunkLocation,
  2582. BufferLength,
  2583. &BytesTaken,
  2584. &(pRequest->ChunkBytesToRead)
  2585. );
  2586. UlTraceVerbose(HTTP_IO, (
  2587. "http!UlpProcessBufferQueue(pReq=%p): Status=0x%x. "
  2588. "Chunk length (a): %d bytes taken, "
  2589. "0x%I64x bytes to read.\n",
  2590. pRequest, Status,
  2591. BytesTaken, pRequest->ChunkBytesToRead
  2592. ));
  2593. //
  2594. // this can't fail, the only failure case from
  2595. // ParseChunkLength spanning buffers, which the parser
  2596. // would have fixed in HandleRequest
  2597. //
  2598. ASSERT(NT_SUCCESS(Status) && BytesTaken > 0);
  2599. ASSERT(pRequest->ChunkBytesToRead > 0);
  2600. ASSERT(BytesTaken <= BufferLength);
  2601. pRequest->pChunkLocation += BytesTaken;
  2602. BufferLength -= BytesTaken;
  2603. } // if (pRequest->ChunkBytesToRead == 0)
  2604. UlTrace(HTTP_IO, (
  2605. "http!UlpProcessBufferQueue(pRequest = %p)\n"
  2606. " finished with pOldBuffer = %p(%d)\n"
  2607. " moved on to pChunkBuffer = %p(%d)\n"
  2608. " pConn(%p)->pCurrentBuffer = %p(%d)\n"
  2609. " pRequest->pLastHeaderBuffer = %p(%d)\n",
  2610. pRequest,
  2611. pOldBuffer,
  2612. pOldBuffer->BufferNumber,
  2613. pRequest->pChunkBuffer,
  2614. pRequest->pChunkBuffer ? pRequest->pChunkBuffer->BufferNumber : -1,
  2615. pRequest->pHttpConn,
  2616. pRequest->pHttpConn->pCurrentBuffer,
  2617. pRequest->pHttpConn->pCurrentBuffer->BufferNumber,
  2618. pRequest->pLastHeaderBuffer,
  2619. pRequest->pLastHeaderBuffer->BufferNumber
  2620. ));
  2621. //
  2622. // let the old buffer go if it doesn't contain any header
  2623. // data. We're done with it.
  2624. //
  2625. if (pOldBuffer != pRequest->pLastHeaderBuffer)
  2626. {
  2627. //
  2628. // the connection should be all done using this, the only
  2629. // way we get here is if the parser has seen this buffer
  2630. // thus pCurrentBuffer points at least to pNewBuffer.
  2631. //
  2632. ASSERT(pRequest->pHttpConn->pCurrentBuffer != pOldBuffer);
  2633. UlFreeRequestBuffer(pOldBuffer);
  2634. pOldBuffer = NULL;
  2635. }
  2636. } // if (pNewBuffer != NULL && pNewBuffer->ParsedBytes > 0)
  2637. } // else if (BufferLength == 0)
  2638. //
  2639. // ok, there's more bytes in the buffer, but how about the chunk?
  2640. //
  2641. //
  2642. // Have we taken all of the current chunk?
  2643. //
  2644. else if (pRequest->ChunkBytesToRead == 0)
  2645. {
  2646. //
  2647. // Are we are still behind the parser?
  2648. //
  2649. if (pRequest->ChunkBytesRead < pRequest->ChunkBytesParsed)
  2650. {
  2651. NTSTATUS Status;
  2652. ULONG BytesTaken;
  2653. ASSERT(pRequest->Chunked == 1);
  2654. //
  2655. // the chunk length is not allowed to span buffers,
  2656. // let's parse it
  2657. //
  2658. Status = UlParseChunkLength(
  2659. pRequest,
  2660. pRequest->pChunkLocation,
  2661. BufferLength,
  2662. &BytesTaken,
  2663. &(pRequest->ChunkBytesToRead)
  2664. );
  2665. UlTraceVerbose(HTTP_IO, (
  2666. "http!UlpProcessBufferQueue(pRequest=%p): Status=0x%x. "
  2667. "chunk length (b): %d bytes taken, "
  2668. "0x%I64x bytes to read.\n",
  2669. pRequest, Status,
  2670. BytesTaken, pRequest->ChunkBytesToRead
  2671. ));
  2672. //
  2673. // this can't fail, the only failure case from
  2674. // ParseChunkLength spanning buffers, which the parser
  2675. // would have fixed in HandleRequest
  2676. //
  2677. ASSERT(NT_SUCCESS(Status) && BytesTaken > 0);
  2678. ASSERT(pRequest->ChunkBytesToRead > 0);
  2679. ASSERT(BytesTaken <= BufferLength);
  2680. pRequest->pChunkLocation += BytesTaken;
  2681. BufferLength -= BytesTaken;
  2682. }
  2683. else
  2684. {
  2685. //
  2686. // Need to wait for the parser to parse more
  2687. //
  2688. UlTraceVerbose(HTTP_IO, (
  2689. "http!UlpProcessBufferQueue(pRequest = %p): "
  2690. "need to parse more\n",
  2691. pRequest
  2692. ));
  2693. break;
  2694. }
  2695. } // else if (pRequest->ChunkBytesToRead == 0)
  2696. //
  2697. // next irp or buffer
  2698. //
  2699. } // while (TRUE)
  2700. //
  2701. // complete the irp we put partial data in
  2702. //
  2703. if (pIrp != NULL)
  2704. {
  2705. //
  2706. // let go of the request reference
  2707. //
  2708. UL_DEREFERENCE_INTERNAL_REQUEST(
  2709. (PUL_INTERNAL_REQUEST)pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer
  2710. );
  2711. pIrpSp->Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  2712. //
  2713. // complete the used irp
  2714. //
  2715. UlTraceVerbose(HTTP_IO, (
  2716. "http!UlpProcessBufferQueue(req=%p): "
  2717. "completing used Irp %p, Status=0x%x\n",
  2718. pRequest,
  2719. pIrp, pIrp->IoStatus.Status
  2720. ));
  2721. UlCompleteRequest(pIrp, g_UlPriorityBoost);
  2722. pIrp = NULL;
  2723. }
  2724. else
  2725. {
  2726. UlTraceVerbose(HTTP_IO, (
  2727. "http!UlpProcessBufferQueue(req=%p): no irp with partial data\n",
  2728. pRequest
  2729. ));
  2730. }
  2731. //
  2732. // Tell the connection how many bytes we consumed. This
  2733. // may allow us to restart receive indications.
  2734. //
  2735. UlTraceVerbose(HTTP_IO, (
  2736. "http!UlpProcessBufferQueue(req=%p, httpconn=%p): "
  2737. "%u bytes consumed\n",
  2738. pRequest, pRequest->pHttpConn, TotalBytesConsumed
  2739. ));
  2740. if (TotalBytesConsumed)
  2741. {
  2742. UlpConsumeBytesFromConnection(
  2743. pRequest->pHttpConn,
  2744. TotalBytesConsumed
  2745. );
  2746. }
  2747. //
  2748. // all done
  2749. //
  2750. } // UlpProcessBufferQueue
  2751. /***************************************************************************++
  2752. Routine Description:
  2753. This function subtracts from the total number of bytes currently buffered
  2754. on the UL_HTTP_CONNECTION object. If there are bytes from the transport
  2755. that we previously refused, this function may issue a receive to restart
  2756. the flow of data from TCP.
  2757. Arguments:
  2758. pConnection - the connection on which the bytes came in
  2759. BytesCount - the number of bytes consumed
  2760. --***************************************************************************/
  2761. VOID
  2762. UlpConsumeBytesFromConnection(
  2763. IN PUL_HTTP_CONNECTION pConnection,
  2764. IN ULONG ByteCount
  2765. )
  2766. {
  2767. KIRQL oldIrql;
  2768. ULONG SpaceAvailable;
  2769. ULONG BytesToRead;
  2770. BOOLEAN IssueReadIrp;
  2771. //
  2772. // Sanity check.
  2773. //
  2774. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  2775. ASSERT(ByteCount != 0);
  2776. //
  2777. // Set up locals.
  2778. //
  2779. BytesToRead = 0;
  2780. IssueReadIrp = FALSE;
  2781. //
  2782. // Consume the bytes.
  2783. //
  2784. UlAcquireSpinLock(
  2785. &pConnection->BufferingInfo.BufferingSpinLock,
  2786. &oldIrql
  2787. );
  2788. ASSERT(ByteCount <= pConnection->BufferingInfo.BytesBuffered);
  2789. if (ByteCount > pConnection->BufferingInfo.BytesBuffered)
  2790. {
  2791. //
  2792. // This should never happen, but if it does then make sure
  2793. // we don't subtract more BufferedBytes than we have.
  2794. //
  2795. ByteCount = pConnection->BufferingInfo.BytesBuffered;
  2796. }
  2797. //
  2798. // Compute the new number of buffered bytes.
  2799. //
  2800. pConnection->BufferingInfo.BytesBuffered -= ByteCount;
  2801. //
  2802. // Trace.
  2803. //
  2804. if (g_UlMaxBufferedBytes > pConnection->BufferingInfo.BytesBuffered)
  2805. {
  2806. SpaceAvailable = g_UlMaxBufferedBytes
  2807. - pConnection->BufferingInfo.BytesBuffered;
  2808. }
  2809. else
  2810. {
  2811. SpaceAvailable = 0;
  2812. }
  2813. UlTrace(HTTP_IO, (
  2814. "UlpConsumeBytesFromConnection(pconn = %p, bytes = %ld)\n"
  2815. " Space = %ld, buffered %ld, not taken = %ld\n",
  2816. pConnection,
  2817. ByteCount,
  2818. SpaceAvailable,
  2819. pConnection->BufferingInfo.BytesBuffered,
  2820. pConnection->BufferingInfo.TransportBytesNotTaken
  2821. ));
  2822. //
  2823. // See if we need to issue a receive to restart the flow of data.
  2824. //
  2825. if ((SpaceAvailable > 0) &&
  2826. (pConnection->BufferingInfo.TransportBytesNotTaken > 0) &&
  2827. (!pConnection->BufferingInfo.ReadIrpPending))
  2828. {
  2829. //
  2830. // Remember that we issued an IRP.
  2831. //
  2832. pConnection->BufferingInfo.ReadIrpPending = TRUE;
  2833. //
  2834. // Issue the Read IRP outside the spinlock.
  2835. //
  2836. IssueReadIrp = TRUE;
  2837. BytesToRead = pConnection->BufferingInfo.TransportBytesNotTaken;
  2838. //
  2839. // Don't read more bytes than we want to buffer.
  2840. //
  2841. BytesToRead = MIN(BytesToRead, SpaceAvailable);
  2842. }
  2843. UlReleaseSpinLock(
  2844. &pConnection->BufferingInfo.BufferingSpinLock,
  2845. oldIrql
  2846. );
  2847. if (IssueReadIrp)
  2848. {
  2849. NTSTATUS Status;
  2850. PUL_REQUEST_BUFFER pRequestBuffer;
  2851. //
  2852. // get a new request buffer, but initialize it
  2853. // with a bogus number. We have to allocate it now,
  2854. // but we want to set the number when the data
  2855. // arrives in the completion routine (like UlHttpReceive
  2856. // does) to avoid synchronization trouble.
  2857. //
  2858. pRequestBuffer = UlCreateRequestBuffer(
  2859. BytesToRead,
  2860. (ULONG)-1 // BufferNumber
  2861. );
  2862. if (pRequestBuffer)
  2863. {
  2864. //
  2865. // Add a backpointer to the connection.
  2866. //
  2867. pRequestBuffer->pConnection = pConnection;
  2868. //
  2869. // We've got the buffer. Issue the receive.
  2870. // Reference the connection so it doesn't
  2871. // go away while we're waiting. The reference
  2872. // will be removed after the completion.
  2873. //
  2874. UL_REFERENCE_HTTP_CONNECTION( pConnection );
  2875. Status = UlReceiveData(
  2876. pConnection->pConnection,
  2877. pRequestBuffer->pBuffer,
  2878. BytesToRead,
  2879. &UlpRestartHttpReceive,
  2880. pRequestBuffer
  2881. );
  2882. }
  2883. else
  2884. {
  2885. //
  2886. // We're out of memory. Nothing we can do.
  2887. //
  2888. Status = STATUS_NO_MEMORY;
  2889. }
  2890. if (!NT_SUCCESS(Status))
  2891. {
  2892. //
  2893. // Couldn't issue the read. Close the connection.
  2894. //
  2895. UlCloseConnection(
  2896. pConnection->pConnection,
  2897. TRUE, // AbortiveDisconnect
  2898. NULL, // pCompletionRoutine
  2899. NULL // pCompletionContext
  2900. );
  2901. }
  2902. }
  2903. } // UlpConsumeBytesFromConnection
  2904. /***************************************************************************++
  2905. Routine Description:
  2906. Once a connection get disconnected gracefully and there's still unreceived
  2907. data on it. We have to drain this extra bytes to expect the tdi disconnect
  2908. indication. We have to drain this data because we need the disconnect indi
  2909. cation to clean up the connection. And we cannot simply abort it. If we do
  2910. not do this we will leak this connection object and finally it will cause
  2911. shutdown failures.
  2912. Arguments:
  2913. pConnection - stuck connection we have to drain out to complete the
  2914. gracefull disconnect.
  2915. --***************************************************************************/
  2916. VOID
  2917. UlpDiscardBytesFromConnection(
  2918. IN PUL_HTTP_CONNECTION pConnection
  2919. )
  2920. {
  2921. NTSTATUS Status;
  2922. PUL_REQUEST_BUFFER pRequestBuffer;
  2923. KIRQL OldIrql;
  2924. ULONG BytesToRead;
  2925. //
  2926. // Sanity check and init
  2927. //
  2928. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  2929. Status = STATUS_SUCCESS;
  2930. BytesToRead = 0;
  2931. pRequestBuffer = NULL;
  2932. //
  2933. // Mark the drain state and restart receive if necessary.
  2934. //
  2935. UlAcquireSpinLock(
  2936. &pConnection->BufferingInfo.BufferingSpinLock,
  2937. &OldIrql
  2938. );
  2939. pConnection->BufferingInfo.DrainAfterDisconnect = TRUE;
  2940. //
  2941. // Even if ReadIrp is pending, it does not matter as we will just discard
  2942. // the indications from now on. We indicate this by marking the above flag
  2943. //
  2944. if ( pConnection->BufferingInfo.ReadIrpPending ||
  2945. pConnection->BufferingInfo.TransportBytesNotTaken == 0
  2946. )
  2947. {
  2948. UlReleaseSpinLock(
  2949. &pConnection->BufferingInfo.BufferingSpinLock,
  2950. OldIrql
  2951. );
  2952. return;
  2953. }
  2954. //
  2955. // As soon as we enter this "DrainAfterDisconnect" state we will not be
  2956. // processing and inserting request buffers anymore. For any new receive
  2957. // indications, we will just mark the whole available data as taken and
  2958. // don't do nothing about it.
  2959. //
  2960. WRITE_REF_TRACE_LOG2(
  2961. g_pTdiTraceLog,
  2962. pConnection->pConnection->pTraceLog,
  2963. REF_ACTION_DRAIN_UL_CONNECTION_START,
  2964. pConnection->pConnection->ReferenceCount,
  2965. pConnection->pConnection,
  2966. __FILE__,
  2967. __LINE__
  2968. );
  2969. //
  2970. // We need to issue a receive to restart the flow of data again. Therefore
  2971. // we can drain.
  2972. //
  2973. pConnection->BufferingInfo.ReadIrpPending = TRUE;
  2974. BytesToRead = pConnection->BufferingInfo.TransportBytesNotTaken;
  2975. UlReleaseSpinLock(
  2976. &pConnection->BufferingInfo.BufferingSpinLock,
  2977. OldIrql
  2978. );
  2979. //
  2980. // Do not try to drain more than g_UlMaxBufferedBytes. If necessary we will
  2981. // issue another receive later.
  2982. //
  2983. BytesToRead = MIN( BytesToRead, g_UlMaxBufferedBytes );
  2984. UlTrace(HTTP_IO,(
  2985. "UlpDiscardBytesFromConnection: pConnection (%p) consuming %d\n",
  2986. pConnection,
  2987. BytesToRead
  2988. ));
  2989. //
  2990. // Issue the Read IRP outside the spinlock. Issue the receive. Reference
  2991. // the connection so it doesn't go away while we're waiting. The reference
  2992. // will be removed after the completion.
  2993. //
  2994. pRequestBuffer = UlCreateRequestBuffer( BytesToRead,
  2995. (ULONG)-1
  2996. );
  2997. if (pRequestBuffer)
  2998. {
  2999. //
  3000. // We won't use this buffer but simply discard it when completion happens.
  3001. // Lets still set the pConnection so that completion function doesn't
  3002. // complain
  3003. //
  3004. pRequestBuffer->pConnection = pConnection;
  3005. UL_REFERENCE_HTTP_CONNECTION( pConnection );
  3006. Status = UlReceiveData(pConnection->pConnection,
  3007. pRequestBuffer->pBuffer,
  3008. BytesToRead,
  3009. &UlpRestartHttpReceive,
  3010. pRequestBuffer
  3011. );
  3012. }
  3013. else
  3014. {
  3015. //
  3016. // We're out of memory. Nothing we can do.
  3017. //
  3018. Status = STATUS_NO_MEMORY;
  3019. }
  3020. if ( !NT_SUCCESS(Status) )
  3021. {
  3022. //
  3023. // Couldn't issue the receive. ABORT the connection.
  3024. //
  3025. // CODEWORK: We need a real abort here. If connection is
  3026. // previously gracefully disconnected and a fatal failure
  3027. // happened during drain after disconnect. This abort will
  3028. // be discarded by the Close handler. We have to provide a
  3029. // way to do a forceful abort here.
  3030. //
  3031. UlCloseConnection(
  3032. pConnection->pConnection,
  3033. TRUE, // Abortive
  3034. NULL, // pCompletionRoutine
  3035. NULL // pCompletionContext
  3036. );
  3037. }
  3038. } // UlpDiscardBytesFromConnection
  3039. /***************************************************************************++
  3040. Routine Description:
  3041. Called on a read completion. This happens when we had stopped
  3042. data indications for some reason and then restarted them. This
  3043. function mirrors UlHttpReceive.
  3044. Arguments:
  3045. pContext - pointer to the FilterRawRead IRP
  3046. Status - Status from UlReceiveData
  3047. Information - bytes transferred
  3048. --***************************************************************************/
  3049. VOID
  3050. UlpRestartHttpReceive(
  3051. IN PVOID pContext,
  3052. IN NTSTATUS Status,
  3053. IN ULONG_PTR Information
  3054. )
  3055. {
  3056. PUL_HTTP_CONNECTION pConnection;
  3057. PUL_REQUEST_BUFFER pRequestBuffer;
  3058. KIRQL oldIrql;
  3059. ULONG TransportBytesNotTaken;
  3060. pRequestBuffer = (PUL_REQUEST_BUFFER)pContext;
  3061. ASSERT(UL_IS_VALID_REQUEST_BUFFER(pRequestBuffer));
  3062. pConnection = pRequestBuffer->pConnection;
  3063. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  3064. if (NT_SUCCESS(Status))
  3065. {
  3066. //
  3067. // update our stats
  3068. //
  3069. UlAcquireSpinLock(
  3070. &pConnection->BufferingInfo.BufferingSpinLock,
  3071. &oldIrql
  3072. );
  3073. ASSERT(Information <= pConnection->BufferingInfo.TransportBytesNotTaken);
  3074. //
  3075. // We've now read they bytes from the transport and
  3076. // buffered them.
  3077. //
  3078. pConnection->BufferingInfo.TransportBytesNotTaken -= (ULONG)Information;
  3079. pConnection->BufferingInfo.BytesBuffered += (ULONG)Information;
  3080. pConnection->BufferingInfo.ReadIrpPending = FALSE;
  3081. if ( pConnection->BufferingInfo.DrainAfterDisconnect )
  3082. {
  3083. //
  3084. // Just free the memory and restart the receive if necessary.
  3085. //
  3086. TransportBytesNotTaken = pConnection->BufferingInfo.TransportBytesNotTaken;
  3087. UlReleaseSpinLock(
  3088. &pConnection->BufferingInfo.BufferingSpinLock,
  3089. oldIrql
  3090. );
  3091. WRITE_REF_TRACE_LOG2(
  3092. g_pTdiTraceLog,
  3093. pConnection->pConnection->pTraceLog,
  3094. REF_ACTION_DRAIN_UL_CONNECTION_RESTART,
  3095. pConnection->pConnection->ReferenceCount,
  3096. pConnection->pConnection,
  3097. __FILE__,
  3098. __LINE__
  3099. );
  3100. if ( TransportBytesNotTaken )
  3101. {
  3102. //
  3103. // Keep draining ...
  3104. //
  3105. UlpDiscardBytesFromConnection( pConnection );
  3106. }
  3107. UlTrace(HTTP_IO,(
  3108. "UlpRestartHttpReceive(d): pConnection (%p) drained %d remaining %d\n",
  3109. pConnection,
  3110. Information,
  3111. TransportBytesNotTaken
  3112. ));
  3113. //
  3114. // Free the request buffer. And release our reference.
  3115. //
  3116. UlFreeRequestBuffer( pRequestBuffer );
  3117. UL_DEREFERENCE_HTTP_CONNECTION( pConnection );
  3118. return;
  3119. }
  3120. //
  3121. // Get the request buffer ready to be inserted.
  3122. //
  3123. pRequestBuffer->UsedBytes = (ULONG) Information;
  3124. ASSERT( 0 != pRequestBuffer->UsedBytes );
  3125. pRequestBuffer->BufferNumber = pConnection->NextBufferNumber;
  3126. pConnection->NextBufferNumber++;
  3127. UlReleaseSpinLock(
  3128. &pConnection->BufferingInfo.BufferingSpinLock,
  3129. oldIrql
  3130. );
  3131. UlTrace(HTTP_IO, (
  3132. "UlpRestartHttpReceive(pconn = %p, %x, %ld)\n"
  3133. " buffered = %ld, not taken = %ld\n",
  3134. pConnection,
  3135. Status,
  3136. (ULONG)Information,
  3137. pConnection->BufferingInfo.BytesBuffered,
  3138. pConnection->BufferingInfo.TransportBytesNotTaken
  3139. ));
  3140. //
  3141. // queue it off
  3142. //
  3143. UlTrace( PARSER, (
  3144. "*** Request Buffer %p has connection %p\n",
  3145. pRequestBuffer,
  3146. pConnection
  3147. ));
  3148. UL_QUEUE_WORK_ITEM(
  3149. &(pRequestBuffer->WorkItem),
  3150. &UlpHandleRequest
  3151. );
  3152. }
  3153. else
  3154. {
  3155. UlCloseConnection(
  3156. pConnection->pConnection,
  3157. TRUE,
  3158. NULL,
  3159. NULL
  3160. );
  3161. //
  3162. // Release the reference we added to the connection
  3163. // before issuing the read. Normally this ref would
  3164. // be released in UlpHandleRequest.
  3165. //
  3166. UL_DEREFERENCE_HTTP_CONNECTION(pConnection);
  3167. //
  3168. // free the request buffer.
  3169. //
  3170. UlFreeRequestBuffer(pRequestBuffer);
  3171. }
  3172. } // UlpRestartHttpReceive
  3173. /***************************************************************************++
  3174. Routine Description:
  3175. cancels the pending user mode irp which was to receive entity body. this
  3176. routine ALWAYS results in the irp being completed.
  3177. note: we queue off to cancel in order to process the cancellation at lower
  3178. irql.
  3179. Arguments:
  3180. pDeviceObject - the device object
  3181. pIrp - the irp to cancel
  3182. --***************************************************************************/
  3183. VOID
  3184. UlpCancelEntityBody(
  3185. IN PDEVICE_OBJECT pDeviceObject,
  3186. IN PIRP pIrp
  3187. )
  3188. {
  3189. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  3190. ASSERT(pIrp != NULL);
  3191. //
  3192. // release the cancel spinlock. This means the cancel routine
  3193. // must be the one completing the irp (to avoid the race of
  3194. // completion + reuse prior to the cancel routine running).
  3195. //
  3196. IoReleaseCancelSpinLock(pIrp->CancelIrql);
  3197. //
  3198. // queue the cancel to a worker to ensure passive irql.
  3199. //
  3200. UL_CALL_PASSIVE(
  3201. UL_WORK_ITEM_FROM_IRP( pIrp ),
  3202. &UlpCancelEntityBodyWorker
  3203. );
  3204. } // UlpCancelEntityBody
  3205. /***************************************************************************++
  3206. Routine Description:
  3207. Actually performs the cancel for the irp.
  3208. Arguments:
  3209. pWorkItem - the work item to process.
  3210. --***************************************************************************/
  3211. VOID
  3212. UlpCancelEntityBodyWorker(
  3213. IN PUL_WORK_ITEM pWorkItem
  3214. )
  3215. {
  3216. PIRP pIrp;
  3217. PUL_INTERNAL_REQUEST pRequest;
  3218. //
  3219. // Sanity check.
  3220. //
  3221. PAGED_CODE();
  3222. //
  3223. // grab the irp off the work item
  3224. //
  3225. pIrp = UL_WORK_ITEM_TO_IRP( pWorkItem );
  3226. ASSERT(IS_VALID_IRP(pIrp));
  3227. //
  3228. // grab the request off the irp
  3229. //
  3230. pRequest = (PUL_INTERNAL_REQUEST)(
  3231. IoGetCurrentIrpStackLocation(pIrp)->
  3232. Parameters.DeviceIoControl.Type3InputBuffer
  3233. );
  3234. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3235. //
  3236. // grab the lock protecting the queue'd irp
  3237. //
  3238. UlAcquireResourceExclusive(&(pRequest->pHttpConn->Resource), TRUE);
  3239. //
  3240. // does it need to be dequeue'd ?
  3241. //
  3242. if (pIrp->Tail.Overlay.ListEntry.Flink != NULL)
  3243. {
  3244. //
  3245. // remove it
  3246. //
  3247. RemoveEntryList(&(pIrp->Tail.Overlay.ListEntry));
  3248. pIrp->Tail.Overlay.ListEntry.Flink = NULL;
  3249. pIrp->Tail.Overlay.ListEntry.Blink = NULL;
  3250. }
  3251. //
  3252. // let the lock go
  3253. //
  3254. UlReleaseResource(&(pRequest->pHttpConn->Resource));
  3255. //
  3256. // let our reference go
  3257. //
  3258. IoGetCurrentIrpStackLocation(pIrp)->
  3259. Parameters.DeviceIoControl.Type3InputBuffer = NULL;
  3260. UL_DEREFERENCE_INTERNAL_REQUEST(pRequest);
  3261. //
  3262. // complete the irp
  3263. //
  3264. pIrp->IoStatus.Status = STATUS_CANCELLED;
  3265. pIrp->IoStatus.Information = 0;
  3266. UlTrace(HTTP_IO, (
  3267. "UlpCancelEntityBodyWorker(pIrp=%p): Status=0x%x.\n",
  3268. pIrp, pIrp->IoStatus.Status
  3269. ));
  3270. UlCompleteRequest( pIrp, g_UlPriorityBoost );
  3271. } // UlpCancelEntityBodyWorker
  3272. //
  3273. // types and functions for sending error responses
  3274. //
  3275. typedef struct _UL_HTTP_ERROR_ENTRY
  3276. {
  3277. USHORT StatusCode;
  3278. ULONG ReasonLength;
  3279. PSTR pReason;
  3280. ULONG BodyLength;
  3281. PSTR pBody;
  3282. } UL_HTTP_ERROR_ENTRY, PUL_HTTP_ERROR_ENTRY;
  3283. #define HTTP_ERROR_ENTRY(StatusCode, pReason, pBody) \
  3284. { \
  3285. (StatusCode), \
  3286. sizeof((pReason))-sizeof(CHAR), \
  3287. (pReason), \
  3288. sizeof((pBody))-sizeof(CHAR), \
  3289. (pBody) \
  3290. }
  3291. //
  3292. // ErrorTable[] must match the order of the UL_HTTP_ERROR enum
  3293. // in httptypes.h
  3294. //
  3295. const
  3296. UL_HTTP_ERROR_ENTRY ErrorTable[] =
  3297. {
  3298. //
  3299. // UlError
  3300. //
  3301. HTTP_ERROR_ENTRY(400, "Bad Request", "<H1>Bad Request</H1>"),
  3302. //
  3303. // UlErrorVerb
  3304. //
  3305. HTTP_ERROR_ENTRY(400, "Bad Request", "<H1>Bad Request (invalid verb)</H1>"),
  3306. //
  3307. // UlErrorUrl
  3308. //
  3309. HTTP_ERROR_ENTRY(400, "Bad Request", "<H1>Bad Request (invalid url)</H1>"),
  3310. //
  3311. // UlErrorHeader
  3312. //
  3313. HTTP_ERROR_ENTRY(400, "Bad Request", "<H1>Bad Request (invalid header name)</H1>"),
  3314. //
  3315. // UlErrorHost
  3316. //
  3317. HTTP_ERROR_ENTRY(400, "Bad Request", "<H1>Bad Request (invalid hostname)</H1>"),
  3318. //
  3319. // UlErrorCRLF
  3320. //
  3321. HTTP_ERROR_ENTRY(400, "Bad Request", "<H1>Bad Request (invalid CR or LF)</H1>"),
  3322. //
  3323. // UlErrorNum
  3324. //
  3325. HTTP_ERROR_ENTRY(400, "Bad Request", "<H1>Bad Request (invalid number)</H1>"),
  3326. //
  3327. // UlErrorFieldLength
  3328. //
  3329. HTTP_ERROR_ENTRY(400, "Bad Request", "<H1>Bad Request (Header Field Too Long)</H1>"),
  3330. //
  3331. // UlErrorUrlLength
  3332. //
  3333. HTTP_ERROR_ENTRY(414, "Bad Request", "<H1>Url Too Long</H1>"),
  3334. //
  3335. // UlErrorRequestLength
  3336. //
  3337. HTTP_ERROR_ENTRY(400, "Bad Request", "<H1>Bad Request (Request Header Too Long)</H1>"),
  3338. //
  3339. // UlErrorVersion
  3340. //
  3341. HTTP_ERROR_ENTRY(505, "HTTP Version not supported", "<H1>HTTP Version not supported</H1>"),
  3342. //
  3343. // UlErrorUnavailable
  3344. //
  3345. HTTP_ERROR_ENTRY(503, "Service Unavailable", "<H1>Service Unavailable</H1>"),
  3346. //
  3347. // UlErrorContentLength
  3348. //
  3349. HTTP_ERROR_ENTRY(411, "Length required", "<H1>Length required</H1>"),
  3350. //
  3351. // UlErrorEntityTooLarge
  3352. //
  3353. HTTP_ERROR_ENTRY(413, "Request Entity Too Large", "<H1>Request Entity Too Large</H1>"),
  3354. //
  3355. // UlErrorConnectionLimit
  3356. //
  3357. HTTP_ERROR_ENTRY(403, "Forbidden", "<H1>Forbidden - Too many users</H1>"),
  3358. //
  3359. // UlErrorNotImplemented
  3360. //
  3361. HTTP_ERROR_ENTRY(501, "Not Implemented", "<H1>Not Implemented</H1>"),
  3362. // UlErrorInternalServer
  3363. //
  3364. HTTP_ERROR_ENTRY(500, "Internal Server Error", "<H1>Internal Server Error</H1>"),
  3365. //
  3366. // UlErrorPreconditionFailed
  3367. //
  3368. HTTP_ERROR_ENTRY(412, "Precondition Failed", "<H1>Precondition Failed</H1>"),
  3369. //
  3370. // UlErrorForbiddenUrl
  3371. //
  3372. HTTP_ERROR_ENTRY(403, "Forbidden", "<H1>Forbidden (Invalid URL)</H1>"),
  3373. }; // ErrorTable[]
  3374. /***************************************************************************++
  3375. Routine Description:
  3376. You should hold the connection Resource before calling this
  3377. function.
  3378. Arguments:
  3379. self explanatory
  3380. --***************************************************************************/
  3381. VOID
  3382. UlSendErrorResponse(
  3383. PUL_HTTP_CONNECTION pConnection
  3384. )
  3385. {
  3386. NTSTATUS Status;
  3387. PUL_INTERNAL_REQUEST pRequest;
  3388. HTTP_RESPONSE Response;
  3389. HTTP_DATA_CHUNK DataChunk;
  3390. PUL_INTERNAL_RESPONSE pKeResponse = NULL;
  3391. CHAR ContentType[] = "text/html";
  3392. USHORT ContentTypeLength = sizeof(ContentType) - sizeof(CHAR);
  3393. //
  3394. // Sanity check.
  3395. //
  3396. PAGED_CODE();
  3397. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pConnection));
  3398. ASSERT(UlDbgResourceOwnedExclusive(&pConnection->Resource));
  3399. pRequest = pConnection->pRequest;
  3400. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3401. //
  3402. // To prevent sending back double responses. We will
  3403. // check if user (WP) has already sent one.
  3404. //
  3405. pConnection->WaitingForResponse = 1;
  3406. UlTrace( PARSER, (
  3407. "*** pConnection %p->WaitingForResponse = 1\n",
  3408. pConnection
  3409. ));
  3410. //
  3411. // We will send a response back. won't we ?
  3412. // An error response.
  3413. //
  3414. if (1 == InterlockedCompareExchange(
  3415. (PLONG)&pRequest->SentResponse,
  3416. 1,
  3417. 0
  3418. ))
  3419. {
  3420. UlTrace( PARSER, (
  3421. "*** pConnection %p, pRequest %p, skipping SendError.\n",
  3422. pConnection,
  3423. pRequest
  3424. ));
  3425. return;
  3426. }
  3427. //
  3428. // Proceed with constructing and sending the error
  3429. // back to the client
  3430. //
  3431. RtlZeroMemory(&Response, sizeof(Response));
  3432. if (pRequest->ErrorCode >= DIMENSION(ErrorTable))
  3433. {
  3434. pRequest->ErrorCode = UlError;
  3435. }
  3436. Response.StatusCode = ErrorTable[pRequest->ErrorCode].StatusCode;
  3437. Response.ReasonLength = ErrorTable[pRequest->ErrorCode].ReasonLength;
  3438. Response.pReason = ErrorTable[pRequest->ErrorCode].pReason;
  3439. Response.Headers.pKnownHeaders[HttpHeaderContentType].RawValueLength =
  3440. ContentTypeLength;
  3441. Response.Headers.pKnownHeaders[HttpHeaderContentType].pRawValue =
  3442. ContentType;
  3443. //
  3444. // generate a body
  3445. //
  3446. DataChunk.DataChunkType = HttpDataChunkFromMemory;
  3447. DataChunk.FromMemory.pBuffer = ErrorTable[pRequest->ErrorCode].pBody;
  3448. DataChunk.FromMemory.BufferLength = ErrorTable[pRequest->ErrorCode].BodyLength;
  3449. Status = UlCaptureHttpResponse(
  3450. &Response,
  3451. pRequest,
  3452. pRequest->Version,
  3453. pRequest->Verb,
  3454. 1,
  3455. &DataChunk,
  3456. UlCaptureCopyDataInKernelMode,
  3457. FALSE,
  3458. NULL,
  3459. &pKeResponse
  3460. );
  3461. if (NT_SUCCESS(Status) == FALSE)
  3462. goto end;
  3463. Status = UlPrepareHttpResponse(
  3464. pRequest->Version,
  3465. &Response,
  3466. pKeResponse
  3467. );
  3468. if (NT_SUCCESS(Status) == FALSE)
  3469. goto end;
  3470. Status = UlSendHttpResponse(
  3471. pRequest,
  3472. pKeResponse,
  3473. HTTP_SEND_RESPONSE_FLAG_DISCONNECT,
  3474. &UlpCompleteSendResponse,
  3475. pKeResponse
  3476. );
  3477. if (NT_SUCCESS(Status) == FALSE)
  3478. goto end;
  3479. ASSERT(Status == STATUS_PENDING);
  3480. end:
  3481. if (NT_SUCCESS(Status) == FALSE)
  3482. {
  3483. if (pKeResponse != NULL)
  3484. {
  3485. UL_DEREFERENCE_INTERNAL_RESPONSE(pKeResponse);
  3486. }
  3487. //
  3488. // Abort the connection
  3489. //
  3490. UlTrace(HTTP_IO, (
  3491. "http!UlSendErrorResponse(%p): Failed to send error response\n",
  3492. pConnection
  3493. ));
  3494. //
  3495. // cancel any pending io
  3496. //
  3497. UlCancelRequestIo(pRequest);
  3498. //
  3499. // abort the connection this request is associated with
  3500. //
  3501. UlCloseConnection(
  3502. pRequest->pHttpConn->pConnection,
  3503. TRUE,
  3504. NULL,
  3505. NULL
  3506. );
  3507. }
  3508. } // UlSendErrorResponse
  3509. VOID
  3510. UlpCompleteSendResponse(
  3511. IN PVOID pCompletionContext,
  3512. IN NTSTATUS Status,
  3513. IN ULONG_PTR Information
  3514. )
  3515. {
  3516. //
  3517. // release the response
  3518. //
  3519. if (pCompletionContext != NULL)
  3520. {
  3521. UL_DEREFERENCE_INTERNAL_RESPONSE(
  3522. (PUL_INTERNAL_RESPONSE)(pCompletionContext)
  3523. );
  3524. }
  3525. } // UlpCompleteSendResponse
  3526. //
  3527. // Types and functions for sending simple status responses
  3528. //
  3529. // REVIEW: Does this status code need to be localized?
  3530. // REVIEW: Do we need to load this as a localized resource?
  3531. //
  3532. typedef struct _UL_SIMPLE_STATUS_ITEM
  3533. {
  3534. UL_WORK_ITEM WorkItem;
  3535. ULONG Length;
  3536. PCHAR pMessage;
  3537. PMDL pMdl;
  3538. PUL_HTTP_CONNECTION pHttpConn;
  3539. } UL_SIMPLE_STATUS_ITEM, *PUL_SIMPLE_STATUS_ITEM;
  3540. typedef struct _UL_HTTP_SIMPLE_STATUS_ENTRY
  3541. {
  3542. USHORT StatusCode; // HTTP Status
  3543. ULONG Length; // size (bytes) of response in pResponse, minus trailing NULL
  3544. PSTR pResponse; // header line only with trailing <CRLF><CRLF>
  3545. PMDL pMdl; // MDL allocated at startup
  3546. } UL_HTTP_SIMPLE_STATUS_ENTRY, *PUL_HTTP_SIMPLE_STATUS_ENTRY;
  3547. #define HTTP_SIMPLE_STATUS_ENTRY(StatusCode, pResp) \
  3548. { \
  3549. (StatusCode), \
  3550. sizeof((pResp))-sizeof(CHAR), \
  3551. (pResp), \
  3552. NULL \
  3553. }
  3554. //
  3555. // This must match the order of UL_HTTP_SIMPLE_STATUS in httptypes.h
  3556. //
  3557. UL_HTTP_SIMPLE_STATUS_ENTRY g_SimpleStatusTable[] =
  3558. {
  3559. //
  3560. // UlStatusContinue
  3561. //
  3562. HTTP_SIMPLE_STATUS_ENTRY( 100, "HTTP/1.1 100 Continue\r\n\r\n" ),
  3563. //
  3564. // UlStatusNoContent
  3565. //
  3566. HTTP_SIMPLE_STATUS_ENTRY( 204, "HTTP/1.1 204 No Content\r\n\r\n" ),
  3567. //
  3568. // UlStatusNotModified (must add Date:)
  3569. //
  3570. HTTP_SIMPLE_STATUS_ENTRY( 304, "HTTP/1.1 304 Not Modified\r\nDate:" ),
  3571. };
  3572. /***************************************************************************++
  3573. Routine Description:
  3574. Sends a "Simple" status response: one which does not have a body and is
  3575. terminated by the first empty line after the header field(s).
  3576. See RFC 2616, Section 4.4 for more info.
  3577. Notes:
  3578. According to RFC 2616, Section 8.2.3 [Use of the 100 (Continue)
  3579. Status], "An origin server that sends a 100 (Continue) response
  3580. MUST ultimately send a final status code, once the request body is
  3581. received and processed, unless it terminates the transport
  3582. connection prematurely."
  3583. The connection will not be closed after the response is sent. Caller
  3584. is responsible for cleanup.
  3585. Arguments:
  3586. pRequest a valid pointer to an internal request object
  3587. Response the status code for the simple response to send
  3588. Return
  3589. ULONG the number of bytes sent for this simple response
  3590. if not successfull returns zero
  3591. --***************************************************************************/
  3592. ULONG
  3593. UlSendSimpleStatus(
  3594. PUL_INTERNAL_REQUEST pRequest,
  3595. UL_HTTP_SIMPLE_STATUS Response
  3596. )
  3597. {
  3598. NTSTATUS Status;
  3599. ULONG BytesSent;
  3600. //
  3601. // Sanity check.
  3602. //
  3603. PAGED_CODE();
  3604. ASSERT(UL_IS_VALID_INTERNAL_REQUEST(pRequest));
  3605. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pRequest->pHttpConn));
  3606. ASSERT( (Response >= 0) && (Response < UlStatusMaxStatus) );
  3607. BytesSent = 0;
  3608. if ( UlStatusNotModified == Response )
  3609. {
  3610. PUL_SIMPLE_STATUS_ITEM pItem;
  3611. ULONG Length;
  3612. PCHAR pTemp;
  3613. CHAR DateBuffer[DATE_HDR_LENGTH + 1];
  3614. LARGE_INTEGER liNow;
  3615. // 304 MUST include a "Date:" header, which is
  3616. // present on the cached item.
  3617. // TODO: Add the ETag as well.
  3618. // Calc size of buffer to send
  3619. Length = g_SimpleStatusTable[Response].Length + // Pre-formed message
  3620. 1 + // space
  3621. DATE_HDR_LENGTH + // size of date field
  3622. (2 * CRLF_SIZE) + // size of two <CRLF> sequences
  3623. 1 ; // trailing NULL (for nifty debug printing)
  3624. // Alloc some non-page buffer for the response
  3625. pItem = UL_ALLOCATE_STRUCT_WITH_SPACE(
  3626. NonPagedPool,
  3627. UL_SIMPLE_STATUS_ITEM,
  3628. Length,
  3629. UL_SIMPLE_STATUS_ITEM_TAG
  3630. );
  3631. if (!pItem)
  3632. {
  3633. Status = STATUS_INSUFFICIENT_RESOURCES;
  3634. goto end;
  3635. }
  3636. // We need to hold a ref to the connection while we send.
  3637. UL_REFERENCE_HTTP_CONNECTION(pRequest->pHttpConn);
  3638. pItem->pHttpConn = pRequest->pHttpConn;
  3639. pItem->Length = Length - 1; // Don't include the NULL in the outbound message
  3640. pItem->pMessage = (PCHAR) (pItem + 1);
  3641. // Get date buffer
  3642. GenerateDateHeader(
  3643. (PUCHAR) DateBuffer,
  3644. &liNow
  3645. );
  3646. // Copy the chunks into the Message buffer
  3647. pTemp = UlStrPrintStr(
  3648. pItem->pMessage,
  3649. g_SimpleStatusTable[Response].pResponse,
  3650. ' '
  3651. );
  3652. pTemp = UlStrPrintStr(
  3653. pTemp,
  3654. DateBuffer,
  3655. '\r' // this is a Nifty Trick(tm) to get a "\r\n\r\n"
  3656. ); // sequence at the end of the buffer.
  3657. pTemp = UlStrPrintStr(
  3658. pTemp,
  3659. "\n\r\n",
  3660. '\0'
  3661. );
  3662. UlTrace(HTTP_IO, (
  3663. "http!SendSimpleStatus: %s\n",
  3664. pItem->pMessage
  3665. ));
  3666. // Construct MDL for buffer
  3667. pItem->pMdl = UlAllocateMdl(
  3668. pItem->pMessage,
  3669. pItem->Length,
  3670. FALSE,
  3671. FALSE,
  3672. NULL
  3673. );
  3674. MmBuildMdlForNonPagedPool(pItem->pMdl);
  3675. BytesSent = pItem->Length;
  3676. //
  3677. // Call UlSendData, passing pMdl as the completion context
  3678. // (so the completion routine can release it...)
  3679. //
  3680. Status = UlSendData(
  3681. pRequest->pHttpConn->pConnection,
  3682. pItem->pMdl,
  3683. pItem->Length,
  3684. UlpRestartSendSimpleStatus,
  3685. pItem, // Completion Context
  3686. NULL, // Own IRP
  3687. NULL, // Own IRP Context
  3688. FALSE // Initiate Disconnect
  3689. );
  3690. }
  3691. else
  3692. {
  3693. //
  3694. // Proceed with constructing and sending the simple response
  3695. // back to the client. Assumes caller will deref both the
  3696. // UL_INTERNAL_REQUEST and the UL_HTTP_CONNECTION
  3697. //
  3698. Status = UlSendData(
  3699. pRequest->pHttpConn->pConnection,
  3700. g_SimpleStatusTable[Response].pMdl,
  3701. g_SimpleStatusTable[Response].Length,
  3702. UlpRestartSendSimpleStatus,
  3703. NULL, // Completion Context
  3704. NULL, // Own IRP
  3705. NULL, // Own IRP Context
  3706. FALSE // Initiate Disconnect
  3707. );
  3708. BytesSent = g_SimpleStatusTable[Response].Length;
  3709. }
  3710. end:
  3711. if (NT_SUCCESS(Status) == FALSE)
  3712. {
  3713. //
  3714. // Abort the connection
  3715. //
  3716. UlTrace(HTTP_IO, (
  3717. "http!SendSimpleStatus(%p, %d): aborting request\n",
  3718. pRequest,
  3719. Response
  3720. ));
  3721. //
  3722. // cancel any pending io
  3723. //
  3724. UlCancelRequestIo(pRequest);
  3725. //
  3726. // abort the connection this request is associated with
  3727. //
  3728. UlCloseConnection(
  3729. pRequest->pHttpConn->pConnection,
  3730. TRUE,
  3731. NULL,
  3732. NULL
  3733. );
  3734. return 0;
  3735. }
  3736. else
  3737. {
  3738. return BytesSent;
  3739. }
  3740. } // UlSendSimpleStatus
  3741. /***************************************************************************++
  3742. Routine Description:
  3743. Callback for when UlSendData completes sending a UL_SIMPLE_STATUS message
  3744. Arguments:
  3745. pCompletionContext (OPTIONAL) -- If non-NULL, a pointer to a
  3746. UL_SIMPLE_STATUS_ITEM.
  3747. Status -- Ignored.
  3748. Information -- Ignored.
  3749. --***************************************************************************/
  3750. VOID
  3751. UlpRestartSendSimpleStatus(
  3752. IN PVOID pCompletionContext,
  3753. IN NTSTATUS Status,
  3754. IN ULONG_PTR Information
  3755. )
  3756. {
  3757. PUL_SIMPLE_STATUS_ITEM pItem;
  3758. UlTrace(HTTP_IO, (
  3759. "http!SendSimpleStatusCompletionRoutine: \n"
  3760. " pCompletionContext: %p\n"
  3761. " Status: 0x%08X\n"
  3762. " Information: %p\n",
  3763. pCompletionContext,
  3764. Status,
  3765. Information
  3766. ));
  3767. if ( pCompletionContext )
  3768. {
  3769. pItem = (PUL_SIMPLE_STATUS_ITEM) pCompletionContext;
  3770. // Queue up work item for passive level
  3771. UL_QUEUE_WORK_ITEM(
  3772. &pItem->WorkItem,
  3773. &UlpSendSimpleCleanupWorker
  3774. );
  3775. }
  3776. } // UlpRestartSendSimpleStatus
  3777. /***************************************************************************++
  3778. Routine Description:
  3779. Worker function to do cleanup work that shouldn't happen above DPC level.
  3780. Arguments:
  3781. pWorkItem -- If non-NULL, a pointer to a UL_WORK_ITEM
  3782. contained within a UL_SIMPLE_STATUS_ITEM.
  3783. --***************************************************************************/
  3784. VOID
  3785. UlpSendSimpleCleanupWorker(
  3786. IN PUL_WORK_ITEM pWorkItem
  3787. )
  3788. {
  3789. KIRQL OldIrql;
  3790. PAGED_CODE();
  3791. ASSERT(pWorkItem);
  3792. PUL_SIMPLE_STATUS_ITEM pItem;
  3793. pItem = CONTAINING_RECORD(
  3794. pWorkItem,
  3795. UL_SIMPLE_STATUS_ITEM,
  3796. WorkItem
  3797. );
  3798. UlTrace(HTTP_IO, (
  3799. "http!SendSimpleStatusCleanupWorker (%p) \n",
  3800. pWorkItem
  3801. ));
  3802. ASSERT(UL_IS_VALID_HTTP_CONNECTION(pItem->pHttpConn));
  3803. //
  3804. // start the Connection Timeout timer
  3805. //
  3806. UlLockTimeoutInfo(
  3807. &(pItem->pHttpConn->TimeoutInfo),
  3808. &OldIrql
  3809. );
  3810. UlSetConnectionTimer(
  3811. &(pItem->pHttpConn->TimeoutInfo),
  3812. TimerConnectionIdle
  3813. );
  3814. UlUnlockTimeoutInfo(
  3815. &(pItem->pHttpConn->TimeoutInfo),
  3816. OldIrql
  3817. );
  3818. UlEvaluateTimerState(
  3819. &(pItem->pHttpConn->TimeoutInfo)
  3820. );
  3821. //
  3822. // deref http connection
  3823. //
  3824. UL_DEREFERENCE_HTTP_CONNECTION( pItem->pHttpConn );
  3825. // if the pCompletionContext is non-NULL< it's a struct which holds the MDL
  3826. // and the memory allocated for the 304 (Not Modified) response. Release both.
  3827. UlFreeMdl( pItem->pMdl );
  3828. UL_FREE_POOL( pItem, UL_SIMPLE_STATUS_ITEM_TAG );
  3829. } // UlpSendSimpleCleanupWorker
  3830. /***************************************************************************++
  3831. Routine Description:
  3832. Alloc & Init the MDL used by the UlpSendContinue function.
  3833. --***************************************************************************/
  3834. NTSTATUS
  3835. UlInitializeHttpRcv()
  3836. {
  3837. NTSTATUS Status;
  3838. PUL_HTTP_SIMPLE_STATUS_ENTRY pSE;
  3839. int i;
  3840. for ( i = 0; i < UlStatusMaxStatus; i++ )
  3841. {
  3842. pSE = &g_SimpleStatusTable[i];
  3843. // Create a MDL for the response header
  3844. pSE->pMdl = UlAllocateMdl(
  3845. pSE->pResponse,
  3846. pSE->Length,
  3847. FALSE,
  3848. FALSE,
  3849. NULL
  3850. );
  3851. if (!pSE->pMdl)
  3852. {
  3853. Status = STATUS_INSUFFICIENT_RESOURCES;
  3854. goto end;
  3855. }
  3856. MmBuildMdlForNonPagedPool(pSE->pMdl);
  3857. }
  3858. Status = STATUS_SUCCESS;
  3859. end:
  3860. if ( STATUS_SUCCESS != Status )
  3861. {
  3862. //
  3863. // FAILED: cleanup any allocated MDLs
  3864. //
  3865. for ( i = 0; i < UlStatusMaxStatus; i++ )
  3866. {
  3867. pSE = &g_SimpleStatusTable[i];
  3868. if (pSE->pMdl)
  3869. {
  3870. UlFreeMdl( pSE->pMdl );
  3871. pSE->pMdl = NULL;
  3872. }
  3873. }
  3874. }
  3875. return Status;
  3876. } // UlInitializeHttpRcv
  3877. /***************************************************************************++
  3878. Routine Description:
  3879. Free the MDL used by the UlpSendContinue function.
  3880. --***************************************************************************/
  3881. VOID
  3882. UlTerminateHttpRcv()
  3883. {
  3884. NTSTATUS Status;
  3885. PUL_HTTP_SIMPLE_STATUS_ENTRY pSE;
  3886. int i;
  3887. for ( i = 0; i < UlStatusMaxStatus; i++ )
  3888. {
  3889. pSE = &g_SimpleStatusTable[i];
  3890. if (pSE->pMdl)
  3891. {
  3892. ASSERT(0 == ((pSE->pMdl->MdlFlags) & MDL_PAGES_LOCKED));
  3893. UlFreeMdl( pSE->pMdl );
  3894. }
  3895. }
  3896. } // UlTerminateHttpRcv
  3897. #if DBG
  3898. /***************************************************************************++
  3899. Routine Description:
  3900. Invasive assert predicate. DEBUG ONLY!!! Use this only inside an
  3901. ASSERT() macro.
  3902. --***************************************************************************/
  3903. BOOLEAN
  3904. UlpIsValidRequestBufferList(
  3905. PUL_HTTP_CONNECTION pHttpConn
  3906. )
  3907. {
  3908. PLIST_ENTRY pEntry;
  3909. PUL_REQUEST_BUFFER pReqBuf;
  3910. ULONG LastSeqNum = 0;
  3911. BOOLEAN fRet = TRUE;
  3912. PAGED_CODE();
  3913. ASSERT( pHttpConn );
  3914. //
  3915. // pop from the head
  3916. //
  3917. pEntry = pHttpConn->BufferHead.Flink;
  3918. while ( pEntry != &(pHttpConn->BufferHead) )
  3919. {
  3920. pReqBuf = CONTAINING_RECORD( pEntry,
  3921. UL_REQUEST_BUFFER,
  3922. ListEntry
  3923. );
  3924. ASSERT( UL_IS_VALID_REQUEST_BUFFER(pReqBuf) );
  3925. ASSERT( pReqBuf->UsedBytes != 0 );
  3926. if ( 0 == pReqBuf->UsedBytes )
  3927. {
  3928. fRet = FALSE;
  3929. }
  3930. //
  3931. // ignore case when BufferNumber is zero (0).
  3932. //
  3933. if ( pReqBuf->BufferNumber && (LastSeqNum >= pReqBuf->BufferNumber) )
  3934. {
  3935. fRet = FALSE;
  3936. }
  3937. LastSeqNum = pReqBuf->BufferNumber;
  3938. pEntry = pEntry->Flink;
  3939. }
  3940. return fRet;
  3941. }
  3942. #endif // DBG
  3943. /***************************************************************************++
  3944. Routine Description:
  3945. Add a reference of the request buffer in the internal request.
  3946. --***************************************************************************/
  3947. BOOLEAN
  3948. UlpReferenceBuffers(
  3949. IN PUL_INTERNAL_REQUEST pRequest,
  3950. IN PUL_REQUEST_BUFFER pRequestBuffer
  3951. )
  3952. {
  3953. PUL_REQUEST_BUFFER * pNewRefBuffers;
  3954. if (pRequest->UsedRefBuffers >= pRequest->AllocRefBuffers)
  3955. {
  3956. ASSERT( pRequest->UsedRefBuffers == pRequest->AllocRefBuffers );
  3957. pNewRefBuffers = UL_ALLOCATE_ARRAY(
  3958. NonPagedPool,
  3959. PUL_REQUEST_BUFFER,
  3960. pRequest->AllocRefBuffers + ALLOC_REQUEST_BUFFER_INCREMENT,
  3961. UL_REF_REQUEST_BUFFER_POOL_TAG
  3962. );
  3963. if (!pNewRefBuffers)
  3964. {
  3965. return FALSE;
  3966. }
  3967. RtlCopyMemory(
  3968. pNewRefBuffers,
  3969. pRequest->pRefBuffers,
  3970. pRequest->UsedRefBuffers * sizeof(PUL_REQUEST_BUFFER)
  3971. );
  3972. if (pRequest->AllocRefBuffers > 1)
  3973. {
  3974. UL_FREE_POOL(
  3975. pRequest->pRefBuffers,
  3976. UL_REF_REQUEST_BUFFER_POOL_TAG
  3977. );
  3978. }
  3979. pRequest->AllocRefBuffers += ALLOC_REQUEST_BUFFER_INCREMENT;
  3980. pRequest->pRefBuffers = pNewRefBuffers;
  3981. }
  3982. pRequest->pRefBuffers[pRequest->UsedRefBuffers] = pRequestBuffer;
  3983. pRequest->UsedRefBuffers++;
  3984. UL_REFERENCE_REQUEST_BUFFER(pRequestBuffer);
  3985. return TRUE;
  3986. }