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.

1408 lines
41 KiB

  1. /*===================================================================
  2. Microsoft Denali
  3. Microsoft Confidential.
  4. Copyright 1996 Microsoft Corporation. All Rights Reserved.
  5. Component: Executor
  6. Owner: DGottner
  7. File: executor.cpp
  8. This file contains the executor, whose job is to co-ordinate the
  9. execution of Denali scripts.
  10. ===================================================================*/
  11. #include "denpre.h"
  12. #pragma hdrstop
  13. #include "exec.h"
  14. #include "response.h"
  15. #include "request.h"
  16. #include "perfdata.h"
  17. #include "memchk.h"
  18. // Local declarations
  19. HRESULT ExecuteGlobal(CHitObj *pHitObj,
  20. const CIntrinsicObjects &intrinsics,
  21. ActiveEngineInfo *pEngineInfo);
  22. HRESULT ExecuteRequest(CTemplate *pTemplate, CHitObj *pHitObj,
  23. const CIntrinsicObjects &intrinsics,
  24. ActiveEngineInfo *pEngineInfo);
  25. HRESULT ReInitIntrinsics(CHitObj *pHitObj, const CIntrinsicObjects &intrinsics,
  26. ActiveEngineInfo *pEngineInfo, BOOL fPostGlobal);
  27. HRESULT AllocAndLoadEngines(CHitObj *pHitObj, CTemplate *pTemplate, ActiveEngineInfo *pEngineInfo,
  28. CScriptingNamespace *pScriptingNamespace, BOOL fGlobalAsa);
  29. VOID DeAllocAndFreeEngines(ActiveEngineInfo *pEngineInfo, CAppln *pAppln);
  30. CScriptEngine *GetScriptEngine(int iScriptEngine, void *pvData);
  31. HRESULT CallScriptFunctionOfEngine(ActiveEngineInfo &engineInfo, short iScriptBlock, wchar_t *strFunction, CASPObjectContext *pASPObjectContext = NULL);
  32. HRESULT CallScriptFunction(ActiveEngineInfo &engineInfo, wchar_t *strFunction);
  33. HRESULT TestScriptFunction(ActiveEngineInfo &engineInfo, wchar_t *strFunction);
  34. /*===================================================================
  35. Execute
  36. Execute a request:
  37. First determine if Global needs to be called
  38. then invoke actual requested template
  39. Parameters:
  40. pTemplate - pointer to loaded template (could be NULL)
  41. pHitObj - pointer to the hit object
  42. intrinsics - pointers to the intrinsic IUnknown pointers.
  43. fChild - flag: TRUE when child request (Server.Execute())
  44. Returns:
  45. S_OK on success
  46. ===================================================================*/
  47. HRESULT Execute
  48. (
  49. CTemplate *pTemplate,
  50. CHitObj *pHitObj,
  51. const CIntrinsicObjects &intrinsics,
  52. BOOL fChild
  53. )
  54. {
  55. HRESULT hr = S_OK;
  56. ActiveEngineInfo engineInfo;
  57. BOOL fRanGlobal = FALSE;
  58. // The hit obj must be valid
  59. Assert(pHitObj != NULL);
  60. pHitObj->AssertValid();
  61. // Check for valid Session codepage. We do it here, rather than in CSession::Init in
  62. // order to avoid generic "New Session Failed" message.
  63. if (pHitObj->GetCodePage() != CP_ACP && !IsValidCodePage(pHitObj->GetCodePage()))
  64. {
  65. HandleErrorMissingFilename(IDE_BAD_CODEPAGE_IN_MB, pHitObj);
  66. return E_FAIL;
  67. }
  68. // Give the engine list to the hitobject
  69. pHitObj->SetActiveEngineInfo(&engineInfo);
  70. /*
  71. * If there is a Global.ASA, call it
  72. */
  73. if (pHitObj->GlobalAspPath() && !fChild)
  74. {
  75. // Clear out the engine info
  76. engineInfo.cEngines = 0;
  77. engineInfo.cActiveEngines = 0;
  78. engineInfo.rgActiveEngines = NULL;
  79. // Init the intrinsics
  80. hr = ReInitIntrinsics(pHitObj, intrinsics, &engineInfo, /* fPostGlobal*/ FALSE);
  81. if (FAILED(hr))
  82. return(hr);
  83. hr = ExecuteGlobal(pHitObj, intrinsics, &engineInfo);
  84. if (intrinsics.PResponse() && intrinsics.PResponse()->FResponseAborted())
  85. {
  86. hr = S_OK;
  87. goto LExit;
  88. }
  89. if (E_SOURCE_FILE_IS_EMPTY == hr)
  90. // bug 977: silently ignore empty global.asa file
  91. hr = S_OK;
  92. else if (FAILED(hr))
  93. {
  94. // Bug 481: If global.asa fails due to Response.End (or Response.Redirect),
  95. // then halt execution of the calling script. If the
  96. // script fails due to Response.End, then return OK status
  97. //
  98. if (hr == DISP_E_EXCEPTION)
  99. hr = S_OK;
  100. // In any case, blow out of here
  101. goto LExit;
  102. }
  103. // Running Global.asa added the scripting namespace to the hitobj. This will cause us problems
  104. // later, remove it.
  105. pHitObj->RemoveScriptingNamespace();
  106. fRanGlobal = TRUE;
  107. }
  108. /*
  109. * If this is not a browser request, then we are done
  110. * For non-browser requests, we do want to run Global.asa (if any), but there is no real template to run.
  111. */
  112. if (!pHitObj->FIsBrowserRequest())
  113. {
  114. hr = S_OK;
  115. goto LExit;
  116. }
  117. // Clear out (or re-clear out) the engine info
  118. engineInfo.cEngines = 0;
  119. engineInfo.cActiveEngines = 0;
  120. engineInfo.rgActiveEngines = NULL;
  121. // Init or Re-Init the intrinsics
  122. ReInitIntrinsics(pHitObj, intrinsics, &engineInfo, fRanGlobal || fChild);
  123. if (!fChild)
  124. {
  125. // For non-child requests hand new Template to Response object
  126. // (for child requests already done)
  127. intrinsics.PResponse()->ReInitTemplate(pTemplate, pHitObj->PSzNewSessionCookie());
  128. }
  129. else
  130. {
  131. // For child requests hand new engine info to the response object
  132. intrinsics.PResponse()->SwapScriptEngineInfo(&engineInfo);
  133. }
  134. // Run the main template
  135. if (pTemplate->FScriptless() && !pHitObj->PAppln()->FDebuggable())
  136. {
  137. // special case scriptless pages
  138. hr = intrinsics.PResponse()->WriteBlock(0);
  139. }
  140. else
  141. {
  142. hr = ExecuteRequest(pTemplate, pHitObj, intrinsics, &engineInfo);
  143. }
  144. LExit:
  145. intrinsics.PResponse()->SwapScriptEngineInfo(NULL);
  146. pHitObj->SetActiveEngineInfo(NULL);
  147. return hr;
  148. }
  149. /*===================================================================
  150. ExecRequest
  151. Execute a request for an actual template (not Global.asa)
  152. execute a request by
  153. - getting the script name
  154. - loading the script into memory
  155. - interpreting the opcodes
  156. Parameters:
  157. pTemplate - pointer to loaded template
  158. pHitObj - pointer to the hit object
  159. intrinsics - pointers to the intrinsic IUnknown pointers.
  160. pEngineInfo - pointers to engine info
  161. Returns:
  162. S_OK on success
  163. ===================================================================*/
  164. HRESULT ExecuteRequest(CTemplate *pTemplate,
  165. CHitObj *pHitObj,
  166. const CIntrinsicObjects &intrinsics,
  167. ActiveEngineInfo *pEngineInfo)
  168. {
  169. HRESULT hr = S_OK;
  170. BOOL fAborted = FALSE;
  171. BOOLB fDebuggerNotifiedOnStart = FALSE;
  172. BOOL fServiceDomainEnterred = FALSE;
  173. CASPObjectContext *pASPObjectContext = NULL;
  174. CASPObjectContext *pPoppedASPObjectContext = NULL;
  175. #ifndef PERF_DISABLE
  176. BOOLB fPerfTransPending = FALSE;
  177. #endif
  178. // The template must be valid
  179. Assert(pTemplate);
  180. // The hit obj must be valid
  181. Assert(pHitObj != NULL);
  182. pHitObj->AssertValid();
  183. // This function should never be called on a non-browser request
  184. Assert(pHitObj->FIsBrowserRequest());
  185. // Remember template's type library wrapper with the HitObj
  186. if (pTemplate->PTypeLibWrapper())
  187. pHitObj->SetTypeLibWrapper(pTemplate->PTypeLibWrapper());
  188. if (pTemplate->FTransacted()) {
  189. #ifndef PERF_DISABLE
  190. g_PerfData.Incr_TRANSTOTAL();
  191. g_PerfData.Incr_TRANSPENDING();
  192. fPerfTransPending = TRUE;
  193. #endif
  194. pASPObjectContext = new CASPObjectContext();
  195. if (!pASPObjectContext) {
  196. hr = E_OUTOFMEMORY;
  197. goto LExit;
  198. }
  199. pPoppedASPObjectContext = pHitObj->SetASPObjectContext(pASPObjectContext);
  200. }
  201. if (pTemplate->PServicesConfig()) {
  202. hr = CoEnterServiceDomain(pTemplate->PServicesConfig());
  203. if (FAILED(hr)) {
  204. goto LExit;
  205. }
  206. fServiceDomainEnterred = TRUE;
  207. }
  208. // load script engines
  209. hr = AllocAndLoadEngines(pHitObj, pTemplate, pEngineInfo, intrinsics.PScriptingNamespace(), /* fGlobalAsa */FALSE);
  210. if (FAILED(hr)) {
  211. pHitObj->SetCompilationFailed();
  212. goto LExit;
  213. }
  214. // If debugging, notify debugger ONPAGESTART
  215. // BUG 138773: Notify debugger AFTER scripts load
  216. // (script must be in running state when AttachTo() is called because debugger may want a code context)
  217. //
  218. if (pHitObj->PAppln()->FDebuggable()) {
  219. pTemplate->AttachTo(pHitObj->PAppln());
  220. if (SUCCEEDED(pTemplate->NotifyDebuggerOnPageEvent(TRUE)))
  221. fDebuggerNotifiedOnStart = TRUE;
  222. }
  223. // bug 1009: if no script engines, do not attempt to do anything
  224. if(0 == pTemplate->CountScriptEngines())
  225. goto LExit;
  226. // run the script by calling primary script engine's global code
  227. hr = CallScriptFunctionOfEngine(*pEngineInfo, // engine-info
  228. 0, // primary script engine
  229. NULL, // call the engine's global code
  230. pHitObj->PASPObjectContext());
  231. if (fServiceDomainEnterred) {
  232. fServiceDomainEnterred = FALSE;
  233. CoLeaveServiceDomain(static_cast<ITransactionStatus *>(pHitObj->PASPObjectContext()));
  234. }
  235. if (pTemplate->FTransacted()) {
  236. fAborted = pHitObj->PASPObjectContext()->FAborted();
  237. }
  238. if (FAILED(hr)) {
  239. /*
  240. * The cryptically named CONTEXT_E_OLDREF error in this case means that
  241. * we are trying to run a transacted web page, but DTC isnt running.
  242. * CONTEXT_E_TMNOTAVAILABLE means the same thing. God knows why
  243. */
  244. if (hr == CONTEXT_E_OLDREF || hr == CONTEXT_E_TMNOTAVAILABLE) {
  245. HandleErrorMissingFilename(IDE_EXECUTOR_DTC_NOT_RUNNING, pHitObj);
  246. }
  247. // Regardless of the error, exit
  248. goto LExit;
  249. }
  250. /*
  251. * If this is a transacted web page, then run either the OnTransactionCommit
  252. * or OnTransactionAbort method in the script, if any.
  253. *
  254. * If the script writer did an explicit SetAbort, or a component run by the script
  255. * did a SetAbort, then we run OnTransactionAbort, otherwise run OnTransactionCommit
  256. */
  257. if (pTemplate->FTransacted()) {
  258. #ifndef PERF_DISABLE
  259. g_PerfData.Incr_TRANSPERSEC();
  260. #endif
  261. if (fAborted) {
  262. hr = CallScriptFunction(*pEngineInfo, L"OnTransactionAbort");
  263. #ifndef PERF_DISABLE
  264. g_PerfData.Incr_TRANSABORTED();
  265. #endif
  266. }
  267. else {
  268. hr = CallScriptFunction(*pEngineInfo, L"OnTransactionCommit");
  269. #ifndef PERF_DISABLE
  270. g_PerfData.Incr_TRANSCOMMIT();
  271. #endif
  272. }
  273. // Ignore UNKNOWNNAME -- this means the author didnt write the method, which is fine
  274. if (hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND)
  275. hr = S_OK;
  276. if (FAILED(hr))
  277. goto LExit;
  278. }
  279. LExit:
  280. if (fServiceDomainEnterred) {
  281. CoLeaveServiceDomain(NULL);
  282. }
  283. #ifndef PERF_DISABLE
  284. if (fPerfTransPending)
  285. g_PerfData.Decr_TRANSPENDING();
  286. #endif
  287. // Uninit the scripting namespace
  288. (VOID)intrinsics.PScriptingNamespace()->UnInit();
  289. // Return the engine(s) to cache
  290. DeAllocAndFreeEngines(pEngineInfo, pHitObj->PAppln());
  291. // If debugging, notify debugger ONPAGEDONE
  292. if (fDebuggerNotifiedOnStart) {
  293. Assert(pHitObj->PAppln()->FDebuggable());
  294. pTemplate->NotifyDebuggerOnPageEvent(FALSE);
  295. }
  296. if (pPoppedASPObjectContext)
  297. pHitObj->SetASPObjectContext(pPoppedASPObjectContext);
  298. if (pASPObjectContext)
  299. pASPObjectContext->Release();
  300. return hr;
  301. }
  302. /*===================================================================
  303. ExecuteGlobal
  304. UNDONE: handle script engine the same manner as mainline script engines
  305. with respect to debugging.
  306. Execute code in Global.ASA as part of application or session start or end.
  307. Parameters:
  308. pHitObj - pointer to the hit object
  309. intrinsics - pointers to the intrinsic IUnknown pointers.
  310. pEngineInfo - pointers to engine info
  311. pfDeleteSession - true if global.asa failed, and therefore the caller should
  312. Returns:
  313. S_OK on success
  314. ===================================================================*/
  315. HRESULT ExecuteGlobal
  316. (
  317. CHitObj *pHitObj,
  318. const CIntrinsicObjects &intrinsics,
  319. ActiveEngineInfo *pEngineInfo
  320. )
  321. {
  322. HRESULT hr = S_OK;
  323. CTemplate *pTemplate = NULL;
  324. WORD iEng;
  325. BOOLB fDebuggerNotifiedOnStart = FALSE;
  326. BOOL fUnHideRequestAndResponse = FALSE;
  327. BOOL fOnStartAppln = FALSE;
  328. BOOL fOnEndAppln = FALSE;
  329. BOOL fOnEndSession = FALSE;
  330. BOOL fGlobalAsaInCache;
  331. BOOL fApplnStarted = FALSE;
  332. BOOL fServiceDomainEnterred = FALSE;
  333. CASPObjectContext *pASPObjectContext = NULL;
  334. CASPObjectContext *pPoppedASPObjectContext = NULL;
  335. // The hit obj must be there, be valid, & have a global.asa name
  336. Assert(pHitObj != NULL);
  337. pHitObj->AssertValid();
  338. Assert(pHitObj->GlobalAspPath() != NULL && *(pHitObj->GlobalAspPath()) != '\0');
  339. // Other arg's must be right
  340. Assert(pEngineInfo != NULL);
  341. // Load the script - cache will AddRef
  342. // bug 1051: load template before possibly removing response object (in switch block, below),
  343. // so error reporting to browser will work
  344. hr = LoadTemplate(pHitObj->GlobalAspPath(), pHitObj, &pTemplate, intrinsics, /* fGlobalAsa */ TRUE, &fGlobalAsaInCache);
  345. if (FAILED(hr))
  346. goto LExit;
  347. Assert(pTemplate != NULL);
  348. // Remember GLOBAL.ASA's type library wrapper with the application
  349. // on the first request
  350. if (pHitObj->FStartApplication() && pTemplate->PTypeLibWrapper())
  351. {
  352. pHitObj->PAppln()->SetGlobTypeLibWrapper(pTemplate->PTypeLibWrapper());
  353. }
  354. if (pTemplate->FTransacted()) {
  355. pASPObjectContext = new CASPObjectContext();
  356. if (!pASPObjectContext) {
  357. hr = E_OUTOFMEMORY;
  358. goto LExit;
  359. }
  360. pPoppedASPObjectContext = pHitObj->SetASPObjectContext(pASPObjectContext);
  361. }
  362. if (pTemplate->PServicesConfig()) {
  363. hr = CoEnterServiceDomain(pTemplate->PServicesConfig());
  364. if (FAILED(hr)) {
  365. goto LExit;
  366. }
  367. fServiceDomainEnterred = TRUE;
  368. }
  369. Assert(pHitObj->FIsValidRequestType());
  370. // Figure out which events to trigger
  371. if (pHitObj->FIsBrowserRequest())
  372. {
  373. fOnStartAppln = pHitObj->FStartApplication();
  374. if (fOnStartAppln)
  375. {
  376. // Hide response and request intrinsics from namespace
  377. pHitObj->HideRequestAndResponseIntrinsics();
  378. // Flag that intrinsics need to be un-hidden back in.
  379. fUnHideRequestAndResponse = TRUE;
  380. }
  381. }
  382. else if (pHitObj->FIsSessionCleanupRequest())
  383. {
  384. fOnEndSession = TRUE;
  385. }
  386. else if (pHitObj->FIsApplnCleanupRequest())
  387. {
  388. fOnEndAppln = TRUE;
  389. }
  390. // If debugging, notify debugger ONPAGESTART
  391. if (pHitObj->PAppln()->FDebuggable())
  392. {
  393. if (SUCCEEDED(pTemplate->NotifyDebuggerOnPageEvent(TRUE)))
  394. fDebuggerNotifiedOnStart = TRUE;
  395. }
  396. hr = AllocAndLoadEngines(pHitObj, pTemplate, pEngineInfo, intrinsics.PScriptingNamespace(), /* fGlobalAsa */TRUE);
  397. if (FAILED(hr))
  398. goto LExit;
  399. // BUG 93991: Defer registration of new document with debugger until after script engines have
  400. // been loaded
  401. //
  402. if (!fGlobalAsaInCache && pHitObj->PAppln()->FDebuggable())
  403. pTemplate->AttachTo(pHitObj->PAppln());
  404. // bug 975: if no script engines, do not attempt to call event functions
  405. if(0 == pTemplate->CountScriptEngines())
  406. goto LExit;
  407. /*
  408. * Call event functions as required
  409. * bug 459: event functions may be in any script engine
  410. */
  411. // First run Application_OnStart
  412. if (fOnStartAppln)
  413. {
  414. pHitObj->SetEventState(eEventAppOnStart);
  415. hr = CallScriptFunction(*pEngineInfo, L"Application_OnStart");
  416. if (SUCCEEDED(hr) || hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND ||
  417. intrinsics.PResponse()->FResponseAborted())
  418. {
  419. if (fUnHideRequestAndResponse)
  420. {
  421. pHitObj->UnHideRequestAndResponseIntrinsics();
  422. fUnHideRequestAndResponse = FALSE;
  423. }
  424. fApplnStarted = TRUE;
  425. hr = S_OK;
  426. }
  427. else
  428. {
  429. goto LExit;
  430. }
  431. }
  432. if (pHitObj->FStartSession())
  433. {
  434. // If application on start was run, add Response and Request names to script engines
  435. if (fOnStartAppln)
  436. {
  437. for (iEng = 0; iEng < pEngineInfo->cActiveEngines; ++iEng)
  438. {
  439. if (FAILED(hr = pEngineInfo->rgActiveEngines[iEng].pScriptEngine->AddAdditionalObject(WSZ_OBJ_RESPONSE, FALSE)))
  440. goto LExit;
  441. if (FAILED(hr = pEngineInfo->rgActiveEngines[iEng].pScriptEngine->AddAdditionalObject(WSZ_OBJ_REQUEST, FALSE)))
  442. goto LExit;
  443. }
  444. }
  445. pHitObj->SetEventState(eEventSesOnStart);
  446. hr = CallScriptFunction(*pEngineInfo, L"Session_OnStart");
  447. if (FAILED(hr) && hr != DISP_E_UNKNOWNNAME && hr != DISP_E_MEMBERNOTFOUND &&
  448. !intrinsics.PResponse()->FResponseAborted())
  449. {
  450. // Mark session as on-start-failed - to be deleted soon
  451. pHitObj->SessionOnStartFailed();
  452. }
  453. else
  454. {
  455. if (SUCCEEDED(hr))
  456. {
  457. // Mark as on-start-invoked -- need to wait for timeout
  458. pHitObj->SessionOnStartInvoked();
  459. }
  460. // Check if Session_OnEnd Present
  461. if (SUCCEEDED(TestScriptFunction(*pEngineInfo, L"Session_OnEnd")))
  462. {
  463. // Mark as on-end-present -- need to execute OnEnd later
  464. pHitObj->SessionOnEndPresent();
  465. }
  466. hr = S_OK;
  467. }
  468. goto LExit;
  469. }
  470. if (fOnEndSession)
  471. {
  472. pHitObj->SetEventState(eEventSesOnEnd);
  473. hr = CallScriptFunction(*pEngineInfo, L"Session_OnEnd");
  474. // We are failing silently here, since there is no corrective action we could take
  475. }
  476. if (fOnEndAppln)
  477. {
  478. pHitObj->SetEventState(eEventAppOnEnd);
  479. hr = CallScriptFunction(*pEngineInfo, L"Application_OnEnd");
  480. // We are failing silently here, since there is no corrective action we could take
  481. }
  482. LExit:
  483. if (fServiceDomainEnterred)
  484. CoLeaveServiceDomain(NULL);
  485. if (fUnHideRequestAndResponse)
  486. {
  487. pHitObj->UnHideRequestAndResponseIntrinsics();
  488. }
  489. if (FAILED(hr) && (hr != E_SOURCE_FILE_IS_EMPTY) && pHitObj->FStartApplication() && !fApplnStarted)
  490. {
  491. pHitObj->ApplnOnStartFailed();
  492. }
  493. pHitObj->SetEventState(eEventNone);
  494. // Uninit the scripting namespace
  495. (VOID)intrinsics.PScriptingNamespace()->UnInit();
  496. // Release the template
  497. if (pTemplate)
  498. {
  499. // bug 975: if no script engines, do not do this
  500. if(pTemplate->CountScriptEngines() > 0)
  501. // Return the engine(s) to cache
  502. DeAllocAndFreeEngines(pEngineInfo, pHitObj->PAppln());
  503. // If debugging, notify debugger ONPAGEDONE
  504. if (fDebuggerNotifiedOnStart)
  505. {
  506. Assert(pHitObj->PAppln()->FDebuggable());
  507. pTemplate->NotifyDebuggerOnPageEvent(FALSE);
  508. }
  509. pTemplate->Release();
  510. }
  511. // It is OK if the event function was not found in global.asa
  512. if (hr == DISP_E_UNKNOWNNAME || hr == DISP_E_MEMBERNOTFOUND)
  513. {
  514. hr = S_OK;
  515. }
  516. if (pPoppedASPObjectContext)
  517. pHitObj->SetASPObjectContext(pPoppedASPObjectContext);
  518. if (pASPObjectContext)
  519. pASPObjectContext->Release();
  520. return hr;
  521. }
  522. /*===================================================================
  523. CIntrinsicObjects::Prepare
  524. Prepare intrinsics for the request processing
  525. Parameters:
  526. pSession session holding the instrinsics (can be NULL)
  527. Returns:
  528. HRESULT
  529. ===================================================================*/
  530. HRESULT CIntrinsicObjects::Prepare
  531. (
  532. CSession *pSession
  533. )
  534. {
  535. HRESULT hr = S_OK;
  536. if (pSession)
  537. {
  538. // get request, response, server from session
  539. if (SUCCEEDED(hr))
  540. {
  541. m_pRequest = pSession->PRequest();
  542. if (m_pRequest)
  543. m_pRequest->AddRef();
  544. else
  545. hr = E_FAIL;
  546. }
  547. if (SUCCEEDED(hr))
  548. {
  549. m_pResponse = pSession->PResponse();
  550. if (m_pResponse)
  551. m_pResponse->AddRef();
  552. else
  553. hr = E_FAIL;
  554. }
  555. if (SUCCEEDED(hr))
  556. {
  557. m_pServer = pSession->PServer();
  558. if (m_pServer)
  559. m_pServer->AddRef();
  560. else
  561. hr = E_FAIL;
  562. }
  563. }
  564. else
  565. {
  566. // create new request, response, server
  567. if (SUCCEEDED(hr))
  568. {
  569. m_pRequest = new CRequest;
  570. if (!m_pRequest)
  571. hr = E_OUTOFMEMORY;
  572. }
  573. if (SUCCEEDED(hr))
  574. {
  575. m_pResponse = new CResponse;
  576. if (!m_pResponse)
  577. hr = E_OUTOFMEMORY;
  578. }
  579. if (SUCCEEDED(hr))
  580. {
  581. m_pServer = new CServer;
  582. if (!m_pServer)
  583. hr = E_OUTOFMEMORY;
  584. }
  585. }
  586. // init request, response, server
  587. if (SUCCEEDED(hr))
  588. {
  589. Assert(m_pRequest);
  590. hr = m_pRequest->Init();
  591. }
  592. if (SUCCEEDED(hr))
  593. {
  594. Assert(m_pResponse);
  595. hr = m_pResponse->Init();
  596. }
  597. if (SUCCEEDED(hr))
  598. {
  599. Assert(m_pServer);
  600. hr = m_pServer->Init();
  601. }
  602. // create the scripting namespace
  603. if (SUCCEEDED(hr))
  604. {
  605. m_pScriptingNamespace = new CScriptingNamespace;
  606. if (!m_pScriptingNamespace)
  607. hr = E_OUTOFMEMORY;
  608. }
  609. // cleanup on error
  610. if (FAILED(hr))
  611. Cleanup();
  612. m_fIsChild = FALSE;
  613. return hr;
  614. }
  615. /*===================================================================
  616. CIntrinsicObjects::PrepareChild
  617. Prepare intrinsics structure for a child request
  618. Parameters:
  619. pResponse parent intrinsic
  620. pRequest parent intrinsic
  621. pServer parent intrinsic
  622. Returns:
  623. HRESULT
  624. ===================================================================*/
  625. HRESULT CIntrinsicObjects::PrepareChild
  626. (
  627. CResponse *pResponse,
  628. CRequest *pRequest,
  629. CServer *pServer
  630. )
  631. {
  632. HRESULT hr = S_OK;
  633. if (!pResponse || !pRequest || !pServer)
  634. {
  635. hr = E_FAIL;
  636. }
  637. if (SUCCEEDED(hr))
  638. {
  639. m_pResponse = pResponse;
  640. m_pResponse->AddRef();
  641. m_pRequest = pRequest;
  642. m_pRequest->AddRef();
  643. m_pServer = pServer;
  644. m_pServer->AddRef();
  645. m_fIsChild = TRUE;
  646. }
  647. if (SUCCEEDED(hr))
  648. {
  649. m_pScriptingNamespace = new CScriptingNamespace;
  650. if (!m_pScriptingNamespace)
  651. hr = E_OUTOFMEMORY;
  652. }
  653. if (FAILED(hr))
  654. Cleanup();
  655. return hr;
  656. }
  657. /*===================================================================
  658. CIntrinsicObjects::Cleanup
  659. Cleanup the intrinsics after the request processing
  660. Parameters:
  661. Returns:
  662. S_OK
  663. ===================================================================*/
  664. HRESULT CIntrinsicObjects::Cleanup()
  665. {
  666. if (m_pRequest)
  667. {
  668. if (!m_fIsChild)
  669. m_pRequest->UnInit();
  670. m_pRequest->Release();
  671. m_pRequest = NULL;
  672. }
  673. if (m_pResponse)
  674. {
  675. if (!m_fIsChild)
  676. m_pResponse->UnInit();
  677. m_pResponse->Release();
  678. m_pResponse = NULL;
  679. }
  680. if (m_pServer)
  681. {
  682. if (!m_fIsChild)
  683. m_pServer->UnInit();
  684. m_pServer->Release();
  685. m_pServer = NULL;
  686. }
  687. if (m_pScriptingNamespace)
  688. {
  689. m_pScriptingNamespace->Release();
  690. m_pScriptingNamespace = NULL;
  691. }
  692. return S_OK;
  693. }
  694. /*===================================================================
  695. ReInitIntrinsics
  696. Call re-init on each of the intrinsics that require it
  697. to run a new page.
  698. Parameters:
  699. pHitObj - pointer to the hit object
  700. intrinsics - pointers to the intrinsic IUnknown pointers.
  701. pEngineInfo - some engine info
  702. fPostGlobal - Is this a reinit after running global.asa?
  703. Returns:
  704. S_OK on success
  705. ===================================================================*/
  706. HRESULT ReInitIntrinsics
  707. (
  708. CHitObj *pHitObj,
  709. const CIntrinsicObjects &intrinsics,
  710. ActiveEngineInfo *pEngineInfo,
  711. BOOL fPostGlobal
  712. )
  713. {
  714. HRESULT hr;
  715. Assert(pHitObj != NULL);
  716. pHitObj->AssertValid();
  717. Assert(pEngineInfo != NULL);
  718. // Hand the new CIsapiReqInfo to the Server object
  719. // Note on bug 682: We do always need to re-init CServer because it takes the phitobj
  720. if (FAILED(hr = intrinsics.PServer()->ReInit(pHitObj->PIReq(), pHitObj)))
  721. goto LExit;
  722. if (FAILED(hr = intrinsics.PScriptingNamespace()->Init()))
  723. goto LExit;
  724. /*
  725. * Bug 682 & 671 (better fix to 452 & 512)
  726. * Dont re-init the Request & response objects after running a Global.Asa
  727. * because, the running of global.asa may have set cookies into request (bug 671), that reinit
  728. * would wipe, and the global.asa may have output headers (or other stuff) which impacts the response
  729. * object (bug 512) that we dont want to reset.
  730. */
  731. if (!fPostGlobal)
  732. {
  733. if (FAILED(hr = intrinsics.PRequest()->ReInit(pHitObj->PIReq(), pHitObj)))
  734. goto LExit;
  735. if (FAILED(hr = intrinsics.PResponse()->ReInit(
  736. pHitObj->PIReq(),
  737. pHitObj->PSzNewSessionCookie(),
  738. intrinsics.PRequest(),
  739. GetScriptEngine,
  740. pEngineInfo,
  741. pHitObj
  742. )))
  743. goto LExit;
  744. }
  745. LExit:
  746. return(hr);
  747. }
  748. /*===================================================================
  749. LoadTemplate
  750. Load a template, cleanup and give appropriate errors on failure.
  751. Parameters:
  752. szFile - the file to load a template for
  753. pHitObj - pointer to the hit object
  754. ppTemplate - The returned loaded template
  755. fGlobalAsa - is this for Global.asa?
  756. Returns:
  757. S_OK on success
  758. ===================================================================*/
  759. HRESULT LoadTemplate
  760. (
  761. const TCHAR *szFile,
  762. CHitObj *pHitObj,
  763. CTemplate **ppTemplate,
  764. const CIntrinsicObjects &intrinsics,
  765. BOOL fGlobalAsa,
  766. BOOL *pfTemplateInCache)
  767. {
  768. HRESULT hr;
  769. Assert(pHitObj != NULL);
  770. pHitObj->AssertValid();
  771. Assert(ppTemplate != NULL);
  772. // Load the script - cache will AddRef
  773. if (FAILED(hr = g_TemplateCache.Load(
  774. fGlobalAsa,
  775. szFile,
  776. pHitObj->DWInstanceID(),
  777. pHitObj,
  778. ppTemplate,
  779. pfTemplateInCache)))
  780. {
  781. // CONSIDER moving this cleanup into Template.Load
  782. if (hr == E_COULDNT_OPEN_SOURCE_FILE || hr == E_SOURCE_FILE_IS_EMPTY)
  783. {
  784. // Load error string from string table
  785. // BUG 731: added if to retrieve the correct header
  786. WCHAR szwErr[128];
  787. if (hr == E_COULDNT_OPEN_SOURCE_FILE)
  788. {
  789. CwchLoadStringOfId(IDH_404_OBJECT_NOT_FOUND, szwErr, 128);
  790. intrinsics.PResponse()->put_Status( szwErr );
  791. HandleSysError(404, 0, IDE_404_OBJECT_NOT_FOUND, NULL, NULL, pHitObj);
  792. #ifndef PERF_DISABLE
  793. g_PerfData.Incr_REQNOTFOUND();
  794. #endif
  795. }
  796. // bug 977: silently ignore empty global.asa file
  797. else if ((E_SOURCE_FILE_IS_EMPTY == hr) && !fGlobalAsa)
  798. {
  799. CwchLoadStringOfId(IDH_204_NO_CONTENT, szwErr, 128);
  800. intrinsics.PResponse()->put_Status( szwErr );
  801. HandleSysError(204, 0, IDE_204_NO_CONTENT, NULL, NULL, pHitObj);
  802. }
  803. }
  804. // fix for bug 371
  805. if (*ppTemplate)
  806. {
  807. (*ppTemplate)->Release();
  808. *ppTemplate = NULL;
  809. }
  810. if (hr == E_OUTOFMEMORY)
  811. {
  812. DBGPRINTF((DBG_CONTEXT, "Loading template returned E_OUTOFMEMORY. Flushing template & Script Cache.\n"));
  813. g_TemplateCache.FlushAll();
  814. g_ScriptManager.FlushAll();
  815. }
  816. }
  817. return(hr);
  818. }
  819. /*===================================================================
  820. AllocAndLoadEngines
  821. Allocate and load all the engines we need
  822. Parameters:
  823. pHitObj - The hit object
  824. pTemplate - The template we're gonna run
  825. pEngineInfo - Engine info to fill in
  826. pScriptingNamespace - scripting namespace
  827. fGlobalAsa - Are we loading engines to run global.asa?
  828. Returns:
  829. S_OK on success
  830. ===================================================================*/
  831. HRESULT AllocAndLoadEngines
  832. (
  833. CHitObj *pHitObj,
  834. CTemplate *pTemplate,
  835. ActiveEngineInfo *pEngineInfo,
  836. CScriptingNamespace *pScriptingNamespace,
  837. BOOL fGlobalAsa
  838. )
  839. {
  840. HRESULT hr = S_OK;
  841. int iObj;
  842. WORD iEng;
  843. WORD iScriptBlock;
  844. WORD cEngines = pTemplate->CountScriptEngines();
  845. Assert(pHitObj != NULL);
  846. pHitObj->AssertValid();
  847. Assert(pTemplate != NULL);
  848. Assert(pEngineInfo != NULL);
  849. Assert(pScriptingNamespace != NULL);
  850. // Load objects from template into hit object
  851. for (iObj = pTemplate->Count(tcompObjectInfo) - 1; iObj >= 0; --iObj)
  852. {
  853. CHAR *szObjectName = NULL;
  854. CLSID clsid;
  855. CompScope scope;
  856. CompModel model;
  857. CMBCSToWChar convStr;
  858. // get object-info from template and add to hitobj's list of objects
  859. hr = pTemplate->GetObjectInfo(iObj, &szObjectName, &clsid, &scope, &model);
  860. if(FAILED(hr))
  861. goto LExit;
  862. hr = convStr.Init(szObjectName);
  863. if (FAILED(hr))
  864. goto LExit;
  865. // ignore error ?
  866. pHitObj->AddComponent(ctTagged, clsid, scope, model, convStr.GetString());
  867. }
  868. // bug 975: if no script engines, exit now
  869. if(cEngines == 0)
  870. goto LExit;
  871. // Allocate space for script engines
  872. //
  873. // NOTE: There is a timing problem here in that the response object needs to
  874. // be instantiated before we instantiate the script engines, but the
  875. // response object needs to be able to access the list of active script
  876. // engines, because it may need to halt execution. To accomplish this,
  877. // the response object is passed a pointer to the "EngineInfo" structure
  878. // as a pointer, and then we modify the contents of the pointer right under
  879. // its nose. We pass an accessor function via pointer so that response just
  880. // sees a void pointer.
  881. //
  882. if (cEngines == 1)
  883. {
  884. // don't do allocations in case of one engine
  885. pEngineInfo->rgActiveEngines = & (pEngineInfo->siOneActiveEngine);
  886. }
  887. else
  888. {
  889. pEngineInfo->rgActiveEngines = new ScriptingInfo[cEngines];
  890. if (pEngineInfo->rgActiveEngines == NULL)
  891. {
  892. hr = E_OUTOFMEMORY;
  893. goto LExit;
  894. }
  895. }
  896. pEngineInfo->cEngines = cEngines;
  897. pEngineInfo->cActiveEngines = 0; // number of SUCCESSFULLY instantiated engines
  898. // Load all of the script engines in advance.
  899. for (iScriptBlock = 0; iScriptBlock < cEngines; ++iScriptBlock)
  900. {
  901. LPCOLESTR wstrScript;
  902. SCRIPTSTATE nScriptState;
  903. ScriptingInfo *pScriptInfo = &pEngineInfo->rgActiveEngines[iScriptBlock];
  904. pTemplate->GetScriptBlock(
  905. iScriptBlock,
  906. &pScriptInfo->szScriptEngine,
  907. &pScriptInfo->pProgLangId,
  908. &wstrScript);
  909. // Populate information required for the line mapping callback.
  910. //
  911. pScriptInfo->LineMapInfo.iScriptBlock = iScriptBlock;
  912. pScriptInfo->LineMapInfo.pTemplate = pTemplate;
  913. // acquire a script engine by:
  914. //
  915. // getting an engine from the template object (if it has one)
  916. // else from the script manager.
  917. //
  918. // If we are in debug mode, the templates tend to be greedy and hold
  919. // onto script engines. (See notes in scrptmgr.h)
  920. //
  921. pScriptInfo->pScriptEngine = NULL;
  922. if (pHitObj->PAppln()->FDebuggable())
  923. {
  924. pScriptInfo->pScriptEngine = pTemplate->GetActiveScript(iScriptBlock);
  925. if (pScriptInfo->pScriptEngine)
  926. {
  927. // If we got one, we don't need to re-init the engine
  928. nScriptState = SCRIPTSTATE_INITIALIZED;
  929. hr = static_cast<CActiveScriptEngine *>(pScriptInfo->pScriptEngine)->ReuseEngine(pHitObj, NULL, iScriptBlock, pHitObj->DWInstanceID());
  930. }
  931. }
  932. if (pScriptInfo->pScriptEngine == NULL)
  933. {
  934. hr = g_ScriptManager.GetEngine(LOCALE_SYSTEM_DEFAULT,
  935. *(pScriptInfo->pProgLangId),
  936. pTemplate->GetSourceFileName(),
  937. pHitObj,
  938. &pScriptInfo->pScriptEngine,
  939. &nScriptState,
  940. pTemplate,
  941. iScriptBlock);
  942. }
  943. if (FAILED(hr))
  944. goto LExit;
  945. // BUG 252: Keep track of how many engines we actually instantiate
  946. ++pEngineInfo->cActiveEngines;
  947. if (nScriptState == SCRIPTSTATE_UNINITIALIZED || fGlobalAsa)
  948. {
  949. if (FAILED(hr = pScriptInfo->pScriptEngine->AddObjects(!fGlobalAsa)))
  950. goto LExit;
  951. }
  952. if (nScriptState == SCRIPTSTATE_UNINITIALIZED)
  953. {
  954. if (FAILED(hr = pScriptInfo->pScriptEngine->AddScriptlet(wstrScript)))
  955. goto LExit;
  956. }
  957. // Add the engine to the scripting namespace
  958. if (FAILED(hr = pScriptingNamespace->AddEngineToNamespace(
  959. (CActiveScriptEngine *)pScriptInfo->pScriptEngine)))
  960. goto LExit;
  961. // Update locale & code page (in case they are different om this page)
  962. pScriptInfo->pScriptEngine->UpdateLocaleInfo(hostinfoLocale);
  963. pScriptInfo->pScriptEngine->UpdateLocaleInfo(hostinfoCodePage);
  964. }
  965. // Add the scripting namespace to each script engine. Because all engines might not
  966. // implement "lazy instantiation", this code requires all
  967. // engines are pre-instantiated (which means we can't do it in the above loop.)
  968. // Add the scripting namespace to the hitobj first
  969. pHitObj->AddScriptingNamespace(pScriptingNamespace);
  970. for (iEng = 0; iEng < pEngineInfo->cActiveEngines; ++iEng)
  971. pEngineInfo->rgActiveEngines[iEng].pScriptEngine->AddScriptingNamespace();
  972. /*
  973. * Bug 735:
  974. * Bring all engines except the "primary engine" (engine 0) to runnable state
  975. * in the order in which script for the given language was found in the script file
  976. */
  977. for (iEng = 1; iEng < pEngineInfo->cActiveEngines; ++iEng)
  978. {
  979. hr = pEngineInfo->rgActiveEngines[iEng].pScriptEngine->MakeEngineRunnable();
  980. if (FAILED(hr))
  981. goto LExit;
  982. }
  983. LExit:
  984. return(hr);
  985. }
  986. /*===================================================================
  987. DeAllocAndFreeEngines
  988. Deallocate and free any loaded engines
  989. Parameters:
  990. pEngineInfo - Engine info to release
  991. Returns:
  992. Nothing
  993. ===================================================================*/
  994. VOID DeAllocAndFreeEngines
  995. (
  996. ActiveEngineInfo *pEngineInfo,
  997. CAppln *pAppln
  998. )
  999. {
  1000. WORD iEng;
  1001. Assert(pEngineInfo != NULL);
  1002. if (pEngineInfo->cActiveEngines > 0) {
  1003. if (pEngineInfo->rgActiveEngines == NULL) {
  1004. Assert(pEngineInfo->rgActiveEngines);
  1005. }
  1006. else {
  1007. for (iEng = 0; iEng < pEngineInfo->cActiveEngines; ++iEng)
  1008. g_ScriptManager.ReturnEngineToCache(&pEngineInfo->rgActiveEngines[iEng].pScriptEngine, pAppln);
  1009. pEngineInfo->cActiveEngines = 0;
  1010. }
  1011. }
  1012. if (pEngineInfo->cEngines > 1)
  1013. {
  1014. delete pEngineInfo->rgActiveEngines;
  1015. }
  1016. pEngineInfo->cEngines = 0;
  1017. pEngineInfo->rgActiveEngines = NULL;
  1018. }
  1019. /*===================================================================
  1020. GetScriptEngine
  1021. Get a script engine based on index. Return NULL if the index
  1022. is not in range. (this is a callback)
  1023. The AllocAndLoadEngines function will create an array of ScriptingInfo
  1024. structures that are defined here. It contains all the infomation
  1025. needed to 1. set up the MapScript2SourceLine callback,
  1026. 2. merge namespaces, 3. set up this callback.
  1027. Parameters:
  1028. iScriptEngine - the script engine to retrieve
  1029. pvData - instance data for the function
  1030. Returns:
  1031. The requested script engine or NULL if not such engine
  1032. Side effects:
  1033. None
  1034. ===================================================================*/
  1035. CScriptEngine *GetScriptEngine
  1036. (
  1037. INT iScriptEngine,
  1038. VOID *pvData
  1039. )
  1040. {
  1041. ActiveEngineInfo *pInfo = static_cast<ActiveEngineInfo *>(pvData);
  1042. if (unsigned(iScriptEngine) >= unsigned(pInfo->cActiveEngines))
  1043. {
  1044. // Note: the caller has no idea how many script engines there are.
  1045. // if the caller asks for an engine out of range, return NULL so they
  1046. // know they have asked for more than there are
  1047. return NULL;
  1048. }
  1049. return(pInfo->rgActiveEngines[iScriptEngine].pScriptEngine);
  1050. }
  1051. /*===================================================================
  1052. CallScriptFunctionOfEngine
  1053. Calls a script engine to execute one of its functions
  1054. Returns:
  1055. S_OK on success
  1056. Side effects:
  1057. None
  1058. ===================================================================*/
  1059. HRESULT CallScriptFunctionOfEngine
  1060. (
  1061. ActiveEngineInfo &engineInfo,
  1062. short iScriptBlock,
  1063. wchar_t *strFunction,
  1064. CASPObjectContext *pASPObjectContext /* = NULL */
  1065. )
  1066. {
  1067. HRESULT hr;
  1068. CScriptEngine *pScriptEngine = (CScriptEngine *)engineInfo.rgActiveEngines[iScriptBlock].pScriptEngine;
  1069. Assert(engineInfo.rgActiveEngines != NULL);
  1070. Assert(pScriptEngine != NULL);
  1071. hr = pScriptEngine->Call(strFunction);
  1072. // housekeeping for the transacted case...
  1073. if (pASPObjectContext != NULL) {
  1074. // If the script timed out or there was an unhandled error, then autoabort
  1075. if (SUCCEEDED(hr) && (pScriptEngine->FScriptTimedOut() || pScriptEngine->FScriptHadError()))
  1076. {
  1077. hr = pASPObjectContext->SetAbort();
  1078. }
  1079. // If the script author did not do an explicit SetComplete or SetAbort
  1080. // then do a SetComplete here so Viper will return the transaction
  1081. // completion status to the caller
  1082. if (SUCCEEDED(hr) && !pASPObjectContext->FAborted())
  1083. {
  1084. hr = pASPObjectContext->SetComplete();
  1085. }
  1086. }
  1087. return hr;
  1088. }
  1089. /*===================================================================
  1090. CallScriptFunction
  1091. Calls each script engine in turn to execute a script function;
  1092. exits when an engine succeeds or we run out of engines.
  1093. Returns:
  1094. S_OK on success
  1095. Side effects:
  1096. None
  1097. ===================================================================*/
  1098. HRESULT CallScriptFunction
  1099. (
  1100. ActiveEngineInfo &engineInfo,
  1101. wchar_t *strFunction
  1102. )
  1103. {
  1104. HRESULT hr = E_FAIL;
  1105. int i;
  1106. for (i = 0; i < engineInfo.cActiveEngines; i++)
  1107. {
  1108. // if execution succeeds, bail
  1109. if (SUCCEEDED(hr = CallScriptFunctionOfEngine(engineInfo, (SHORT)i, strFunction)))
  1110. goto LExit;
  1111. // if execution fails with exception other then unknown name, bail
  1112. if (hr != DISP_E_UNKNOWNNAME && hr != DISP_E_MEMBERNOTFOUND)
  1113. goto LExit;
  1114. }
  1115. LExit:
  1116. return hr;
  1117. }
  1118. /*===================================================================
  1119. TestScriptFunction
  1120. Tests each script engine in turn to test [the existance of] a script
  1121. function; exits when an engine succeeds or we run out of engines.
  1122. Parameters
  1123. ActiveEngineInfo &engineInfo
  1124. wchar_t *strFunction functions name
  1125. Returns:
  1126. S_OK if exists
  1127. Side effects:
  1128. None
  1129. ===================================================================*/
  1130. HRESULT TestScriptFunction
  1131. (
  1132. ActiveEngineInfo &engineInfo,
  1133. wchar_t *strFunction
  1134. )
  1135. {
  1136. HRESULT hr = E_FAIL;
  1137. for (int i = 0; i < engineInfo.cActiveEngines; i++)
  1138. {
  1139. hr = engineInfo.rgActiveEngines[i].pScriptEngine->
  1140. CheckEntryPoint(strFunction);
  1141. // if execution succeeds, bail
  1142. if (SUCCEEDED(hr))
  1143. break;
  1144. // if fails with result other then unknown name, bail
  1145. if (hr != DISP_E_UNKNOWNNAME && hr != DISP_E_MEMBERNOTFOUND)
  1146. break;
  1147. }
  1148. return hr;
  1149. }