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.

698 lines
16 KiB

  1. /*++
  2. Copyright (c) 1995-1996 Microsoft Corporation
  3. Module Name :
  4. nsclogp.cpp
  5. Abstract:
  6. NCSA Logging Format implementation
  7. Author:
  8. Terence Kwan ( terryk ) 18-Sep-1996
  9. Project:
  10. IIS Logging 3.0
  11. --*/
  12. #include "precomp.hxx"
  13. #include <stdio.h>
  14. #include <script.h>
  15. #include "LogScript.hxx"
  16. #include <ilogobj.hxx>
  17. #include "filectl.hxx"
  18. #include "ncslogc.hxx"
  19. CHAR szNCSANoPeriodPattern[] = "ncsa*.log";
  20. // -----------------------------------------------------------------------------
  21. // -----------------------------------------------------------------------------
  22. CNCSALOG::CNCSALOG()
  23. {
  24. //
  25. // set the time zone offset
  26. //
  27. {
  28. TIME_ZONE_INFORMATION tzTimeZone;
  29. DWORD dwError;
  30. DWORD minutes;
  31. DWORD hours;
  32. LONG bias;
  33. CHAR szTmp[MAX_PATH];
  34. dwError = GetTimeZoneInformation(&tzTimeZone);
  35. if ( dwError == 0xffffffff ) {
  36. bias = 0;
  37. } else {
  38. bias = tzTimeZone.Bias;
  39. }
  40. if ( bias > 0 )
  41. {
  42. lstrcpyA(m_szGMTOffset,"-");
  43. m_GMTDateCorrection = -1;
  44. }
  45. else
  46. {
  47. lstrcpyA(m_szGMTOffset,"+");
  48. m_GMTDateCorrection = 1;
  49. bias *= -1;
  50. }
  51. hours = bias/60;
  52. minutes = bias % 60;
  53. //
  54. // set up the "+0800" or "-0800" NCSA information
  55. //
  56. wsprintfA(szTmp,"%02lu",hours);
  57. lstrcatA(m_szGMTOffset,szTmp);
  58. wsprintfA(szTmp,"%02lu",minutes);
  59. lstrcatA(m_szGMTOffset,szTmp);
  60. m_GMTDateCorrection = m_GMTDateCorrection * ( hours/24.0 + minutes/60.0 );
  61. }
  62. } // CNCSALOG::CNCSALOG()
  63. // -----------------------------------------------------------------------------
  64. // -----------------------------------------------------------------------------
  65. CNCSALOG::~CNCSALOG()
  66. {
  67. }
  68. // -----------------------------------------------------------------------------
  69. // -----------------------------------------------------------------------------
  70. LPCSTR
  71. CNCSALOG::QueryNoPeriodPattern(
  72. VOID
  73. )
  74. {
  75. return szNCSANoPeriodPattern;
  76. } // CNCSALOG::QueryNoPeriodPattern
  77. // -----------------------------------------------------------------------------
  78. // -----------------------------------------------------------------------------
  79. VOID
  80. CNCSALOG::FormNewLogFileName(
  81. IN LPSYSTEMTIME pstNow
  82. )
  83. /*++
  84. This function that forms the new log file name based on
  85. type of periodic logging done.
  86. Arguments:
  87. pstNow pointer to SystemTime which contains the current time.
  88. Returns:
  89. TRUE on success in forming the name or FALSE if there is any error.
  90. --*/
  91. {
  92. I_FormNewLogFileName(pstNow,DEFAULT_NCSA_LOG_FILE_NAME);
  93. return;
  94. } // INET_FILE_LOG::FormNewLogFileName()
  95. // -----------------------------------------------------------------------------
  96. // -----------------------------------------------------------------------------
  97. BOOL
  98. CNCSALOG::FormatLogBuffer(
  99. IN IInetLogInformation *pLogObj,
  100. IN LPSTR pBuf,
  101. IN DWORD *pcbSize,
  102. OUT SYSTEMTIME *pLocalTime
  103. )
  104. {
  105. CHAR rgchDateTime[32];
  106. PCHAR pBuffer = pBuf;
  107. DWORD nRequired = 0;
  108. PCHAR pTmp;
  109. DWORD cbTmp;
  110. BOOL fUseBytesSent = TRUE;
  111. if ( pBuf == NULL ) {
  112. return ERROR_INVALID_PARAMETER;
  113. }
  114. //
  115. // We use local time
  116. //
  117. GetLocalTime(pLocalTime);
  118. INT cchDateTime = wsprintf( rgchDateTime,
  119. _T(" [%02d/%s/%d:%02d:%02d:%02d %s] "),
  120. pLocalTime->wDay,
  121. Month3CharNames(pLocalTime->wMonth-1),
  122. pLocalTime->wYear,
  123. pLocalTime->wHour,
  124. pLocalTime->wMinute,
  125. pLocalTime->wSecond,
  126. m_szGMTOffset
  127. );
  128. //
  129. // Format is:
  130. // Host - UserName [date] Operation Target status bytes
  131. //
  132. //
  133. // HostName
  134. //
  135. pTmp = pLogObj->GetClientHostName( NULL, &cbTmp );
  136. if ( cbTmp == 0 ) {
  137. cbTmp = 1;
  138. pTmp = "-";
  139. }
  140. nRequired += cbTmp;
  141. if ( nRequired <= *pcbSize ) {
  142. CopyMemory(pBuffer, pTmp, cbTmp);
  143. pBuffer += cbTmp;
  144. }
  145. //
  146. // Append " - "
  147. //
  148. cbTmp = 3;
  149. pTmp = " - ";
  150. nRequired += cbTmp;
  151. if ( nRequired <= *pcbSize ) {
  152. CopyMemory(pBuffer, pTmp, cbTmp);
  153. pBuffer += cbTmp;
  154. }
  155. //
  156. // append user name
  157. //
  158. pTmp = pLogObj->GetClientUserName( NULL, &cbTmp );
  159. if ( cbTmp == 0 ) {
  160. cbTmp = 1;
  161. pTmp = "-";
  162. }
  163. nRequired += cbTmp;
  164. if ( nRequired <= *pcbSize ) {
  165. CopyMemory(pBuffer, pTmp, cbTmp);
  166. pBuffer += cbTmp;
  167. }
  168. //
  169. // append date time
  170. //
  171. pTmp = rgchDateTime;
  172. cbTmp = cchDateTime;
  173. nRequired += cbTmp;
  174. if ( nRequired <= *pcbSize ) {
  175. CopyMemory(pBuffer, pTmp, cbTmp);
  176. pBuffer += cbTmp;
  177. }
  178. //
  179. // Operation
  180. //
  181. pTmp = pLogObj->GetOperation( NULL, &cbTmp );
  182. if ( cbTmp == 0 ) {
  183. cbTmp = 1;
  184. pTmp = "-";
  185. } else {
  186. if ( (_stricmp(pTmp,"PUT") == 0) ||
  187. (_stricmp(pTmp,"POST") == 0) ) {
  188. fUseBytesSent = FALSE;
  189. }
  190. }
  191. nRequired += (cbTmp + 1 + 1); // +1 for delimeter, +1 for \"
  192. if ( nRequired <= *pcbSize ) {
  193. *(pBuffer++) = '\"';
  194. CopyMemory(pBuffer, pTmp, cbTmp);
  195. pBuffer += cbTmp;
  196. //
  197. // Add space delimiter
  198. //
  199. *(pBuffer++) = ' ';
  200. }
  201. //
  202. // Target
  203. //
  204. pTmp = pLogObj->GetTarget( NULL, &cbTmp );
  205. if ( cbTmp == 0 ) {
  206. cbTmp = 1;
  207. pTmp = "-";
  208. }
  209. nRequired += cbTmp;
  210. if ( nRequired <= *pcbSize ) {
  211. CopyMemory(pBuffer, pTmp, cbTmp);
  212. pBuffer += cbTmp;
  213. }
  214. //
  215. // Parameters
  216. //
  217. pTmp = pLogObj->GetParameters( NULL, &cbTmp );
  218. if ( cbTmp != 0 ) {
  219. nRequired += cbTmp + 1; // 1 for ?
  220. if ( nRequired <= *pcbSize ) {
  221. *(pBuffer++) = '?';
  222. CopyMemory(pBuffer, pTmp, cbTmp);
  223. pBuffer += cbTmp;
  224. }
  225. }
  226. //
  227. // close request block version + status + bytes
  228. //
  229. {
  230. CHAR tmpBuf[MAX_PATH];
  231. DWORD bytes;
  232. PCHAR pVersion = pLogObj->GetVersionString(NULL, &cbTmp);
  233. if (cbTmp ==0) {
  234. pVersion = "HTTP/1.0";
  235. cbTmp = 8;
  236. }
  237. nRequired += cbTmp + 1 + 1 + 1; // 1 for beginning delimiter, 1 for ", 1 for ending delimiter
  238. if ( nRequired <= *pcbSize ) {
  239. *(pBuffer++) = ' ';
  240. CopyMemory(pBuffer, pVersion, cbTmp);
  241. pBuffer += cbTmp;
  242. *(pBuffer++) = '"';
  243. *(pBuffer++) = ' ';
  244. }
  245. cbTmp = FastDwToA(tmpBuf, pLogObj->GetProtocolStatus());
  246. *(tmpBuf+cbTmp) = ' ';
  247. cbTmp++;
  248. bytes = fUseBytesSent ? pLogObj->GetBytesSent( ) :
  249. pLogObj->GetBytesRecvd( );
  250. cbTmp += FastDwToA( tmpBuf+cbTmp, bytes);
  251. *(tmpBuf+cbTmp) = '\r';
  252. *(tmpBuf+cbTmp+1) = '\n';
  253. cbTmp += 2;
  254. nRequired += cbTmp;
  255. if ( nRequired <= *pcbSize ) {
  256. CopyMemory(pBuffer, tmpBuf, cbTmp);
  257. pBuffer += cbTmp;
  258. }
  259. }
  260. if ( nRequired > *pcbSize ) {
  261. *pcbSize = nRequired;
  262. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  263. return(FALSE);
  264. } else {
  265. *pcbSize = nRequired;
  266. return(TRUE);
  267. }
  268. } // CNCSALOG::FormatLogBuffer
  269. // -----------------------------------------------------------------------------
  270. // -----------------------------------------------------------------------------
  271. HRESULT
  272. CNCSALOG::ReadFileLogRecord(
  273. IN FILE *fpLogFile,
  274. IN LPINET_LOGLINE pInetLogLine,
  275. IN PCHAR pszLogLine,
  276. IN DWORD dwLogLineSize
  277. )
  278. {
  279. CHAR * pszTimeZone;
  280. CHAR * pCh;
  281. CHAR * szDateString, * szTimeString;
  282. double GMTCorrection;
  283. int iSign = 1;
  284. getnewline:
  285. pCh = pszLogLine;
  286. if (fgets(pCh, dwLogLineSize, fpLogFile) == NULL)
  287. {
  288. return E_FAIL;
  289. }
  290. pCh = SkipWhite(pCh);
  291. if (('\n' == *pCh) || ('\0' == *pCh))
  292. {
  293. // Empty line. Get Next line
  294. goto getnewline;
  295. }
  296. //
  297. // We have a log line.
  298. //
  299. // Format is:
  300. // Host - UserName [date] Operation Target status bytes
  301. //
  302. if ( NULL == (pCh = strtok(pCh," \t\r\n")) )
  303. {
  304. return E_FAIL;
  305. }
  306. pInetLogLine->pszClientHostName = pCh;
  307. //
  308. // This field is always "-"
  309. //
  310. if ( ( NULL == (pCh = strtok(NULL," \t\r\n")) )||
  311. ('-' != *pCh) )
  312. {
  313. return E_FAIL;
  314. }
  315. if ( NULL == (pCh = strtok(NULL," \t\r\n")) )
  316. {
  317. return E_FAIL;
  318. }
  319. pInetLogLine->pszClientUserName = pCh;
  320. //
  321. // This is the date field. It starts with a [, followed by date:time timezone]
  322. //
  323. pCh += strlen(pCh)+1;
  324. if (*pCh != '[')
  325. {
  326. return E_FAIL;
  327. }
  328. pCh++;
  329. if ( NULL == (pCh = strtok(pCh,":")) )
  330. {
  331. return E_FAIL;
  332. }
  333. szDateString = pCh;
  334. if ( NULL == (pCh = strtok(NULL," \t\r\n")) )
  335. {
  336. return E_FAIL;
  337. }
  338. szTimeString = pCh;
  339. pCh = strtok(NULL," \t\r\n");
  340. if ( (NULL == pCh) || ( ']' != *(pCh+strlen(pCh)-1)) || (strlen(pCh) < 4))
  341. {
  342. return E_FAIL;
  343. }
  344. pszTimeZone = pCh;
  345. //
  346. // Time Zone is in format [+/-]HHMM. Convert this to GMT and DATE format
  347. //
  348. if ( ! ConvertNCSADateToVariantDate(szDateString, szTimeString, &(pInetLogLine->DateTime)) )
  349. {
  350. return E_FAIL;
  351. }
  352. if (*pCh == '-')
  353. {
  354. iSign = -1;
  355. pszTimeZone = pCh+1;
  356. }
  357. else if (*pCh == '+')
  358. {
  359. iSign = 1;
  360. pszTimeZone = pCh+1;
  361. }
  362. GMTCorrection = (pszTimeZone[0]-'0' +pszTimeZone[1]-'0')/24.0 +
  363. (pszTimeZone[2]-'0' +pszTimeZone[3]-'0')/60.0;
  364. pInetLogLine->DateTime -= iSign*GMTCorrection;
  365. //
  366. // The Query String. Starts with " followed by method target version"
  367. //
  368. pCh += strlen(pCh)+1;
  369. *(pCh-2)='\0'; // Zero out the ] for the time zone
  370. if ('"' != *pCh)
  371. {
  372. return E_FAIL;
  373. }
  374. pCh++;
  375. if ( NULL == (pCh = strtok(pCh," \t\r\n")) )
  376. {
  377. return E_FAIL;
  378. }
  379. pInetLogLine->pszOperation = pCh;
  380. if ( NULL == (pCh = strtok(NULL," \t\r\n")) )
  381. {
  382. return E_FAIL;
  383. }
  384. pInetLogLine->pszTarget = pCh;
  385. //
  386. // In the Target, Parameters are separated by ?
  387. //
  388. pInetLogLine->pszParameters = strchr(pCh, '?');
  389. if (pInetLogLine->pszParameters != NULL)
  390. {
  391. *(pInetLogLine->pszParameters)='\0';
  392. (pInetLogLine->pszParameters)++;
  393. }
  394. pCh = strtok(NULL," \t\r\n");
  395. if ( (NULL == pCh) || ('"' != *(pCh+strlen(pCh)-1)) )
  396. {
  397. return E_FAIL;
  398. }
  399. pInetLogLine->pszVersion = pCh;
  400. //
  401. // Now the status code & bytes sent
  402. //
  403. pCh += strlen(pCh)+1;
  404. *(pCh-2)='\0'; // Zero out the " for the version string
  405. if ( NULL == (pCh = strtok(pCh," \t\r\n")) )
  406. {
  407. return E_FAIL;
  408. }
  409. pInetLogLine->pszProtocolStatus = pCh;
  410. if ( NULL == (pCh = strtok(NULL," \t\r\n")) )
  411. {
  412. return E_FAIL;
  413. }
  414. pInetLogLine->pszBytesSent = pCh;
  415. return S_OK;
  416. }
  417. // -----------------------------------------------------------------------------
  418. // -----------------------------------------------------------------------------
  419. HRESULT
  420. CNCSALOG::WriteFileLogRecord(
  421. IN FILE *fpLogFile,
  422. IN ILogScripting *pILogScripting,
  423. IN bool
  424. )
  425. {
  426. HRESULT hr = E_FAIL;
  427. CHAR szLogLine[4096];
  428. DWORD dwIndex = 0;
  429. //
  430. // Format is:
  431. // Host - UserName [date] Operation Target status bytes
  432. //
  433. VARIANT szHostName, szUserName, szOperation, szTarget, szParameters, szProtocolVersion;
  434. VARIANT DateTime;
  435. VARIANT lBytesSent, lProtocolStatus;
  436. SYSTEMTIME localTime;
  437. if (SUCCEEDED(pILogScripting->get_ClientIP ( &szHostName)) &&
  438. SUCCEEDED(pILogScripting->get_UserName ( &szUserName)) &&
  439. SUCCEEDED(pILogScripting->get_DateTime ( &DateTime)) &&
  440. SUCCEEDED(pILogScripting->get_Method ( &szOperation)) &&
  441. SUCCEEDED(pILogScripting->get_URIStem ( &szTarget)) &&
  442. SUCCEEDED(pILogScripting->get_URIQuery ( &szParameters)) &&
  443. SUCCEEDED(pILogScripting->get_BytesSent ( &lBytesSent)) &&
  444. SUCCEEDED(pILogScripting->get_ProtocolStatus( &lProtocolStatus))&&
  445. SUCCEEDED(pILogScripting->get_ProtocolVersion( &szProtocolVersion))&&
  446. VariantTimeToSystemTime( DateTime.date+m_GMTDateCorrection, &localTime)
  447. )
  448. {
  449. sprintf(szLogLine, "%ws - %ws [%02d/%s/%d:%02d:%02d:%02d %s] \"%ws %ws",
  450. GetBstrFromVariant( &szHostName),
  451. GetBstrFromVariant( &szUserName),
  452. localTime.wDay,
  453. Month3CharNames(localTime.wMonth-1),
  454. localTime.wYear,
  455. localTime.wHour,
  456. localTime.wMinute,
  457. localTime.wSecond,
  458. m_szGMTOffset,
  459. GetBstrFromVariant( &szOperation),
  460. GetBstrFromVariant( &szTarget)
  461. );
  462. if ( ( VT_NULL != szParameters.vt) &&
  463. ( VT_EMPTY != szParameters.vt )
  464. )
  465. {
  466. sprintf(szLogLine+strlen(szLogLine), "?%ws", GetBstrFromVariant( &szParameters));
  467. }
  468. sprintf(szLogLine+strlen(szLogLine), " %ws\"", GetBstrFromVariant( &szProtocolVersion));
  469. dwIndex = (DWORD)strlen(szLogLine);
  470. szLogLine[dwIndex++] = ' ';
  471. dwIndex += GetLongFromVariant( &lProtocolStatus, szLogLine+dwIndex );
  472. szLogLine[dwIndex++] = ' ';
  473. dwIndex += GetLongFromVariant( &lBytesSent, szLogLine+dwIndex );
  474. szLogLine[dwIndex++] = '\0';
  475. fprintf(fpLogFile, "%s\n", szLogLine);
  476. hr = S_OK;
  477. }
  478. return hr;
  479. }
  480. // -----------------------------------------------------------------------------
  481. // -----------------------------------------------------------------------------
  482. BOOL
  483. CNCSALOG::ConvertNCSADateToVariantDate(PCHAR szDateString, PCHAR szTimeString, DATE * pDateTime)
  484. {
  485. PCHAR pCh;
  486. WORD iVal;
  487. CHAR *szMonths[12] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
  488. SYSTEMTIME sysTime;
  489. //
  490. // Process the Date. Format is 23/Sep/1997 ( Day/Month/Year )
  491. //
  492. pCh = szDateString;
  493. iVal = *pCh -'0';
  494. if ( *(pCh+1) != '/')
  495. {
  496. iVal = iVal*10 + *(pCh+1) - '0';
  497. pCh++;
  498. }
  499. sysTime.wDay = iVal;
  500. pCh += 2;
  501. for (WORD i=0; i<12;i++)
  502. {
  503. if ( 0 == strncmp(pCh,szMonths[i],3) )
  504. {
  505. sysTime.wMonth = i+1;
  506. break;
  507. }
  508. }
  509. pCh += 4;
  510. sysTime.wYear = (*pCh-'0')*1000 + ( *(pCh+1)-'0' )*100 +
  511. ( *(pCh+2)-'0')*10 + ( *(pCh+3)-'0');
  512. //
  513. // Process the Time. Format is 10:47:44 ( HH:MM:SS )
  514. //
  515. pCh = szTimeString;
  516. iVal = *pCh -'0';
  517. if ( *(pCh+1) != ':')
  518. {
  519. iVal = iVal*10 + *(pCh+1) - '0';
  520. pCh++;
  521. }
  522. sysTime.wHour = iVal;
  523. pCh += 2;
  524. iVal = *pCh -'0';
  525. if ( *(pCh+1) != ':')
  526. {
  527. iVal = iVal*10 + *(pCh+1) - '0';
  528. pCh++;
  529. }
  530. sysTime.wMinute = iVal;
  531. pCh += 2;
  532. iVal = *pCh -'0';
  533. if ( *(pCh+1) != '\0')
  534. {
  535. iVal = iVal*10 + *(pCh+1) - '0';
  536. }
  537. sysTime.wSecond = iVal;
  538. return SystemTimeToVariantTime(&sysTime, pDateTime);
  539. }