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.

619 lines
15 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. ullog.c (UL IIS+ HIT Logging)
  5. Abstract:
  6. This module implements the logging facilities
  7. for IIS+ including the NCSA, IIS and W3CE types
  8. of logging.
  9. Author:
  10. Ali E. Turkoglu (aliTu) 10-May-2000
  11. Revision History:
  12. --*/
  13. #ifndef _ULLOG_H_
  14. #define _ULLOG_H_
  15. #ifdef __cplusplus
  16. extern "C" {
  17. #endif
  18. //
  19. // Forwarders.
  20. //
  21. typedef struct _UL_FULL_TRACKER *PUL_FULL_TRACKER;
  22. typedef struct _UL_INTERNAL_REQUEST *PUL_INTERNAL_REQUEST;
  23. typedef struct _UL_CONFIG_GROUP_OBJECT *PUL_CONFIG_GROUP_OBJECT;
  24. //
  25. // Brief information about how logging locks works; Whole link list is controlled
  26. // by a global EResource g_pUlNonpagedData->LogListResource. Functions that require
  27. // read access to this list are Hit(),CacheHit() & BufferFlush() and the ReCycle().
  28. // Whereas functions that requires write access are Create(),Remove() and ReConfig().
  29. // Also the log entry eresource (EntryResource) controls the per entry buffer.
  30. // This eresource is acquired shared for the log hits.
  31. //
  32. //
  33. // Structure to hold a log file buffer
  34. //
  35. typedef struct _UL_LOG_FILE_BUFFER
  36. {
  37. //
  38. // PagedPool
  39. //
  40. //
  41. // This MUST be the first field in the structure. This is the linkage
  42. // used by the lookaside package for storing entries in the lookaside
  43. // list.
  44. //
  45. SINGLE_LIST_ENTRY LookasideEntry;
  46. //
  47. // Signature is UL_LOG_FILE_BUFFER_POOL_TAG.
  48. //
  49. ULONG Signature;
  50. //
  51. // I/O status block for UlpBufferFlushAPC.
  52. //
  53. IO_STATUS_BLOCK IoStatusBlock;
  54. //
  55. // Bytes used in the allocated buffered space.
  56. //
  57. LONG BufferUsed;
  58. //
  59. // The real buffered space for log records.
  60. //
  61. PUCHAR Buffer;
  62. } UL_LOG_FILE_BUFFER, *PUL_LOG_FILE_BUFFER;
  63. #define IS_VALID_LOG_FILE_BUFFER( entry ) \
  64. ( (entry != NULL) && ((entry)->Signature == UL_LOG_FILE_BUFFER_POOL_TAG) )
  65. //
  66. // Structure to hold info for a log file
  67. //
  68. typedef struct _UL_LOG_FILE_ENTRY
  69. {
  70. //
  71. // Signature is UL_LOG_FILE_ENTRY_POOL_TAG.
  72. //
  73. ULONG Signature;
  74. //
  75. // This lock protects the whole entry. The ZwWrite operation
  76. // that's called after the lock acquired cannot run at APC_LEVEL
  77. // therefore we have to go back to eresource to prevent a bugcheck
  78. //
  79. UL_ERESOURCE EntryResource;
  80. //
  81. // The name of the file. Full path including the directory.
  82. //
  83. UNICODE_STRING FileName;
  84. PWSTR pShortName;
  85. //
  86. // The open file handle. Note that this handle is only valid
  87. // in the context of the system process.
  88. //
  89. HANDLE hFile;
  90. //
  91. // File-specific information gleaned from the file system.
  92. //
  93. FILE_STANDARD_INFORMATION FileInfo;
  94. //
  95. // links all log file entries
  96. //
  97. LIST_ENTRY LogFileListEntry;
  98. HTTP_LOGGING_TYPE Format;
  99. HTTP_LOGGING_PERIOD Period;
  100. ULONG TruncateSize;
  101. ULONG LogExtFileFlags;
  102. //
  103. // Time to expire field in terms of Hours.
  104. // This could be at most 24 * 31, that's for monthly
  105. // log cycling. Basically we keep a single periodic hourly
  106. // timer and every time it expires we traverse the
  107. // log list to figure out which log files are expired
  108. // at that time by looking at this fields. And then we
  109. // recylcle the log if necessary.
  110. //
  111. ULONG TimeToExpire;
  112. //
  113. // If this entry has MAX_SIZE or UNLIMITED
  114. // log period
  115. //
  116. ULONG SequenceNumber;
  117. ULARGE_INTEGER TotalWritten;
  118. //
  119. // To be able to close the file handle on threadpool.
  120. //
  121. UL_WORK_ITEM WorkItem;
  122. KEVENT CloseEvent;
  123. // TODO: Usage for RecyclePending Flag
  124. // TODO: If disk was full during the last recycle of this entry.
  125. // TODO: This value get set. And later (every 1 minute) it might be
  126. // TODO: (if there's any space then) reset by DISKFULL_TIMER
  127. // TODO: if none of the entries in the list is pending anymore
  128. // TODO: then timer get destroyed until when we hit to disk full
  129. // TODO: again.
  130. union
  131. {
  132. // Flags to show the field states mostly. Used by
  133. // recycling.
  134. LONG Value;
  135. struct
  136. {
  137. ULONG StaleSequenceNumber:1;
  138. ULONG StaleTimeToExpire:1;
  139. ULONG RecyclePending:1;
  140. ULONG LogTitleWritten:1;
  141. };
  142. } Flags;
  143. //
  144. // Each log file entry keeps a fixed amount of log buffer.
  145. // The buffer size is g_AllocationGranularity comes from
  146. // the system's allocation granularity.
  147. //
  148. PUL_LOG_FILE_BUFFER LogBuffer;
  149. } UL_LOG_FILE_ENTRY, *PUL_LOG_FILE_ENTRY;
  150. #define IS_VALID_LOG_FILE_ENTRY( pEntry ) \
  151. ( (pEntry != NULL) && ((pEntry)->Signature == UL_LOG_FILE_ENTRY_POOL_TAG) )
  152. #define SET_SEQUNCE_NUMBER_STALE(pEntry) do{ \
  153. pEntry->Flags.StaleSequenceNumber = 1; \
  154. }while(FALSE)
  155. #define RESET_SEQUNCE_NUMBER_STALE(pEntry) do{ \
  156. pEntry->Flags.StaleSequenceNumber = 0; \
  157. }while(FALSE)
  158. #define SET_TIME_TO_EXPIRE_STALE(pEntry) do{ \
  159. pEntry->Flags.StaleTimeToExpire = 1; \
  160. }while(FALSE)
  161. #define RESET_TIME_TO_EXPIRE_STALE(pEntry) do{ \
  162. pEntry->Flags.StaleTimeToExpire = 0; \
  163. }while(FALSE)
  164. //
  165. // Some directory name related Macros
  166. //
  167. // Device Prefix
  168. #define UL_LOCAL_PATH_PREFIX (L"\\??\\")
  169. #define UL_LOCAL_PATH_PREFIX_LENGTH (4)
  170. #define UL_UNC_PATH_PREFIX (L"\\dosdevices\\UNC")
  171. #define UL_UNC_PATH_PREFIX_LENGTH (15)
  172. #define UL_MAX_PATH_PREFIX_LENGTH (15)
  173. // Put some Limit to the length of the Log Directory name will
  174. // be passed down by WAS. In Bytes.
  175. #define UL_MAX_FULL_PATH_DIR_NAME_SIZE (10*1024)
  176. #define IS_VALID_DIR_NAME(s) \
  177. (((s)!=NULL) && \
  178. ((s)->MaximumLength > (s)->Length) && \
  179. ((s)->Length != 0) && \
  180. ((s)->Buffer != NULL) && \
  181. ((s)->Buffer[(s)->Length/sizeof(WCHAR)] == UNICODE_NULL) && \
  182. ((s)->MaximumLength <= UL_MAX_FULL_PATH_DIR_NAME_SIZE) \
  183. )
  184. //
  185. // Followings are all parts of our internal buffer to hold
  186. // the Logging information. We copy over this info from WP
  187. // buffer upon SendResponse request. Yet few of this fields
  188. // are calculated directly by us and filled.
  189. //
  190. typedef enum _UL_LOG_FIELD_TYPE
  191. {
  192. UlLogFieldDate = 0, // 0
  193. UlLogFieldTime,
  194. UlLogFieldSiteName,
  195. UlLogFieldServerName,
  196. UlLogFieldServerIp,
  197. UlLogFieldMethod, // 5
  198. UlLogFieldUriStem,
  199. UlLogFieldUriQuery,
  200. UlLogFieldProtocolStatus,
  201. UlLogFieldWin32Status,
  202. UlLogFieldServerPort, // 10
  203. UlLogFieldUserName,
  204. UlLogFieldClientIp,
  205. UlLogFieldProtocolVersion,
  206. UlLogFieldUserAgent,
  207. UlLogFieldCookie, // 15
  208. UlLogFieldReferrer,
  209. UlLogFieldHost,
  210. UlLogFieldBytesSent,
  211. UlLogFieldBytesReceived,
  212. UlLogFieldTimeTaken, // 20
  213. UlLogFieldMaximum
  214. } UL_LOG_FIELD_TYPE, *PUL_LOG_FIELD_TYPE;
  215. //
  216. // Size of the pre-allocated log line buffer inside the request structure.
  217. //
  218. #define UL_LOG_LINE_BUFFER_SIZE (4*1024)
  219. #define UL_MAX_LOG_LINE_BUFFER_SIZE (10*1024)
  220. #define UL_MAX_TITLE_BUFFER_SIZE (512)
  221. //
  222. // To avoid the infinite loop situation we have to set the minimum
  223. // allowable log file size to something bigger than maximum allowable
  224. // log record line;
  225. //
  226. #define UL_MIN_ALLOWED_TRUNCATESIZE (16*1024)
  227. C_ASSERT(UL_MIN_ALLOWED_TRUNCATESIZE >
  228. (UL_MAX_TITLE_BUFFER_SIZE + UL_MAX_LOG_LINE_BUFFER_SIZE));
  229. //
  230. // If somebody overwrites the default log buffering size which
  231. // is system granularity size of 64K. We have to make sure the
  232. // buffer size is not smaller then miminum allowed. Which is
  233. // MaximumAlowed Logrecord size of 10K. Also it should be 4k
  234. // aligned therefore makes it 12k at least.
  235. //
  236. #define MINIMUM_ALLOWED_LOG_BUFFER_SIZE (12*1024)
  237. C_ASSERT(MINIMUM_ALLOWED_LOG_BUFFER_SIZE >
  238. (UL_MAX_TITLE_BUFFER_SIZE + UL_MAX_LOG_LINE_BUFFER_SIZE));
  239. #define MAXIMUM_ALLOWED_LOG_BUFFER_SIZE (64*1024)
  240. //
  241. // Following is the definition of the Internal Log Data Buffer.
  242. // It also holds the required pointer to pRequest.
  243. //
  244. typedef struct _UL_LOG_DATA_BUFFER
  245. {
  246. //
  247. // A work item, used for queuing to a worker thread.
  248. //
  249. UL_WORK_ITEM WorkItem;
  250. //
  251. // Our private pointer to the Internal Request structure
  252. // to be ensure to have the request around until we are done
  253. // with logging. Even if connection get reset by client, before
  254. // we get a chance to log. See the definition of UlLogHttpHit
  255. // for further complicated comments.
  256. //
  257. PUL_INTERNAL_REQUEST pRequest;
  258. //
  259. // For Cache&Send Responses we won't be copying and allocating
  260. // a new internal buffer again and again but instead will keep
  261. // the original we have allocated during the capturing the res-
  262. // ponse. This flag shows that the buffer is ready as it is and
  263. // no need to copy over log data from cache again.
  264. //
  265. BOOLEAN CacheAndSendResponse;
  266. //
  267. // The total amount of send_response bytes
  268. //
  269. ULONGLONG BytesTransferred;
  270. //
  271. // For cache hits we can get the corresponding cgroup frm uri_cache
  272. // entry to avoid the costly cgroup lookup.
  273. //
  274. PUL_CONFIG_GROUP_OBJECT pConfigGroup;
  275. //
  276. // Capture the log format/flags when the sendresponse happens. And
  277. // discard the changes to it during the hit processing.
  278. //
  279. HTTP_LOGGING_TYPE Format;
  280. ULONG Flags;
  281. //
  282. // Total length of the required fields in the final output buffer
  283. // according to the Log Type & Syntax and included fields.
  284. // It's in WideChars
  285. //
  286. ULONG Length;
  287. ULONG Used;
  288. //
  289. // Individual log fields are captured in the following
  290. // line. For NCSA and IIS formats two additional ushort
  291. // fields keep private offsets that represents either
  292. // the beginning of a certain field ( date for NCSA )
  293. // or the used amount from the each fragment ( for IIS )
  294. // Refer to UlpBuildCacheEntry for their usage.
  295. //
  296. USHORT UsedOffset1;
  297. USHORT UsedOffset2;
  298. //
  299. // The actual log line for W3C & NCSA formats. IIS reformat and allocate
  300. // a new buffer.
  301. //
  302. PCHAR Line;
  303. CHAR Buffer[UL_LOG_LINE_BUFFER_SIZE];
  304. } UL_LOG_DATA_BUFFER, *PUL_LOG_DATA_BUFFER;
  305. #define NCSA_FIX_DATE_AND_TIME_FIELD_SIZE (29)
  306. //
  307. // IIS Log line is fragmented at the capture time the offsets
  308. // are as follows and never get changed even if buffer get re
  309. // allocated.
  310. //
  311. #define IIS_LOG_LINE_FIRST_FRAGMENT_OFFSET (0)
  312. #define IIS_LOG_LINE_SECOND_FRAGMENT_OFFSET (512)
  313. #define IIS_LOG_LINE_THIRD_FRAGMENT_OFFSET (1024)
  314. //
  315. // The HTTP Hit Logging functions which we expose in this module.
  316. //
  317. NTSTATUS
  318. UlInitializeLogs(
  319. VOID
  320. );
  321. VOID
  322. UlTerminateLogs(
  323. VOID
  324. );
  325. NTSTATUS
  326. UlSetUTF8Logging (
  327. IN BOOLEAN UTF8Logging
  328. );
  329. NTSTATUS
  330. UlCreateLog(
  331. IN OUT PUL_CONFIG_GROUP_OBJECT pConfigGroup
  332. );
  333. VOID
  334. UlRemoveLogFileEntry(
  335. PUL_LOG_FILE_ENTRY pEntry
  336. );
  337. VOID
  338. UlLogTimerHandler(
  339. IN PUL_WORK_ITEM pWorkItem
  340. );
  341. VOID
  342. UlLogTimerDpcRoutine(
  343. PKDPC Dpc,
  344. PVOID DeferredContext,
  345. PVOID SystemArgument1,
  346. PVOID SystemArgument2
  347. );
  348. VOID
  349. UlBufferTimerHandler(
  350. IN PUL_WORK_ITEM pWorkItem
  351. );
  352. VOID
  353. UlBufferTimerDpcRoutine(
  354. PKDPC Dpc,
  355. PVOID DeferredContext,
  356. PVOID SystemArgument1,
  357. PVOID SystemArgument2
  358. );
  359. NTSTATUS
  360. UlReConfigureLogEntry(
  361. IN PUL_CONFIG_GROUP_OBJECT pConfigGroup,
  362. IN PHTTP_CONFIG_GROUP_LOGGING pCfgOld,
  363. IN PHTTP_CONFIG_GROUP_LOGGING pCfgNew
  364. );
  365. NTSTATUS
  366. UlProbeLogData(
  367. IN PHTTP_LOG_FIELDS_DATA pLogData
  368. );
  369. NTSTATUS
  370. UlCaptureLogFieldsW3C(
  371. IN PHTTP_LOG_FIELDS_DATA pLogData,
  372. IN HTTP_VERSION Version,
  373. OUT PUL_LOG_DATA_BUFFER pLogBuffer
  374. );
  375. NTSTATUS
  376. UlCaptureLogFieldsNCSA(
  377. IN PHTTP_LOG_FIELDS_DATA pLogData,
  378. IN HTTP_VERSION Version,
  379. OUT PUL_LOG_DATA_BUFFER pLogBuffer
  380. );
  381. NTSTATUS
  382. UlCaptureLogFieldsIIS(
  383. IN PHTTP_LOG_FIELDS_DATA pLogData,
  384. IN HTTP_VERSION Version,
  385. OUT PUL_LOG_DATA_BUFFER pLogBuffer
  386. );
  387. __inline
  388. NTSTATUS
  389. FASTCALL
  390. UlCaptureLogFields(
  391. IN PHTTP_LOG_FIELDS_DATA pLogData,
  392. IN HTTP_VERSION Version,
  393. OUT PUL_LOG_DATA_BUFFER pLogBuffer
  394. )
  395. {
  396. switch( pLogBuffer->Format )
  397. {
  398. case HttpLoggingTypeW3C:
  399. return UlCaptureLogFieldsW3C( pLogData, Version, pLogBuffer );
  400. break;
  401. case HttpLoggingTypeNCSA:
  402. return UlCaptureLogFieldsNCSA( pLogData, Version, pLogBuffer );
  403. break;
  404. case HttpLoggingTypeIIS:
  405. return UlCaptureLogFieldsIIS( pLogData, Version, pLogBuffer );
  406. break;
  407. default:
  408. ASSERT(!"Unknown Log Format.\n");
  409. return STATUS_INVALID_PARAMETER;
  410. }
  411. }
  412. NTSTATUS
  413. UlAllocateLogDataBuffer(
  414. OUT PUL_LOG_DATA_BUFFER pLogData,
  415. IN PUL_INTERNAL_REQUEST pRequest,
  416. IN PUL_CONFIG_GROUP_OBJECT pConfigGroup
  417. );
  418. VOID
  419. UlDestroyLogDataBufferWorker(
  420. IN PUL_WORK_ITEM pWorkItem
  421. );
  422. /***************************************************************************++
  423. Routine Description:
  424. Wrapper function to ensure we are not touching to paged-pool allocated
  425. large log buffer on elevated IRQL. It's important that this function has
  426. been written with the assumption of Request doesn't go away until we
  427. properly execute the possible passive worker. This is indeed the case
  428. because request(with the embedded logdata) has been refcounted up by the
  429. logdata.
  430. Arguments:
  431. pLogData - The buffer to be destroyed
  432. --***************************************************************************/
  433. __inline
  434. VOID
  435. FASTCALL
  436. UlDestroyLogDataBuffer(
  437. IN PUL_LOG_DATA_BUFFER pLogData
  438. )
  439. {
  440. //
  441. // Sanity check
  442. //
  443. ASSERT(pLogData);
  444. //
  445. // If we are running on elevated IRQL and large log line allocated
  446. // then queue a passive worker otherwise complete inline.
  447. //
  448. if (pLogData->Length > UL_LOG_LINE_BUFFER_SIZE)
  449. {
  450. UL_CALL_PASSIVE( &pLogData->WorkItem,
  451. &UlDestroyLogDataBufferWorker );
  452. }
  453. else
  454. {
  455. UlDestroyLogDataBufferWorker( &pLogData->WorkItem );
  456. }
  457. }
  458. NTSTATUS
  459. UlLogHttpHit(
  460. IN PUL_LOG_DATA_BUFFER pLogBuffer
  461. );
  462. NTSTATUS
  463. UlLogHttpCacheHit(
  464. IN PUL_FULL_TRACKER pTracker
  465. );
  466. NTSTATUS
  467. UlCheckLogDirectory(
  468. IN PUNICODE_STRING pDirName
  469. );
  470. #ifdef __cplusplus
  471. }; // extern "C"
  472. #endif
  473. #endif // _ULLOG_H_