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

1484 lines
33 KiB

  1. /*++
  2. Copyright (c) 1998-2002 Microsoft Corporation
  3. Module Name:
  4. sendresponse.h
  5. Abstract:
  6. This module contains declarations for manipulating HTTP responses.
  7. Author:
  8. Keith Moore (keithmo) 07-Aug-1998
  9. Revision History:
  10. Paul McDaniel (paulmcd) 15-Mar-1999 Modified SendResponse
  11. --*/
  12. #ifndef _SENDRESPONSE_H_
  13. #define _SENDRESPONSE_H_
  14. //
  15. // Forwarders.
  16. //
  17. typedef struct _UL_INTERNAL_DATA_CHUNK *PUL_INTERNAL_DATA_CHUNK;
  18. typedef struct _UL_INTERNAL_REQUEST *PUL_INTERNAL_REQUEST;
  19. typedef struct _UL_INTERNAL_RESPONSE *PUL_INTERNAL_RESPONSE;
  20. typedef struct _UL_HTTP_CONNECTION *PUL_HTTP_CONNECTION;
  21. typedef struct _UL_LOG_DATA_BUFFER *PUL_LOG_DATA_BUFFER;
  22. typedef struct _UL_URI_CACHE_ENTRY *PUL_URI_CACHE_ENTRY;
  23. typedef enum _UL_SEND_CACHE_RESULT
  24. {
  25. UlSendCacheResultNotSet, // Not yet set
  26. UlSendCacheServedFromCache, // Served from cache successfully
  27. UlSendCacheMiss, // Need to bounce up to user mode
  28. UlSendCacheConnectionRefused, // Connection is refused (con limits)
  29. UlSendCachePreconditionFailed, // Need to terminate connection
  30. UlSendCacheFailed, // Other failure (memory etc) need to terminate
  31. UlSendCacheMaximum
  32. } UL_SEND_CACHE_RESULT, *PUL_SEND_CACHE_RESULT;
  33. #define TRANSLATE_SEND_CACHE_RESULT(r) \
  34. ((r) == UlSendCacheResultNotSet ? "ResultNotSet" : \
  35. (r) == UlSendCacheServedFromCache ? "ServedFromCache" : \
  36. (r) == UlSendCacheMiss ? "CacheMiss" : \
  37. (r) == UlSendCacheConnectionRefused ? "ConnectionRefused" : \
  38. (r) == UlSendCachePreconditionFailed ? "PreconditionFailed" : \
  39. (r) == UlSendCacheFailed ? "SendCacheFailed" : "UNKNOWN")
  40. typedef enum _UL_RESUME_PARSING_TYPE
  41. {
  42. UlResumeParsingNone, // No need to resume parsing
  43. UlResumeParsingOnLastSend, // Resume parsing on last send
  44. UlResumeParsingOnSendCompletion, // Resume parsing on send completion
  45. UlResumeParsingMaximum
  46. } UL_RESUME_PARSING_TYPE, *PUL_RESUME_PARSING_TYPE;
  47. NTSTATUS
  48. UlSendHttpResponse(
  49. IN PUL_INTERNAL_REQUEST pRequest,
  50. IN PUL_INTERNAL_RESPONSE pResponse,
  51. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  52. IN PVOID pCompletionContext
  53. );
  54. NTSTATUS
  55. UlSendCachedResponse(
  56. IN PUL_HTTP_CONNECTION pHttpConn,
  57. OUT PUL_SEND_CACHE_RESULT pSendCacheResult,
  58. OUT PBOOLEAN pResumeParsing
  59. );
  60. NTSTATUS
  61. UlCacheAndSendResponse(
  62. IN PUL_INTERNAL_REQUEST pRequest,
  63. IN PUL_INTERNAL_RESPONSE pResponse,
  64. IN PUL_APP_POOL_PROCESS pProcess,
  65. IN HTTP_CACHE_POLICY Policy,
  66. IN PUL_COMPLETION_ROUTINE pCompletionRoutine,
  67. IN PVOID pCompletionContext,
  68. OUT PBOOLEAN pServedFromCache
  69. );
  70. typedef enum _UL_CAPTURE_FLAGS
  71. {
  72. UlCaptureNothing = 0x00,
  73. UlCaptureCopyData = 0x01,
  74. UlCaptureKernelMode = 0x02,
  75. UlCaptureCopyDataInKernelMode = UlCaptureCopyData | UlCaptureKernelMode,
  76. } UL_CAPTURE_FLAGS;
  77. typedef struct _UL_INTERNAL_DATA_CHUNK
  78. {
  79. //
  80. // Chunk type.
  81. //
  82. HTTP_DATA_CHUNK_TYPE ChunkType;
  83. //
  84. // The data chunk structures, one per supported data chunk type.
  85. //
  86. union
  87. {
  88. //
  89. // From memory data chunk.
  90. //
  91. struct
  92. {
  93. PMDL pMdl;
  94. PVOID pCopiedBuffer;
  95. PVOID pUserBuffer;
  96. ULONG BufferLength;
  97. } FromMemory;
  98. //
  99. // From file handle data chunk.
  100. //
  101. struct
  102. {
  103. HTTP_BYTE_RANGE ByteRange;
  104. HANDLE FileHandle;
  105. UL_FILE_CACHE_ENTRY FileCacheEntry;
  106. } FromFileHandle;
  107. //
  108. // From fragment cache data chunk.
  109. //
  110. struct
  111. {
  112. PUL_URI_CACHE_ENTRY pCacheEntry;
  113. } FromFragmentCache;
  114. };
  115. } UL_INTERNAL_DATA_CHUNK, *PUL_INTERNAL_DATA_CHUNK;
  116. #define IS_FROM_MEMORY( pchunk ) \
  117. ( (pchunk)->ChunkType == HttpDataChunkFromMemory )
  118. #define IS_FROM_FILE_HANDLE( pchunk ) \
  119. ( (pchunk)->ChunkType == HttpDataChunkFromFileHandle )
  120. #define IS_FROM_FRAGMENT_CACHE( pchunk ) \
  121. ( (pchunk)->ChunkType == HttpDataChunkFromFragmentCache )
  122. #define UL_IS_VALID_INTERNAL_RESPONSE(x) \
  123. HAS_VALID_SIGNATURE(x, UL_INTERNAL_RESPONSE_POOL_TAG)
  124. //
  125. // WARNING! All fields of this structure must be explicitly initialized.
  126. //
  127. typedef struct _UL_INTERNAL_RESPONSE
  128. {
  129. //
  130. // NonPagedPool
  131. //
  132. //
  133. // This MUST be the first field in the structure. This is the linkage
  134. // used by the lookaside package for storing entries in the lookaside
  135. // list.
  136. //
  137. SLIST_ENTRY LookasideEntry;
  138. //
  139. // UL_INTERNAL_RESPONSE_POOL_TAG
  140. //
  141. ULONG Signature;
  142. //
  143. // Reference count.
  144. //
  145. LONG ReferenceCount;
  146. //
  147. // The original request.
  148. //
  149. PUL_INTERNAL_REQUEST pRequest;
  150. //
  151. // Does the response need to perform a sync I/O read?
  152. //
  153. BOOLEAN SyncRead;
  154. //
  155. // Was a Content-Length specified?
  156. //
  157. BOOLEAN ContentLengthSpecified;
  158. //
  159. // Should we generate a Date: header?
  160. //
  161. BOOLEAN GenDateHeader;
  162. //
  163. // Was Transfer-Encoding "Chunked" specified?
  164. //
  165. BOOLEAN ChunkedSpecified;
  166. //
  167. // Is this from a lookaside list? Used to determine how to free.
  168. //
  169. BOOLEAN FromLookaside;
  170. //
  171. // Is this from kernel mode (UlSendErrorResponse)?
  172. //
  173. BOOLEAN FromKernelMode;
  174. //
  175. // Has this response gone through the EnqueueSendHttpResponse logic?
  176. //
  177. BOOLEAN SendEnqueued;
  178. //
  179. // Should we try to copy some data so we can complete the IRP early?
  180. //
  181. BOOLEAN CopySend;
  182. //
  183. // The maximum IRP stack size of all file systems associated
  184. // with this response.
  185. //
  186. CCHAR MaxFileSystemStackSize;
  187. //
  188. // If parsing needs to be resumed on send completion.
  189. //
  190. UL_RESUME_PARSING_TYPE ResumeParsingType;
  191. //
  192. // HTTP_SEND_RESPONSE flags.
  193. //
  194. ULONG Flags;
  195. //
  196. // Status code & verb.
  197. //
  198. USHORT StatusCode;
  199. HTTP_VERB Verb;
  200. //
  201. // Should we generate a ConnectionHeader?
  202. //
  203. UL_CONN_HDR ConnHeader;
  204. //
  205. // The headers.
  206. //
  207. ULONG HeaderLength;
  208. ULONG VariableHeaderLength;
  209. PUCHAR pHeaders;
  210. PUCHAR pVariableHeader;
  211. //
  212. // System time of Date header
  213. //
  214. LARGE_INTEGER CreationTime;
  215. //
  216. // ETag from HTTP_RESPONSE
  217. //
  218. ULONG ETagLength;
  219. PUCHAR pETag;
  220. //
  221. // Content-Type and Content-Encoding from HTTP_RESPONSE
  222. //
  223. UL_CONTENT_TYPE ContentType;
  224. ULONG ContentEncodingLength;
  225. PUCHAR pContentEncoding;
  226. //
  227. // Optional pointer to the space containing all embedded
  228. // file names and copied data. This may be NULL for in-memory-only
  229. // responses that are strictly locked down.
  230. //
  231. ULONG AuxBufferLength;
  232. PVOID pAuxiliaryBuffer;
  233. //
  234. // Logging data passed down by the user
  235. //
  236. PUL_LOG_DATA_BUFFER pLogData;
  237. //
  238. // Length of the entire response
  239. //
  240. ULONGLONG ResponseLength;
  241. //
  242. // Total length of the FromMemory chunks of the response
  243. //
  244. ULONGLONG FromMemoryLength;
  245. //
  246. // "Quota" taken in either ConnectionSendLimit or GlobalSendLimit
  247. //
  248. ULONGLONG ConnectionSendBytes;
  249. ULONGLONG GlobalSendBytes;
  250. //
  251. // Total number of bytes transferred for the entire
  252. // response. These are necessary to properly complete the IRP.
  253. //
  254. ULONGLONG BytesTransferred;
  255. //
  256. // A push lock taken when a send (call to TDI) is in progress.
  257. //
  258. UL_PUSH_LOCK PushLock;
  259. //
  260. // IoStatus and IRP used to complete the send response IRP.
  261. //
  262. IO_STATUS_BLOCK IoStatus;
  263. PIRP pIrp;
  264. //
  265. // Completion routine & context.
  266. //
  267. PUL_COMPLETION_ROUTINE pCompletionRoutine;
  268. PVOID pCompletionContext;
  269. //
  270. // Current file read offset and bytes remaining.
  271. //
  272. ULARGE_INTEGER FileOffset;
  273. ULARGE_INTEGER FileBytesRemaining;
  274. //
  275. // The total number of chunks in pDataChunks[].
  276. //
  277. ULONG ChunkCount;
  278. //
  279. // The current chunk in pDataChunks[].
  280. //
  281. ULONG CurrentChunk;
  282. //
  283. // The data chunks describing the data for this response.
  284. //
  285. UL_INTERNAL_DATA_CHUNK pDataChunks[0];
  286. } UL_INTERNAL_RESPONSE, *PUL_INTERNAL_RESPONSE;
  287. #define IS_SEND_COMPLETE( resp ) \
  288. ( ( (resp)->CurrentChunk ) == (resp)->ChunkCount )
  289. #define IS_DISCONNECT_TIME( resp ) \
  290. ( (((resp)->Flags & HTTP_SEND_RESPONSE_FLAG_DISCONNECT) != 0) && \
  291. (((resp)->Flags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0) )
  292. //
  293. // Types of trackers
  294. //
  295. typedef enum _UL_TRACKER_TYPE
  296. {
  297. UlTrackerTypeSend,
  298. UlTrackerTypeBuildUriEntry,
  299. UlTrackerTypeMaximum
  300. } UL_TRACKER_TYPE, *PUL_TRACKER_TYPE;
  301. //
  302. // A MDL_RUN is a set of MDLs that came from the same source (either
  303. // a series of memory buffers, or data from a single file read) that
  304. // can be released all at once with the same mechanism.
  305. //
  306. #define UL_MAX_MDL_RUNS 5
  307. typedef struct _UL_MDL_RUN
  308. {
  309. PMDL pMdlTail;
  310. UL_FILE_BUFFER FileBuffer;
  311. } UL_MDL_RUN, *PUL_MDL_RUN;
  312. //
  313. // The UL_CHUNK_TRACKER is for iterating through the chunks in
  314. // a UL_INTERNAL_RESPONSE. It is used for sending responses
  315. // and generating cache entries.
  316. //
  317. // WARNING! All fields of this structure must be explicitly initialized.
  318. //
  319. typedef struct _UL_CHUNK_TRACKER
  320. {
  321. //
  322. // This MUST be the first field in the structure. This is the linkage
  323. // used by the lookaside package for storing entries in the lookaside
  324. // list.
  325. //
  326. SLIST_ENTRY LookasideEntry;
  327. //
  328. // A signature.
  329. //
  330. ULONG Signature;
  331. //
  332. // Refcount on the tracker. We only use this refcount for the non-cache
  333. // case to sync various aynsc paths happening because of two outstanding
  334. // IRPs; Read and Send IRPs.
  335. //
  336. LONG RefCount;
  337. //
  338. // Flag to understand whether we have completed the send request on
  339. // this tracker or not. To synch the multiple completion paths.
  340. //
  341. LONG Terminated;
  342. //
  343. // Is this from a lookaside list? Used to determine how to free.
  344. //
  345. BOOLEAN FromLookaside;
  346. //
  347. // First piece of the response (MDL_RUN) of SendHttpResponse/EntityBody.
  348. //
  349. BOOLEAN FirstResponse;
  350. //
  351. // type of tracker
  352. //
  353. UL_TRACKER_TYPE Type;
  354. //
  355. // this connection keeps our reference count on the UL_CONNECTION
  356. //
  357. PUL_HTTP_CONNECTION pHttpConnection;
  358. //
  359. // The actual response.
  360. //
  361. PUL_INTERNAL_RESPONSE pResponse;
  362. //
  363. // The precreated file read and send IRP.
  364. //
  365. PIRP pIrp;
  366. //
  367. // The precreated IRP context for send.
  368. //
  369. UL_IRP_CONTEXT IrpContext;
  370. //
  371. // A work item, used for queuing to a worker thread.
  372. //
  373. UL_WORK_ITEM WorkItem;
  374. //
  375. // WARNING: RtlZeroMemory is only called for feilds below this line.
  376. // All fields above should be explicitly initialized.
  377. //
  378. IO_STATUS_BLOCK IoStatus;
  379. //
  380. // Used to queue the tracker on the pending response list.
  381. //
  382. LIST_ENTRY ListEntry;
  383. union
  384. {
  385. struct _SEND_TRACK_INFO
  386. {
  387. //
  388. // The head of the MDL chain buffered for this send.
  389. //
  390. PMDL pMdlHead;
  391. //
  392. // Pointer to the Next field of the last MDL on the chain.
  393. // This makes it very easy to append to the chain.
  394. //
  395. PMDL *pMdlLink;
  396. //
  397. // The number of bytes currently buffered in the MDL chain.
  398. //
  399. ULONG BytesBuffered;
  400. //
  401. // The number of active MDL runs.
  402. //
  403. ULONG MdlRunCount;
  404. //
  405. // This is the MDL in the MDL chain starting from pMdlHead that
  406. // we are going to split.
  407. //
  408. PMDL pMdlToSplit;
  409. //
  410. // This is the MDL whose Next field points to pMdlToSplit or it is
  411. // NULL when pMdlToSplit == pMdlHead.
  412. //
  413. PMDL pMdlPrevious;
  414. //
  415. // This is the partial MDL we have built for the split send and
  416. // represents the first part of the data in pMdlToSplit; or
  417. // it can be pMdlToSplit itself where the MDL chain up to
  418. // pMdlToSplit has exactly 1/2 of BytesBuffered.
  419. //
  420. PMDL pMdlSplitFirst;
  421. //
  422. // This is the partial MDL we have built for the split send and
  423. // represents the second part of the data in pMdlToSplit; or
  424. // it can be pMdlToSplit->Next where the MDL chain up to
  425. // pMdlToSplit has exactly 1/2 of BytesBuffered.
  426. //
  427. PMDL pMdlSplitSecond;
  428. //
  429. // How many sends (TDI calls) we have issued to flush the tracker.
  430. //
  431. LONG SendCount;
  432. //
  433. // The MDL runs.
  434. //
  435. UL_MDL_RUN MdlRuns[UL_MAX_MDL_RUNS];
  436. } SendInfo;
  437. struct _BUILD_TRACK_INFO
  438. {
  439. //
  440. // The cache entry
  441. //
  442. PUL_URI_CACHE_ENTRY pUriEntry;
  443. //
  444. // File buffer information for reading.
  445. //
  446. UL_FILE_BUFFER FileBuffer;
  447. //
  448. // Offset inside pUriEntry->pMdl to copy the next buffer.
  449. //
  450. ULONG Offset;
  451. } BuildInfo;
  452. };
  453. } UL_CHUNK_TRACKER, *PUL_CHUNK_TRACKER;
  454. #define IS_VALID_CHUNK_TRACKER( tracker ) \
  455. (HAS_VALID_SIGNATURE(tracker, UL_CHUNK_TRACKER_POOL_TAG) \
  456. && ((tracker)->Type < UlTrackerTypeMaximum) )
  457. //
  458. // This structure is for tracking an autonomous send with one full response
  459. //
  460. // WARNING! All fields of this structure must be explicitly initialized.
  461. //
  462. typedef struct _UL_FULL_TRACKER
  463. {
  464. //
  465. // This MUST be the first field in the structure. This is the linkage
  466. // used by the lookaside package for storing entries in the lookaside
  467. // list.
  468. //
  469. SLIST_ENTRY LookasideEntry;
  470. //
  471. // A signature.
  472. //
  473. ULONG Signature;
  474. //
  475. // The HTTP Verb
  476. //
  477. HTTP_VERB RequestVerb;
  478. //
  479. // The HTTP status code (e.g. 200).
  480. //
  481. USHORT ResponseStatusCode;
  482. //
  483. // Is this from a lookaside list? Used to determine how to free.
  484. //
  485. BOOLEAN FromLookaside;
  486. //
  487. // Is this from the internal request? Won't try to free if set.
  488. //
  489. BOOLEAN FromRequest;
  490. //
  491. // Set if send is buffered for this response.
  492. //
  493. BOOLEAN SendBuffered;
  494. //
  495. // If parsing needs to be resumed on send completion.
  496. //
  497. UL_RESUME_PARSING_TYPE ResumeParsingType;
  498. //
  499. // A work item, used for queuing to a worker thread.
  500. //
  501. UL_WORK_ITEM WorkItem;
  502. //
  503. // The cache entry.
  504. //
  505. PUL_URI_CACHE_ENTRY pUriEntry;
  506. //
  507. // Preallocated buffer for the fixed headers, variable headers and entity
  508. // body to be copied in the cache-miss case, or for the variable headers
  509. // only in the cache-hit case.
  510. //
  511. ULONG AuxilaryBufferLength;
  512. PUCHAR pAuxiliaryBuffer;
  513. //
  514. // MDL for the variable headers in the cache-hit case or for both the
  515. // fixed headers and variable headers plus the copied entity body in
  516. // the cache-miss case.
  517. //
  518. union
  519. {
  520. PMDL pMdlVariableHeaders;
  521. PMDL pMdlAuxiliary;
  522. };
  523. //
  524. // MDL for the fixed headers in the cache-hit case or for the user
  525. // buffer in the cache-miss case.
  526. //
  527. union
  528. {
  529. PMDL pMdlFixedHeaders;
  530. PMDL pMdlUserBuffer;
  531. };
  532. //
  533. // MDL for the content in the cache-hit case.
  534. //
  535. PMDL pMdlContent;
  536. //
  537. // The original request that is saved for logging purpose.
  538. //
  539. PUL_INTERNAL_REQUEST pRequest;
  540. //
  541. // This connection keeps our reference count on the UL_CONNECTION.
  542. //
  543. PUL_HTTP_CONNECTION pHttpConnection;
  544. //
  545. // The log data captured if any.
  546. //
  547. PUL_LOG_DATA_BUFFER pLogData;
  548. //
  549. // Completion routine & context.
  550. //
  551. PUL_COMPLETION_ROUTINE pCompletionRoutine;
  552. PVOID pCompletionContext;
  553. //
  554. // Flags.
  555. //
  556. ULONG Flags;
  557. //
  558. // The precreated send IRP.
  559. //
  560. PIRP pSendIrp;
  561. //
  562. // The precreated IRP context for send.
  563. //
  564. UL_IRP_CONTEXT IrpContext;
  565. //
  566. // The orignal user send IRP if exists.
  567. //
  568. PIRP pUserIrp;
  569. //
  570. // "Quota" taken in either ConnectionSendLimit or GlobalSendLimit.
  571. //
  572. ULONGLONG ConnectionSendBytes;
  573. ULONGLONG GlobalSendBytes;
  574. //
  575. // I/O status from the completion routine.
  576. //
  577. IO_STATUS_BLOCK IoStatus;
  578. } UL_FULL_TRACKER, *PUL_FULL_TRACKER;
  579. #define IS_VALID_FULL_TRACKER( tracker ) \
  580. HAS_VALID_SIGNATURE(tracker, UL_FULL_TRACKER_POOL_TAG)
  581. //
  582. // An inline function to initialize the full tracker.
  583. //
  584. __inline
  585. VOID
  586. UlInitializeFullTrackerPool(
  587. IN PUL_FULL_TRACKER pTracker,
  588. IN CCHAR SendIrpStackSize
  589. )
  590. {
  591. USHORT SendIrpSize;
  592. UlInitializeWorkItem(&pTracker->WorkItem);
  593. //
  594. // Set up the IRP.
  595. //
  596. SendIrpSize = IoSizeOfIrp(SendIrpStackSize);
  597. pTracker->pSendIrp =
  598. (PIRP)((PCHAR)pTracker +
  599. ALIGN_UP(sizeof(UL_FULL_TRACKER), PVOID));
  600. IoInitializeIrp(
  601. pTracker->pSendIrp,
  602. SendIrpSize,
  603. SendIrpStackSize
  604. );
  605. pTracker->pLogData = NULL;
  606. //
  607. // Set the Mdl's for the FixedHeaders/Variable pair and
  608. // the UserBuffer/AuxiliaryBuffer pair.
  609. //
  610. pTracker->pMdlFixedHeaders =
  611. (PMDL)((PCHAR)pTracker->pSendIrp + SendIrpSize);
  612. pTracker->pMdlVariableHeaders =
  613. (PMDL)((PCHAR)pTracker->pMdlFixedHeaders + g_UlFixedHeadersMdlLength);
  614. pTracker->pMdlContent =
  615. (PMDL)((PCHAR)pTracker->pMdlVariableHeaders + g_UlVariableHeadersMdlLength);
  616. //
  617. // Set up the auxiliary buffer pointer for the variable header plus
  618. // the fixed header and the entity body in the cache-miss case.
  619. //
  620. pTracker->pAuxiliaryBuffer =
  621. (PUCHAR)((PCHAR)pTracker->pMdlContent + g_UlContentMdlLength);
  622. //
  623. // Initialize the auxiliary MDL.
  624. //
  625. MmInitializeMdl(
  626. pTracker->pMdlAuxiliary,
  627. pTracker->pAuxiliaryBuffer,
  628. pTracker->AuxilaryBufferLength
  629. );
  630. MmBuildMdlForNonPagedPool( pTracker->pMdlAuxiliary );
  631. }
  632. NTSTATUS
  633. UlCaptureHttpResponse(
  634. IN PUL_APP_POOL_PROCESS pProcess OPTIONAL,
  635. IN PHTTP_RESPONSE pUserResponse OPTIONAL,
  636. IN PUL_INTERNAL_REQUEST pRequest,
  637. IN USHORT ChunkCount,
  638. IN PHTTP_DATA_CHUNK pDataChunks,
  639. IN UL_CAPTURE_FLAGS Flags,
  640. IN ULONG SendFlags,
  641. IN BOOLEAN CaptureCache,
  642. IN PHTTP_LOG_FIELDS_DATA pLogData OPTIONAL,
  643. OUT PUSHORT pStatusCode,
  644. OUT PUL_INTERNAL_RESPONSE *ppKernelResponse
  645. );
  646. NTSTATUS
  647. UlCaptureUserLogData(
  648. IN PHTTP_LOG_FIELDS_DATA pCapturedUserLogData,
  649. IN PUL_INTERNAL_REQUEST pRequest,
  650. OUT PUL_LOG_DATA_BUFFER *ppKernelLogData
  651. );
  652. NTSTATUS
  653. UlPrepareHttpResponse(
  654. IN HTTP_VERSION Version,
  655. IN PHTTP_RESPONSE pUserResponse,
  656. IN PUL_INTERNAL_RESPONSE pResponse,
  657. IN KPROCESSOR_MODE AccessMode
  658. );
  659. VOID
  660. UlCleanupHttpResponse(
  661. IN PUL_INTERNAL_RESPONSE pResponse
  662. );
  663. VOID
  664. UlReferenceHttpResponse(
  665. IN PUL_INTERNAL_RESPONSE pResponse
  666. REFERENCE_DEBUG_FORMAL_PARAMS
  667. );
  668. VOID
  669. UlDereferenceHttpResponse(
  670. IN PUL_INTERNAL_RESPONSE pResponse
  671. REFERENCE_DEBUG_FORMAL_PARAMS
  672. );
  673. #define UL_REFERENCE_INTERNAL_RESPONSE( presp ) \
  674. UlReferenceHttpResponse( \
  675. (presp) \
  676. REFERENCE_DEBUG_ACTUAL_PARAMS \
  677. )
  678. #define UL_DEREFERENCE_INTERNAL_RESPONSE( presp ) \
  679. UlDereferenceHttpResponse( \
  680. (presp) \
  681. REFERENCE_DEBUG_ACTUAL_PARAMS \
  682. )
  683. PMDL
  684. UlAllocateLockedMdl(
  685. IN PVOID VirtualAddress,
  686. IN ULONG Length,
  687. IN LOCK_OPERATION Operation
  688. );
  689. VOID
  690. UlFreeLockedMdl(
  691. PMDL pMdl
  692. );
  693. NTSTATUS
  694. UlInitializeAndLockMdl(
  695. IN PMDL pMdl,
  696. IN PVOID VirtualAddress,
  697. IN ULONG Length,
  698. IN LOCK_OPERATION Operation
  699. );
  700. VOID
  701. UlCompleteSendResponse(
  702. IN PUL_CHUNK_TRACKER pTracker,
  703. IN NTSTATUS Status
  704. );
  705. VOID
  706. UlSetRequestSendsPending(
  707. IN PUL_INTERNAL_REQUEST pRequest,
  708. IN OUT PUL_LOG_DATA_BUFFER * ppLogData,
  709. IN OUT PUL_RESUME_PARSING_TYPE pResumeParsingType
  710. );
  711. VOID
  712. UlUnsetRequestSendsPending(
  713. IN PUL_INTERNAL_REQUEST pRequest,
  714. OUT PUL_LOG_DATA_BUFFER * ppLogData,
  715. OUT PBOOLEAN pResumeParsing
  716. );
  717. //
  718. // Check pRequest->SentResponse and pRequest->SentLast flags for
  719. // UlSendHttpResponseIoctl
  720. //
  721. __inline
  722. NTSTATUS
  723. UlCheckSendHttpResponseFlags(
  724. IN PUL_INTERNAL_REQUEST pRequest,
  725. IN ULONG Flags
  726. )
  727. {
  728. NTSTATUS Status = STATUS_SUCCESS;
  729. //
  730. // Make sure only one response header goes back. We can test this
  731. // without acquiring the request resource, since the flag is only set
  732. // (never reset).
  733. //
  734. if (1 == InterlockedCompareExchange(
  735. (PLONG)&pRequest->SentResponse,
  736. 1,
  737. 0
  738. ))
  739. {
  740. //
  741. // Already sent a response. Bad.
  742. //
  743. Status = STATUS_INVALID_PARAMETER;
  744. UlTraceError(SEND_RESPONSE, (
  745. "http!UlCheckSendHttpResponseFlags(pRequest = %p (%I64x)) %s\n"
  746. " Tried to send a second response!\n",
  747. pRequest,
  748. pRequest->RequestId,
  749. HttpStatusToString(Status)
  750. ));
  751. goto end;
  752. }
  753. //
  754. // Also ensure that all previous calls to SendHttpResponse
  755. // and SendEntityBody had the MORE_DATA flag set.
  756. //
  757. if (0 == (Flags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA))
  758. {
  759. //
  760. // Remember if the more data flag is not set.
  761. //
  762. if (1 == InterlockedCompareExchange(
  763. (PLONG)&pRequest->SentLast,
  764. 1,
  765. 0
  766. ))
  767. {
  768. Status = STATUS_INVALID_PARAMETER;
  769. UlTraceError(SEND_RESPONSE, (
  770. "http!UlCheckSendHttpResponseFlags(pRequest = %p (%I64x)) %s\n"
  771. " Last send after previous last send!\n",
  772. pRequest,
  773. pRequest->RequestId,
  774. HttpStatusToString(Status)
  775. ));
  776. goto end;
  777. }
  778. }
  779. else
  780. if (pRequest->SentLast == 1)
  781. {
  782. Status = STATUS_INVALID_PARAMETER;
  783. UlTraceError(SEND_RESPONSE, (
  784. "http!UlCheckSendHttpResponseFlags(pRequest = %p (%I64x)) %s\n"
  785. " Tried to send again after last send!\n",
  786. pRequest,
  787. pRequest->RequestId,
  788. HttpStatusToString(Status)
  789. ));
  790. goto end;
  791. }
  792. end:
  793. return Status;
  794. } // UlCheckSendHttpResponseFlags
  795. //
  796. // Check pRequest->SentResponse and pRequest->SentLast flags for
  797. // UlSendEntityBodyIoctl
  798. //
  799. __inline
  800. NTSTATUS
  801. UlCheckSendEntityBodyFlags(
  802. IN PUL_INTERNAL_REQUEST pRequest,
  803. IN ULONG Flags
  804. )
  805. {
  806. NTSTATUS Status = STATUS_SUCCESS;
  807. //
  808. // Ensure a response has already been sent. We can test this without
  809. // acquiring the request resource, since the flag is only set (never
  810. // reset).
  811. //
  812. if (pRequest->SentResponse == 0)
  813. {
  814. //
  815. // The application is sending entity without first having
  816. // send a response header. This is generally an error, however
  817. // we allow the application to override this by passing
  818. // the HTTP_SEND_RESPONSE_FLAG_RAW_HEADER flag.
  819. //
  820. if (Flags & HTTP_SEND_RESPONSE_FLAG_RAW_HEADER)
  821. {
  822. UlTrace(SEND_RESPONSE, (
  823. "http!UlCheckSendEntityBodyFlags(pRequest = %p (%I64x))\n"
  824. " Intentionally sending raw header!\n",
  825. pRequest,
  826. pRequest->RequestId
  827. ));
  828. if (1 == InterlockedCompareExchange(
  829. (PLONG)&pRequest->SentResponse,
  830. 1,
  831. 0
  832. ))
  833. {
  834. Status = STATUS_INVALID_PARAMETER;
  835. UlTraceError(SEND_RESPONSE, (
  836. "http!UlCheckSendEntityBodyFlags(pRequest = %p (%I64x))\n"
  837. " Already sent a response, %s!\n",
  838. pRequest,
  839. pRequest->RequestId,
  840. HttpStatusToString(Status)
  841. ));
  842. goto end;
  843. }
  844. }
  845. else
  846. {
  847. Status = STATUS_INVALID_PARAMETER;
  848. UlTraceError(SEND_RESPONSE, (
  849. "http!UlCheckSendEntityBodyFlags(pRequest = %p (%I64x)) %s\n"
  850. " No response yet!\n",
  851. pRequest,
  852. pRequest->RequestId,
  853. HttpStatusToString(Status)
  854. ));
  855. goto end;
  856. }
  857. }
  858. //
  859. // Also ensure that all previous calls to SendHttpResponse
  860. // and SendEntityBody had the MORE_DATA flag set.
  861. //
  862. if ((Flags & HTTP_SEND_RESPONSE_FLAG_MORE_DATA) == 0)
  863. {
  864. //
  865. // Remember that this was the last send. We shouldn't
  866. // get any more data after this.
  867. //
  868. if (1 == InterlockedCompareExchange(
  869. (PLONG)&pRequest->SentLast,
  870. 1,
  871. 0
  872. ))
  873. {
  874. Status = STATUS_INVALID_PARAMETER;
  875. UlTraceError(SEND_RESPONSE, (
  876. "http!UlCheckSendEntityBodyFlags(pRequest = %p (%I64x)) %s\n"
  877. " Last send after previous last send!\n",
  878. pRequest,
  879. pRequest->RequestId,
  880. HttpStatusToString(Status)
  881. ));
  882. goto end;
  883. }
  884. }
  885. else
  886. if (pRequest->SentLast == 1)
  887. {
  888. Status = STATUS_INVALID_PARAMETER;
  889. UlTraceError(SEND_RESPONSE, (
  890. "http!UlCheckSendEntityBodyFlags(pRequest = %p (%I64x)) %s\n"
  891. " Tried to send again after last send!\n",
  892. pRequest,
  893. pRequest->RequestId,
  894. HttpStatusToString(Status)
  895. ));
  896. goto end;
  897. }
  898. end:
  899. return Status;
  900. } // UlCheckSendEntityBodyFlags
  901. //
  902. // Check/Uncheck ConnectionSendLimit and GlobalSendLimit
  903. //
  904. extern ULONGLONG g_UlTotalSendBytes;
  905. extern UL_EXCLUSIVE_LOCK g_UlTotalSendBytesExLock;
  906. __inline
  907. NTSTATUS
  908. UlCheckSendLimit(
  909. IN PUL_HTTP_CONNECTION pHttpConnection,
  910. IN ULONGLONG SendBytes,
  911. IN PULONGLONG pConnectionSendBytes,
  912. IN PULONGLONG pGlobalSendBytes
  913. )
  914. {
  915. NTSTATUS Status = STATUS_DEVICE_BUSY;
  916. PAGED_CODE();
  917. ASSERT( pConnectionSendBytes && pGlobalSendBytes );
  918. ASSERT( *pConnectionSendBytes == 0 && *pGlobalSendBytes == 0 );
  919. //
  920. // Try ConnectionSendLimit first.
  921. //
  922. UlAcquireExclusiveLock( &pHttpConnection->ExLock );
  923. if (pHttpConnection->TotalSendBytes <= g_UlConnectionSendLimit)
  924. {
  925. pHttpConnection->TotalSendBytes += SendBytes;
  926. *pConnectionSendBytes = SendBytes;
  927. Status = STATUS_SUCCESS;
  928. }
  929. UlReleaseExclusiveLock( &pHttpConnection->ExLock );
  930. if (STATUS_SUCCESS == Status)
  931. {
  932. return Status;
  933. }
  934. //
  935. // If we fail the ConnectionSendLimit test, try GlobalSendLimit.
  936. //
  937. UlAcquireExclusiveLock( &g_UlTotalSendBytesExLock );
  938. if (g_UlTotalSendBytes <= g_UlGlobalSendLimit)
  939. {
  940. g_UlTotalSendBytes += SendBytes;
  941. *pGlobalSendBytes = SendBytes;
  942. Status = STATUS_SUCCESS;
  943. }
  944. UlReleaseExclusiveLock( &g_UlTotalSendBytesExLock );
  945. return Status;
  946. } // UlCheckSendLimit
  947. __inline
  948. VOID
  949. UlUncheckSendLimit(
  950. IN PUL_HTTP_CONNECTION pHttpConnection,
  951. IN ULONGLONG ConnectionSendBytes,
  952. IN ULONGLONG GlobalSendBytes
  953. )
  954. {
  955. if (ConnectionSendBytes)
  956. {
  957. ASSERT( GlobalSendBytes == 0 );
  958. UlAcquireExclusiveLock( &pHttpConnection->ExLock );
  959. pHttpConnection->TotalSendBytes -= ConnectionSendBytes;
  960. UlReleaseExclusiveLock( &pHttpConnection->ExLock );
  961. }
  962. if (GlobalSendBytes)
  963. {
  964. ASSERT( ConnectionSendBytes == 0 );
  965. UlAcquireExclusiveLock( &g_UlTotalSendBytesExLock );
  966. g_UlTotalSendBytes -= GlobalSendBytes;
  967. UlReleaseExclusiveLock( &g_UlTotalSendBytesExLock );
  968. }
  969. } // UlUncheckSendLimit
  970. //
  971. // Checkout a cache entry using the fragment name
  972. //
  973. __inline
  974. NTSTATUS
  975. UlCheckoutFragmentCacheEntry(
  976. IN PCWSTR pFragmentName,
  977. IN ULONG FragmentNameLength,
  978. IN PUL_APP_POOL_PROCESS pProcess,
  979. OUT PUL_URI_CACHE_ENTRY *pFragmentCacheEntry
  980. )
  981. {
  982. PUL_URI_CACHE_ENTRY pCacheEntry = NULL;
  983. URI_SEARCH_KEY SearchKey;
  984. NTSTATUS Status = STATUS_SUCCESS;
  985. *pFragmentCacheEntry = NULL;
  986. if (!g_UriCacheConfig.EnableCache)
  987. {
  988. Status = STATUS_NOT_SUPPORTED;
  989. goto end;
  990. }
  991. SearchKey.Type = UriKeyTypeNormal;
  992. SearchKey.Key.Hash = HashStringNoCaseW(pFragmentName, 0);
  993. SearchKey.Key.Hash = HashRandomizeBits(SearchKey.Key.Hash);
  994. SearchKey.Key.pUri = (PWSTR) pFragmentName;
  995. SearchKey.Key.Length = FragmentNameLength;
  996. SearchKey.Key.pPath = NULL;
  997. pCacheEntry = UlCheckoutUriCacheEntry(&SearchKey);
  998. if (NULL == pCacheEntry)
  999. {
  1000. Status = STATUS_OBJECT_PATH_NOT_FOUND;
  1001. goto end;
  1002. }
  1003. //
  1004. // Return error if the cache entry has no content.
  1005. //
  1006. if (0 == pCacheEntry->ContentLength)
  1007. {
  1008. Status = STATUS_FILE_INVALID;
  1009. goto end;
  1010. }
  1011. //
  1012. // Make sure the process belongs to the same AppPool that created
  1013. // the fragment cache entry or this is a full response cache that
  1014. // is meant to be public.
  1015. //
  1016. if (IS_FRAGMENT_CACHE_ENTRY(pCacheEntry) &&
  1017. pCacheEntry->pAppPool != pProcess->pAppPool)
  1018. {
  1019. Status = STATUS_INVALID_ID_AUTHORITY;
  1020. goto end;
  1021. }
  1022. end:
  1023. if (NT_SUCCESS(Status))
  1024. {
  1025. *pFragmentCacheEntry = pCacheEntry;
  1026. }
  1027. else
  1028. {
  1029. if (pCacheEntry)
  1030. {
  1031. UlCheckinUriCacheEntry(pCacheEntry);
  1032. }
  1033. }
  1034. return Status;
  1035. } // UlCheckoutFragmentCacheEntry
  1036. //
  1037. // Check to if we need to log.
  1038. //
  1039. __inline
  1040. VOID
  1041. UlLogHttpResponse(
  1042. IN PUL_INTERNAL_REQUEST pRequest,
  1043. IN PUL_LOG_DATA_BUFFER pLogData
  1044. )
  1045. {
  1046. //
  1047. // If this is the last response for this request and there was a
  1048. // log data passed down by the user then now its time to log.
  1049. //
  1050. ASSERT( UL_IS_VALID_INTERNAL_REQUEST( pRequest ) );
  1051. ASSERT( IS_VALID_LOG_DATA_BUFFER( pLogData ) );
  1052. //
  1053. // Update the send status if send was not success.
  1054. //
  1055. LOG_UPDATE_WIN32STATUS( pLogData, pRequest->LogStatus );
  1056. //
  1057. // Pick the right logging type.
  1058. //
  1059. if (pLogData->Flags.Binary)
  1060. {
  1061. UlRawLogHttpHit( pLogData );
  1062. }
  1063. else
  1064. {
  1065. UlLogHttpHit( pLogData );
  1066. }
  1067. //
  1068. // Done with pLogData.
  1069. //
  1070. UlDestroyLogDataBuffer( pLogData );
  1071. } // UlLogHttpResponse
  1072. //
  1073. // Validate and sanitize the specified file byte range.
  1074. //
  1075. __inline
  1076. NTSTATUS
  1077. UlSanitizeFileByteRange (
  1078. IN PHTTP_BYTE_RANGE InByteRange,
  1079. OUT PHTTP_BYTE_RANGE OutByteRange,
  1080. IN ULONGLONG FileLength
  1081. )
  1082. {
  1083. ULONGLONG Offset;
  1084. ULONGLONG Length;
  1085. Offset = InByteRange->StartingOffset.QuadPart;
  1086. Length = InByteRange->Length.QuadPart;
  1087. if (HTTP_BYTE_RANGE_TO_EOF == Offset) {
  1088. return STATUS_NOT_SUPPORTED;
  1089. }
  1090. if (HTTP_BYTE_RANGE_TO_EOF == Length) {
  1091. if (Offset > FileLength) {
  1092. return STATUS_FILE_INVALID;
  1093. }
  1094. Length = FileLength - Offset;
  1095. }
  1096. if (Length > FileLength || Offset > (FileLength - Length)) {
  1097. return STATUS_FILE_INVALID;
  1098. }
  1099. OutByteRange->StartingOffset.QuadPart = Offset;
  1100. OutByteRange->Length.QuadPart = Length;
  1101. return STATUS_SUCCESS;
  1102. } // UlSanitizeFileByteRange
  1103. #endif // _SENDRESPONSE_H_