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.

2528 lines
70 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Error handling
  6. File: Error.cpp
  7. Owner: AndrewS
  8. This file contains general error reporting routines for Denali.
  9. ===================================================================*/
  10. #include "denpre.h"
  11. #pragma hdrstop
  12. #include <psapi.h>
  13. #include "debugger.h"
  14. #include "asperror.h"
  15. #include "memchk.h"
  16. #define DELIMITER "~"
  17. #define MAX_HEADERSIZE 128
  18. #define MAX_TEMPLATELEN 128
  19. //The order of ErrTemplate_Index should be exactly the same order as the IDS_BROWSER_TEMPLATE
  20. //in the aspresource.h, and as the same order we output the template to the browser.
  21. //Implementation will loop through the index and picking the string from the resource file.
  22. //Implementation will also loop through the index and write the string to browser.
  23. #define ErrTemplate_BEGIN 0
  24. #define ErrTemplate_ENGINE_BEGIN 1
  25. #define ErrTemplate_ENGINE_END 2
  26. #define ErrTemplate_ERROR_BEGIN 3
  27. #define ErrTemplate_ERROR_END 4
  28. #define ErrTemplate_SHORT_BEGIN 5
  29. #define ErrTemplate_SHORT_END 6
  30. #define ErrTemplate_FILE_BEGIN 7
  31. #define ErrTemplate_FILE_END 8
  32. #define ErrTemplate_LINE_BEGIN 9
  33. #define ErrTemplate_LINE_END 10
  34. #define ErrTemplate_CODE_BEGIN 11
  35. #define ErrTemplate_CODE_END 12
  36. #define ErrTemplate_LONG_BEGIN 13
  37. #define ErrTemplate_LONG_END 14
  38. #define ErrTemplate_END 15
  39. #define ErrTemplateMAX 16
  40. const DWORD dwDefaultMask = 0x6; // toNTLog(OFF), toIISLog(ON), toBrowser(ON)
  41. CHAR g_szErrTemplate[ErrTemplateMAX][MAX_TEMPLATELEN];
  42. const LPSTR szErrSysTemplate[] = { "<html><body><h1> HTTP/1.1 ",
  43. "</h1></body></html>"};
  44. CErrInfo g_ErrInfoOOM, g_ErrInfoUnExpected;
  45. CHAR szIISErrorPrefix[20];
  46. DWORD cszIISErrorPrefix;
  47. CPINFO g_SystemCPInfo; // global System CodePage default info.
  48. static char s_szContentTypeTextHtml[] = "Content-type: text/html\r\n\r\n";
  49. CHAR *SzScodeToErrorCode(HRESULT hrError);
  50. void FreeNullifySz(CHAR **szIn);
  51. BOOL FIsResStrFormatted(char *szIn);
  52. extern LONG g_nOOMErrors;
  53. /*===================================================================
  54. FreeNullifySz
  55. Free the memory allocated in szIn, and Nullify the szIn.
  56. ===================================================================*/
  57. void FreeNullifySz(CHAR **szIn)
  58. {
  59. if(*szIn)
  60. {
  61. free(*szIn);
  62. *szIn = NULL;
  63. }
  64. }
  65. /*===================================================================
  66. ErrHandleInit
  67. PreLoad strings for
  68. 1> OOM
  69. 2> Browser Output Template
  70. Returns:
  71. HRESULT
  72. ===================================================================*/
  73. HRESULT ErrHandleInit(void)
  74. {
  75. INT iEntry, iEntryID;
  76. HRESULT hr;
  77. // Retrieve global system codepage and stores it.
  78. GetCPInfo(CP_ACP, &g_SystemCPInfo);
  79. //Init g_szErrTemplate
  80. //Loop through, and load strings from resource file.
  81. for (iEntry = ErrTemplate_BEGIN, iEntryID = IDS_BROWSER_TEMPLATE_BEGIN;
  82. iEntry < ErrTemplateMAX; iEntry ++, iEntryID++)
  83. {
  84. CchLoadStringOfId(iEntryID, (CHAR *)g_szErrTemplate[iEntry], MAX_TEMPLATELEN);
  85. }
  86. g_ErrInfoOOM.m_szItem[Im_szErrorCode] = (CHAR *)malloc(sizeof(CHAR)*20*g_SystemCPInfo.MaxCharSize);
  87. g_ErrInfoOOM.m_szItem[Im_szShortDescription] = (CHAR *)malloc(sizeof(CHAR)*256*g_SystemCPInfo.MaxCharSize);
  88. g_ErrInfoOOM.m_szItem[Im_szLongDescription] = (CHAR *)malloc(sizeof(CHAR)*512*g_SystemCPInfo.MaxCharSize);
  89. if (!g_ErrInfoOOM.m_szItem[Im_szErrorCode] ||
  90. !g_ErrInfoOOM.m_szItem[Im_szShortDescription] ||
  91. !g_ErrInfoOOM.m_szItem[Im_szLongDescription])
  92. {
  93. return E_OUTOFMEMORY;
  94. }
  95. hr = LoadErrResString(IDE_OOM,
  96. &g_ErrInfoOOM.m_dwMask,
  97. g_ErrInfoOOM.m_szItem[Im_szErrorCode],
  98. g_ErrInfoOOM.m_szItem[Im_szShortDescription],
  99. g_ErrInfoOOM.m_szItem[Im_szLongDescription]);
  100. g_ErrInfoUnExpected.m_szItem[Im_szErrorCode] = (CHAR *)malloc(sizeof(CHAR)*20*g_SystemCPInfo.MaxCharSize);
  101. g_ErrInfoUnExpected.m_szItem[Im_szShortDescription] = (CHAR *)malloc(sizeof(CHAR)*256*g_SystemCPInfo.MaxCharSize);
  102. g_ErrInfoUnExpected.m_szItem[Im_szLongDescription] = (CHAR *)malloc(sizeof(CHAR)*512*g_SystemCPInfo.MaxCharSize);
  103. if (!g_ErrInfoUnExpected.m_szItem[Im_szErrorCode] ||
  104. !g_ErrInfoUnExpected.m_szItem[Im_szShortDescription] ||
  105. !g_ErrInfoUnExpected.m_szItem[Im_szLongDescription])
  106. {
  107. return E_OUTOFMEMORY;
  108. }
  109. hr = LoadErrResString(IDE_UNEXPECTED,
  110. &g_ErrInfoUnExpected.m_dwMask,
  111. g_ErrInfoUnExpected.m_szItem[Im_szErrorCode],
  112. g_ErrInfoUnExpected.m_szItem[Im_szShortDescription],
  113. g_ErrInfoUnExpected.m_szItem[Im_szLongDescription]);
  114. cszIISErrorPrefix = CchLoadStringOfId(IDS_IISLOG_PREFIX , szIISErrorPrefix, 20);
  115. return hr;
  116. }
  117. /*===================================================================
  118. ErrHandleUnInit
  119. Unit the global err-handling data.
  120. Free up the OOM CErrInfo.
  121. Side Effect:
  122. Free up memory.
  123. ===================================================================*/
  124. HRESULT ErrHandleUnInit(void)
  125. {
  126. FreeNullifySz((CHAR **)&g_ErrInfoOOM.m_szItem[Im_szErrorCode]);
  127. FreeNullifySz((CHAR **)&g_ErrInfoOOM.m_szItem[Im_szShortDescription]);
  128. FreeNullifySz((CHAR **)&g_ErrInfoOOM.m_szItem[Im_szLongDescription]);
  129. FreeNullifySz((CHAR **)&g_ErrInfoUnExpected.m_szItem[Im_szErrorCode]);
  130. FreeNullifySz((CHAR **)&g_ErrInfoUnExpected.m_szItem[Im_szShortDescription]);
  131. FreeNullifySz((CHAR **)&g_ErrInfoUnExpected.m_szItem[Im_szLongDescription]);
  132. return S_OK;
  133. }
  134. /*===================================================================
  135. Constructor
  136. ===================================================================*/
  137. CErrInfo::CErrInfo()
  138. {
  139. for (UINT iErrInfo = 0; iErrInfo < Im_szItemMAX; iErrInfo++)
  140. m_szItem[iErrInfo] = NULL;
  141. m_bstrLineText = NULL;
  142. m_nColumn = -1;
  143. m_dwMask = 0;
  144. m_pIReq = NULL;
  145. m_pHitObj = NULL;
  146. m_dwHttpErrorCode = 0;
  147. m_dwHttpSubErrorCode = 0;
  148. }
  149. /*===================================================================
  150. CErrInfo::ParseResourceString
  151. Parse Resource String to get default mask, error type, short description,
  152. and long description.
  153. Assume resource string is proper formmated.
  154. Format of resource string
  155. DefaultMask~errortype~shortdescription~longdescription
  156. In case we can not allocate szResourceString(szResourceString), we use default.
  157. Returns:
  158. Nothing
  159. ===================================================================*/
  160. HRESULT CErrInfo::ParseResourceString(CHAR *szResourceString)
  161. {
  162. CHAR *szToken = NULL;
  163. INT cfield = 0;
  164. INT iItem = 0;
  165. INT iIndex = 0;
  166. INT rgErrInfoIndex[3] = {Im_szErrorCode, Im_szShortDescription, Im_szLongDescription};
  167. if(NULL == szResourceString)
  168. {
  169. m_dwMask = dwDefaultMask;
  170. for(iItem = 0, iIndex = 0; iIndex < 3; iIndex++)
  171. {
  172. iItem = rgErrInfoIndex[iIndex];
  173. m_szItem[iItem] = g_ErrInfoUnExpected.m_szItem[iItem];
  174. }
  175. return S_OK;
  176. }
  177. //Mask
  178. szToken = (char *)_mbstok((unsigned char *)szResourceString, (unsigned char *)DELIMITER);
  179. if(szToken != NULL)
  180. {
  181. m_dwMask = atoi(szToken);
  182. cfield++;
  183. }
  184. else
  185. {
  186. m_dwMask = dwDefaultMask;
  187. }
  188. //3 String Items, ErrorCode,ShortDescription,LongDescription
  189. for(iItem = 0, iIndex = 0; iIndex < 3; iIndex++)
  190. {
  191. szToken = (char *)_mbstok(NULL, (unsigned char *)DELIMITER);
  192. iItem = rgErrInfoIndex[iIndex];
  193. if (szToken != NULL)
  194. {
  195. m_szItem[iItem] = szToken;
  196. cfield++;
  197. }
  198. else
  199. {
  200. // Long Description is optional.
  201. if (Im_szLongDescription != iItem)
  202. {
  203. m_szItem[iItem] = g_ErrInfoUnExpected.m_szItem[iItem];
  204. }
  205. cfield++;
  206. }
  207. }
  208. //check wether we have wrong format of resource string.
  209. Assert(cfield == 4);
  210. return S_OK;
  211. }
  212. /*===================================================================
  213. CErrInfo::LogError(void)
  214. Perform all the switch logic in this functions. Send error to NT Log,
  215. IIS Log, or Browser.
  216. When reach this point, we assume all the strings have allocated, and will not be used after this
  217. function.
  218. Side effects:
  219. Returns:
  220. HRESULT
  221. ===================================================================*/
  222. HRESULT CErrInfo::LogError(void)
  223. {
  224. HRESULT hr = S_OK;
  225. HRESULT hr_ret = S_OK;
  226. UINT iEInfo = 0;
  227. BOOL fIISLogFailed, fDupToNTLog;
  228. #if DBG
  229. // Print details about the error to debug window; don't bother if
  230. // info is NULL (happens for things like 404 not found, etc.)
  231. if (m_szItem[Im_szEngine] != NULL && m_szItem[Im_szFileName] != NULL)
  232. {
  233. DBGERROR((DBG_CONTEXT, "%s error in %s at line %s\n",
  234. m_szItem[Im_szEngine],
  235. m_szItem[Im_szFileName],
  236. m_szItem[Im_szLineNum]? m_szItem[Im_szLineNum] : "?"));
  237. DBGPRINTF((DBG_CONTEXT, " %s: %s\n",
  238. m_szItem[Im_szErrorCode],
  239. m_szItem[Im_szShortDescription]));
  240. }
  241. else
  242. DBGERROR((DBG_CONTEXT, "ASP Error: %s\n", m_szItem[Im_szShortDescription]? m_szItem[Im_szShortDescription] : "?"));
  243. #endif
  244. // Attach ASP error to HitObj (if exists and in 'executing' state)
  245. if (m_pHitObj && m_pHitObj->FExecuting())
  246. {
  247. CASPError *pASPError = new CASPError(this);
  248. if (pASPError)
  249. m_pHitObj->SetASPError(pASPError);
  250. }
  251. hr = LogErrortoIISLog(&fIISLogFailed, &fDupToNTLog);
  252. if (FAILED(hr))
  253. {
  254. hr_ret = hr;
  255. }
  256. //fIISLogFailed, if it is TRUE, then, this error was upgraded, and should be a WARNING type in
  257. //NT event log.
  258. hr = LogErrortoNTEventLog(fIISLogFailed, fDupToNTLog);
  259. if (FAILED(hr))
  260. {
  261. hr_ret = hr;
  262. }
  263. hr = LogErrortoBrowserWrapper();
  264. if (FAILED(hr))
  265. {
  266. hr_ret = hr;
  267. }
  268. if (m_pHitObj)
  269. {
  270. m_pHitObj->SetExecStatus(eExecFailed);
  271. }
  272. //In case of an error, hr_ret is the last error reported from the 3 logging functions.
  273. return hr_ret;
  274. }
  275. /*===================================================================
  276. CErrInfo::LogErrortoNTEventLog
  277. Log Error/Event to NT Event Log.
  278. Returns:
  279. Nothing
  280. ===================================================================*/
  281. HRESULT CErrInfo::LogErrortoNTEventLog
  282. (
  283. BOOL fIISLogFailed,
  284. BOOL fDupToNTLog
  285. )
  286. {
  287. CHAR szErrNTLogEntry[4096];
  288. CHAR szStringTemp[MAX_PATH];
  289. INT cch = 0;
  290. if(Glob(fLogErrorRequests))
  291. {
  292. //Is the error serious enough to get into NT log
  293. if(ERR_FLogtoNT(m_dwMask) || fIISLogFailed || fDupToNTLog)
  294. {
  295. szErrNTLogEntry[0] = '\0';
  296. if (fIISLogFailed)
  297. {
  298. cch = CchLoadStringOfId(IDS_LOG_IISLOGFAILED, szStringTemp, MAX_PATH);
  299. strncat(szErrNTLogEntry, szStringTemp, cch);
  300. }
  301. if (m_szItem[Im_szFileName] != NULL)
  302. {
  303. cch = CchLoadStringOfId(IDS_LOGTOEVENTLOG_FILE, szStringTemp, MAX_PATH);
  304. strncat(szErrNTLogEntry, szStringTemp, cch);
  305. strncat(szErrNTLogEntry, m_szItem[Im_szFileName], 512);
  306. }
  307. strncat(szErrNTLogEntry, " ", 1);
  308. if (m_szItem[Im_szLineNum] != NULL)
  309. {
  310. cch = CchLoadStringOfId(IDS_LOGTOEVENTLOG_LINE, szStringTemp, MAX_PATH);
  311. strncat(szErrNTLogEntry, szStringTemp, cch);
  312. strncat(szErrNTLogEntry, m_szItem[Im_szLineNum], 48);
  313. }
  314. strncat(szErrNTLogEntry, " ", 1);
  315. //Ok, do we have something to log.
  316. if (m_szItem[Im_szShortDescription] != NULL)
  317. {
  318. // ShortDescription does not have ". " at the end.
  319. // Therefore, the next strncat need to concatenate two sentences together with
  320. // a period ". ".
  321. char szTempPeriod[] = ". ";
  322. strncat(szErrNTLogEntry, m_szItem[Im_szShortDescription], 512);
  323. strncat(szErrNTLogEntry, szTempPeriod, 512);
  324. }
  325. else
  326. {
  327. DWORD dwMask;
  328. CHAR szDenaliNotWorking[MAX_PATH];
  329. LoadErrResString(IDE_UNEXPECTED, &dwMask, NULL, szDenaliNotWorking, NULL);
  330. strncat(szErrNTLogEntry, szDenaliNotWorking, strlen(szDenaliNotWorking));
  331. }
  332. //Ok, do we have something to log.
  333. if (m_szItem[Im_szLongDescription] != NULL)
  334. {
  335. strncat(szErrNTLogEntry, m_szItem[Im_szLongDescription], 512);
  336. }
  337. if (fIISLogFailed || fDupToNTLog)
  338. MSG_Warning((LPCSTR)szErrNTLogEntry);
  339. else
  340. MSG_Error((LPCSTR)szErrNTLogEntry);
  341. }
  342. }
  343. return S_OK;
  344. }
  345. /*===================================================================
  346. CErrInfo::LogErrortoIISLog
  347. Log Error/Event to IIS Log.
  348. If we fail to log the message then upgrade logging to NT event Log
  349. with entries indicate the error and the IIS log failed.
  350. Also do the upgrade if the global setting says so.
  351. Returns:
  352. Nothing
  353. ===================================================================*/
  354. HRESULT CErrInfo::LogErrortoIISLog
  355. (
  356. BOOL *pfIISLogFailed,
  357. BOOL *pfDupToNTLog
  358. )
  359. {
  360. HRESULT hr = S_OK;
  361. const LPSTR szIISDelimiter = "|";
  362. const DWORD cszIISDelimiter = 1; // strlen("|");
  363. const LPSTR szIISNoInfo = "-";
  364. const DWORD cszIISNoInfo = 1; // strlen("-");
  365. const CHAR chProxy = '_';
  366. CIsapiReqInfo *pIReq = NULL;
  367. *pfIISLogFailed = FALSE;
  368. *pfDupToNTLog = FALSE;
  369. if (m_pIReq == NULL && m_pHitObj == NULL)
  370. return S_OK;
  371. //Try to write to IISLog via pIReq->QueryPszLogData()
  372. if (ERR_FLogtoIIS(m_dwMask))
  373. {
  374. //get pIReq
  375. if (m_pHitObj)
  376. {
  377. pIReq = m_pHitObj->PIReq();
  378. }
  379. if (NULL == pIReq)
  380. {
  381. pIReq = m_pIReq;
  382. }
  383. if (pIReq == NULL)
  384. {
  385. *pfIISLogFailed = TRUE;
  386. return E_FAIL;
  387. }
  388. // Setup the sub-string array
  389. const DWORD crgsz = 3;
  390. LPSTR rgsz[crgsz];
  391. rgsz[0] = m_szItem[Im_szLineNum];
  392. rgsz[1] = m_szItem[Im_szErrorCode];
  393. rgsz[2] = m_szItem[Im_szShortDescription];
  394. // Allocate the log entry string
  395. CHAR *szLogEntry = NULL;
  396. DWORD cszLogEntry = (cszIISDelimiter * crgsz) + 1;
  397. DWORD dwIndex;
  398. for (dwIndex = 0; dwIndex < crgsz; dwIndex++)
  399. {
  400. if (rgsz[dwIndex])
  401. cszLogEntry += strlen(rgsz[dwIndex]);
  402. else
  403. cszLogEntry += cszIISNoInfo;
  404. }
  405. szLogEntry = new CHAR[cszLogEntry];
  406. if (NULL == szLogEntry) {
  407. return E_OUTOFMEMORY;
  408. }
  409. // Copy the entry, proxy bad characters
  410. CHAR *szSource = NULL;
  411. CHAR *szDest = szLogEntry;
  412. // Start with a delimiter to separate us from
  413. // the request query
  414. memcpy(szDest, szIISDelimiter, cszIISDelimiter);
  415. szDest += cszIISDelimiter;
  416. for (dwIndex = 0; dwIndex < crgsz; dwIndex++)
  417. {
  418. szSource = rgsz[dwIndex];
  419. if (szSource)
  420. {
  421. while (*szSource)
  422. {
  423. if (isleadbyte(*szSource))
  424. {
  425. *szDest++ = *szSource++;
  426. *szDest++ = *szSource++;
  427. }
  428. else if ((*szSource == ',') ||
  429. (*szSource == ' ') ||
  430. (*szSource == '\r') ||
  431. (*szSource == '\n') ||
  432. (*szSource == '\"'))
  433. {
  434. *szDest++ = chProxy;
  435. szSource++;
  436. }
  437. else
  438. *szDest++ = *szSource++;
  439. }
  440. }
  441. else
  442. {
  443. memcpy(szDest, szIISNoInfo, cszIISNoInfo);
  444. szDest += cszIISNoInfo;
  445. }
  446. if ((dwIndex + 1) < crgsz)
  447. {
  448. // Another sub-string comming, use a delimiter
  449. memcpy(szDest, szIISDelimiter, cszIISDelimiter);
  450. szDest += cszIISDelimiter;
  451. }
  452. }
  453. *szDest = '\0';
  454. // Log it
  455. BOOL fResult = TRUE;
  456. fResult = SUCCEEDED(pIReq->AppendLogParameter(szLogEntry));
  457. // Set "500" error in log.
  458. if (pIReq->ECB()->dwHttpStatusCode == 200) // error content sent, OK, but really an error
  459. pIReq->ECB()->dwHttpStatusCode = 500;
  460. // Release log string
  461. delete [] szLogEntry;
  462. // If any error occurred while writing to log, upgrade to NT Event log
  463. if (!fResult)
  464. {
  465. m_dwMask = ERR_SetLogtoNT(m_dwMask);
  466. *pfIISLogFailed = TRUE;
  467. }
  468. // Even if successful we might still want the message
  469. // in the NT event log if the global setting to do so is on.
  470. else if (Glob(fDupIISLogToNTLog))
  471. {
  472. if (!ERR_FLogtoNT(m_dwMask))
  473. {
  474. // Need to remember the flag in order to insert
  475. // the upgraded IIS log error as NT log warnings.
  476. // The errors already destined for NT log should
  477. // stay as errors.
  478. m_dwMask = ERR_SetLogtoNT(m_dwMask);
  479. *pfDupToNTLog = TRUE;
  480. }
  481. }
  482. hr = S_OK;
  483. }
  484. return(hr);
  485. }
  486. /*===================================================================
  487. CErrInfo::LogErrortoBrowserWrapper
  488. Just a Wrapper around Log Error/Event to Browser.
  489. In this function, pIReq or pResponse is resolved.
  490. NOTE:
  491. Unfortunately, this function can not tell pResponse is inited or not.
  492. In case when pResponse has not been inited, pResponse is not NULL, but things
  493. in pResponse are invalid.
  494. Therefore, caller need to provide pIReq in case where pResponse has not been inited.
  495. Returns:
  496. HRESULT
  497. ===================================================================*/
  498. HRESULT CErrInfo::LogErrortoBrowserWrapper()
  499. {
  500. HRESULT hr = S_OK;
  501. //
  502. // Must have passed in either an CIsapiReqInfo or a HITOBJ. Otherwise, there is nothing we can do.
  503. // This condition occurs in case of HandleOOMError
  504. //
  505. if (m_pIReq == NULL && m_pHitObj == NULL)
  506. return E_FAIL;
  507. // Remember response object if any
  508. CResponse *pResponse = m_pHitObj ? m_pHitObj->PResponse() : NULL;
  509. CIsapiReqInfo *pIReq =
  510. (m_pHitObj && pResponse && m_pHitObj->PIReq()) ?
  511. m_pHitObj->PIReq() : m_pIReq;
  512. if (!pIReq)
  513. return E_FAIL;
  514. // Do custom errors only if response headers aren't written already
  515. // ALSO: No custom error if called from global.asa, with intrinsic objects hidden.
  516. // (Appln_OnStart & Session_OnStart)
  517. //
  518. // for errors in Appln_OnEnd or Session_OnEnd, these are not browser requests
  519. // and so pResponse == NULL in this case.
  520. if (!pResponse || !pResponse->FHeadersWritten())
  521. {
  522. BOOL fIntrinsicsWereHidden = FALSE;
  523. if (m_pHitObj)
  524. {
  525. fIntrinsicsWereHidden = m_pHitObj->FRequestAndResponseIntrinsicsHidden();
  526. m_pHitObj->UnHideRequestAndResponseIntrinsics();
  527. }
  528. BOOL fCustom = FALSE;
  529. hr = LogCustomErrortoBrowser(pIReq, &fCustom);
  530. if (fIntrinsicsWereHidden)
  531. m_pHitObj->HideRequestAndResponseIntrinsics();
  532. if (fCustom)
  533. return hr;
  534. }
  535. // No custom error - do regular error from this object
  536. if (m_szItem[Im_szHeader])
  537. {
  538. BOOL fRet = pIReq->SendHeader
  539. (
  540. m_szItem[Im_szHeader],
  541. strlen(m_szItem[Im_szHeader]) + 1,
  542. s_szContentTypeTextHtml,
  543. sizeof(s_szContentTypeTextHtml),
  544. FALSE
  545. );
  546. if (!fRet)
  547. return E_FAIL;
  548. }
  549. if (pResponse)
  550. hr = LogErrortoBrowser(pResponse);
  551. else
  552. hr = LogErrortoBrowser(pIReq);
  553. return hr;
  554. }
  555. /*===================================================================
  556. CErrInfo::LogCustomErrortoBrowser
  557. Called by LogErrortoBrowserWrapper.
  558. Parameters
  559. pIReq
  560. pfCustomErrorProcessed
  561. Returns:
  562. HRESULT
  563. ===================================================================*/
  564. HRESULT CErrInfo::LogCustomErrortoBrowser
  565. (
  566. CIsapiReqInfo *pIReq,
  567. BOOL *pfCustomErrorProcessed
  568. )
  569. {
  570. // Custom errors when HttpErrorCode is specified (404 or 500),
  571. // or '500;100' ASP scripting error case
  572. BOOL fTryErrorTransfer = FALSE;
  573. DWORD dwCode, dwSubCode;
  574. if (m_dwHttpErrorCode == 404 || m_dwHttpErrorCode == 500 || m_dwHttpErrorCode == 401)
  575. {
  576. dwCode = m_dwHttpErrorCode;
  577. dwSubCode = m_dwHttpSubErrorCode;
  578. }
  579. else if (m_dwHttpErrorCode == 0 && m_pHitObj &&
  580. m_pHitObj->FHasASPError() && // there's an error on this page
  581. m_pHitObj->FExecuting() && // while executing
  582. !m_pHitObj->FInTransferOnError() && // not inside transfer-on-error already
  583. m_pHitObj->PAppln() && m_pHitObj->PResponse() && m_pHitObj->PServer() &&
  584. m_pHitObj->PAppln()->QueryAppConfig()->pCLSIDDefaultEngine()) // engine in the registry is valid
  585. {
  586. dwCode = 500;
  587. dwSubCode = 100;
  588. fTryErrorTransfer = TRUE;
  589. }
  590. else
  591. {
  592. // no need to try
  593. *pfCustomErrorProcessed = FALSE;
  594. return S_OK;
  595. }
  596. // Get custom error from W3SVC
  597. STACK_BUFFER( tempParamBuf, MAX_PATH );
  598. TCHAR *szBuf = (TCHAR *)tempParamBuf.QueryPtr();
  599. DWORD dwLen = MAX_PATH;
  600. BOOL fIsFileError;
  601. BOOL fSendErrorBody;
  602. BOOL fRet = pIReq->GetCustomError(dwCode, dwSubCode, dwLen, szBuf, &dwLen, &fIsFileError, &fSendErrorBody);
  603. if (!fRet && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
  604. if (tempParamBuf.Resize(dwLen) == TRUE) {
  605. szBuf = (TCHAR *)tempParamBuf.QueryPtr();
  606. fRet = pIReq->GetCustomError(dwCode, dwSubCode, dwLen, szBuf, &dwLen, &fIsFileError, &fSendErrorBody);
  607. }
  608. }
  609. if (fRet) {
  610. if (fSendErrorBody == FALSE) {
  611. // suppress all output through intrinsic
  612. if (m_pHitObj && m_pHitObj->PResponse())
  613. m_pHitObj->PResponse()->SetIgnoreWrites();
  614. }
  615. if (fIsFileError) {
  616. // Verify that the error file can be read
  617. if (FAILED(AspGetFileAttributes(szBuf)))
  618. fRet = FALSE;
  619. }
  620. else {
  621. // Avoid circular client redirections
  622. // (check if the current URL is the same as error URL
  623. if (_tcsicmp(szBuf, pIReq->QueryPszPathInfo()) == 0)
  624. fRet = FALSE;
  625. }
  626. }
  627. if (!fRet) {
  628. // no custom error found
  629. *pfCustomErrorProcessed = FALSE;
  630. return S_OK;
  631. }
  632. // There's a custom error - use it
  633. HRESULT hr = S_OK;
  634. if (fIsFileError)
  635. {
  636. if (fSendErrorBody)
  637. // in case of file errors mime type follows the file path
  638. // in the returned buffer
  639. hr = WriteCustomFileError(pIReq, szBuf, szBuf+_tcslen(szBuf)+1);
  640. }
  641. else if (fTryErrorTransfer)
  642. {
  643. // transfer to URL
  644. // need to Map Path first
  645. TCHAR szTemplate[MAX_PATH];
  646. WCHAR *pErrorURL;
  647. #if UNICODE
  648. pErrorURL = szBuf;
  649. #else
  650. CMBCSToWChar convStr;
  651. if (FAILED(convStr.Init(szBuf))) {
  652. *pfCustomErrorProcessed = FALSE;
  653. return S_OK;
  654. }
  655. pErrorURL = convStr.GetString();
  656. #endif
  657. if (FAILED(m_pHitObj->PServer()->MapPathInternal(0, pErrorURL, szTemplate))) {
  658. // could use custom error
  659. *pfCustomErrorProcessed = FALSE;
  660. return S_OK;
  661. }
  662. Normalize(szTemplate);
  663. // do the transfer
  664. m_pHitObj->SetInTransferOnError();
  665. hr = m_pHitObj->ExecuteChildRequest(TRUE, szTemplate, szBuf);
  666. if (FAILED(hr))
  667. {
  668. // error while reporting error -- report both
  669. LogErrortoBrowser(m_pHitObj->PResponse());
  670. }
  671. }
  672. else
  673. {
  674. // client redirect to URL
  675. hr = WriteCustomURLError(pIReq, szBuf);
  676. }
  677. if (fIsFileError || !fTryErrorTransfer)
  678. {
  679. // suppress all output through intrinsic
  680. if (m_pHitObj && m_pHitObj->PResponse())
  681. m_pHitObj->PResponse()->SetIgnoreWrites();
  682. }
  683. *pfCustomErrorProcessed = TRUE;
  684. return hr;
  685. }
  686. /*===================================================================
  687. CErrInfo::WriteCustomFileError
  688. Dumps the content of a custom error file to the browser
  689. Returns:
  690. NONE.
  691. ===================================================================*/
  692. HRESULT CErrInfo::WriteCustomFileError
  693. (
  694. CIsapiReqInfo *pIReq,
  695. TCHAR *szPath,
  696. TCHAR *szMimeType
  697. )
  698. {
  699. HRESULT hr = S_OK;
  700. char *szStatus = m_szItem[Im_szHeader];
  701. char *pszMBCSMimeType;
  702. #if UNICODE
  703. CWCharToMBCS convStr;
  704. if (FAILED(hr = convStr.Init(szMimeType, 65001))) {
  705. return hr;
  706. }
  707. else {
  708. pszMBCSMimeType = convStr.GetString();
  709. }
  710. #else
  711. pszMBCSMimeType = szMimeType;
  712. #endif
  713. if (szStatus == NULL) {
  714. // no status set -- get it from the response object if available
  715. CResponse *pResponse = m_pHitObj ? m_pHitObj->PResponse() : NULL;
  716. if (pResponse)
  717. szStatus = pResponse->PCustomStatus();
  718. }
  719. hr = CResponse::SyncWriteFile(pIReq,
  720. szPath,
  721. pszMBCSMimeType,
  722. szStatus); // NULL is OK - means 200
  723. return hr;
  724. }
  725. /*===================================================================
  726. CErrInfo::WriteCustomURLError
  727. Sends client redirect to the custom URL error
  728. Returns:
  729. NONE.
  730. ===================================================================*/
  731. HRESULT CErrInfo::WriteCustomURLError(
  732. CIsapiReqInfo *pIReq,
  733. TCHAR *sztURL)
  734. {
  735. // Header is
  736. // Location: redirect_URL?code;http://original_url
  737. HRESULT hr = S_OK;
  738. char *szURL;
  739. #if UNICODE
  740. CWCharToMBCS convRedirURL;
  741. if (FAILED(hr = convRedirURL.Init(sztURL,65001))) {
  742. return hr;
  743. }
  744. szURL = convRedirURL.GetString();
  745. #else
  746. szURL = sztURL;
  747. #endif
  748. // code
  749. char szCode[8];
  750. if (m_dwHttpErrorCode > 0 && m_dwHttpErrorCode < 1000)
  751. ltoa(m_dwHttpErrorCode, szCode, 10);
  752. else
  753. return E_FAIL;
  754. // get the current URL
  755. char szServer[128];
  756. DWORD dwServerSize = sizeof(szServer);
  757. STACK_BUFFER( tempHeader, 256 );
  758. if (!pIReq->GetServerVariableA("SERVER_NAME", szServer, &dwServerSize))
  759. return E_FAIL; // shouldn't happen
  760. char *szOrigURL;
  761. #if UNICODE
  762. CWCharToMBCS convOrigStr;
  763. if (FAILED(hr = convOrigStr.Init(pIReq->QueryPszPathInfo(), 65001))) {
  764. return hr;
  765. }
  766. szOrigURL = convOrigStr.GetString();
  767. #else
  768. szOrigURL = pIReq->QueryPszPathInfo();
  769. #endif
  770. // estimate of the length
  771. DWORD cchHeaderMax = strlen(szURL)
  772. + strlen(szServer)
  773. + strlen(szOrigURL)
  774. + 80; // decorations
  775. if (tempHeader.Resize(cchHeaderMax) == FALSE) {
  776. return E_OUTOFMEMORY;
  777. }
  778. char *szHeader = (char *)tempHeader.QueryPtr();
  779. // construct the redirection header
  780. char *szBuf = szHeader;
  781. szBuf = strcpyExA(szBuf, "Location: ");
  782. szBuf = strcpyExA(szBuf, szURL);
  783. szBuf = strcpyExA(szBuf, "?");
  784. szBuf = strcpyExA(szBuf, szCode);
  785. szBuf = strcpyExA(szBuf, ";http://");
  786. szBuf = strcpyExA(szBuf, szServer);
  787. szBuf = strcpyExA(szBuf, szOrigURL);
  788. szBuf = strcpyExA(szBuf, "\r\n\r\n");
  789. Assert(strlen(szHeader) < cchHeaderMax);
  790. // set the status
  791. static char s_szRedirected[] = "302 Object moved";
  792. pIReq->SetDwHttpStatusCode(302);
  793. // send the header
  794. BOOL fRet = pIReq->SendHeader(s_szRedirected,
  795. sizeof(s_szRedirected),
  796. szHeader,
  797. strlen(szHeader) + 1,
  798. FALSE);
  799. return (fRet ? S_OK : E_FAIL);
  800. }
  801. /*===================================================================
  802. CErrInfo::WriteHTMLEncodedErrToBrowser
  803. Log Error/Event to Browser with HTMLEncoded via either pResponse or pIReq.
  804. Either pResponse or pIReq must be valid.
  805. Returns:
  806. NONE.
  807. ===================================================================*/
  808. void CErrInfo::WriteHTMLEncodedErrToBrowser
  809. (
  810. const CHAR *StrIn,
  811. CResponse *pResponse,
  812. CIsapiReqInfo *pIReq
  813. )
  814. {
  815. CHAR szHTMLEncoded[2*MAX_RESSTRINGSIZE];
  816. LPSTR pszHTMLEncoded = NULL;
  817. LPSTR pStartszHTMLEncoded = NULL;
  818. DWORD nszHTMLEncoded = 0;
  819. BOOL fStrAllocated = FALSE;
  820. nszHTMLEncoded = HTMLEncodeLen(StrIn, CP_ACP, NULL);
  821. if (nszHTMLEncoded > 0)
  822. {
  823. if (nszHTMLEncoded > 2 * MAX_RESSTRINGSIZE)
  824. {
  825. pszHTMLEncoded = new char[nszHTMLEncoded+2];
  826. if (pszHTMLEncoded)
  827. {
  828. fStrAllocated = TRUE;
  829. }
  830. else
  831. {
  832. HandleOOMError(NULL, NULL);
  833. return;
  834. }
  835. }
  836. else
  837. pszHTMLEncoded = &szHTMLEncoded[0];
  838. pStartszHTMLEncoded = pszHTMLEncoded;
  839. pszHTMLEncoded = HTMLEncode(pszHTMLEncoded, StrIn, CP_ACP, NULL);
  840. nszHTMLEncoded--; // take out the count for '\0'.
  841. if (pResponse)
  842. pResponse->WriteSz((CHAR *)pStartszHTMLEncoded, nszHTMLEncoded);
  843. else
  844. CResponse::StaticWrite(pIReq, pStartszHTMLEncoded, nszHTMLEncoded);
  845. }
  846. if (fStrAllocated)
  847. delete [] pStartszHTMLEncoded;
  848. return;
  849. }
  850. /*===================================================================
  851. CErrInfo::LogErrortoBrowser
  852. Log Error/Event to Browser via pResponse.
  853. We will output
  854. 1> default ScriptErrorMessage or
  855. 2> Error Info/Default Template/has long description available or
  856. 3> Error Info/Default Template/no long description available
  857. Returns:
  858. HRESULT
  859. ===================================================================*/
  860. HRESULT CErrInfo::LogErrortoBrowser(CResponse *pResponse)
  861. {
  862. INT cch = 0;
  863. INT cLine = 0;
  864. INT iErrTemplate = 0;
  865. Assert(NULL != pResponse);
  866. // When the error code is zero, then it's coming from a 500 error code path.
  867. // (HandleSysError presets the code to 404 or 204.)
  868. //
  869. if (!pResponse->FHeadersWritten() && (m_dwHttpErrorCode == 500 || m_dwHttpErrorCode == 0))
  870. pResponse->put_Status(L"500 Internal Server Error");
  871. if(ERR_FIsSysFormat(m_dwMask))
  872. {
  873. DWORD cChHeader = strlen(szErrSysTemplate[0]);
  874. DWORD cChTail = strlen(szErrSysTemplate[1]);
  875. pResponse->WriteSz((CHAR *)szErrSysTemplate[0], cChHeader);
  876. WriteHTMLEncodedErrToBrowser((CHAR *)m_szItem[Im_szShortDescription], pResponse, NULL);
  877. pResponse->WriteSz((CHAR *)szErrSysTemplate[1], cChTail);
  878. return S_OK;
  879. }
  880. if (!(m_pHitObj->QueryAppConfig())->fScriptErrorsSentToBrowser())
  881. {
  882. cch = strlen((CHAR *)((m_pHitObj->QueryAppConfig())->szScriptErrorMessage()));
  883. GlobStringUseLock();
  884. pResponse->WriteSz((CHAR *)((m_pHitObj->QueryAppConfig())->szScriptErrorMessage()),cch);
  885. GlobStringUseUnLock();
  886. }
  887. else
  888. {
  889. // line 0 is the begin line.
  890. cch = strlen((CHAR *)g_szErrTemplate[ErrTemplate_BEGIN]);
  891. pResponse->WriteSz((CHAR *)g_szErrTemplate[ErrTemplate_BEGIN], cch);
  892. //7 standard items(file, line, engine, error#, short description, code, long description)
  893. //If any info missing(is NULL), we skip.
  894. for (cLine = 0; cLine < 7; cLine++)
  895. {
  896. if (NULL == m_szItem[cLine])
  897. continue;
  898. iErrTemplate = cLine * 2 + 1;
  899. /* BUG 78782 (IIS Active) */
  900. //WriteHTMLEncodedErrToBrowser((CHAR *)g_szErrTemplate[iErrTemplate], pResponse, NULL);
  901. pResponse->WriteSz((CHAR *)g_szErrTemplate[iErrTemplate], strlen((CHAR *)g_szErrTemplate[iErrTemplate]));
  902. WriteHTMLEncodedErrToBrowser((CHAR *)m_szItem[cLine], pResponse, NULL);
  903. iErrTemplate++;
  904. /* BUG 78782 (IIS Active) */
  905. //WriteHTMLEncodedErrToBrowser((CHAR *)g_szErrTemplate[iErrTemplate], pResponse, NULL);
  906. pResponse->WriteSz((CHAR *)g_szErrTemplate[iErrTemplate], strlen((CHAR *)g_szErrTemplate[iErrTemplate]));
  907. }
  908. //ouput the end line
  909. cch = strlen((CHAR *)g_szErrTemplate[ErrTemplate_END]);
  910. pResponse->WriteSz((CHAR *)g_szErrTemplate[ErrTemplate_END], cch);
  911. }
  912. return S_OK;
  913. }
  914. /*===================================================================
  915. CErrInfo::LogErrortoBrowser
  916. Log Error/Event to Browser via pIReq.
  917. We will output
  918. 1> default ScriptErrorMessage or
  919. 2> Error Info/Default Template/has long description available or
  920. 3> Error Info/Default Template/no long description available
  921. Returns:
  922. HRESULT
  923. ===================================================================*/
  924. HRESULT CErrInfo::LogErrortoBrowser(CIsapiReqInfo *pIReq)
  925. {
  926. INT cLine = 0;
  927. INT iErrTemplate = 0;
  928. Assert(NULL != pIReq);
  929. //HTTP type error, 204, 404, 500
  930. //mimic IIS error reporting
  931. //And send out the header.
  932. if(ERR_FIsSysFormat(m_dwMask))
  933. {
  934. CResponse::StaticWrite(pIReq, szErrSysTemplate[0]);
  935. WriteHTMLEncodedErrToBrowser((CHAR *)m_szItem[Im_szShortDescription], NULL, pIReq);
  936. CResponse::StaticWrite(pIReq, szErrSysTemplate[1]);
  937. return S_OK;
  938. }
  939. if (!(m_pHitObj->QueryAppConfig())->fScriptErrorsSentToBrowser())
  940. {
  941. GlobStringUseLock();
  942. CResponse::StaticWrite(pIReq, (CHAR *)((m_pHitObj->QueryAppConfig())->szScriptErrorMessage()));
  943. GlobStringUseUnLock();
  944. }
  945. else
  946. {
  947. // line 0 is the begin line.
  948. CResponse::StaticWrite(pIReq, g_szErrTemplate[ErrTemplate_BEGIN]);
  949. //7 standard items(file, line, engine, error#, short description, code, long description)
  950. //If any info missing(is NULL), we skip.
  951. for (cLine = 0; cLine < 5; cLine++)
  952. {
  953. if (NULL == m_szItem[cLine])
  954. continue;
  955. iErrTemplate = cLine * 2 + 1;
  956. WriteHTMLEncodedErrToBrowser((CHAR *)g_szErrTemplate[iErrTemplate], NULL, pIReq);
  957. WriteHTMLEncodedErrToBrowser((CHAR *)m_szItem[cLine], NULL, pIReq);
  958. iErrTemplate++;
  959. WriteHTMLEncodedErrToBrowser((CHAR *)g_szErrTemplate[iErrTemplate], NULL, pIReq);
  960. }
  961. //ouput the end line
  962. CResponse::StaticWrite(pIReq, g_szErrTemplate[ErrTemplate_END]);
  963. }
  964. return S_OK;
  965. }
  966. /*===================================================================
  967. CchLoadStringOfId
  968. Loads a string from the string table.
  969. Returns:
  970. sz - the returned string
  971. INT - 0 if string load failed, otherwise number of characters loaded.
  972. ===================================================================*/
  973. INT CchLoadStringOfId
  974. (
  975. UINT id,
  976. CHAR *sz,
  977. INT cchMax
  978. )
  979. {
  980. INT cchRet;
  981. // The handle to the DLL instance should have been set up when we were loaded
  982. if (g_hResourceDLL == (HINSTANCE)0)
  983. {
  984. // Totally bogus
  985. Assert(FALSE);
  986. return(0);
  987. }
  988. cchRet = LoadStringA(g_hResourceDLL, id, sz, cchMax);
  989. IF_DEBUG(ERROR)
  990. {
  991. // For debugging purposes, if we get back 0, get the last error info
  992. if (cchRet == 0)
  993. {
  994. DWORD err = GetLastError();
  995. DBGERROR((DBG_CONTEXT, "Failed to load string resource. Id = %d, error = %d\n", id, err));
  996. DBG_ASSERT(FALSE);
  997. }
  998. }
  999. return(cchRet);
  1000. }
  1001. /*===================================================================
  1002. CwchLoadStringOfId
  1003. Loads a string from the string table as a UNICODE string.
  1004. Returns:
  1005. sz - the returned string
  1006. INT - 0 if string load failed, otherwise number of characters loaded.
  1007. ===================================================================*/
  1008. INT CwchLoadStringOfId
  1009. (
  1010. UINT id,
  1011. WCHAR *sz,
  1012. INT cchMax
  1013. )
  1014. {
  1015. INT cchRet;
  1016. // The handle to the DLL instance should have been set up when we were loaded
  1017. if (g_hResourceDLL == (HINSTANCE)0)
  1018. {
  1019. // Totally bogus
  1020. Assert(FALSE);
  1021. return(0);
  1022. }
  1023. cchRet = LoadStringW(g_hResourceDLL, id, sz, cchMax);
  1024. IF_DEBUG(ERROR)
  1025. {
  1026. // For debugging purposes, if we get back 0, get the last error info
  1027. if (cchRet == 0)
  1028. {
  1029. DWORD err = GetLastError();
  1030. DBGERROR((DBG_CONTEXT, "Failed to load string resource. Id = %d, error = %d\n", id, err));
  1031. DBG_ASSERT(FALSE);
  1032. }
  1033. }
  1034. return(cchRet);
  1035. }
  1036. /*===================================================================
  1037. HandleSysError
  1038. Dumps the error to the client and/or to the log
  1039. Loads a string from the string table as a UNICODE string.
  1040. Returns:
  1041. sz - the returned string
  1042. INT - 0 if string load failed, otherwise number of characters loaded.
  1043. ===================================================================*/
  1044. HRESULT HandleSysError( DWORD dwHttpError,
  1045. DWORD dwHttpSubError,
  1046. UINT ErrorID,
  1047. UINT ErrorHeaderID,
  1048. CIsapiReqInfo *pIReq,
  1049. CHitObj *pHitObj)
  1050. {
  1051. CErrInfo SysErrInfo;
  1052. CErrInfo *pErrInfo;
  1053. CHAR szResourceStr[MAX_RESSTRINGSIZE];
  1054. CHAR szHeader[MAX_HEADERSIZE];
  1055. INT cch;
  1056. pErrInfo = (CErrInfo *)&SysErrInfo;
  1057. pErrInfo->m_pHitObj = pHitObj;
  1058. pErrInfo->m_pIReq = pIReq;
  1059. if (ErrorHeaderID != 0)
  1060. {
  1061. cch = CchLoadStringOfId(ErrorHeaderID, szHeader, MAX_HEADERSIZE);
  1062. pErrInfo->m_szItem[Im_szHeader] = szHeader;
  1063. }
  1064. else
  1065. {
  1066. pErrInfo->m_szItem[Im_szHeader] = NULL;
  1067. }
  1068. if (ErrorID != 0)
  1069. cch = CchLoadStringOfId(ErrorID, szResourceStr, MAX_RESSTRINGSIZE);
  1070. pErrInfo->ParseResourceString(szResourceStr);
  1071. pErrInfo->m_dwMask = ERR_SetSysFormat(pErrInfo->m_dwMask);
  1072. pErrInfo->m_dwHttpErrorCode = dwHttpError;
  1073. pErrInfo->m_dwHttpSubErrorCode = dwHttpSubError;
  1074. pErrInfo->LogError();
  1075. return S_OK;
  1076. }
  1077. /*===================================================================
  1078. Handle500Error
  1079. Based on ErrorID determines headerID, code, sub-code, and
  1080. calls HandleSysError()
  1081. Returns:
  1082. HRESULT
  1083. ===================================================================*/
  1084. HRESULT Handle500Error( UINT errorId,
  1085. CIsapiReqInfo *pIReq)
  1086. {
  1087. UINT headerId;
  1088. DWORD dwHttpSubError;
  1089. switch (errorId)
  1090. {
  1091. case IDE_SERVER_TOO_BUSY:
  1092. headerId = IDH_500_SERVER_ERROR;
  1093. dwHttpSubError = SUBERRORCODE500_SERVER_TOO_BUSY;
  1094. break;
  1095. case IDE_SERVER_SHUTTING_DOWN:
  1096. headerId = IDH_500_SERVER_ERROR;
  1097. dwHttpSubError = SUBERRORCODE500_SHUTTING_DOWN;
  1098. break;
  1099. case IDE_GLOBAL_ASA_CHANGED:
  1100. headerId = IDH_500_SERVER_ERROR;
  1101. dwHttpSubError = SUBERRORCODE500_RESTARTING_APP;
  1102. break;
  1103. case IDE_INVALID_APPLICATION:
  1104. headerId = IDH_500_SERVER_ERROR;
  1105. dwHttpSubError = SUBERRORCODE500_INVALID_APP;
  1106. break;
  1107. case IDE_GLOBAL_ASA_FORBIDDEN:
  1108. headerId = IDH_500_SERVER_ERROR;
  1109. dwHttpSubError = SUBERRORCODE500_GLOBALASA_FORBIDDEN;
  1110. break;
  1111. default:
  1112. headerId = IDH_500_SERVER_ERROR;
  1113. dwHttpSubError = SUBERRORCODE500_SERVER_ERROR;
  1114. break;
  1115. }
  1116. pIReq->SetDwHttpStatusCode(500);
  1117. return HandleSysError(500, dwHttpSubError, errorId, headerId, pIReq, NULL);
  1118. }
  1119. /*===================================================================
  1120. HandleOOMError
  1121. Handle OOM error with special care, because we can not do any dynamic allocation.
  1122. if pIReq or pHitObj is NULL, nothing will be reported to browser
  1123. Returns:
  1124. Nothing
  1125. ===================================================================*/
  1126. HRESULT HandleOOMError( CIsapiReqInfo *pIReq,
  1127. CHitObj *pHitObj)
  1128. {
  1129. CErrInfo OOMErrInfo;
  1130. CErrInfo *pErrInfo;
  1131. // Note the OOM occurred
  1132. InterlockedIncrement(&g_nOOMErrors);
  1133. pErrInfo = (CErrInfo *)&OOMErrInfo;
  1134. pErrInfo->m_pIReq = pIReq;
  1135. pErrInfo->m_pHitObj = pHitObj;
  1136. pErrInfo->m_dwMask = g_ErrInfoOOM.m_dwMask;
  1137. pErrInfo->m_szItem[Im_szErrorCode] = g_ErrInfoOOM.m_szItem[Im_szErrorCode];
  1138. pErrInfo->m_szItem[Im_szShortDescription] = g_ErrInfoOOM.m_szItem[Im_szShortDescription];
  1139. pErrInfo->m_szItem[Im_szLongDescription] = g_ErrInfoOOM.m_szItem[Im_szLongDescription];
  1140. pErrInfo->LogError();
  1141. return S_OK;
  1142. }
  1143. /*===================================================================
  1144. HandleError
  1145. Handle reporting of errors given ErrorID, FileName, and LineNum.
  1146. If Caller provide ErrCode or LongDescription, the default value will be overwriten.
  1147. Strings passed in will be freed. That is, consider the function as a sink. Caller
  1148. should not use strings after the call.
  1149. Returns:
  1150. Nothing
  1151. ===================================================================*/
  1152. HRESULT HandleError( UINT ErrorID,
  1153. CHAR *szFileName,
  1154. CHAR *szLineNum,
  1155. CHAR *szEngine,
  1156. CHAR *szErrCode,
  1157. CHAR *szLongDes,
  1158. CIsapiReqInfo *pIReq,
  1159. CHitObj *pHitObj,
  1160. va_list *pArgs)
  1161. {
  1162. CErrInfo SysErrInfo;
  1163. CErrInfo *pErrInfo;
  1164. CHAR szResourceStr[MAX_RESSTRINGSIZE];
  1165. CHAR szUnformattedResStr[MAX_RESSTRINGSIZE];
  1166. HRESULT hr = S_OK;
  1167. pErrInfo = (CErrInfo *)&SysErrInfo;
  1168. pErrInfo->m_szItem[Im_szFileName] = szFileName;
  1169. pErrInfo->m_szItem[Im_szLineNum] = szLineNum;
  1170. pErrInfo->m_szItem[Im_szEngine] = szEngine;
  1171. pErrInfo->m_pHitObj = pHitObj;
  1172. pErrInfo->m_pIReq = pIReq;
  1173. //Load resource string according to the resource ID.
  1174. if (pArgs) {
  1175. CchLoadStringOfId(ErrorID, szUnformattedResStr, MAX_RESSTRINGSIZE);
  1176. vsprintf(szResourceStr, szUnformattedResStr, *pArgs);
  1177. }
  1178. else {
  1179. CchLoadStringOfId(ErrorID, szResourceStr, MAX_RESSTRINGSIZE);
  1180. }
  1181. pErrInfo->ParseResourceString(szResourceStr);
  1182. //NOTE: if ErrorCode/LongDescription not NULL, caller want to overwrite.
  1183. if (szErrCode)
  1184. {
  1185. pErrInfo->m_szItem[Im_szErrorCode] = szErrCode;
  1186. }
  1187. if(szLongDes)
  1188. {
  1189. pErrInfo->m_szItem[Im_szLongDescription] = szLongDes;
  1190. }
  1191. hr = pErrInfo->LogError();
  1192. //free up the inputs
  1193. FreeNullifySz((CHAR **)&szFileName);
  1194. FreeNullifySz((CHAR **)&szLineNum);
  1195. FreeNullifySz((CHAR **)&szEngine);
  1196. FreeNullifySz((CHAR **)&szErrCode);
  1197. FreeNullifySz((CHAR **)&szLongDes);
  1198. return hr;
  1199. }
  1200. /*===================================================================
  1201. HandleError
  1202. Handle reporting of errors given all the info.
  1203. This is basically a cover over HandleErrorSz which called from OnScriptError.
  1204. Strings passed in will be freed. That is, consider the function as a sink. Caller
  1205. should not use strings after the call.
  1206. Returns:
  1207. Nothing
  1208. ===================================================================*/
  1209. HRESULT HandleError( CHAR *szShortDes,
  1210. CHAR *szLongDes,
  1211. DWORD dwMask,
  1212. CHAR *szFileName,
  1213. CHAR *szLineNum,
  1214. CHAR *szEngine,
  1215. CHAR *szErrCode,
  1216. CIsapiReqInfo *pIReq,
  1217. CHitObj *pHitObj)
  1218. {
  1219. CErrInfo SysErrInfo;
  1220. CErrInfo *pErrInfo;
  1221. HRESULT hr = S_OK;
  1222. pErrInfo = (CErrInfo *)&SysErrInfo;
  1223. pErrInfo->m_dwMask = dwMask;
  1224. pErrInfo->m_szItem[Im_szHeader] = NULL; // Caller has already sent out header
  1225. pErrInfo->m_szItem[Im_szFileName] = szFileName;
  1226. pErrInfo->m_szItem[Im_szLineNum] = szLineNum;
  1227. pErrInfo->m_szItem[Im_szEngine] = szEngine;
  1228. pErrInfo->m_szItem[Im_szErrorCode] = szErrCode;
  1229. pErrInfo->m_szItem[Im_szShortDescription] = szShortDes;
  1230. pErrInfo->m_szItem[Im_szLongDescription] = szLongDes;
  1231. pErrInfo->m_pHitObj = pHitObj;
  1232. pErrInfo->m_pIReq = pIReq;
  1233. hr = pErrInfo->LogError();
  1234. //free up the inputs
  1235. FreeNullifySz((CHAR **)&szFileName);
  1236. FreeNullifySz((CHAR **)&szLineNum);
  1237. FreeNullifySz((CHAR **)&szEngine);
  1238. FreeNullifySz((CHAR **)&szErrCode);
  1239. FreeNullifySz((CHAR **)&szShortDes);
  1240. FreeNullifySz((CHAR **)&szLongDes);
  1241. return hr;
  1242. }
  1243. /*===================================================================
  1244. HandleError
  1245. Handle reporting of errors given the IActiveScriptError and PFNLINEMAP.
  1246. This is basically a cover over HandleErrorSz which called from OnScriptError.
  1247. Returns:
  1248. Nothing
  1249. ===================================================================*/
  1250. HRESULT HandleError( IActiveScriptError *pscripterror,
  1251. CTemplate *pTemplate,
  1252. DWORD dwEngineID,
  1253. CIsapiReqInfo *pIReq,
  1254. CHitObj *pHitObj )
  1255. {
  1256. UINT cchBuf = 0;
  1257. CHAR *szOrigin = NULL;
  1258. CHAR *szDesc = NULL;
  1259. CHAR *szLine = NULL;
  1260. CHAR *szPrefix = NULL;
  1261. UINT cchOrigin = 0;
  1262. UINT cchDesc = 0;
  1263. UINT cchLineNum = 0;
  1264. UINT cchLine = 0;
  1265. EXCEPINFO excepinfo = {0};
  1266. CHAR *szResult = NULL;
  1267. BSTR bstrLine = NULL;
  1268. HRESULT hr;
  1269. DWORD dwSourceContext = 0; // Don't trust this one
  1270. ULONG ulLineError = 0;
  1271. BOOLB fGuessedLine = FALSE; // see bug 379
  1272. CHAR *szLineNumT = NULL;
  1273. LPTSTR szPathInfo = NULL;
  1274. LPTSTR szPathTranslated = NULL;
  1275. LONG ichError = -1;
  1276. CErrInfo SysErrInfo;
  1277. CErrInfo *pErrInfo;
  1278. wchar_t wszUnknownException[128];
  1279. wchar_t wszUnknownEngine[32];
  1280. CWCharToMBCS convStr;
  1281. pErrInfo = (CErrInfo *)&SysErrInfo;
  1282. pErrInfo->m_pIReq = pIReq;
  1283. pErrInfo->m_pHitObj = pHitObj;
  1284. if (pscripterror == NULL)
  1285. return E_POINTER;
  1286. hr = pscripterror->GetExceptionInfo(&excepinfo);
  1287. if (FAILED(hr))
  1288. goto LExit;
  1289. // bug 99543 If details are deferrred, use the callback to get
  1290. // detailed information.
  1291. if (excepinfo.pfnDeferredFillIn)
  1292. excepinfo.pfnDeferredFillIn(&excepinfo);
  1293. // if error is OOM, then increment the global counter.
  1294. if ((excepinfo.wCode == ERROR_OUTOFMEMORY)
  1295. || ((excepinfo.wCode == 0) && (excepinfo.scode == ERROR_OUTOFMEMORY)))
  1296. InterlockedIncrement(&g_nOOMErrors);
  1297. hr = pscripterror->GetSourcePosition(&dwSourceContext, &ulLineError, &ichError);
  1298. if (FAILED(hr))
  1299. goto LExit;
  1300. // Intentionally ignore any error
  1301. (VOID)pscripterror->GetSourceLineText(&bstrLine);
  1302. if (pTemplate == NULL)
  1303. goto LExit;
  1304. // call GetScriptSourceInfo to get path-info (of file) and actual line number where error occurred
  1305. // bug 379: if GetScriptSourceInfo returns fGuessedLine = TRUE, it means we gave it a non-authored line,
  1306. // so we adjust below by not printing bstrLine in the error msg
  1307. if (ulLineError > 0)
  1308. pTemplate->GetScriptSourceInfo(dwEngineID, ulLineError, &szPathInfo, &szPathTranslated, &ulLineError, NULL, &fGuessedLine);
  1309. else
  1310. {
  1311. // ulLineError was zero - no line # specified, so assume main file (usually this will be "out of memory"
  1312. // so effect will be to display the script that was running when this occurred.
  1313. //
  1314. szPathInfo = pTemplate->GetSourceFileName(SOURCEPATHTYPE_VIRTUAL);
  1315. szPathTranslated = pTemplate->GetSourceFileName(SOURCEPATHTYPE_PHYSICAL);
  1316. }
  1317. // if we have HitObj use it to get the virtual path to avoid
  1318. // displaying of wrong path for shared templates
  1319. //
  1320. // first verify that PathTranslated == main file path; this file could be
  1321. // an include file, in which case PszPathInfo is incorrect.
  1322. //
  1323. if (!pTemplate->FGlobalAsa() && szPathTranslated && _tcscmp(szPathTranslated, pTemplate->GetSourceFileName()) == 0 && pHitObj != NULL && pHitObj->PIReq())
  1324. szPathInfo = pHitObj->PSzCurrTemplateVirtPath();
  1325. #if UNICODE
  1326. pErrInfo->m_szItem[Im_szFileName] = StringDupUTF8(szPathInfo);
  1327. #else
  1328. pErrInfo->m_szItem[Im_szFileName] = StringDupA(szPathInfo);
  1329. #endif
  1330. szLineNumT = (CHAR *)malloc(10*sizeof(CHAR));
  1331. if (szLineNumT)
  1332. {
  1333. // convert the line number
  1334. _ltoa(ulLineError, szLineNumT, 10);
  1335. }
  1336. pErrInfo->m_szItem[Im_szLineNum] = szLineNumT;
  1337. // is the scode one of the VBScript of JavaScript errors (this needs to be lang independent)
  1338. // excepinfo.bstrDescription now has the formatted error string.
  1339. if (excepinfo.bstrSource && excepinfo.bstrDescription)
  1340. {
  1341. // Bug 81954: Misbehaved objects may throw an exception without providing any information
  1342. wchar_t *wszDescription;
  1343. if (excepinfo.bstrDescription[0] == L'\0')
  1344. {
  1345. HRESULT hrError;
  1346. if (0 == excepinfo.wCode)
  1347. hrError = excepinfo.scode;
  1348. else
  1349. hrError = excepinfo.wCode;
  1350. wszUnknownException[0] = '\0';
  1351. // Bug 91847 Attempt to get a description via FormatMessage()
  1352. if (!HResultToWsz(hrError, wszUnknownException, 128))
  1353. CwchLoadStringOfId(IDE_SCRIPT_UNKNOWN, wszUnknownException, sizeof(wszUnknownException)/sizeof(WCHAR));
  1354. wszDescription = wszUnknownException;
  1355. }
  1356. else
  1357. wszDescription = excepinfo.bstrDescription;
  1358. wchar_t *wszSource;
  1359. if (excepinfo.bstrSource[0] == L'\0')
  1360. {
  1361. wszUnknownEngine[0] = '\0';
  1362. CwchLoadStringOfId(IDS_DEBUG_APP, wszUnknownEngine, sizeof(wszUnknownEngine)/sizeof(WCHAR));
  1363. wszSource = wszUnknownEngine;
  1364. }
  1365. else
  1366. wszSource = excepinfo.bstrSource;
  1367. CHAR *ch = NULL;
  1368. // convert the Source to ascii
  1369. if (convStr.Init(wszSource) != NO_ERROR) {
  1370. szOrigin = NULL;
  1371. }
  1372. else {
  1373. szOrigin = convStr.GetString(TRUE);
  1374. }
  1375. if (NULL != szOrigin)
  1376. {
  1377. // Remove the word "error"from the string, if any, because we will
  1378. //print out "error" when we print out the errorID
  1379. cchOrigin = strlen(szOrigin);
  1380. if (cchOrigin > 5) // 5 is strlen("error")
  1381. {
  1382. ch = szOrigin + cchOrigin - 5;
  1383. if (!strncmp(ch, "error", 5))
  1384. {// we found the word "error", truncate the szOrigin by null out the word "error"
  1385. *ch = '\0';
  1386. }
  1387. }
  1388. ch = NULL;
  1389. }
  1390. pErrInfo->m_szItem[Im_szEngine] = szOrigin;
  1391. // convert the sDescription to ascii
  1392. if (convStr.Init(wszDescription) != NO_ERROR) {
  1393. szDesc = NULL;
  1394. }
  1395. else {
  1396. szDesc = convStr.GetString(TRUE);
  1397. }
  1398. //check whether the szDesc is Denali/formatted error resource string or other unformatted string
  1399. if (FALSE == FIsResStrFormatted(szDesc))
  1400. {
  1401. //unformatted string.
  1402. pErrInfo->m_dwMask = dwDefaultMask;
  1403. if (0 == excepinfo.wCode)
  1404. pErrInfo->m_szItem[Im_szErrorCode] = SzScodeToErrorCode(excepinfo.scode);
  1405. else
  1406. pErrInfo->m_szItem[Im_szErrorCode] = SzScodeToErrorCode(excepinfo.wCode);
  1407. pErrInfo->m_szItem[Im_szShortDescription] = StringDupA(szDesc);
  1408. pErrInfo->m_szItem[Im_szLongDescription] = NULL;
  1409. }
  1410. else
  1411. {
  1412. pErrInfo->ParseResourceString(szDesc);
  1413. char *szTempErrorCode = SzScodeToErrorCode(excepinfo.scode);
  1414. char *szTempErrorASPCode = StringDupA(pErrInfo->m_szItem[Im_szErrorCode]);
  1415. int nstrlen = strlen(szTempErrorCode) + strlen(szTempErrorASPCode);
  1416. pErrInfo->m_szItem[Im_szErrorCode] = new char[nstrlen+4];
  1417. if(pErrInfo->m_szItem[Im_szErrorCode])
  1418. sprintf(pErrInfo->m_szItem[Im_szErrorCode], "%s : %s", szTempErrorASPCode, szTempErrorCode);
  1419. if (szTempErrorCode)
  1420. delete [] szTempErrorCode;
  1421. if(szTempErrorASPCode)
  1422. delete [] szTempErrorASPCode;
  1423. //pErrInfo->m_szItem[Im_szErrorCode] = StrDup(pErrInfo->m_szItem[Im_szErrorCode]);
  1424. pErrInfo->m_szItem[Im_szShortDescription] = StringDupA(pErrInfo->m_szItem[Im_szShortDescription]);
  1425. pErrInfo->m_szItem[Im_szLongDescription] = StringDupA(pErrInfo->m_szItem[Im_szLongDescription]);
  1426. }
  1427. /*
  1428. * If we didnt guess a line, and we have a line of source code to display
  1429. * then attempt to display it and hopefully a line of ------^ to point to the error
  1430. */
  1431. if (!fGuessedLine && bstrLine != NULL)
  1432. {
  1433. INT cchDBCS = 0; // Number of DBCS characters in source line
  1434. CHAR *pszTemp = NULL; // Temp sz pointer used to calculate cchDBCS
  1435. // convert the source code line
  1436. if (FAILED(hr = convStr.Init(bstrLine))) {
  1437. goto LExit;
  1438. }
  1439. szLine = convStr.GetString();
  1440. cchLine = strlen(szLine);
  1441. if (0 == cchLine)
  1442. goto LExit;
  1443. // Check for DBCS character, and cchLine -= NumberofDBCScharacter, such that
  1444. // the ----^ will point to the right position.
  1445. pszTemp = szLine;
  1446. while(*pszTemp != NULL)
  1447. {
  1448. if (IsDBCSLeadByte(*pszTemp))
  1449. {
  1450. cchDBCS++;
  1451. pszTemp += 2; // skip 2 bytes
  1452. }
  1453. else
  1454. {
  1455. pszTemp++; // single byte
  1456. }
  1457. }
  1458. // compute the size of the source code indicator:
  1459. // "<source line> + '\r\n' + <error pos>*'-' + '^'
  1460. // 3 chars. without source line and '-'
  1461. LONG ichErrorT = ichError;
  1462. cchBuf += cchLine + ichErrorT + 3;
  1463. // allocate the result buffer
  1464. szResult = new(char[cchBuf + 2]);
  1465. if (szResult == NULL)
  1466. goto LExit;
  1467. // fill up the buffer
  1468. ch = szResult;
  1469. // append the <PRE>
  1470. // bug 87118, moved to template for a proper HTML encoding
  1471. // <source line>
  1472. if (cchLine)
  1473. strncpy(ch, szLine, cchLine);
  1474. ch += cchLine;
  1475. // stick the "----^" string on the end
  1476. if (ichErrorT > -1)
  1477. {
  1478. // prepend the '\n'
  1479. strncpy(ch, "\r\n", 2);
  1480. ch += 2;
  1481. // put in the "---"'s, and shrink "---" by #ofDBCS
  1482. ichErrorT -= cchDBCS;
  1483. while (ichErrorT-- > 0)
  1484. *ch++ = '-';
  1485. *ch++ = '^';
  1486. }
  1487. // append the </PRE>
  1488. // bug 87118, moved to template for a proper HTML encoding
  1489. // terminate the string
  1490. *ch++ = '\0';
  1491. pErrInfo->m_szItem[Im_szCode] = szResult;
  1492. // add line and column to error object
  1493. pErrInfo->m_nColumn = ichError;
  1494. pErrInfo->m_bstrLineText = bstrLine;
  1495. }
  1496. }
  1497. else
  1498. {
  1499. // Not VBS or other Engine errors/Unknown error
  1500. // Load Default
  1501. // try to compute a specific error message
  1502. HRESULT hr_def;
  1503. hr_def = GetSpecificError(pErrInfo, excepinfo.scode);
  1504. CHAR *szShortDescription = new CHAR[256];
  1505. // if that failed try to compute a generic error
  1506. if (FAILED(hr_def))
  1507. {
  1508. pErrInfo->m_dwMask = dwDefaultMask;
  1509. if (0 == excepinfo.wCode)
  1510. {
  1511. pErrInfo->m_szItem[Im_szErrorCode] = SzScodeToErrorCode(excepinfo.scode);
  1512. // Bug 91847 Attempt to get a description via FormatMessage()
  1513. if ((szShortDescription != NULL) &&
  1514. !HResultToSz(excepinfo.scode, szShortDescription, 256))
  1515. {
  1516. // Displaying the error number twice would be redundant, delete it
  1517. delete [] szShortDescription;
  1518. szShortDescription = NULL;
  1519. }
  1520. }
  1521. else
  1522. {
  1523. pErrInfo->m_szItem[Im_szErrorCode] = SzScodeToErrorCode(excepinfo.wCode);
  1524. // Bug 91847 Attempt to get a description via FormatMessage()
  1525. if ((szShortDescription != NULL) &&
  1526. !HResultToSz(excepinfo.wCode, szShortDescription, 256))
  1527. {
  1528. // Displaying the error number twice would be redundant, delete it
  1529. delete [] szShortDescription;
  1530. szShortDescription = NULL;
  1531. }
  1532. }
  1533. pErrInfo->m_szItem[Im_szEngine] = NULL;
  1534. pErrInfo->m_szItem[Im_szShortDescription] = szShortDescription;
  1535. pErrInfo->m_szItem[Im_szLongDescription] = NULL;
  1536. }
  1537. }
  1538. LExit:
  1539. if (excepinfo.bstrSource)
  1540. {
  1541. SysFreeString(excepinfo.bstrSource);
  1542. }
  1543. if (excepinfo.bstrDescription)
  1544. {
  1545. SysFreeString(excepinfo.bstrDescription);
  1546. }
  1547. if (excepinfo.bstrHelpFile)
  1548. {
  1549. SysFreeString(excepinfo.bstrHelpFile);
  1550. }
  1551. pErrInfo->LogError();
  1552. if (bstrLine)
  1553. {
  1554. SysFreeString(bstrLine);
  1555. }
  1556. FreeNullifySz((CHAR **)&szDesc);
  1557. for(INT iErrInfo = 0; iErrInfo < Im_szItemMAX; iErrInfo++)
  1558. {
  1559. FreeNullifySz((CHAR **)&pErrInfo->m_szItem[iErrInfo]);
  1560. }
  1561. return S_OK;
  1562. }
  1563. /*===================================================================
  1564. LoadErrResString
  1565. Loads an error string(formatted) from the string table.
  1566. Returns:
  1567. pdwMask
  1568. szErrorCode
  1569. szShortDes
  1570. szLongDes
  1571. if any of the szVariable is NULL, that particular string value will not be loaded.
  1572. S_OK if successes.
  1573. E_FAIL if fails.
  1574. Side Effect
  1575. NONE
  1576. ===================================================================*/
  1577. HRESULT LoadErrResString(
  1578. UINT ErrID/*IN*/,
  1579. DWORD *pdwMask,
  1580. CHAR *szErrorCode,
  1581. CHAR *szShortDes,
  1582. CHAR *szLongDes)
  1583. {
  1584. CHAR *szToken = NULL;
  1585. CHAR szResTemp[2*MAX_RESSTRINGSIZE]; //ResourceTempString
  1586. INT cch = 0;
  1587. cch = CchLoadStringOfId(ErrID, szResTemp, MAX_RESSTRINGSIZE);
  1588. //Mask
  1589. szToken = (char *)_mbstok((unsigned char *)szResTemp, (unsigned char *)DELIMITER);
  1590. if (NULL != szToken)
  1591. *pdwMask = atoi(szToken);
  1592. else
  1593. Assert(FALSE);
  1594. //ErrorCode
  1595. szToken = (char *)_mbstok(NULL, (unsigned char *)DELIMITER);
  1596. if (NULL != szToken && NULL != szErrorCode)
  1597. {
  1598. cch = strlen(szToken);
  1599. memcpy(szErrorCode, szToken, cch);
  1600. szErrorCode[cch] = '\0';
  1601. }
  1602. //ShortDescription
  1603. szToken = (char *)_mbstok(NULL, (unsigned char *)DELIMITER);
  1604. if (NULL != szToken && NULL != szShortDes)
  1605. {
  1606. cch = strlen(szToken);
  1607. memcpy(szShortDes, szToken, cch);
  1608. szShortDes[cch] = '\0';
  1609. }
  1610. //LongDescription
  1611. szToken = (char *)_mbstok(NULL, (unsigned char *)DELIMITER);
  1612. if (NULL != szToken && NULL != szLongDes)
  1613. {
  1614. cch = strlen(szToken);
  1615. memcpy(szLongDes, szToken, cch);
  1616. szLongDes[cch] = '\0';
  1617. }
  1618. return S_OK;
  1619. }
  1620. /*===================================================================
  1621. SzScodeToErrorCode
  1622. Conver Scode to string
  1623. Returns:
  1624. Composed string
  1625. Side Effects:
  1626. ***ALLOCATES MEMORY -- CALLER MUST FREE***
  1627. ===================================================================*/
  1628. CHAR *SzScodeToErrorCode
  1629. (
  1630. HRESULT hrError
  1631. )
  1632. {
  1633. CHAR *szResult = NULL;
  1634. CHAR szBuf[17];
  1635. CHAR *szNumber;
  1636. CHAR *szError;
  1637. INT iC;
  1638. INT cch;
  1639. // put a bunch of zeros into the buffer
  1640. for (iC = 0; iC < 16; ++iC)
  1641. szBuf[iC] = '0';
  1642. // szNumber points half way into the buffer
  1643. szNumber = &szBuf[8];
  1644. // get the error szNumber as a hex string
  1645. _ltoa(hrError, szNumber, 16);
  1646. // back up szNumber to allow a total of 8 digits
  1647. szNumber -= 8 - strlen(szNumber);
  1648. cch = strlen(szNumber) + 1;
  1649. szError = new(CHAR[cch]);
  1650. if (szError != NULL)
  1651. {
  1652. szError[0] = '\0';
  1653. strcat(szError, szNumber);
  1654. szResult = szError;
  1655. }
  1656. else
  1657. {
  1658. HandleOOMError(NULL, NULL);
  1659. }
  1660. return(szResult);
  1661. }
  1662. /*===================================================================
  1663. SzComposeSpecificError
  1664. Compose a specific error for an HRESULT of the form:
  1665. <string> <error-number>
  1666. This is our last resort if there is not more useful information to be had.
  1667. Returns:
  1668. Composed string
  1669. Side Effects:
  1670. ***ALLOCATES MEMORY -- CALLER MUST FREE***
  1671. ===================================================================*/
  1672. HRESULT GetSpecificError
  1673. (
  1674. CErrInfo *pErrInfo,
  1675. HRESULT hrError
  1676. )
  1677. {
  1678. HRESULT hr_return = E_FAIL;
  1679. UINT idErr;
  1680. switch (hrError)
  1681. {
  1682. case DISP_E_MEMBERNOTFOUND:
  1683. idErr = IDE_SCRIPT_METHOD_NOT_FOUND;
  1684. break;
  1685. case DISP_E_UNKNOWNNAME:
  1686. idErr = IDE_SCRIPT_UNKNOWN_NAME;
  1687. break;
  1688. case DISP_E_UNKNOWNINTERFACE:
  1689. idErr = IDE_SCRIPT_UNKNOWN_INTERFACE;
  1690. break;
  1691. case DISP_E_PARAMNOTOPTIONAL:
  1692. idErr = IDE_SCRIPT_MISSING_PARAMETER;
  1693. break;
  1694. default:
  1695. // Not one of the errors we know how to handle specially. E_FAIL will be returned.
  1696. idErr = 0;
  1697. break;
  1698. }
  1699. // build a szResult string if we find a match
  1700. if (idErr != 0)
  1701. {
  1702. hr_return = LoadErrResString(idErr,
  1703. &(pErrInfo->m_dwMask),
  1704. pErrInfo->m_szItem[Im_szErrorCode],
  1705. pErrInfo->m_szItem[Im_szShortDescription],
  1706. pErrInfo->m_szItem[Im_szLongDescription]
  1707. );
  1708. }
  1709. return(hr_return);
  1710. }
  1711. /*===================================================================
  1712. HResultToWsz
  1713. Tranlates a HRESULT to a description string of the HRESULT. Attempts
  1714. to use FormatMessage() to get a
  1715. Parameters:
  1716. hrIn The error to lookup
  1717. wszOut String to output the description to
  1718. cdwOut Number of WCHARs wszOut can hold
  1719. Returns:
  1720. TRUE if a description string was found
  1721. FALSE if the error number was output instead
  1722. Notes:
  1723. Added to resolve bug 91847. When unexpected errors are processed
  1724. the naked error number was output, which developers would then
  1725. have to look up in winerror.h.
  1726. ===================================================================*/
  1727. BOOL HResultToWsz(HRESULT hrIn, WCHAR *wszOut, DWORD cdwOut)
  1728. {
  1729. LANGID langID = LANG_NEUTRAL;
  1730. DWORD dwFound = 0;
  1731. HMODULE hMsgModule = NULL;
  1732. #ifdef USE_LOCALE
  1733. LANGID *pLangID;
  1734. pLangID = (LANGID *)TlsGetValue(g_dwTLS);
  1735. if (NULL != pLangID)
  1736. langID = *pLangID;
  1737. #endif
  1738. if (HRESULT_FACILITY(hrIn) == (HRESULT)FACILITY_INTERNET)
  1739. hMsgModule = GetModuleHandleA("METADATA");
  1740. else
  1741. hMsgModule = GetModuleHandleA("ASP");
  1742. dwFound = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
  1743. hMsgModule,
  1744. hrIn,
  1745. langID,
  1746. wszOut,
  1747. cdwOut,
  1748. NULL);
  1749. if (!dwFound)
  1750. {
  1751. // Error not found, make a string out of the error number
  1752. WCHAR *wszResult = NULL;
  1753. WCHAR wszBuf[17];
  1754. WCHAR *wszNumber;
  1755. WCHAR *wszError;
  1756. INT iC;
  1757. // put a bunch of zeros into the buffer
  1758. for (iC = 0; iC < 16; ++iC)
  1759. wszBuf[iC] = L'0';
  1760. // wszNumber points half way into the buffer
  1761. wszNumber = &wszBuf[8];
  1762. // get the error wszNumber as a hex string
  1763. _ltow(hrIn, wszNumber, 16);
  1764. // back up szNumber to allow a total of 8 digits
  1765. wszNumber -= 8 - wcslen(wszNumber);
  1766. // Copy the result to wszOut
  1767. wcsncpy(wszOut, wszNumber, cdwOut);
  1768. return FALSE;
  1769. }
  1770. else
  1771. return TRUE;
  1772. }
  1773. HMODULE GetModuleHandleForHRESULT(HRESULT hrIn)
  1774. {
  1775. char szModuleName[MAX_PATH];
  1776. DWORD pathLen = 0;
  1777. char *pch;
  1778. szModuleName[0] = '\0';
  1779. if (g_fOOP) {
  1780. strcat(szModuleName, "INETSRV\\");
  1781. }
  1782. if (HRESULT_FACILITY(hrIn) == (HRESULT)FACILITY_INTERNET)
  1783. strcat(szModuleName, "METADATA.DLL");
  1784. else
  1785. strcat(szModuleName, "ASP.DLL");
  1786. return(LoadLibraryExA(szModuleName, NULL, LOAD_LIBRARY_AS_DATAFILE));
  1787. }
  1788. /*===================================================================
  1789. HResultToSz
  1790. Tranlates a HRESULT to a description string of the HRESULT. Attempts
  1791. to use FormatMessage() to get a
  1792. Parameters:
  1793. hrIn The error to lookup
  1794. szOut String to output the description to
  1795. cdwOut Number of WCHARs wszOut can hold
  1796. Returns:
  1797. TRUE if a description string was found
  1798. FALSE if the error number was output instead
  1799. Notes:
  1800. Added to resolve bug 91847. When unexpected errors are processed
  1801. the naked error number was output, which developers would then
  1802. have to look up in winerror.h.
  1803. ===================================================================*/
  1804. BOOL HResultToSz(HRESULT hrIn, CHAR *szOut, DWORD cdwOut)
  1805. {
  1806. LANGID langID = LANG_NEUTRAL;
  1807. HMODULE hMsgModule = NULL;
  1808. BOOL bFound = FALSE;
  1809. #ifdef USE_LOCALE
  1810. LANGID *pLangID;
  1811. pLangID = (LANGID *)TlsGetValue(g_dwTLS);
  1812. if (NULL != pLangID)
  1813. langID = *pLangID;
  1814. #endif
  1815. hMsgModule = GetModuleHandleForHRESULT(hrIn);
  1816. HRESULT hr = GetLastError();
  1817. bFound = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
  1818. hMsgModule,
  1819. hrIn,
  1820. langID,
  1821. szOut,
  1822. cdwOut,
  1823. NULL);
  1824. // make one additional check before giving up. If the facility of the error is
  1825. // WIN32, then retry the call after masking out the facility code to get standard
  1826. // WIN32 errors. I.E. 80070005 is really just 5 - access denied
  1827. if (!bFound && (HRESULT_FACILITY(hrIn) == (HRESULT)FACILITY_WIN32)) {
  1828. bFound = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_FROM_HMODULE,
  1829. NULL,
  1830. hrIn & 0xffff,
  1831. langID,
  1832. szOut,
  1833. cdwOut,
  1834. NULL);
  1835. }
  1836. if (hMsgModule)
  1837. FreeLibrary(hMsgModule);
  1838. if (!bFound )
  1839. {
  1840. // Error not found, make a string out of the error number
  1841. CHAR *szResult = NULL;
  1842. CHAR szBuf[17];
  1843. CHAR *szNumber;
  1844. CHAR *szError;
  1845. INT iC;
  1846. // put a bunch of zeros into the buffer
  1847. for (iC = 0; iC < 16; ++iC)
  1848. szBuf[iC] = L'0';
  1849. // wszNumber points half way into the buffer
  1850. szNumber = &szBuf[8];
  1851. // get the error wszNumber as a hex string
  1852. _ltoa(hrIn, szNumber, 16);
  1853. // back up szNumber to allow a total of 8 digits
  1854. szNumber -= 8 - strlen(szNumber);
  1855. // Copy the result to wszOut
  1856. strncpy(szOut, szNumber, cdwOut);
  1857. return FALSE;
  1858. }
  1859. else
  1860. return TRUE;
  1861. }
  1862. /*===================================================================
  1863. FIsResStrFormatted
  1864. Check for formatted resource string.
  1865. RETURN:
  1866. TRUE/FALSE
  1867. ===================================================================*/
  1868. BOOL FIsResStrFormatted(char *szIn)
  1869. {
  1870. BOOL freturn = FALSE;
  1871. UINT cDelimiter = 0;
  1872. CHAR *pch;
  1873. if(szIn)
  1874. {
  1875. pch = szIn;
  1876. while(*pch)
  1877. {
  1878. if ('~' == *pch)
  1879. cDelimiter++;
  1880. pch = CharNextA(pch);
  1881. }
  1882. if(3 == cDelimiter)
  1883. return TRUE;
  1884. }
  1885. return freturn;
  1886. }
  1887. /*===================================================================
  1888. HandleErrorMissingFilename
  1889. In several circumstances we want to report an error, but
  1890. we have no filename, and the normal method for getting
  1891. the filename from the template wont work because we have
  1892. no line number info either (e.g. Script timeout, GPF, control GPF, etc)
  1893. Get the filename from the CIsapiReqInfo (if possible) and report the error.
  1894. Returns:
  1895. Nothing
  1896. ===================================================================*/
  1897. VOID HandleErrorMissingFilename
  1898. (
  1899. UINT errorID,
  1900. CHitObj *pHitObj,
  1901. BOOL fAddlInfo /* = FALSE */,
  1902. ...
  1903. )
  1904. {
  1905. va_list args;
  1906. if (fAddlInfo)
  1907. va_start(args, fAddlInfo);
  1908. CHAR *szFileName = NULL;
  1909. if (pHitObj && pHitObj->PSzCurrTemplateVirtPath())
  1910. {
  1911. #if UNICODE
  1912. szFileName = StringDupUTF8(pHitObj->PSzCurrTemplateVirtPath());
  1913. #else
  1914. szFileName = StringDupA(pHitObj->PSzCurrTemplateVirtPath());
  1915. #endif
  1916. }
  1917. char szEngine[64];
  1918. CchLoadStringOfId(IDS_ENGINE, szEngine, sizeof szEngine);
  1919. char *pszEngine = new char [strlen(szEngine) + 1];
  1920. if (pszEngine)
  1921. {
  1922. // If the alloc failed, we will pass NULL to HandleError for pszEngine, which is fine.
  1923. // (old code used to pass NULL) All that will happen is that the AspError.Category == "". Oh Well.
  1924. // TODO: change this function to return an HRESULT.
  1925. //
  1926. strcpy(pszEngine, szEngine);
  1927. }
  1928. HandleError(errorID, szFileName, NULL, pszEngine, NULL, NULL, NULL, pHitObj, fAddlInfo ? &args : NULL);
  1929. }
  1930. /*===================================================================
  1931. DebugError
  1932. Handle a script error by invoking the debugger.
  1933. Returns:
  1934. fails if debugger cannot be invoked.
  1935. If this function fails, no other action is taken.
  1936. (Therefore, the caller should make sure error is reported in
  1937. some other way)
  1938. ===================================================================*/
  1939. HRESULT DebugError(IActiveScriptError *pScriptError, CTemplate *pTemplate, DWORD dwEngineID, IDebugApplication *pDebugApp)
  1940. {
  1941. EXCEPINFO excepinfo = {0};
  1942. BSTR bstrLine = NULL;
  1943. DWORD dwSourceContext = 0;
  1944. ULONG ulLineError = 0;
  1945. ULONG ichLineError = 0; // character offset of the line in the source
  1946. ULONG cchLineError = 0; // length of the source line
  1947. BOOLB fGuessedLine = FALSE; // see bug 379
  1948. LPTSTR szPathInfo = NULL;
  1949. LPTSTR szPathTranslated = NULL;
  1950. LONG ichError = -1;
  1951. HRESULT hr = S_OK;
  1952. IDebugDocumentContext *pDebugContext = NULL;
  1953. wchar_t *wszErrNum, *wszShortDesc, *wszLongDesc; // Used to tokenize resource strings
  1954. if (pScriptError == NULL || pTemplate == NULL || pDebugApp == NULL)
  1955. return E_POINTER;
  1956. if (FAILED(pScriptError->GetSourcePosition(&dwSourceContext, &ulLineError, &ichError)))
  1957. return E_FAIL;
  1958. if (FAILED(pScriptError->GetExceptionInfo(&excepinfo)))
  1959. return E_FAIL;
  1960. // call template object to get line number and character offset where error occurred
  1961. // (It returns both - caller discards whichever it does not want)
  1962. // bug 379: if pTemplate returns fGuessedLine == TRUE, it means we gave it a non-authored
  1963. // line, so we adjust below by not printing bstrLine in the error msg
  1964. pTemplate->GetScriptSourceInfo(dwEngineID, ulLineError, &szPathInfo, &szPathTranslated, NULL, &ichLineError, NULL);
  1965. // Create a new document context for this statement
  1966. // CONSIDER: character count that we return is bogus - however our debugging
  1967. // client (Caesar's) does not use this information anyway.
  1968. //
  1969. // If this is in the main file, create a document context based on the CTemplate compiled source
  1970. if (_tcscmp(szPathTranslated, pTemplate->GetSourceFileName()) == 0)
  1971. pDebugContext = new CTemplateDocumentContext(pTemplate, ichLineError, 1);
  1972. // source refers to an include file, so create a documet context based on cached CIncFile dependency graph
  1973. else
  1974. {
  1975. CIncFile *pIncFile;
  1976. if (FAILED(g_IncFileMap.GetIncFile(szPathTranslated, &pIncFile)))
  1977. {
  1978. hr = E_FAIL;
  1979. goto LExit;
  1980. }
  1981. pDebugContext = new CIncFileDocumentContext(pIncFile, ichLineError, 1);
  1982. pIncFile->Release();
  1983. }
  1984. if (pDebugContext == NULL)
  1985. {
  1986. hr = E_OUTOFMEMORY;
  1987. goto LExit;
  1988. }
  1989. // Yes it does, bring up the debugger on this line
  1990. hr = InvokeDebuggerWithThreadSwitch
  1991. (
  1992. pDebugApp,
  1993. DEBUGGER_UI_BRING_DOC_CONTEXT_TO_TOP,
  1994. pDebugContext
  1995. );
  1996. if (FAILED(hr))
  1997. goto LExit;
  1998. // pop up a message box with the error description
  1999. // Bug 81954: Misbehaved objects may throw an exception without providing any information
  2000. wchar_t wszExceptionBuffer[256];
  2001. wchar_t *wszDescription;
  2002. if (excepinfo.bstrDescription == NULL || excepinfo.bstrDescription[0] == L'\0')
  2003. {
  2004. HRESULT hrError;
  2005. if (0 == excepinfo.wCode)
  2006. hrError = excepinfo.scode;
  2007. else
  2008. hrError = excepinfo.wCode;
  2009. // Bug 91847 Attempt to get a description via FormatMessage()
  2010. if (!HResultToWsz(hrError, wszExceptionBuffer, 128))
  2011. CwchLoadStringOfId(IDE_SCRIPT_UNKNOWN, wszExceptionBuffer, sizeof(wszExceptionBuffer)/sizeof(WCHAR));
  2012. wszDescription = wszExceptionBuffer;
  2013. }
  2014. else
  2015. wszDescription = excepinfo.bstrDescription;
  2016. wchar_t wszSource[35];
  2017. CwchLoadStringOfId(IDS_SCRIPT_ERROR, wszSource, sizeof(wszSource)/sizeof(WCHAR));
  2018. // See if this is resource formatted string, and if it is, get pointers to short & long string
  2019. // resource formatted strings are delimited by '~' characters There are three '~' characters
  2020. // in the resource formatted string
  2021. //
  2022. wszErrNum = wcschr(wszDescription, L'~');
  2023. if (wszErrNum)
  2024. {
  2025. wszShortDesc = wcschr(wszErrNum + 1, L'~');
  2026. if (wszShortDesc)
  2027. {
  2028. wszLongDesc = wcschr(wszShortDesc + 1, L'~');
  2029. // OK. If all three tests succeeded, we know this is a resource formatted string,
  2030. // and we have pointers to all three segments. Replace each '~' with two newlines.
  2031. // First: Load resource strings
  2032. wchar_t wszErrorBegin[20], wszErrorEnd[5];
  2033. wchar_t *pwchEnd;
  2034. CwchLoadStringOfId(IDS_DEBUGGER_TEMPLATE_BEGIN, wszErrorBegin, sizeof(wszErrorBegin)/sizeof(WCHAR));
  2035. CwchLoadStringOfId(IDS_DEBUGGER_TEMPLATE_END, wszErrorEnd, sizeof(wszErrorEnd)/sizeof(WCHAR));
  2036. // Tokenize string by setting '~' characters to NULL and incrementing ptrs
  2037. *wszErrNum++ = *wszShortDesc++ = *wszLongDesc++ = L'\0';
  2038. // Build the string
  2039. pwchEnd = strcpyExW(wszExceptionBuffer, excepinfo.bstrSource);
  2040. *pwchEnd++ = L' ';
  2041. pwchEnd = strcpyExW(pwchEnd, wszErrorBegin);
  2042. pwchEnd = strcpyExW(pwchEnd, wszErrNum);
  2043. pwchEnd = strcpyExW(pwchEnd, wszErrorEnd);
  2044. *pwchEnd++ = L'\n';
  2045. *pwchEnd++ = L'\n';
  2046. pwchEnd = strcpyExW(pwchEnd, wszShortDesc);
  2047. *pwchEnd++ = L'\n';
  2048. *pwchEnd++ = L'\n';
  2049. pwchEnd = strcpyExW(pwchEnd, wszLongDesc);
  2050. wszDescription = wszExceptionBuffer;
  2051. }
  2052. }
  2053. MessageBoxW(NULL, wszDescription, wszSource, MB_SERVICE_NOTIFICATION | MB_TOPMOST | MB_OK | MB_ICONEXCLAMATION);
  2054. LExit:
  2055. if (pDebugContext)
  2056. pDebugContext->Release();
  2057. if (excepinfo.bstrSource)
  2058. SysFreeString(excepinfo.bstrSource);
  2059. if (excepinfo.bstrDescription)
  2060. SysFreeString(excepinfo.bstrDescription);
  2061. if (excepinfo.bstrHelpFile)
  2062. SysFreeString(excepinfo.bstrHelpFile);
  2063. return hr;
  2064. }