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.

312 lines
8.5 KiB

  1. /*--
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name: LOG.CPP
  4. Author: John Spaith
  5. Abstract: Logging functions
  6. --*/
  7. #include "pch.h"
  8. #pragma hdrstop
  9. // Responsible for log handling functions.
  10. // A curhttpd.log and prvhttpd.log keep track of current and the previous
  11. // changes. The format for each line is stolen from IIS, except that we
  12. // include the date in each line; they create a new log for each day.
  13. #include "httpd.h"
  14. #ifdef WEB_SERVER_LOGGING
  15. // const char cszDateOutputFmt[] = "%3s, %02d %3s %04d %02d:%02d:%02d ";
  16. #define CURRENT_LOG_NAME L"\\current-httpd.log"
  17. #define PREVIOUS_LOG_NAME L"\\previous-httpd.log"
  18. #define LOG_REMOTE_ADDR_SIZE 50
  19. #define LOG_EXTRA_BUFFER_LEN 100
  20. void CLog::WriteEvent(DWORD dwEvent,...)
  21. {
  22. CHAR szOutput[MINBUFSIZE];
  23. WCHAR wszFormat[512];
  24. WCHAR wszOutput[512];
  25. PSTR pszTrav = szOutput;
  26. SYSTEMTIME st;
  27. va_list ap;
  28. if (!LoadString(g_hInst,dwEvent,wszFormat,celems(wszFormat)))
  29. return;
  30. va_start(ap,dwEvent);
  31. wvsprintf(wszOutput,wszFormat,ap);
  32. va_end (ap);
  33. GetSystemTime(&st);
  34. pszTrav = WriteHTTPDate(szOutput,&st,FALSE);
  35. pszTrav += MyW2A(wszOutput,pszTrav,MINBUFSIZE - (pszTrav - szOutput)) - 1;
  36. WriteData(szOutput,pszTrav - szOutput);
  37. }
  38. CLog::~CLog()
  39. {
  40. WriteEvent(IDS_HTTPD_SHUTDOWN_COMPLETE);
  41. MyCloseHandle(m_hLog);
  42. DeleteCriticalSection(&m_CritSection);
  43. }
  44. #define MAX_LOG_OPEN_ATTEMPTS 15
  45. CLog::CLog(DWORD_PTR dwMaxFileLen, WCHAR * lpszLogDir)
  46. {
  47. int i;
  48. memset(this, 0, sizeof(*this));
  49. if (0 == dwMaxFileLen || NULL == lpszLogDir)
  50. {
  51. TraceTag(ttidWebServer, "HTTPD: No logging to be performed, because of on registry settings");
  52. m_hLog = INVALID_HANDLE_VALUE;
  53. return;
  54. }
  55. m_dwMaxFileSize = dwMaxFileLen;
  56. InitializeCriticalSection(&m_CritSection);
  57. TraceTag(ttidWebServer, "HTTPD: Initializing log files");
  58. // remove trailing "\" if log file dir entry ends in it
  59. if ( lpszLogDir[wcslen(lpszLogDir) - 1] == L'\\')
  60. lpszLogDir[wcslen(lpszLogDir) - 1] = L'\0';
  61. wsprintf(lpszCurrentLog,L"%s%s",lpszLogDir, CURRENT_LOG_NAME);
  62. wsprintf(lpszPrevLog,L"%s%s",lpszLogDir,PREVIOUS_LOG_NAME);
  63. // Note: It's possible that the log file is being written to a flash
  64. // drive, in which case the web server initialization routines would
  65. // be called before the drive is ready during boot time, in which
  66. // case we get an INVALID_HANDLE_VALUE. To make sure the drive has
  67. // time to initialize, we go through this loop before failing.
  68. for (i = 0; i < MAX_LOG_OPEN_ATTEMPTS; i++)
  69. {
  70. if (INVALID_HANDLE_VALUE != (m_hLog = MyOpenAppendFile(lpszCurrentLog)))
  71. {
  72. break;
  73. }
  74. Sleep(1000);
  75. }
  76. if (INVALID_HANDLE_VALUE == m_hLog)
  77. {
  78. TraceTag(ttidWebServer, "HTTPD: CreateFile fails for log <<%s>>, no logging will be done, GLE=0x%08x",lpszCurrentLog,GetLastError());
  79. return;
  80. }
  81. m_dwFileSize = GetFileSize(m_hLog,NULL);
  82. if ((DWORD)-1 == m_dwFileSize)
  83. {
  84. TraceTag(ttidWebServer, "HTTPD: Get file size on log <<%s>> failed, err = %d",lpszCurrentLog,GetLastError());
  85. m_hLog = INVALID_HANDLE_VALUE;
  86. return;
  87. }
  88. if (m_dwFileSize != 0) // This moves filePtr to append log file
  89. {
  90. if ((DWORD)-1 == SetFilePointer(m_hLog, (DWORD)m_dwFileSize, NULL, FILE_BEGIN))
  91. {
  92. TraceTag(ttidWebServer, "HTTPD: Get file size on log %s failed, err = %d",lpszCurrentLog,GetLastError());
  93. m_hLog = INVALID_HANDLE_VALUE;
  94. return;
  95. }
  96. }
  97. WriteEvent(IDS_HTTPD_STARTUP);
  98. }
  99. // The log written has the following format
  100. // (DATE) (TIME) (IP of requester) (Method) (Request-URI) (Status returned)
  101. // DATE is in the same format as the recommended one for httpd headers
  102. // TIME is GMT
  103. void CLog::WriteLog(CHttpRequest* pRequest)
  104. {
  105. CHAR szBuffer[MINBUFSIZE];
  106. PSTR psz = szBuffer;
  107. DWORD_PTR dwToWrite = 0;
  108. DEBUGCHK(pRequest != NULL);
  109. if (INVALID_HANDLE_VALUE == m_hLog) // no logging setup in reg, or prev failure
  110. return;
  111. // Make sure that buffer is big enough for filter additions, append if not so
  112. // We add LOG_EXTRA_BUFFER_LEN to account for date, spaces, and HTTP status code.
  113. DWORD cbNeeded = LOG_EXTRA_BUFFER_LEN + pRequest->GetLogBufferSize();
  114. if (cbNeeded > MINBUFSIZE)
  115. {
  116. psz = MyRgAllocNZ(CHAR,cbNeeded);
  117. if (!psz)
  118. return;
  119. }
  120. pRequest->GenerateLog(psz,&dwToWrite);
  121. WriteData(psz,dwToWrite);
  122. if (szBuffer != psz)
  123. MyFree(psz);
  124. }
  125. void CLog::WriteData(PSTR szBuffer, DWORD_PTR dwToWrite)
  126. {
  127. DWORD dwWritten = 0;
  128. EnterCriticalSection(&m_CritSection);
  129. {
  130. m_dwFileSize += dwToWrite;
  131. // roll over the logs once the maximum size has been reached.
  132. if (m_dwFileSize > m_dwMaxFileSize)
  133. {
  134. MyCloseHandle(m_hLog);
  135. DeleteFile(lpszPrevLog);
  136. MoveFile(lpszCurrentLog,lpszPrevLog);
  137. m_hLog = MyOpenAppendFile(lpszCurrentLog);
  138. m_dwFileSize = dwToWrite;
  139. }
  140. if (m_hLog != INVALID_HANDLE_VALUE)
  141. {
  142. WriteFile(m_hLog,(LPCVOID) szBuffer,(DWORD)dwToWrite,&dwWritten,NULL);
  143. TraceTag(ttidWebServer, "HTTPD: Wrote log out to file");
  144. }
  145. }
  146. LeaveCriticalSection(&m_CritSection);
  147. }
  148. // Returns the size of the buffer we'll need.
  149. DWORD CHttpRequest::GetLogBufferSize()
  150. {
  151. PHTTP_FILTER_LOG pFLog = m_pFInfo ? m_pFInfo->m_pFLog : NULL;
  152. DWORD cbNeeded;
  153. // remotehost
  154. if (pFLog && pFLog->pszClientHostName)
  155. cbNeeded = strlen(pFLog->pszClientHostName);
  156. else
  157. cbNeeded = LOG_REMOTE_ADDR_SIZE;
  158. if (pFLog && pFLog->pszOperation)
  159. cbNeeded += strlen(pFLog->pszOperation);
  160. else if (m_pszMethod)
  161. cbNeeded += strlen(m_pszMethod);
  162. if (pFLog && pFLog->pszTarget)
  163. cbNeeded += strlen(pFLog->pszTarget);
  164. else if (m_pszURL)
  165. cbNeeded += strlen(m_pszURL);
  166. if (m_pszLogParam)
  167. cbNeeded += strlen(m_pszLogParam);
  168. return cbNeeded;
  169. }
  170. // Generates the log. First this fcn sees if a filter has created a new
  171. // logging structure, in which case valid data in pFLog will override actual
  172. // server data. In the typical case we just use CHttpRequest info.
  173. void CHttpRequest::GenerateLog(PSTR szBuffer, DWORD_PTR *pdwToWrite)
  174. {
  175. SYSTEMTIME st;
  176. PSTR pszTarget = NULL;
  177. PSTR pszTrav = szBuffer;
  178. int i = 0;
  179. GetSystemTime(&st); // Use GMT time for the log, too
  180. PHTTP_FILTER_LOG pFLog = m_pFInfo ? m_pFInfo->m_pFLog : NULL;
  181. // date and time
  182. pszTrav = WriteHTTPDate(pszTrav,&st,FALSE);
  183. // i += sprintf(szBuffer + i, cszDateOutputFmt,
  184. // rgWkday[st.wDayOfWeek], st.wDay, rgMonth[st.wMonth], st.wYear, st.wHour, st.wMinute, st.wSecond);
  185. // remotehost
  186. if (pFLog && pFLog->pszClientHostName)
  187. {
  188. pszTrav = strcpyEx(pszTrav,pFLog->pszClientHostName);
  189. }
  190. else
  191. {
  192. CHAR szAddress[LOG_REMOTE_ADDR_SIZE];
  193. GetRemoteAddress(m_socket,szAddress);
  194. pszTrav = strcpyEx(pszTrav,szAddress);
  195. }
  196. *pszTrav++ = ' ';
  197. // The method (GET, POST, ...)
  198. if (pFLog && pFLog->pszOperation)
  199. pszTrav = strcpyEx(pszTrav,pFLog->pszOperation);
  200. else if (m_pszMethod)
  201. pszTrav = strcpyEx(pszTrav,m_pszMethod);
  202. else
  203. *pszTrav++ = '\t'; // If we get a bad request from browser, m_pszMethod may be NULL.
  204. *pszTrav++ = ' ';
  205. // target (URI)
  206. if (pFLog && pFLog->pszTarget)
  207. pszTarget = (PSTR) pFLog->pszTarget;
  208. else
  209. pszTarget = m_pszURL;
  210. // like IIS, we convert any spaces in here into "+" signs.
  211. // NOTES: IIS does this for both filter changed targets and URLS.
  212. // It only does it with spaces, doesn't convert \r\n, tabs, or any other escape
  213. // characters
  214. if (pszTarget) // on a bad request, m_pszURL may = NULL. Check.
  215. {
  216. while ( *pszTarget)
  217. {
  218. if ( *pszTarget == ' ')
  219. *pszTrav++ = '+';
  220. else
  221. *pszTrav++ = *pszTarget;
  222. pszTarget++;
  223. }
  224. }
  225. *pszTrav++ = ' ';
  226. // status
  227. if (pFLog)
  228. _itoa(pFLog->dwHttpStatus,pszTrav,10);
  229. else
  230. _itoa(rgStatus[m_rs].dwStatusNumber,pszTrav,10);
  231. pszTrav = strchr(pszTrav,'\0');
  232. *pszTrav++ = ' ';
  233. if (m_pszLogParam) // ISAPI Extension logging has modified something
  234. pszTrav = strcpyEx(pszTrav,m_pszLogParam);
  235. *pszTrav++ = '\r';
  236. *pszTrav++ = '\n';
  237. *pszTrav= '\0';
  238. *pdwToWrite = pszTrav - szBuffer;
  239. return;
  240. }
  241. #endif //!WEB_SERVER_LOGGING