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.

566 lines
18 KiB

  1. /*++
  2. Copyright (c) 2000-2002 Microsoft Corporation
  3. Module Name:
  4. ullogp.h (Http.sys Ansi Logging)
  5. Abstract:
  6. This module implements the logging facilities
  7. for Http.sys 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 _ULLOGP_H_
  14. #define _ULLOGP_H_
  15. //
  16. // Private definitions for the Ul Logging Module
  17. //
  18. #define UTF8_LOGGING_ENABLED() (g_UTF8Logging)
  19. #define _UL_GET_LOG_FILE_NAME_PREFIX(x) \
  20. ( (x) == HttpLoggingTypeW3C ? L"\\extend" : \
  21. (x) == HttpLoggingTypeIIS ? L"\\inetsv" : \
  22. (x) == HttpLoggingTypeNCSA ? L"\\ncsa" : L"\\unknwn" \
  23. )
  24. #define _UL_GET_LOG_FILE_NAME_PREFIX_UTF8(x) \
  25. ( (x) == HttpLoggingTypeW3C ? L"\\u_extend" : \
  26. (x) == HttpLoggingTypeIIS ? L"\\u_inetsv" : \
  27. (x) == HttpLoggingTypeNCSA ? L"\\u_ncsa" : L"\\u_unknwn" \
  28. )
  29. #define UL_GET_LOG_FILE_NAME_PREFIX(x) \
  30. (UTF8_LOGGING_ENABLED() ? _UL_GET_LOG_FILE_NAME_PREFIX_UTF8(x) :\
  31. _UL_GET_LOG_FILE_NAME_PREFIX(x))
  32. //
  33. // Obsolete - Only used by Old Hit
  34. // Replace this with a switch statement inside a inline function
  35. // which is more efficient, if u start using it again
  36. //
  37. #define UL_GET_NAME_FOR_HTTP_VERB(v) \
  38. ( (v) == HttpVerbUnparsed ? L"UNPARSED" : \
  39. (v) == HttpVerbUnknown ? L"UNKNOWN" : \
  40. (v) == HttpVerbInvalid ? L"INVALID" : \
  41. (v) == HttpVerbOPTIONS ? L"OPTIONS" : \
  42. (v) == HttpVerbGET ? L"GET" : \
  43. (v) == HttpVerbHEAD ? L"HEAD" : \
  44. (v) == HttpVerbPOST ? L"POST" : \
  45. (v) == HttpVerbPUT ? L"PUT" : \
  46. (v) == HttpVerbDELETE ? L"DELETE" : \
  47. (v) == HttpVerbTRACE ? L"TRACE" : \
  48. (v) == HttpVerbCONNECT ? L"CONNECT" : \
  49. (v) == HttpVerbTRACK ? L"TRACK" : \
  50. (v) == HttpVerbMOVE ? L"MOVE" : \
  51. (v) == HttpVerbCOPY ? L"COPY" : \
  52. (v) == HttpVerbPROPFIND ? L"PROPFIND" : \
  53. (v) == HttpVerbPROPPATCH ? L"PROPPATCH" : \
  54. (v) == HttpVerbMKCOL ? L"MKCOL" : \
  55. (v) == HttpVerbLOCK ? L"LOCK" : \
  56. (v) == HttpVerbUNLOCK ? L"UNLOCK" : \
  57. (v) == HttpVerbSEARCH ? L"SEARCH" : \
  58. L"???" \
  59. )
  60. #define UL_DEFAULT_NCSA_FIELDS (MD_EXTLOG_CLIENT_IP | \
  61. MD_EXTLOG_USERNAME | \
  62. MD_EXTLOG_DATE | \
  63. MD_EXTLOG_TIME | \
  64. MD_EXTLOG_METHOD | \
  65. MD_EXTLOG_URI_STEM | \
  66. MD_EXTLOG_URI_QUERY | \
  67. MD_EXTLOG_PROTOCOL_VERSION | \
  68. MD_EXTLOG_HTTP_STATUS | \
  69. MD_EXTLOG_BYTES_SENT)
  70. #define UL_DEFAULT_IIS_FIELDS (MD_EXTLOG_CLIENT_IP | \
  71. MD_EXTLOG_USERNAME | \
  72. MD_EXTLOG_DATE | \
  73. MD_EXTLOG_TIME | \
  74. MD_EXTLOG_SITE_NAME | \
  75. MD_EXTLOG_COMPUTER_NAME | \
  76. MD_EXTLOG_SERVER_IP | \
  77. MD_EXTLOG_TIME_TAKEN | \
  78. MD_EXTLOG_BYTES_RECV | \
  79. MD_EXTLOG_BYTES_SENT | \
  80. MD_EXTLOG_HTTP_STATUS | \
  81. MD_EXTLOG_WIN32_STATUS | \
  82. MD_EXTLOG_METHOD | \
  83. MD_EXTLOG_URI_STEM)
  84. #define UL_GET_LOG_TYPE_MASK(x,y) \
  85. ( (x) == HttpLoggingTypeW3C ? (y) : \
  86. (x) == HttpLoggingTypeIIS ? UL_DEFAULT_IIS_FIELDS : \
  87. (x) == HttpLoggingTypeNCSA ? UL_DEFAULT_NCSA_FIELDS : 0 \
  88. )
  89. //
  90. // The order of the following should match with
  91. // UL_LOG_FIELD_TYPE enum definition.
  92. //
  93. PWSTR UlFieldTitleLookupTable[] =
  94. {
  95. L" date",
  96. L" time",
  97. L" s-sitename",
  98. L" s-computername",
  99. L" s-ip",
  100. L" cs-method",
  101. L" cs-uri-stem",
  102. L" cs-uri-query",
  103. L" s-port",
  104. L" cs-username",
  105. L" c-ip",
  106. L" cs-version",
  107. L" cs(User-Agent)",
  108. L" cs(Cookie)",
  109. L" cs(Referer)",
  110. L" cs-host",
  111. L" sc-status",
  112. L" sc-substatus",
  113. L" sc-win32-status",
  114. L" sc-bytes",
  115. L" cs-bytes",
  116. L" time-taken"
  117. };
  118. #define UL_GET_LOG_FIELD_TITLE(x) \
  119. ((x)>=UlLogFieldMaximum ? L"Unknown" : UlFieldTitleLookupTable[(x)])
  120. #define UL_GET_LOG_TITLE_IF_PICKED(x,y,z) \
  121. ((y)&(z) ? UL_GET_LOG_FIELD_TITLE((x)) : L"")
  122. //
  123. // Pick the local time for file name & rollover if format is NCSA or IIS,
  124. // otherwise (W3C) pick the local time only if LocaltimeRollover is set.
  125. //
  126. #define UL_PICK_TIME_FIELD(pEntry, tflocal,tfgmt) \
  127. ((pEntry->Flags.LocaltimeRollover || \
  128. (pEntry->Format != HttpLoggingTypeW3C)) ? (tflocal) : (tfgmt))
  129. #define DEFAULT_LOG_FILE_EXTENSION L"log"
  130. #define DEFAULT_LOG_FILE_EXTENSION_PLUS_DOT L".log"
  131. #define SIZE_OF_GMT_OFFSET (6)
  132. #define IS_LOGGING_DISABLED(g) \
  133. ((g) == NULL || \
  134. (g)->LoggingConfig.Flags.Present == 0 || \
  135. (g)->LoggingConfig.LoggingEnabled == FALSE)
  136. //
  137. // UlpWriteW3CLogRecord attempts to use a buffer size upto this
  138. //
  139. #define UL_DEFAULT_WRITE_BUFFER_LEN (512)
  140. //
  141. // When a log field exceeds its limit it's replaced by
  142. // the following default warning string.
  143. //
  144. #define LOG_FIELD_TOO_BIG "..."
  145. //
  146. // No log record can be longer than this. Applies to all
  147. // log formats.
  148. //
  149. #define MAX_LOG_RECORD_LEN (10240)
  150. //
  151. // Any log field provided to the driver enforced by some
  152. // sanity limit.
  153. //
  154. #define MAX_LOG_DEFAULT_FIELD_LEN (64)
  155. //
  156. // WARNING: Logging capturing functions, especially the W3C
  157. // one has been designed with respect to the above hard coded
  158. // numbers. If you change any of the above numbers,you SHOULD
  159. // review the capturing functions to avoid the buffer overruns.
  160. // See also the MAX_LOG_RECORD_ALLOCATION_LENGTH down below.
  161. //
  162. //
  163. // W3C Capture and complete functions will allocate and use this
  164. // much extra space for non-string fields for cache-miss case.
  165. // This is used for worst case allocation.
  166. //
  167. #define MAX_W3C_FIX_FIELD_OVERHEAD \
  168. (/* Date */ W3C_DATE_FIELD_LEN + 1 + \
  169. /* Time */ W3C_TIME_FIELD_LEN + 1 + \
  170. /* ServerPort */ MAX_USHORT_STR + 1 + \
  171. /* PVersion */ UL_HTTP_VERSION_LENGTH + 1 + \
  172. /* PStatus */ UL_MAX_HTTP_STATUS_CODE_LENGTH + 1 + \
  173. /* Win32Status */ MAX_ULONG_STR + 1 + \
  174. /* SubStatus */ MAX_USHORT_STR + 1 + \
  175. /* BSent */ MAX_ULONGLONG_STR + 1 + \
  176. /* BReceived */ MAX_ULONGLONG_STR + 1 + \
  177. /* TTaken */ MAX_ULONGLONG_STR + 1 + \
  178. /* "\r\n\0" */ 3 \
  179. )
  180. //
  181. // W3C complete function will allocate and use this much
  182. // much extra space for non-string fields for cache-hit
  183. // case. This is used for worst case allocation.
  184. //
  185. #define MAX_W3C_CACHE_FIELD_OVERHEAD \
  186. (/* Date */ W3C_DATE_FIELD_LEN + 1 + \
  187. /* Time */ W3C_TIME_FIELD_LEN + 1 + \
  188. /* UserName "- "*/ 2 + \
  189. /* ClientIp */ MAX_IP_ADDR_STRING_LEN + 1 + \
  190. /* PVersion */ UL_HTTP_VERSION_LENGTH + 1 + \
  191. /* PStatus */ UL_MAX_HTTP_STATUS_CODE_LENGTH + 1 + \
  192. /* Win32Status */ MAX_ULONG_STR + 1 + \
  193. /* SubStatus */ MAX_USHORT_STR + 1 + \
  194. /* BSent */ MAX_ULONGLONG_STR + 1 + \
  195. /* BReceived */ MAX_ULONGLONG_STR + 1 + \
  196. /* TTaken */ MAX_ULONGLONG_STR + 1 + \
  197. /* "\r\n\0" */ 3 \
  198. )
  199. //
  200. // Similar definitions for NCSA and IIS formats.
  201. //
  202. #define MAX_NCSA_CACHE_FIELD_OVERHEAD \
  203. (/* ClientIp */ MAX_IP_ADDR_STRING_LEN + 1 + \
  204. /* Fix Dash */ 2 + \
  205. /* UserName */ 2 + \
  206. /* Date & Time */ NCSA_FIX_DATE_AND_TIME_FIELD_SIZE + \
  207. /* PVersion " */ UL_HTTP_VERSION_LENGTH + 1 + 1 + \
  208. /* PStatus */ UL_MAX_HTTP_STATUS_CODE_LENGTH + 1 + \
  209. /* BSent */ MAX_ULONGLONG_STR + \
  210. /* \r\n\0 */ 3 \
  211. )
  212. #define MAX_IIS_CACHE_FIELD_OVERHEAD \
  213. (/* Client Ip */ MAX_IP_ADDR_STRING_LEN + 2 + \
  214. /* UserName */ 3 + \
  215. /* Date & Time */ IIS_MAX_DATE_AND_TIME_FIELD_SIZE + \
  216. /* TTaken */ MAX_ULONGLONG_STR + 2 + \
  217. /* BReceived */ MAX_ULONGLONG_STR + 2 + \
  218. /* BSent */ MAX_ULONGLONG_STR + 2 + \
  219. /* PStatus */ UL_MAX_HTTP_STATUS_CODE_LENGTH + 2 + \
  220. /* Win32Status */ MAX_ULONG_STR + 2 \
  221. )
  222. //
  223. // Default IIS fragments must be big enough to hold the max-length fields.
  224. //
  225. C_ASSERT(IIS_LOG_LINE_DEFAULT_FIRST_FRAGMENT_ALLOCATION_SIZE >=
  226. (/* ClientIp */ 2 + MAX_LOG_DEFAULT_FIELD_LEN +
  227. /* UserName */ 2 + MAX_LOG_USERNAME_FIELD_LEN +
  228. /* Date&Time */ 2 + IIS_MAX_DATE_AND_TIME_FIELD_SIZE));
  229. C_ASSERT(IIS_LOG_LINE_DEFAULT_FIRST_FRAGMENT_ALLOCATION_SIZE >=
  230. (/* ServiceName */ 2 + MAX_LOG_DEFAULT_FIELD_LEN +
  231. /* ServerName */ 2 + MAX_LOG_DEFAULT_FIELD_LEN +
  232. /* ServerIp */ 2 + MAX_LOG_DEFAULT_FIELD_LEN +
  233. /* TimeTaken */ 2 + MAX_ULONGLONG_STR +
  234. /* BytesReceived */ 2 + MAX_ULONGLONG_STR +
  235. /* BytesSend */ 2 + MAX_ULONGLONG_STR +
  236. /* Protocol St. */ 2 + UL_MAX_HTTP_STATUS_CODE_LENGTH +
  237. /* Win32 St. */ 2 + MAX_ULONG_STR
  238. ));
  239. #define IIS_LOG_LINE_MAX_THIRD_FRAGMENT_SIZE \
  240. (/* Method */ 2 + MAX_LOG_METHOD_FIELD_LEN + \
  241. /* UriQuery */ 2 + MAX_LOG_EXTEND_FIELD_LEN + \
  242. /* UriStem */ 2 + MAX_LOG_EXTEND_FIELD_LEN + \
  243. /* "r\n\0" */ 3)
  244. C_ASSERT(UL_ANSI_LOG_LINE_BUFFER_SIZE ==
  245. (IIS_LOG_LINE_DEFAULT_FIRST_FRAGMENT_ALLOCATION_SIZE +
  246. IIS_LOG_LINE_DEFAULT_SECOND_FRAGMENT_ALLOCATION_SIZE +
  247. IIS_LOG_LINE_DEFAULT_THIRD_FRAGMENT_ALLOCATION_SIZE) );
  248. //
  249. // Maximum log record allocation for W3C format;
  250. //
  251. // MAX_LOG_RECORD_LEN : Upper limit for log record
  252. // + 16 Bytes : 4 * (sizeof(LOG_FIELD_TOO_BIG) +
  253. // SeparatorSpace:' ')
  254. // : For UserAgent,Cookie,Referer,Host
  255. // + MAX_W3C_FIX_FIELD_OVERHEAD : To be able to ensure reserved space for
  256. // : post-generated log fields.
  257. #define MAX_LOG_RECORD_ALLOCATION_LENGTH \
  258. (MAX_LOG_RECORD_LEN + \
  259. 4 * (STRLEN_LIT(LOG_FIELD_TOO_BIG) + 1) + \
  260. MAX_W3C_FIX_FIELD_OVERHEAD \
  261. )
  262. //
  263. // Private function calls
  264. //
  265. NTSTATUS
  266. UlpConstructLogEntry(
  267. IN PHTTP_CONFIG_GROUP_LOGGING pConfig,
  268. OUT PUL_LOG_FILE_ENTRY * ppEntry
  269. );
  270. VOID
  271. UlpInsertLogEntry(
  272. IN PUL_LOG_FILE_ENTRY pEntry
  273. );
  274. NTSTATUS
  275. UlpAppendW3CLogTitle(
  276. IN PUL_LOG_FILE_ENTRY pEntry,
  277. OUT PCHAR pDestBuffer,
  278. IN OUT PULONG pBytesCopied
  279. );
  280. VOID
  281. UlpInitializeTimers(
  282. VOID
  283. );
  284. VOID
  285. UlpTerminateTimers(
  286. VOID
  287. );
  288. NTSTATUS
  289. UlpRecycleLogFile(
  290. IN PUL_LOG_FILE_ENTRY pEntry
  291. );
  292. NTSTATUS
  293. UlpHandleRecycle(
  294. IN OUT PVOID pContext
  295. );
  296. __inline
  297. BOOLEAN
  298. UlpIsLogFileOverFlow(
  299. IN PUL_LOG_FILE_ENTRY pEntry,
  300. IN ULONG ReqdBytes
  301. );
  302. VOID
  303. UlpEventLogWriteFailure(
  304. IN PUL_LOG_FILE_ENTRY pEntry,
  305. IN NTSTATUS Status
  306. );
  307. NTSTATUS
  308. UlpFlushLogFile(
  309. IN PUL_LOG_FILE_ENTRY pEntry
  310. );
  311. NTSTATUS
  312. UlpRefreshFileName(
  313. IN PUNICODE_STRING pDirectory,
  314. IN PUL_LOG_FILE_ENTRY pEntry
  315. );
  316. VOID
  317. UlpGetGMTOffset();
  318. VOID
  319. UlpLogHttpCacheHitWorker(
  320. IN PUL_LOG_DATA_BUFFER pLogData,
  321. IN PUL_CONFIG_GROUP_OBJECT pConfigGroup
  322. );
  323. NTSTATUS
  324. UlpWriteToLogFile(
  325. IN PUL_LOG_FILE_ENTRY pFile,
  326. IN ULONG RecordSize,
  327. IN PCHAR pRecord,
  328. IN ULONG UsedOffset1,
  329. IN ULONG UsedOffset2
  330. );
  331. NTSTATUS
  332. UlpWriteToLogFileShared(
  333. IN PUL_LOG_FILE_ENTRY pFile,
  334. IN ULONG RecordSize,
  335. IN PCHAR pRecord,
  336. IN ULONG UsedOffset1,
  337. IN ULONG UsedOffset2
  338. );
  339. NTSTATUS
  340. UlpWriteToLogFileExclusive(
  341. IN PUL_LOG_FILE_ENTRY pFile,
  342. IN ULONG RecordSize,
  343. IN PCHAR pRecord,
  344. IN ULONG UsedOffset1,
  345. IN ULONG UsedOffset2
  346. );
  347. NTSTATUS
  348. UlpWriteToLogFileDebug(
  349. IN PUL_LOG_FILE_ENTRY pFile,
  350. IN ULONG RecordSize,
  351. IN PCHAR pRecord,
  352. IN ULONG UsedOffset1,
  353. IN ULONG UsedOffset2
  354. );
  355. NTSTATUS
  356. UlpMakeEntryInactive(
  357. IN OUT PUL_LOG_FILE_ENTRY pEntry
  358. );
  359. PUL_LOG_DATA_BUFFER
  360. UlpAllocateLogDataBuffer(
  361. IN ULONG Size,
  362. IN PUL_INTERNAL_REQUEST pRequest,
  363. IN PUL_CONFIG_GROUP_OBJECT pConfigGroup
  364. );
  365. NTSTATUS
  366. UlpCreateLogFile(
  367. IN OUT PUL_LOG_FILE_ENTRY pEntry,
  368. IN PUL_CONFIG_GROUP_OBJECT pConfigGroup
  369. );
  370. #ifdef IMPLEMENT_SELECTIVE_LOGGING
  371. /***************************************************************************++
  372. Routine Description:
  373. Simple macro will return TRUE if request status code type is matching
  374. with user's selection in the logging config.
  375. Arguments:
  376. pConfigGroup - Config Group for the logging configuration.
  377. StatusCode - Protocol status code.
  378. --***************************************************************************/
  379. __inline
  380. BOOLEAN
  381. UlpIsRequestSelected(
  382. IN PUL_CONFIG_GROUP_OBJECT pConfigGroup,
  383. IN USHORT StatusCode
  384. )
  385. {
  386. ASSERT(StatusCode <= UL_MAX_HTTP_STATUS_CODE);
  387. ASSERT(IS_VALID_CONFIG_GROUP(pConfigGroup));
  388. //
  389. // The 4xx and 5xx status codes are considered an error.
  390. //
  391. // - 4xx: Client Error - The request contains bad syntax or cannot
  392. // be fulfilled
  393. //
  394. // - 5xx: Server Error - The server failed to fulfill an apparently
  395. // valid request
  396. //
  397. switch(pConfigGroup->LoggingConfig.SelectiveLogging)
  398. {
  399. case HttpLogAllRequests:
  400. return TRUE;
  401. break;
  402. case HttpLogSuccessfulRequests:
  403. return ((BOOLEAN) (StatusCode < 400 || StatusCode >= 600));
  404. break;
  405. case HttpLogErrorRequests:
  406. return ((BOOLEAN) (StatusCode >= 400 && StatusCode < 600));
  407. break;
  408. default:
  409. ASSERT(!"Invalid Selective Logging Type !");
  410. break;
  411. }
  412. return FALSE;
  413. }
  414. #endif
  415. __inline
  416. NTSTATUS
  417. UlpCheckAndWrite(
  418. IN OUT PUL_LOG_FILE_ENTRY pEntry,
  419. IN PUL_CONFIG_GROUP_OBJECT pConfigGroup,
  420. IN PUL_LOG_DATA_BUFFER pLogData
  421. )
  422. {
  423. NTSTATUS Status = STATUS_SUCCESS;
  424. PUL_STR_LOG_DATA pStrData = &pLogData->Data.Str;
  425. ASSERT(IS_VALID_LOG_FILE_ENTRY(pEntry));
  426. ASSERT(IS_VALID_CONFIG_GROUP(pConfigGroup));
  427. //
  428. // Check whether we have to create the log file first or not.
  429. //
  430. if (!pEntry->Flags.Active)
  431. {
  432. UlAcquirePushLockExclusive(&pEntry->EntryPushLock);
  433. //
  434. // Ping again to see if we have been blocked on the lock, and
  435. // somebody else already took care of the creation.
  436. //
  437. if (!pEntry->Flags.Active)
  438. {
  439. Status = UlpCreateLogFile(pEntry, pConfigGroup);
  440. }
  441. UlReleasePushLockExclusive(&pEntry->EntryPushLock);
  442. if (!NT_SUCCESS(Status))
  443. {
  444. return Status;
  445. }
  446. }
  447. //
  448. // Now we know that the log file is there, therefore it's time to write.
  449. //
  450. Status =
  451. UlpWriteToLogFile (
  452. pEntry,
  453. pStrData->Offset1 + pStrData->Offset2 + pLogData->Used,
  454. (PCHAR) pLogData->Line,
  455. pStrData->Offset1,
  456. pStrData->Offset2
  457. );
  458. return Status;
  459. }
  460. ULONG
  461. UlpGetLogLineSizeForW3C(
  462. IN PHTTP_LOG_FIELDS_DATA pLogData,
  463. IN ULONG Mask,
  464. IN BOOLEAN Utf8Enabled
  465. );
  466. #define IS_PURE_CACHE_HIT(pUriEntry, pLogData) \
  467. ((pUriEntry) && ((pLogData)->Flags.CacheAndSendResponse == 0))
  468. #endif // _ULLOGP_H_