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.

3811 lines
120 KiB

  1. // This is a part of the Active Template Library.
  2. // Copyright (C) 1996-2001 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Active Template Library Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Active Template Library product.
  10. #ifndef __ATLSTENCIL_H__
  11. #define __ATLSTENCIL_H__
  12. #pragma once
  13. #ifdef _ATL_MIN_CRT
  14. #error "_ATL_MIN_CRT cannot be used with atlstencil.h"
  15. #endif
  16. #include <atlisapi.h>
  17. #include <atlfile.h>
  18. #include <atlutil.h>
  19. #ifndef ATL_NO_MLANG
  20. #include <mlang.h>
  21. #endif
  22. #ifndef _ATL_NO_DEFAULT_LIBS
  23. #pragma comment(lib, "shlwapi.lib")
  24. #endif // !_ATL_NO_DEFAULT_LIBS
  25. #pragma warning( push )
  26. #pragma warning( disable: 4127 )
  27. #pragma warning(disable: 4511) // copy constructor could not be generated
  28. #pragma warning(disable: 4512) // assignment operator could not be generated
  29. #pragma warning(disable: 4702) // assignment operator could not be generated
  30. namespace ATL {
  31. // Token types
  32. // These tags are token tags for the standard tag replacer implementation
  33. extern __declspec(selectany) const DWORD STENCIL_TEXTTAG = 0x00000000;
  34. extern __declspec(selectany) const DWORD STENCIL_REPLACEMENT = 0x00000001;
  35. extern __declspec(selectany) const DWORD STENCIL_ITERATORSTART = 0x00000002;
  36. extern __declspec(selectany) const DWORD STENCIL_ITERATOREND = 0x00000003;
  37. extern __declspec(selectany) const DWORD STENCIL_CONDITIONALSTART = 0x00000004;
  38. extern __declspec(selectany) const DWORD STENCIL_CONDITIONALELSE = 0x00000005;
  39. extern __declspec(selectany) const DWORD STENCIL_CONDITIONALEND = 0x00000006;
  40. extern __declspec(selectany) const DWORD STENCIL_STENCILINCLUDE = 0x00000007;
  41. extern __declspec(selectany) const DWORD STENCIL_STATICINCLUDE = 0x00000008;
  42. extern __declspec(selectany) const DWORD STENCIL_LOCALE = 0x00000009;
  43. extern __declspec(selectany) const DWORD STENCIL_CODEPAGE = 0x0000000a;
  44. // The base for user defined token types
  45. extern __declspec(selectany) const DWORD STENCIL_USER_TOKEN_BASE = 0x00001000;
  46. // Symbols to use in error handling in the stencil processor
  47. #define STENCIL_INVALIDINDEX 0xFFFFFFFF
  48. #define STENCIL_INVALIDOFFSET 0xFFFFFFFF
  49. // error codes
  50. #define STENCIL_SUCCESS HTTP_SUCCESS
  51. #define STENCL_FAIL HTTP_FAIL
  52. #define STENCIL_BASIC_MAP 0
  53. #define STENCIL_ATTR_MAP 1
  54. #ifndef ATL_MAX_METHOD_NAME_LEN
  55. #define ATL_MAX_METHOD_NAME_LEN 64
  56. #endif
  57. #ifndef ATL_MAX_BLOCK_STACK
  58. #define ATL_MAX_BLOCK_STACK 128
  59. #endif
  60. template <class TBase, typename T>
  61. struct CTagReplacerMethodsEx
  62. {
  63. typedef HTTP_CODE (TBase::*REPLACE_FUNC)();
  64. typedef HTTP_CODE (TBase::*REPLACE_FUNC_EX)(T*);
  65. typedef HTTP_CODE (TBase::*PARSE_FUNC)(IAtlMemMgr *, LPCSTR, T**);
  66. typedef HTTP_CODE (TBase::*REPLACE_FUNC_EX_V)(void *);
  67. typedef HTTP_CODE (TBase::*PARSE_FUNC_V)(IAtlMemMgr *, LPCSTR, void**);
  68. static REPLACE_FUNC_EX_V CheckRepl(REPLACE_FUNC p) throw()
  69. {
  70. return (REPLACE_FUNC_EX_V) p;
  71. }
  72. static REPLACE_FUNC_EX_V CheckReplEx(REPLACE_FUNC_EX p) throw()
  73. {
  74. return (REPLACE_FUNC_EX_V) p;
  75. }
  76. static PARSE_FUNC_V CheckParse(PARSE_FUNC p) throw()
  77. {
  78. return (PARSE_FUNC_V) p;
  79. }
  80. };
  81. template <class TBase>
  82. struct CTagReplacerMethods
  83. {
  84. union
  85. {
  86. HTTP_CODE (TBase::*pfnMethodEx)(void *);
  87. HTTP_CODE (TBase::*pfnMethod)();
  88. };
  89. HTTP_CODE (TBase::*pfnParse)(IAtlMemMgr *pMemMgr, LPCSTR, void **);
  90. };
  91. #define REPLACEMENT_ENTRY_DEFAULT 0
  92. #define REPLACEMENT_ENTRY_ARGS 1
  93. template <class TBase>
  94. struct CTagReplacerMethodEntry
  95. {
  96. int nType; // REPLACEMENT_ENTRY_*
  97. LPCSTR szMethodName;
  98. CTagReplacerMethods<TBase> Methods;
  99. };
  100. #define BEGIN_REPLACEMENT_METHOD_MAP(className)\
  101. public:\
  102. void GetReplacementMethodMap(const ATL::CTagReplacerMethodEntry<className> ** ppOut) const throw()\
  103. {\
  104. typedef className __className;\
  105. static const ATL::CTagReplacerMethodEntry<className> methods[] = {
  106. #define REPLACEMENT_METHOD_ENTRY(methodName, methodFunc)\
  107. { 0, methodName, { ATL::CTagReplacerMethodsEx<__className, void>::CheckRepl(methodFunc), NULL } },
  108. #define REPLACEMENT_METHOD_ENTRY_EX(methodName, methodFunc, paramType, parseFunc)\
  109. { 1, methodName, { ATL::CTagReplacerMethodsEx<__className, paramType>::CheckReplEx(methodFunc), ATL::CTagReplacerMethodsEx<__className, paramType>::CheckParse(parseFunc) } },
  110. #define REPLACEMENT_METHOD_ENTRY_EX_STR(methodName, methodFunc) \
  111. { 1, methodName, { ATL::CTagReplacerMethodsEx<__className, char>::CheckReplEx(methodFunc), ATL::CTagReplacerMethodsEx<__className, char>::CheckParse(DefaultParseString) } },
  112. #define END_REPLACEMENT_METHOD_MAP()\
  113. { 0, NULL, NULL } };\
  114. *ppOut = methods;\
  115. }
  116. #define BEGIN_ATTR_REPLACEMENT_METHOD_MAP(className)\
  117. public:\
  118. void GetAttrReplacementMethodMap(const CTagReplacerMethodEntry<className> ** ppOut) const throw()\
  119. {\
  120. typedef className __className;\
  121. static const ATL::CTagReplacerMethodEntry<className> methods[] = {
  122. #define END_ATTR_REPLACEMENT_METHOD_MAP()\
  123. { NULL, NULL, NULL } };\
  124. *ppOut = methods;\
  125. }
  126. template <class T>
  127. class ITagReplacerImpl : public ITagReplacer
  128. {
  129. protected:
  130. IWriteStream *m_pStream;
  131. public:
  132. typedef HTTP_CODE (T::*REPLACEMENT_METHOD)();
  133. typedef HTTP_CODE (T::*REPLACEMENT_METHOD_EX)(void *pvParam);
  134. ITagReplacerImpl() throw()
  135. :m_pStream(NULL)
  136. {
  137. }
  138. IWriteStream *SetStream(IWriteStream *pStream) throw()
  139. {
  140. IWriteStream *pRetStream = m_pStream;
  141. m_pStream = pStream;
  142. return pRetStream;
  143. }
  144. // Looks up the replacement method offset. Optionally, it will
  145. // look up the replacement method and object offset of an alternate
  146. // tag replacer.
  147. HTTP_CODE FindReplacementOffset(
  148. LPCSTR szMethodName,
  149. DWORD *pdwMethodOffset,
  150. LPCSTR szHandlerName,
  151. DWORD *pdwHandlerOffset,
  152. DWORD *pdwMap, void **ppvParam, IAtlMemMgr *pMemMgr) throw(...)
  153. {
  154. // we at least have to be looking up a method offset
  155. if (!pdwMethodOffset || !szMethodName)
  156. return HTTP_ERROR(500, ISE_SUBERR_UNEXPECTED);
  157. *pdwMethodOffset = STENCIL_INVALIDOFFSET;
  158. HTTP_CODE hcErr = HTTP_FAIL;
  159. T *pT = static_cast<T *>(this);
  160. char szName[ATL_MAX_METHOD_NAME_LEN];
  161. // if a handler name was supplied, we will try to
  162. // find a different object to handle the method
  163. if (szHandlerName && *szHandlerName)
  164. {
  165. if (!pdwHandlerOffset)
  166. return HTTP_ERROR(500, ISE_SUBERR_UNEXPECTED);
  167. hcErr = pT->GetHandlerOffset(szHandlerName, pdwHandlerOffset);
  168. // got the alternate handler, now look up the method offset on
  169. // the handler.
  170. if (!hcErr)
  171. {
  172. CComPtr<ITagReplacer> spAltTagReplacer;
  173. hcErr = pT->GetReplacementObject(*pdwHandlerOffset, &spAltTagReplacer);
  174. if (!hcErr)
  175. hcErr = spAltTagReplacer->FindReplacementOffset(szMethodName, pdwMethodOffset,
  176. NULL, NULL, pdwMap, ppvParam, pMemMgr);
  177. return hcErr;
  178. }
  179. else
  180. return hcErr;
  181. }
  182. strcpy(szName, szMethodName);
  183. // check for params
  184. char *szLeftPar = strchr(szName, '(');
  185. if (szLeftPar)
  186. {
  187. *szLeftPar = '\0';
  188. szLeftPar++;
  189. char *szRightPar = strchr(szLeftPar, ')');
  190. if (!szRightPar)
  191. return HTTP_ERROR(500, ISE_SUBERR_UNEXPECTED);
  192. *szRightPar = '\0';
  193. szMethodName = szName;
  194. }
  195. // No handler name is specified, so we look up the method name in
  196. // T's replacement method map
  197. const CTagReplacerMethodEntry<T> *pEntry;
  198. pT->GetReplacementMethodMap(&pEntry);
  199. hcErr = FindReplacementOffsetInMap(szMethodName, pdwMethodOffset, pEntry);
  200. if (hcErr != HTTP_SUCCESS)
  201. {
  202. pT->GetAttrReplacementMethodMap(&pEntry);
  203. hcErr = FindReplacementOffsetInMap(szMethodName, pdwMethodOffset, pEntry);
  204. if (hcErr == HTTP_SUCCESS)
  205. *pdwMap = STENCIL_ATTR_MAP;
  206. }
  207. else
  208. {
  209. *pdwMap = STENCIL_BASIC_MAP;
  210. }
  211. // This assert will be triggered if arguments are passed to a replacement method that doesn't handle them
  212. ATLASSERT( szLeftPar == NULL || (szLeftPar != NULL && (pEntry != NULL && pEntry[*pdwMethodOffset].Methods.pfnParse) != NULL) );
  213. if (hcErr == HTTP_SUCCESS && pEntry && pEntry[*pdwMethodOffset].Methods.pfnParse)
  214. hcErr = (pT->*pEntry[*pdwMethodOffset].Methods.pfnParse)(pMemMgr, szLeftPar, ppvParam);
  215. return hcErr;
  216. }
  217. HTTP_CODE FindReplacementOffsetInMap(
  218. LPCSTR szMethodName,
  219. LPDWORD pdwMethodOffset,
  220. const CTagReplacerMethodEntry<T> *pEntry) throw()
  221. {
  222. if (pEntry == NULL)
  223. return HTTP_FAIL;
  224. const CTagReplacerMethodEntry<T> *pEntryHead = pEntry;
  225. while (pEntry->szMethodName)
  226. {
  227. if (strcmp(pEntry->szMethodName, szMethodName) == 0)
  228. {
  229. if (pEntry->Methods.pfnMethod)
  230. {
  231. *pdwMethodOffset = (DWORD)(pEntry-pEntryHead);
  232. return HTTP_SUCCESS;
  233. }
  234. }
  235. pEntry++;
  236. }
  237. return HTTP_FAIL;
  238. }
  239. // Used to render a single replacement tag into a stream.
  240. // Looks up a pointer to a member function in user code by offseting into the users
  241. // replacement map. Much faster than the other overload of this function since
  242. // no string compares are performed.
  243. HTTP_CODE RenderReplacement(DWORD dwFnOffset, DWORD dwObjOffset, DWORD dwMap, void *pvParam) throw(...)
  244. {
  245. HTTP_CODE hcErr = HTTP_FAIL;
  246. T *pT = static_cast<T *>(this);
  247. // if we were not passed an object offset, then we assume
  248. // that the function at dwFnOffset is in T's replacement
  249. // map
  250. if (dwObjOffset == STENCIL_INVALIDOFFSET)
  251. {
  252. // call a function in T's replacement map
  253. ATLASSERT(dwFnOffset != STENCIL_INVALIDOFFSET);
  254. const CTagReplacerMethodEntry<T> *pEntry;
  255. if (dwMap == STENCIL_BASIC_MAP)
  256. pT->GetReplacementMethodMap(&pEntry);
  257. else
  258. pT->GetAttrReplacementMethodMap(&pEntry);
  259. if (pEntry)
  260. {
  261. if (pEntry[dwFnOffset].nType == REPLACEMENT_ENTRY_DEFAULT)
  262. {
  263. REPLACEMENT_METHOD pfn = NULL;
  264. pfn = pEntry[dwFnOffset].Methods.pfnMethod;
  265. ATLASSERT(pfn);
  266. if (pfn)
  267. {
  268. hcErr = (pT->*pfn)();
  269. }
  270. }
  271. else if (pEntry[dwFnOffset].nType == REPLACEMENT_ENTRY_ARGS)
  272. {
  273. REPLACEMENT_METHOD_EX pfn = NULL;
  274. pfn = pEntry[dwFnOffset].Methods.pfnMethodEx;
  275. ATLASSERT(pfn);
  276. if (pfn)
  277. {
  278. hcErr = (pT->*pfn)(pvParam);
  279. }
  280. }
  281. else
  282. {
  283. // unknown entry type
  284. ATLASSERT(FALSE);
  285. }
  286. }
  287. }
  288. else
  289. {
  290. // otherwise, we were passed an object offset. The object
  291. // offset is a dword ID that T can use to look up the
  292. // ITagReplacer* of a tag replacer that will render this
  293. // replacement.
  294. CComPtr<ITagReplacer> spAltReplacer = NULL;
  295. if (!pT->GetReplacementObject(dwObjOffset, &spAltReplacer))
  296. {
  297. spAltReplacer->SetStream(m_pStream);
  298. hcErr = spAltReplacer->RenderReplacement(dwFnOffset, STENCIL_INVALIDOFFSET, dwMap, pvParam);
  299. }
  300. }
  301. return hcErr;
  302. }
  303. // Default GetHandlerOffset, does nothing
  304. HTTP_CODE GetHandlerOffset(LPCSTR /*szHandlerName*/, DWORD* pdwOffset) throw()
  305. {
  306. if (pdwOffset)
  307. *pdwOffset = 0;
  308. return HTTP_FAIL;
  309. }
  310. // Default GetReplacementObject, does nothing
  311. HTTP_CODE GetReplacementObject(DWORD /*dwObjOffset*/, ITagReplacer **ppReplacer) throw()
  312. {
  313. if (ppReplacer)
  314. *ppReplacer = NULL;
  315. return HTTP_FAIL;
  316. }
  317. void GetReplacementMethodMap(const CTagReplacerMethodEntry<T> ** ppOut) const throw()
  318. {
  319. static const CTagReplacerMethodEntry<T> methods[] = { { NULL, NULL } };
  320. *ppOut = methods;
  321. }
  322. void GetAttrReplacementMethodMap(const CTagReplacerMethodEntry<T> **ppOut) const throw()
  323. {
  324. static const CTagReplacerMethodEntry<T> methods[] = { { NULL, NULL } };
  325. *ppOut = methods;
  326. }
  327. HRESULT GetContext(REFIID, void**) throw()
  328. {
  329. return E_NOINTERFACE;
  330. }
  331. HTTP_CODE FreeParam(void * /*pvParam*/) throw()
  332. {
  333. return HTTP_SUCCESS;
  334. }
  335. HTTP_CODE DefaultParseString(IAtlMemMgr *pMemMgr, LPCSTR szParams, char **ppParam) throw(...)
  336. {
  337. ATLASSERT(szParams);
  338. size_t nLen = strlen(szParams);
  339. if (nLen)
  340. {
  341. nLen++;
  342. *ppParam = (char *) pMemMgr->Allocate(nLen);
  343. if (*ppParam)
  344. memcpy(*ppParam, szParams, nLen);
  345. else
  346. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  347. }
  348. return HTTP_SUCCESS;
  349. }
  350. HTTP_CODE DefaultParseUChar(IAtlMemMgr *pMemMgr, LPCSTR szParams, unsigned char **ppParam) throw(...)
  351. {
  352. ATLASSERT(szParams);
  353. *ppParam = (unsigned char *) pMemMgr->Allocate(sizeof(unsigned char));
  354. if (*ppParam)
  355. {
  356. char *szEnd;
  357. **ppParam = (unsigned char) strtoul(szParams, &szEnd, 10);
  358. }
  359. else
  360. {
  361. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  362. }
  363. return HTTP_SUCCESS;
  364. }
  365. HTTP_CODE DefaultParseShort(IAtlMemMgr *pMemMgr, LPCSTR szParams, short **ppParam) throw(...)
  366. {
  367. ATLASSERT(szParams);
  368. *ppParam = (short *) pMemMgr->Allocate(sizeof(short));
  369. if (*ppParam)
  370. {
  371. **ppParam = (short)atoi(szParams);
  372. }
  373. else
  374. {
  375. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  376. }
  377. return HTTP_SUCCESS;
  378. }
  379. HTTP_CODE DefaultParseUShort(IAtlMemMgr *pMemMgr, LPCSTR szParams, unsigned short **ppParam) throw(...)
  380. {
  381. ATLASSERT(szParams);
  382. *ppParam = (unsigned short *) pMemMgr->Allocate(sizeof(short));
  383. if (*ppParam)
  384. {
  385. char *szEnd;
  386. **ppParam = (unsigned short) strtoul(szParams, &szEnd, 10);
  387. }
  388. else
  389. {
  390. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  391. }
  392. return HTTP_SUCCESS;
  393. }
  394. HTTP_CODE DefaultParseInt(IAtlMemMgr *pMemMgr, LPCSTR szParams, int **ppParam) throw(...)
  395. {
  396. ATLASSERT(szParams);
  397. *ppParam = (int *) pMemMgr->Allocate(sizeof(int));
  398. if (*ppParam)
  399. {
  400. **ppParam = atoi(szParams);
  401. }
  402. else
  403. {
  404. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  405. }
  406. return HTTP_SUCCESS;
  407. }
  408. HTTP_CODE DefaultParseUInt(IAtlMemMgr *pMemMgr, LPCSTR szParams, unsigned int **ppParam) throw(...)
  409. {
  410. ATLASSERT(szParams);
  411. *ppParam = (unsigned int *) pMemMgr->Allocate(sizeof(unsigned int));
  412. if (*ppParam)
  413. {
  414. char *szEnd;
  415. **ppParam = strtoul(szParams, &szEnd, 10);
  416. }
  417. else
  418. {
  419. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  420. }
  421. return HTTP_SUCCESS;
  422. }
  423. HTTP_CODE DefaultParseInt64(IAtlMemMgr *pMemMgr, LPCSTR szParams, __int64 **ppParam) throw(...)
  424. {
  425. ATLASSERT(szParams);
  426. *ppParam = (__int64 *) pMemMgr->Allocate(sizeof(__int64));
  427. if (*ppParam)
  428. {
  429. **ppParam = _atoi64(szParams);
  430. }
  431. else
  432. {
  433. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  434. }
  435. return HTTP_SUCCESS;
  436. }
  437. HTTP_CODE DefaultParseUInt64(IAtlMemMgr *pMemMgr, LPCSTR szParams, unsigned __int64 **ppParam) throw(...)
  438. {
  439. ATLASSERT(szParams);
  440. *ppParam = (unsigned __int64 *) pMemMgr->Allocate(sizeof(unsigned __int64));
  441. if (*ppParam)
  442. {
  443. char *szEnd;
  444. **ppParam = _strtoui64(szParams, &szEnd, 10);
  445. }
  446. else
  447. {
  448. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  449. }
  450. return HTTP_SUCCESS;
  451. }
  452. HTTP_CODE DefaultParseBool(IAtlMemMgr *pMemMgr, LPCSTR szParams, bool **ppParam) throw(...)
  453. {
  454. ATLASSERT(szParams);
  455. *ppParam = (bool *) pMemMgr->Allocate(sizeof(bool));
  456. if (*ppParam)
  457. {
  458. if (!_strnicmp(szParams, "true", sizeof("true")-sizeof('\0')))
  459. **ppParam = true;
  460. else
  461. **ppParam = false;
  462. }
  463. else
  464. {
  465. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  466. }
  467. return HTTP_SUCCESS;
  468. }
  469. HTTP_CODE DefaultParseDouble(IAtlMemMgr *pMemMgr, LPCSTR szParams, double **ppParam) throw(...)
  470. {
  471. ATLASSERT(szParams);
  472. *ppParam = (double *) pMemMgr->Allocate(sizeof(double));
  473. if (*ppParam)
  474. {
  475. **ppParam = atof(szParams);
  476. }
  477. else
  478. {
  479. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  480. }
  481. return HTTP_SUCCESS;
  482. }
  483. HTTP_CODE DefaultParseFloat(IAtlMemMgr *pMemMgr, LPCSTR szParams, float **ppParam) throw(...)
  484. {
  485. ATLASSERT(szParams);
  486. *ppParam = (float *) pMemMgr->Allocate(sizeof(float));
  487. if (*ppParam)
  488. {
  489. **ppParam = (float) atof(szParams);
  490. }
  491. else
  492. {
  493. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  494. }
  495. return HTTP_SUCCESS;
  496. }
  497. };
  498. inline LPSTR SkipSpace(LPSTR sz, WORD nCodePage)
  499. {
  500. while (_istspace(*sz))
  501. sz = CharNextExA(nCodePage, sz, 0);
  502. return sz;
  503. }
  504. inline LPSTR RSkipSpace(LPSTR pStart, LPSTR sz, WORD nCodePage) throw()
  505. {
  506. while (_istspace(*sz))
  507. sz = CharPrevExA(nCodePage, pStart, sz, 0);
  508. return sz;
  509. }
  510. //
  511. // StencilToken
  512. // The stencil class will create an array of these tokens during the parse
  513. // phase and use them during rendering to render the stencil
  514. struct StencilToken
  515. {
  516. LPSTR pStart; // Start of fragment to be rendered
  517. LPSTR pEnd; // End of fragment to be rendered
  518. DWORD type; // Type of token
  519. DWORD dwFnOffset; // Offset into the replacement map for the handler function.
  520. DWORD dwMap;
  521. DWORD dwObjOffset; // An identifier for the caller to use in identifiying the
  522. // object that will render this token.
  523. CHAR szHandlerName[ATL_MAX_HANDLER_NAME_LEN + 1]; // Name of handler object.
  524. CHAR szMethodName[ATL_MAX_METHOD_NAME_LEN + 1]; // Name of handler method.
  525. DWORD dwLoopIndex; // Offset into array of StencilTokens of the other loop tag
  526. DWORD_PTR dwData;
  527. BOOL bDynamicAlloc;
  528. };
  529. // Specialization of CElementTraitsBase so you can put a StencilToken safely in
  530. // a collection object.
  531. template<>
  532. class CElementTraits< StencilToken > :
  533. public CElementTraitsBase< StencilToken >
  534. {
  535. public:
  536. static ULONG Hash( INARGTYPE t ) throw()
  537. {
  538. return( ULONG( ULONG_PTR( &t ) ) );
  539. }
  540. static bool CompareElements( INARGTYPE element1, INARGTYPE element2 ) throw()
  541. {
  542. return( (element1.pStart == element2.pStart) && (element1.pEnd == element2.pEnd) );
  543. }
  544. static int CompareElementsOrdered( INARGTYPE element1, INARGTYPE element2 ) throw()
  545. {
  546. if( element1.pStart < element2.pStart )
  547. {
  548. return( -1 );
  549. }
  550. else if( CompareElements(element1,element2) )
  551. {
  552. return( 0 );
  553. }
  554. else
  555. {
  556. ATLASSERT( element1.pStart > element2.pStart );
  557. return( 1 );
  558. }
  559. }
  560. };
  561. //
  562. // Class CStencil
  563. // The CStencil class is used to map in a stencil from a file or resource
  564. // and parse the stencil into an array of StencilTokens. We then render
  565. // the stencil from the array of tokens. This class's parse and render
  566. // functions depend on an IReplacementHandlerLookup interface pointer to be
  567. // passed so it can retrieve the IReplacementHandler interface pointer of the
  568. // handler object that will be called to render replacement tags
  569. class CStencil :
  570. public IMemoryCacheClient
  571. {
  572. private:
  573. LPSTR m_pBufferStart; // Beginning of CHAR buffer that holds the stencil.
  574. // For mapped files this is the beginning of the mapping.
  575. LPSTR m_pBufferEnd; // End of CHAR buffer that holds the stencil.
  576. CAtlArray<StencilToken> m_arrTokens; //An array of tokens.
  577. FILETIME m_ftLastModified; // Last modified time (0 for resource)
  578. FILETIME m_ftLastChecked; // Last time we retrieved last modified time (0 for resource)
  579. HCACHEITEM m_hCacheItem;
  580. WORD m_nCodePage;
  581. BOOL m_bUseLocaleACP;
  582. char m_szDllPath[MAX_PATH+1];
  583. char m_szHandlerName[ATL_MAX_HANDLER_NAME_LEN+1]; // Room for the path, the handler
  584. // the '/' and the '\0'
  585. #ifdef ATL_DEBUG_STENCILS
  586. struct ParseError
  587. {
  588. char m_szError[256];
  589. LPCSTR m_szPosition;
  590. LPCSTR m_szStartLine;
  591. LPCSTR m_szEndLine;
  592. int m_nLineNumber;
  593. bool operator==(const ParseError& that) const throw()
  594. {
  595. return (m_nLineNumber == that.m_nLineNumber);
  596. }
  597. };
  598. CSimpleArray<ParseError> m_Errors;
  599. class CParseErrorProvider : public ITagReplacerImpl<CParseErrorProvider>,
  600. public CComObjectRootEx<CComSingleThreadModel>
  601. {
  602. public:
  603. BEGIN_COM_MAP(CParseErrorProvider)
  604. COM_INTERFACE_ENTRY(ITagReplacer)
  605. END_COM_MAP()
  606. CSimpleArray<ParseError> *m_pErrors;
  607. int m_nCurrentError;
  608. CParseErrorProvider() throw() :
  609. m_pErrors(NULL),
  610. m_nCurrentError(-1)
  611. {
  612. }
  613. void Initialize(CSimpleArray<ParseError> *pErrors) throw()
  614. {
  615. m_pErrors = pErrors;
  616. }
  617. HTTP_CODE OnGetNextError() throw()
  618. {
  619. m_nCurrentError++;
  620. if (m_nCurrentError >= m_pErrors->GetSize() ||
  621. m_nCurrentError < 0 )
  622. {
  623. m_nCurrentError = -1;
  624. return HTTP_S_FALSE;
  625. }
  626. else
  627. return HTTP_SUCCESS;
  628. }
  629. HTTP_CODE OnGetErrorLineNumber() throw(...)
  630. {
  631. if (m_pErrors->GetSize() == 0)
  632. return HTTP_SUCCESS;
  633. if (m_nCurrentError > m_pErrors->GetSize() ||
  634. m_nCurrentError < 0)
  635. m_nCurrentError = 0;
  636. CWriteStreamHelper c(m_pStream);
  637. if (!c.Write((*m_pErrors)[m_nCurrentError].m_nLineNumber))
  638. return HTTP_FAIL;
  639. return HTTP_SUCCESS;
  640. }
  641. HTTP_CODE OnGetErrorText() throw(...)
  642. {
  643. if (m_pErrors->GetSize() == 0)
  644. return HTTP_SUCCESS;
  645. if (m_nCurrentError > m_pErrors->GetSize() ||
  646. m_nCurrentError < 0)
  647. m_nCurrentError = 0;
  648. CWriteStreamHelper c(m_pStream);
  649. if (!c.Write((*m_pErrors)[m_nCurrentError].m_szError))
  650. return HTTP_FAIL;
  651. return HTTP_SUCCESS;
  652. }
  653. HTTP_CODE OnGetErrorLine() throw(...)
  654. {
  655. if (m_pErrors->GetSize() == 0)
  656. return HTTP_SUCCESS;
  657. if (m_nCurrentError > m_pErrors->GetSize() ||
  658. m_nCurrentError < 0)
  659. m_nCurrentError = 0;
  660. m_pStream->WriteStream((*m_pErrors)[m_nCurrentError].m_szStartLine,
  661. (int)((*m_pErrors)[m_nCurrentError].m_szEndLine - (*m_pErrors)[m_nCurrentError].m_szStartLine), NULL);
  662. return HTTP_SUCCESS;
  663. }
  664. BEGIN_REPLACEMENT_METHOD_MAP(CParseErrorProvider)
  665. REPLACEMENT_METHOD_ENTRY("GetNextError", OnGetNextError)
  666. REPLACEMENT_METHOD_ENTRY("GetErrorText", OnGetErrorText)
  667. REPLACEMENT_METHOD_ENTRY("GetErrorLine", OnGetErrorLine)
  668. REPLACEMENT_METHOD_ENTRY("GetErrorLineNumber", OnGetErrorLineNumber)
  669. END_REPLACEMENT_METHOD_MAP()
  670. };
  671. #else
  672. bool m_bErrorsOccurred;
  673. #endif
  674. class CSaveThreadLocale
  675. {
  676. LCID m_locale;
  677. public:
  678. CSaveThreadLocale() throw()
  679. {
  680. m_locale = GetThreadLocale();
  681. }
  682. ~CSaveThreadLocale() throw()
  683. {
  684. SetThreadLocale(m_locale);
  685. }
  686. };
  687. protected:
  688. ITagReplacer *m_pReplacer;
  689. IAtlMemMgr *m_pMemMgr;
  690. static CCRTHeap m_crtHeap;
  691. public:
  692. enum PARSE_TOKEN_RESULT { INVALID_TOKEN, NORMAL_TOKEN, RESERVED_TOKEN };
  693. CStencil(IAtlMemMgr *pMemMgr=NULL) throw()
  694. {
  695. m_pBufferStart = NULL;
  696. m_pBufferEnd = NULL;
  697. m_hCacheItem = NULL;
  698. m_ftLastModified.dwLowDateTime = 0;
  699. m_ftLastModified.dwHighDateTime = 0;
  700. m_ftLastChecked.dwLowDateTime = 0;
  701. m_ftLastChecked.dwHighDateTime = 0;
  702. m_arrTokens.SetCount(0, 128);
  703. m_nCodePage = CP_ACP;
  704. m_bUseLocaleACP = TRUE;
  705. m_szHandlerName[0] = '\0';
  706. m_szDllPath[0] = '\0';
  707. m_pMemMgr = pMemMgr;
  708. if (!pMemMgr)
  709. m_pMemMgr = &m_crtHeap;
  710. #ifdef ATL_DEBUG_STENCILS
  711. // m_pErrorStencil = NULL;
  712. #else
  713. m_bErrorsOccurred = false;
  714. #endif
  715. }
  716. #ifdef ATL_DEBUG_STENCILS
  717. virtual LPCSTR GetErrorStencil() throw()
  718. {
  719. static LPCSTR s_szString =
  720. "<h1><font color=#ff0000> While trying to parse a stencil file, "
  721. "the following errors occurred:</font></h1>\r\n"
  722. "{{while GetNextError}}"
  723. "<table border=1 width=50%>\r\n"
  724. "<tr><td width=25%>Error type</td><td>{{GetErrorText}}</td></tr>\r\n"
  725. "<tr><td>Line number</td><td>{{GetErrorLineNumber}}</td></tr>\r\n"
  726. "<tr><td>Error text</td><td><pre>{{GetErrorLine}}</pre></td></tr>\r\n"
  727. "</table>\r\n"
  728. "{{endwhile}}"
  729. "<br>Stencil output follows:\r\n"
  730. "<hr>";
  731. return s_szString;
  732. }
  733. bool RenderErrors(IWriteStream *pStream) throw(...)
  734. {
  735. if (!pStream)
  736. return false;
  737. LPCSTR szString = GetErrorStencil();
  738. if (szString == NULL)
  739. {
  740. // assume user doesn't want errors rendered
  741. return true;
  742. }
  743. CComObjectStackEx<CParseErrorProvider> Errors;
  744. Errors.Initialize(&m_Errors);
  745. CStencil ErrorStencil;
  746. HTTP_CODE hcRet = ErrorStencil.LoadFromString(szString, (DWORD)strlen(szString));
  747. if (hcRet != HTTP_SUCCESS)
  748. {
  749. return false;
  750. }
  751. if (!ErrorStencil.ParseReplacements(static_cast<ITagReplacer *>(&Errors)))
  752. {
  753. return false;
  754. }
  755. ErrorStencil.FinishParseReplacements();
  756. HTTP_CODE hcErrorCode = ErrorStencil.Render(static_cast<ITagReplacer *>(&Errors), pStream);
  757. if (HTTP_ERROR_CODE(hcErrorCode) >= 400)
  758. return false;
  759. return true;
  760. }
  761. bool ParseSuccessful() throw()
  762. {
  763. return (m_Errors.GetSize() == 0);
  764. }
  765. bool AddError(LPCSTR szErrorText, LPCSTR szPosition) throw()
  766. {
  767. int nLineNum = 0;
  768. LPCSTR szStartLine = NULL;
  769. LPCSTR szPtr = m_pBufferStart;
  770. while (szPtr < szPosition)
  771. {
  772. if (*szPtr == '\n')
  773. {
  774. szStartLine = szPtr + 1;
  775. nLineNum++;
  776. }
  777. LPSTR szNext = CharNextExA(m_nCodePage, szPtr, 0);
  778. if (szNext == szPtr)
  779. {
  780. break;
  781. }
  782. szPtr = szNext;
  783. }
  784. LPCSTR szEndLine = szPtr;
  785. while (*szPtr)
  786. {
  787. if (*szPtr == '\n')
  788. break;
  789. szEndLine = szPtr;
  790. LPSTR szNext = CharNextExA(m_nCodePage, szPtr, 0);
  791. if (szNext == szPtr)
  792. {
  793. break;
  794. }
  795. szPtr = szNext;
  796. }
  797. ParseError p;
  798. strcpy(p.m_szError, szErrorText);
  799. p.m_szPosition = szPosition;
  800. p.m_nLineNumber = nLineNum;
  801. p.m_szStartLine = szStartLine;
  802. p.m_szEndLine = szEndLine;
  803. return (m_Errors.Add(p) == TRUE);
  804. }
  805. #else
  806. bool ParseSuccessful() throw()
  807. {
  808. return m_bErrorsOccurred;
  809. }
  810. void AddError(LPCSTR /*szErrorText*/, LPCSTR /*szPosition*/) throw()
  811. {
  812. m_bErrorsOccurred = true;
  813. }
  814. #endif
  815. // Call Uninitialize if you want to re-use an already initialized CStencil
  816. void Uninitialize() throw(...)
  817. {
  818. int nSize = (int) m_arrTokens.GetCount();
  819. for (int nIndex = 0; nIndex < nSize; nIndex++)
  820. {
  821. if (m_arrTokens[nIndex].bDynamicAlloc)
  822. delete [] m_arrTokens[nIndex].pStart;
  823. if (m_arrTokens[nIndex].dwData != 0 && m_arrTokens[nIndex].type != STENCIL_LOCALE)
  824. m_pMemMgr->Free((void *) m_arrTokens[nIndex].dwData);
  825. }
  826. m_arrTokens.RemoveAll();
  827. if ((m_ftLastModified.dwLowDateTime || m_ftLastModified.dwHighDateTime) && m_pBufferStart)
  828. delete [] m_pBufferStart;
  829. m_pBufferStart = NULL;
  830. m_pBufferEnd = NULL;
  831. }
  832. void GetLastModified(FILETIME *pftLastModified) throw()
  833. {
  834. ATLASSERT(pftLastModified);
  835. *pftLastModified = m_ftLastModified;
  836. }
  837. void GetLastChecked(FILETIME *pftLastChecked) throw()
  838. {
  839. ATLASSERT(pftLastChecked);
  840. *pftLastChecked = m_ftLastChecked;
  841. }
  842. void SetLastChecked(FILETIME *pftLastChecked) throw()
  843. {
  844. ATLASSERT(pftLastChecked);
  845. m_ftLastChecked = *pftLastChecked;
  846. }
  847. HCACHEITEM GetCacheItem() throw()
  848. {
  849. return m_hCacheItem;
  850. }
  851. void SetCacheItem(HCACHEITEM hCacheItem) throw()
  852. {
  853. ATLASSERT(m_hCacheItem == NULL);
  854. m_hCacheItem = hCacheItem;
  855. }
  856. void GetHandlerName(LPSTR szDllPath, LPSTR szHandlerName) throw()
  857. {
  858. strcpy(szDllPath, m_szDllPath);
  859. strcpy(szHandlerName, m_szHandlerName);
  860. }
  861. // Adds a token to the token array, handler name, method name
  862. // and handler function offset are optional
  863. ATL_NOINLINE DWORD AddToken(
  864. LPSTR pStart,
  865. LPSTR pEnd,
  866. DWORD dwType,
  867. LPCSTR szHandlerName = NULL,
  868. LPCSTR szMethodName = NULL,
  869. DWORD dwFnOffset = STENCIL_INVALIDOFFSET,
  870. DWORD dwObjOffset = STENCIL_INVALIDOFFSET,
  871. DWORD_PTR dwData = 0,
  872. DWORD dwMap = 0,
  873. BOOL bDynamicAlloc = 0) throw()
  874. {
  875. StencilToken t;
  876. memset(&t, 0x00, sizeof(t));
  877. t.pStart = pStart;
  878. t.pEnd = pEnd;
  879. t.type = dwType;
  880. t.dwLoopIndex = STENCIL_INVALIDINDEX;
  881. t.dwFnOffset = dwFnOffset;
  882. t.dwObjOffset = dwObjOffset;
  883. t.dwData = dwData;
  884. t.dwMap = dwMap;
  885. t.bDynamicAlloc = bDynamicAlloc;
  886. if (szHandlerName && (sizeof(t.szHandlerName) > strlen(szHandlerName)))
  887. strcpy(t.szHandlerName, szHandlerName);
  888. else
  889. t.szHandlerName[0] = '\0';
  890. if (szMethodName && (sizeof(t.szMethodName) > strlen(szMethodName)))
  891. strcpy(t.szMethodName, szMethodName);
  892. else
  893. t.szMethodName[0] = '\0';
  894. _ATLTRY
  895. {
  896. return (DWORD) m_arrTokens.Add(t);
  897. }
  898. _ATLCATCHALL()
  899. {
  900. return STENCIL_INVALIDINDEX;
  901. }
  902. }
  903. // maps a stencil file into memory
  904. HTTP_CODE LoadFile(LPCSTR szFileName) throw()
  905. {
  906. HRESULT hr = E_FAIL;
  907. ULONGLONG dwLen = 0;
  908. CAtlFile file;
  909. hr = file.Create(CA2CTEX<MAX_PATH+1>(szFileName), GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
  910. if (FAILED(hr) || GetFileType(file) != FILE_TYPE_DISK)
  911. return HTTP_ERROR(500, ISE_SUBERR_STENCIL_LOAD_FAIL); // couldn't load SRF!
  912. if (GetFileTime(file, NULL, NULL, &m_ftLastModified))
  913. {
  914. if (SUCCEEDED(file.GetSize(dwLen)))
  915. {
  916. ATLASSERT(!m_pBufferStart);
  917. GetSystemTimeAsFileTime(&m_ftLastChecked);
  918. m_pBufferStart = NULL;
  919. ATLTRY(m_pBufferStart = new CHAR[(UINT) dwLen]);
  920. if (m_pBufferStart == NULL)
  921. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM); // out of memory
  922. DWORD dwRead;
  923. hr = file.Read(m_pBufferStart, (DWORD) dwLen, dwRead);
  924. if (FAILED(hr))
  925. {
  926. delete [] m_pBufferStart;
  927. m_pBufferStart = NULL;
  928. return HTTP_ERROR(500, ISE_SUBERR_READFILEFAIL); // ReadFile failed
  929. }
  930. m_pBufferEnd = m_pBufferStart + dwRead;
  931. }
  932. }
  933. return HTTP_SUCCESS;
  934. }
  935. // loads a stencil from the specified resource.
  936. HTTP_CODE LoadFromResource(HINSTANCE hInstRes, LPCSTR szID, LPCSTR szType = NULL) throw()
  937. {
  938. if (!szType)
  939. szType = (LPCSTR) RT_HTML;
  940. HRSRC hRsrc = FindResourceA(hInstRes, szID, szType);
  941. HGLOBAL hgResource = NULL;
  942. if (hRsrc)
  943. {
  944. hgResource = LoadResource(hInstRes, hRsrc);
  945. if (!hgResource)
  946. return HTTP_FAIL;
  947. }
  948. else
  949. return HTTP_FAIL;
  950. DWORD dwSize = SizeofResource(hInstRes, hRsrc);
  951. m_pBufferStart = (LPSTR)LockResource(hgResource);
  952. m_pBufferEnd = m_pBufferStart+dwSize;
  953. return HTTP_SUCCESS;
  954. }
  955. // loads a stencil from the specified resource
  956. HTTP_CODE LoadFromResource(HINSTANCE hInstRes, UINT nId, LPCSTR szType = NULL) throw()
  957. {
  958. return LoadFromResource(hInstRes, MAKEINTRESOURCEA(nId), szType);
  959. }
  960. // loads a stencil from a string
  961. HTTP_CODE LoadFromString(LPCSTR szString, DWORD dwSize) throw()
  962. {
  963. m_pBufferStart = (LPSTR) szString;
  964. m_pBufferEnd = m_pBufferStart+dwSize;
  965. return HTTP_SUCCESS;
  966. }
  967. inline BOOL CheckTag(LPCSTR szTag, DWORD dwTagLen, LPSTR szStart, DWORD dwLen) throw()
  968. {
  969. if (dwLen < dwTagLen)
  970. return FALSE;
  971. if (memcmp(szStart, szTag, dwTagLen))
  972. return FALSE;
  973. if (_istspace(szStart[dwTagLen]) || szStart[dwTagLen] == '}')
  974. return TRUE;
  975. return FALSE;
  976. }
  977. inline void FindTagArgs(LPSTR& szstart, LPSTR& szend, int nKeywordChars) throw()
  978. {
  979. if (*szstart == '{')
  980. szstart += 2; // move past {{
  981. szstart = SkipSpace(szstart, m_nCodePage); // move past whitespace
  982. szstart += nKeywordChars; // move past keyword
  983. szstart = SkipSpace(szstart, m_nCodePage); // move past whitespace after keyword
  984. if (*szend == '}')
  985. szend -=2; // chop off }}
  986. szend = RSkipSpace(szstart, szend, m_nCodePage); // chop of trailing whitespace
  987. }
  988. // Cracks the loaded stencil into an array of StencilTokens in preparation for
  989. // rendering. LoadStencil must be called prior to calling this function.
  990. virtual bool ParseReplacements(ITagReplacer* pReplacer) throw(...)
  991. {
  992. return ParseReplacements(pReplacer, GetBufferStart(), GetBufferEnd());
  993. }
  994. virtual void FinishParseReplacements() throw(...)
  995. {
  996. DWORD dwSize = (DWORD) m_arrTokens.GetCount();
  997. for (DWORD dwIndex = 0; dwIndex < dwSize; dwIndex++)
  998. {
  999. StencilToken& token = m_arrTokens[dwIndex];
  1000. bool bUnclosedBlock = ((token.type == STENCIL_CONDITIONALSTART ||
  1001. token.type == STENCIL_CONDITIONALELSE ||
  1002. token.type == STENCIL_ITERATORSTART) &&
  1003. token.dwLoopIndex == STENCIL_INVALIDINDEX);
  1004. if (token.szMethodName[0] &&
  1005. (token.dwFnOffset == STENCIL_INVALIDOFFSET || bUnclosedBlock))
  1006. {
  1007. if (bUnclosedBlock ||
  1008. m_pReplacer->FindReplacementOffset(
  1009. token.szMethodName, &token.dwFnOffset,
  1010. token.szHandlerName, &token.dwObjOffset,
  1011. &token.dwMap, (void **)(&token.dwData), m_pMemMgr) != HTTP_SUCCESS)
  1012. {
  1013. if (bUnclosedBlock && token.type == STENCIL_CONDITIONALSTART)
  1014. AddError("{{if}} without {{endif}}", token.pStart);
  1015. else if (bUnclosedBlock && token.type == STENCIL_CONDITIONALELSE)
  1016. AddError("{{else}} without {{endif}}", token.pStart);
  1017. else if (bUnclosedBlock && token.type == STENCIL_ITERATORSTART)
  1018. AddError("{{while}} without {{endwhile}}", token.pStart);
  1019. else
  1020. {
  1021. char szBuf[ATL_MAX_METHOD_NAME_LEN+sizeof("Unresolved replacement : ''")];
  1022. _snprintf(szBuf,
  1023. ATL_MAX_METHOD_NAME_LEN+sizeof("Unresolved replacement : ''")-1,
  1024. "Unresolved replacement : '%s'", token.szMethodName);
  1025. AddError(szBuf, token.pStart);
  1026. }
  1027. // unresolved replacement, convert it to a text token
  1028. token.type = STENCIL_TEXTTAG;
  1029. // convert all linked tokens to text tokens as well
  1030. // this includes: endif, else, endwhile
  1031. DWORD dwLoopIndex = token.dwLoopIndex;
  1032. while (dwLoopIndex != dwIndex && dwLoopIndex != STENCIL_INVALIDINDEX)
  1033. {
  1034. m_arrTokens[dwLoopIndex].type = STENCIL_TEXTTAG;
  1035. dwLoopIndex = m_arrTokens[dwLoopIndex].dwLoopIndex;
  1036. }
  1037. }
  1038. }
  1039. }
  1040. }
  1041. virtual bool Parse(ITagReplacer *pReplacer) throw( ... )
  1042. {
  1043. if (ParseReplacements(pReplacer))
  1044. {
  1045. FinishParseReplacements();
  1046. return true;
  1047. }
  1048. return false;
  1049. }
  1050. DWORD CheckTopAndPop(DWORD *pBlockStack, DWORD *pdwTop, DWORD dwToken) throw()
  1051. {
  1052. if (*pdwTop == 0)
  1053. return STENCIL_INVALIDINDEX;
  1054. if (m_arrTokens[pBlockStack[*pdwTop]].type == dwToken)
  1055. {
  1056. *pdwTop = (*pdwTop) - 1;
  1057. return pBlockStack[(*pdwTop)+1];
  1058. }
  1059. return STENCIL_INVALIDINDEX;
  1060. }
  1061. DWORD ParseReplacement( LPSTR szTokenStart,
  1062. LPSTR szTokenEnd,
  1063. DWORD * /*pBlockStack*/,
  1064. DWORD * /*pdwTop*/,
  1065. DWORD dwTokenType = STENCIL_REPLACEMENT,
  1066. DWORD dwKeywordLen = 0) throw()
  1067. {
  1068. // hold on to the start and end pointers (before removing curlies and whitespace)
  1069. // this is needed so that we can convert the token to a text token if the method
  1070. // is not resolved (in FinishParseReplacements)
  1071. LPSTR szStart = szTokenStart;
  1072. LPSTR szEnd = szTokenEnd;
  1073. FindTagArgs(szTokenStart, szTokenEnd, dwKeywordLen);
  1074. char szMethodName[ATL_MAX_METHOD_NAME_LEN+1];
  1075. char szHandlerName[ATL_MAX_HANDLER_NAME_LEN+1];
  1076. DWORD dwIndex;
  1077. //look up the handler name, method name and handler interface
  1078. if (HTTP_SUCCESS == GetHandlerAndMethodNames(szTokenStart, szTokenEnd,
  1079. szMethodName,
  1080. szHandlerName))
  1081. dwIndex = AddToken(szStart, szEnd, dwTokenType,
  1082. szHandlerName, szMethodName,
  1083. STENCIL_INVALIDINDEX, STENCIL_INVALIDINDEX,
  1084. 0, STENCIL_BASIC_MAP);
  1085. else
  1086. dwIndex = STENCIL_INVALIDINDEX;
  1087. return dwIndex;
  1088. }
  1089. DWORD PushToken(DWORD *pBlockStack, DWORD *pdwTop, DWORD dwIndex) throw()
  1090. {
  1091. if (*pdwTop < (ATL_MAX_BLOCK_STACK-1))
  1092. {
  1093. *pdwTop = (*pdwTop) + 1;
  1094. pBlockStack[*pdwTop] = dwIndex;
  1095. }
  1096. else
  1097. {
  1098. dwIndex = STENCIL_INVALIDINDEX;
  1099. }
  1100. return dwIndex;
  1101. }
  1102. DWORD ParseWhile(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD *pBlockStack, DWORD *pdwTop) throw()
  1103. {
  1104. DWORD dwIndex = ParseReplacement(szTokenStart, szTokenEnd, pBlockStack, pdwTop, STENCIL_ITERATORSTART, 5);
  1105. if (dwIndex == STENCIL_INVALIDINDEX)
  1106. return dwIndex;
  1107. return PushToken(pBlockStack, pdwTop, dwIndex);
  1108. }
  1109. DWORD ParseEndWhile(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD *pBlockStack, DWORD *pdwTop) throw()
  1110. {
  1111. DWORD dwTopIndex = CheckTopAndPop(pBlockStack, pdwTop, STENCIL_ITERATORSTART);
  1112. if (dwTopIndex == STENCIL_INVALIDINDEX)
  1113. {
  1114. AddError("{{endwhile}} without {{while}}", szTokenStart);
  1115. return dwTopIndex;
  1116. }
  1117. DWORD dwIndex = AddToken(szTokenStart, szTokenEnd, STENCIL_ITERATOREND);
  1118. m_arrTokens[dwTopIndex].dwLoopIndex = dwIndex;
  1119. m_arrTokens[dwIndex].dwLoopIndex = dwTopIndex;
  1120. return dwIndex;
  1121. }
  1122. DWORD ParseIf(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD *pBlockStack, DWORD *pdwTop) throw()
  1123. {
  1124. DWORD dwIndex = ParseReplacement(szTokenStart, szTokenEnd, pBlockStack, pdwTop, STENCIL_CONDITIONALSTART, 2);
  1125. if (dwIndex == STENCIL_INVALIDINDEX)
  1126. return dwIndex;
  1127. return PushToken(pBlockStack, pdwTop, dwIndex);
  1128. }
  1129. DWORD ParseElse(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD *pBlockStack, DWORD *pdwTop) throw()
  1130. {
  1131. DWORD dwTopIndex = CheckTopAndPop(pBlockStack, pdwTop, STENCIL_CONDITIONALSTART);
  1132. if (dwTopIndex == STENCIL_INVALIDINDEX)
  1133. {
  1134. AddError("{{else}} without {{if}}", szTokenStart);
  1135. return dwTopIndex;
  1136. }
  1137. DWORD dwIndex = AddToken(szTokenStart, szTokenEnd, STENCIL_CONDITIONALELSE);
  1138. m_arrTokens[dwTopIndex].dwLoopIndex = dwIndex;
  1139. return PushToken(pBlockStack, pdwTop, dwIndex);
  1140. }
  1141. DWORD ParseEndIf(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD *pBlockStack, DWORD *pdwTop) throw()
  1142. {
  1143. DWORD dwTopIndex = CheckTopAndPop(pBlockStack, pdwTop, STENCIL_CONDITIONALSTART);
  1144. if (dwTopIndex == STENCIL_INVALIDINDEX)
  1145. {
  1146. dwTopIndex = CheckTopAndPop(pBlockStack, pdwTop, STENCIL_CONDITIONALELSE);
  1147. if (dwTopIndex == STENCIL_INVALIDINDEX)
  1148. {
  1149. AddError("{{endif}} without {{if}}", szTokenStart);
  1150. return dwTopIndex;
  1151. }
  1152. }
  1153. DWORD dwIndex = AddToken(szTokenStart, szTokenEnd, STENCIL_CONDITIONALEND);
  1154. m_arrTokens[dwTopIndex].dwLoopIndex = dwIndex;
  1155. return dwIndex;
  1156. }
  1157. DWORD ParseLocale(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD * /*pBlockStack*/, DWORD * /*pdwTop*/) throw()
  1158. {
  1159. LPSTR szstart = szTokenStart;
  1160. LPSTR szend = szTokenEnd;
  1161. LCID locale = 0xFFFFFFFF;
  1162. FindTagArgs(szstart, szend, 6);
  1163. #ifndef ATL_NO_MLANG
  1164. if (isdigit(szstart[0]))
  1165. {
  1166. locale = (LCID) atoi(szstart);
  1167. }
  1168. else
  1169. {
  1170. HRESULT hr;
  1171. CComPtr<IMultiLanguage> pML;
  1172. hr = pML.CoCreateInstance(__uuidof(CMultiLanguage));
  1173. if (FAILED(hr))
  1174. {
  1175. ATLTRACE(atlTraceStencil, 0, _T("Couldn't create CMultiLanguage object. check MLANG installation."));
  1176. AddError("Couldn't create CMultiLanguage", szTokenStart);
  1177. }
  1178. else
  1179. {
  1180. CStringW str(szstart, (int)((szend-szstart)+1));
  1181. #ifdef __IMultiLanguage2_INTERFACE_DEFINED__
  1182. // use IMultiLanguage2 if possible
  1183. CComPtr<IMultiLanguage2> spML2;
  1184. hr = pML.QueryInterface(&spML2);
  1185. if (FAILED(hr) || !spML2.p)
  1186. hr = pML->GetLcidFromRfc1766(&locale, CComBSTR(str));
  1187. else
  1188. hr = spML2->GetLcidFromRfc1766(&locale, CComBSTR(str));
  1189. #else // __IMultiLanguage2_INTERFACE_DEFINED__
  1190. hr = pML->GetLcidFromRfc1766(&locale, CComBSTR(str));
  1191. #endif // __IMultiLanguage2_INTERFACE_DEFINED__
  1192. if (FAILED(hr))
  1193. AddError("Error getting lcid", szTokenStart);
  1194. }
  1195. if (FAILED(hr))
  1196. locale = 0xFFFFFFFF;
  1197. }
  1198. #else
  1199. locale = (LCID) atoi(szstart);
  1200. #endif
  1201. if (m_bUseLocaleACP)
  1202. {
  1203. TCHAR szACP[7];
  1204. if (GetLocaleInfo(locale, LOCALE_IDEFAULTANSICODEPAGE, szACP, 7) != 0)
  1205. {
  1206. m_nCodePage = (WORD) _ttoi(szACP);
  1207. }
  1208. else
  1209. {
  1210. AddError("GetLocaleInfo failed", szTokenStart);
  1211. }
  1212. }
  1213. DWORD dwCurrentTokenIndex = STENCIL_INVALIDINDEX;
  1214. if (locale != 0xFFFFFFFF)
  1215. dwCurrentTokenIndex = AddToken(NULL, NULL, STENCIL_LOCALE,
  1216. NULL, NULL, STENCIL_INVALIDOFFSET, STENCIL_INVALIDOFFSET, locale);
  1217. else
  1218. return STENCIL_INVALIDINDEX;
  1219. return dwCurrentTokenIndex;
  1220. }
  1221. DWORD ParseCodepage(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD * /*pBlockStack*/, DWORD * /*pdwTop*/) throw()
  1222. {
  1223. LPSTR szstart = szTokenStart;
  1224. LPSTR szend = szTokenEnd;
  1225. WORD nCodePage = 0xFFFF;
  1226. FindTagArgs(szstart, szend, 8);
  1227. #ifndef ATL_NO_MLANG
  1228. if (isdigit(szstart[0]))
  1229. {
  1230. nCodePage = (WORD) atoi(szstart);
  1231. }
  1232. else
  1233. {
  1234. HRESULT hr;
  1235. CComPtr<IMultiLanguage> pML;
  1236. hr = pML.CoCreateInstance(__uuidof(CMultiLanguage));
  1237. if (FAILED(hr))
  1238. {
  1239. ATLTRACE(atlTraceStencil, 0, _T("Couldn't create CMultiLanguage object. check MLANG installation."));
  1240. AddError("Couldn't CoCreate CMultiLanguage object", szTokenStart);
  1241. }
  1242. else
  1243. {
  1244. CStringW str(szstart, (int)((szend-szstart)+1));
  1245. MIMECSETINFO info;
  1246. #ifdef __IMultiLanguage2_INTERFACE_DEFINED__
  1247. // use IMultiLanguage2 if possible
  1248. CComPtr<IMultiLanguage2> spML2;
  1249. hr = pML.QueryInterface(&spML2);
  1250. if (FAILED(hr) || !spML2.p)
  1251. hr = pML->GetCharsetInfo(CComBSTR(str), &info);
  1252. else
  1253. hr = spML2->GetCharsetInfo(CComBSTR(str), &info);
  1254. #else // __IMultiLanguage2_INTERFACE_DEFINED__
  1255. hr = pML->GetCharsetInfo(CComBSTR(str), &info);
  1256. #endif // __IMultiLanguage2_INTERFACE_DEFINED__
  1257. // for most character sets, uiCodePage and uiInternetEncoding
  1258. // are the same. UTF-8 is the exception that we're concerned about.
  1259. // for that character set, we want uiInternetEncoding (65001 - UTF-8)
  1260. // instead of uiCodePage (1200 - UCS-2)
  1261. if (SUCCEEDED(hr))
  1262. nCodePage = (WORD) info.uiInternetEncoding;
  1263. else
  1264. AddError("GetCharsetInfo failed", szTokenStart);
  1265. }
  1266. if (FAILED(hr))
  1267. nCodePage = 0xFFFF;
  1268. }
  1269. #else
  1270. nCodePage = (WORD) atoi(szstart);
  1271. #endif
  1272. if (nCodePage != 0xFFFF)
  1273. m_nCodePage = nCodePage;
  1274. m_bUseLocaleACP = FALSE;
  1275. return STENCIL_INVALIDINDEX;
  1276. }
  1277. PARSE_TOKEN_RESULT ParseHandler(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD * /*pBlockStack*/, DWORD * /*pdwTop*/) throw()
  1278. {
  1279. LPSTR szstart = szTokenStart;
  1280. LPSTR szend = szTokenEnd;
  1281. if (m_szHandlerName[0] && m_szDllPath[0])
  1282. return RESERVED_TOKEN; // already found the handler and path dll names
  1283. FindTagArgs(szstart, szend, 7);
  1284. size_t nlen = (szend-szstart)+1;
  1285. char szHandlerDllName[MAX_PATH + ATL_MAX_HANDLER_NAME_LEN + 2];
  1286. if (nlen < MAX_PATH + ATL_MAX_HANDLER_NAME_LEN + 2)
  1287. {
  1288. memcpy(szHandlerDllName, szstart, szend-szstart+1);
  1289. szHandlerDllName[szend-szstart+1] = '\0';
  1290. DWORD dwDllPathLen = MAX_PATH+1;
  1291. DWORD dwHandlerNameLen = ATL_MAX_HANDLER_NAME_LEN+1;
  1292. if (!_AtlCrackHandler(szHandlerDllName, m_szDllPath, &dwDllPathLen, m_szHandlerName, &dwHandlerNameLen))
  1293. {
  1294. return INVALID_TOKEN;
  1295. }
  1296. }
  1297. return RESERVED_TOKEN;
  1298. }
  1299. virtual PARSE_TOKEN_RESULT ParseToken(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD *pBlockStack, DWORD *pdwTop) throw()
  1300. {
  1301. LPSTR pStart = szTokenStart;
  1302. pStart += 2; //skip curlies
  1303. pStart = SkipSpace(pStart, m_nCodePage);
  1304. DWORD dwLen = (DWORD)(szTokenEnd - szTokenStart);
  1305. DWORD dwIndex = STENCIL_INVALIDINDEX;
  1306. PARSE_TOKEN_RESULT ret = RESERVED_TOKEN;
  1307. if (CheckTag("endwhile", 8, pStart, dwLen))
  1308. dwIndex = ParseEndWhile(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  1309. else if (CheckTag("while", 5, pStart, dwLen))
  1310. dwIndex = ParseWhile(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  1311. else if (CheckTag("endif", 5, pStart, dwLen))
  1312. dwIndex = ParseEndIf(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  1313. else if (CheckTag("else", 4, pStart, dwLen))
  1314. dwIndex = ParseElse(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  1315. else if (CheckTag("if", 2, pStart, dwLen))
  1316. dwIndex = ParseIf(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  1317. else if (CheckTag("locale", 6, pStart, dwLen))
  1318. dwIndex = ParseLocale(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  1319. else if (CheckTag("handler", 7, pStart, dwLen))
  1320. {
  1321. return ParseHandler(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  1322. }
  1323. else if (CheckTag("codepage", 8, pStart, dwLen))
  1324. {
  1325. ParseCodepage(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  1326. return RESERVED_TOKEN;
  1327. }
  1328. else
  1329. {
  1330. dwIndex = ParseReplacement(szTokenStart, szTokenEnd, pBlockStack, pdwTop, STENCIL_REPLACEMENT);
  1331. if (dwIndex == STENCIL_INVALIDINDEX)
  1332. return INVALID_TOKEN;
  1333. ret = NORMAL_TOKEN;
  1334. }
  1335. if (dwIndex == STENCIL_INVALIDINDEX)
  1336. return INVALID_TOKEN;
  1337. return ret;
  1338. }
  1339. virtual bool ParseReplacements(ITagReplacer* pReplacer, LPSTR pStart, LPSTR pEnd) throw()
  1340. {
  1341. LPSTR szCurr = pStart;
  1342. DWORD BlockStack[ATL_MAX_BLOCK_STACK];
  1343. DWORD dwTop = 0;
  1344. m_pReplacer = pReplacer;
  1345. DWORD dwCurrentTokenIndex = 0;
  1346. if (!szCurr)
  1347. {
  1348. ATLASSERT(FALSE);
  1349. AddError("NULL parameter to ParseReplacements", NULL);
  1350. return false;
  1351. }
  1352. LPSTR szEnd = pEnd;
  1353. if (szEnd <= szCurr)
  1354. {
  1355. ATLASSERT(FALSE);
  1356. AddError("Empty or negative string passed to ParseReplacements", NULL);
  1357. return true;
  1358. }
  1359. while(szCurr < szEnd)
  1360. {
  1361. //mark the start of this block, then find the end of the block
  1362. //the end is denoted by an opening curly
  1363. LPSTR szStart = szCurr;
  1364. while (szCurr < szEnd && (*szCurr != '{' || szCurr[1] != '{'))
  1365. {
  1366. LPSTR szNext = CharNextExA(m_nCodePage, szCurr, 0);
  1367. if (szNext == szCurr)
  1368. {
  1369. // embedded null
  1370. AddError("Embedded null character in stencil", NULL);
  1371. return true;
  1372. }
  1373. szCurr = szNext;
  1374. }
  1375. //special case for the last text block, if there is one
  1376. if (szCurr >= szEnd)
  1377. {
  1378. // add the last token. This is everything after the last
  1379. // double curly block, which is text.
  1380. dwCurrentTokenIndex = AddToken(szStart, szEnd-1, STENCIL_TEXTTAG);
  1381. break;
  1382. }
  1383. //if there are any characters between szStart and szCurr inclusive,
  1384. //copy them to a text token.
  1385. if (szCurr-1 >= szStart)
  1386. dwCurrentTokenIndex = AddToken(szStart, szCurr-1, STENCIL_TEXTTAG);
  1387. //find the end of the tag
  1388. LPSTR szEndTag;
  1389. szStart = szCurr;
  1390. szCurr += 2; // Skip over the two '{' s
  1391. while (szCurr < szEnd)
  1392. {
  1393. if (szCurr[0] == '}' && szCurr[1] == '}')
  1394. break;
  1395. else if (szCurr[0] == '{')
  1396. break;
  1397. LPSTR szNext = CharNextExA(m_nCodePage, szCurr, 0);
  1398. if (szNext == szCurr)
  1399. {
  1400. // embedded null
  1401. AddError("Embedded null character in stencil", NULL);
  1402. return true;
  1403. }
  1404. szCurr = szNext;
  1405. }
  1406. if (szCurr >= szEnd)
  1407. {
  1408. AddError("Unmatched {{", szStart);
  1409. AddToken(szStart, szCurr-1, STENCIL_TEXTTAG);
  1410. break;
  1411. }
  1412. if (szCurr[0] == '{')
  1413. {
  1414. if (szCurr[1] != '{')
  1415. {
  1416. szCurr--;
  1417. }
  1418. AddError("Mismatched {{", szStart);
  1419. AddToken(szStart, szCurr-1, STENCIL_TEXTTAG);
  1420. continue;
  1421. }
  1422. szEndTag = CharNextExA(m_nCodePage, szCurr, 0);
  1423. if (szEndTag == szCurr)
  1424. {
  1425. // embedded null
  1426. AddError("Embedded null character in stencil", NULL);
  1427. return true;
  1428. }
  1429. PARSE_TOKEN_RESULT ret = ParseToken(szStart, szEndTag, BlockStack, &dwTop);
  1430. if (ret == INVALID_TOKEN)
  1431. {
  1432. dwCurrentTokenIndex = AddToken(szStart, szEndTag, STENCIL_TEXTTAG);
  1433. szCurr = CharNextExA(m_nCodePage, szEndTag, 0);
  1434. continue;
  1435. }
  1436. szCurr = CharNextExA(m_nCodePage, szEndTag, 0);
  1437. if (szEndTag == szCurr)
  1438. {
  1439. // embedded null
  1440. AddError("Embedded null character in stencil", NULL);
  1441. return true;
  1442. }
  1443. if (ret == RESERVED_TOKEN)
  1444. {
  1445. // REVIEW: should these be using CharNextExA
  1446. if (szCurr < szEnd && *szCurr == '\n')
  1447. szCurr++;
  1448. else if ((szCurr+1 < szEnd && *szCurr == '\r' && *(szCurr+1) == '\n'))
  1449. szCurr += 2;
  1450. }
  1451. }
  1452. return true;
  1453. }
  1454. HTTP_CODE GetHandlerAndMethodNames(
  1455. LPSTR pStart,
  1456. LPSTR pEnd,
  1457. LPSTR pszMethodName,
  1458. LPSTR pszHandlerName) throw()
  1459. {
  1460. if (!pszMethodName || !pszHandlerName)
  1461. {
  1462. ATLASSERT(FALSE);
  1463. AddError("Bad parameter", pStart);
  1464. return HTTP_ERROR(500, ISE_SUBERR_UNEXPECTED);
  1465. }
  1466. *pszMethodName = '\0';
  1467. *pszHandlerName = '\0';
  1468. CHAR szMethodString[ATL_MAX_METHOD_NAME_LEN + ATL_MAX_HANDLER_NAME_LEN+1]; //*2 in case the tag is an id.tag and +1 for the dot
  1469. HTTP_CODE hcErr = HTTP_SUCCESS;
  1470. //
  1471. // copy the method string
  1472. //
  1473. size_t nMethodLen = (pEnd-pStart)+1;
  1474. if (nMethodLen >= (ATL_MAX_METHOD_NAME_LEN + ATL_MAX_HANDLER_NAME_LEN+1))
  1475. {
  1476. AddError("Method name too long", pStart);
  1477. return HTTP_ERROR(500, ISE_SUBERR_LONGMETHODNAME);
  1478. }
  1479. memcpy(szMethodString, pStart, nMethodLen);
  1480. szMethodString[nMethodLen] = '\0';
  1481. //
  1482. // now crack the method string and get the handler
  1483. // id and function name
  1484. //
  1485. LPSTR szParen = strchr(szMethodString, '(');
  1486. LPSTR szDot = strchr(szMethodString, '.');
  1487. if (szDot && (!szParen || (szDot < szParen)))
  1488. {
  1489. *szDot = '\0';
  1490. szDot++;
  1491. // copy method name
  1492. if (strlen(szDot)<ATL_MAX_METHOD_NAME_LEN)
  1493. strcpy(pszMethodName, szDot);
  1494. else
  1495. {
  1496. AddError("Method name too long", pStart + (szDot - szMethodString));
  1497. hcErr = HTTP_ERROR(500, ISE_SUBERR_LONGMETHODNAME);
  1498. }
  1499. // copy handler name
  1500. if (!hcErr)
  1501. {
  1502. if (strlen(szMethodString) < ATL_MAX_METHOD_NAME_LEN)
  1503. strcpy(pszHandlerName, szMethodString);
  1504. else
  1505. {
  1506. AddError("Handler name too long", pStart);
  1507. hcErr = HTTP_ERROR(500, ISE_SUBERR_LONGHANDLERNAME);
  1508. }
  1509. }
  1510. }
  1511. else
  1512. {
  1513. // only a method name so just copy it.
  1514. if (strlen(szMethodString) < ATL_MAX_METHOD_NAME_LEN)
  1515. strcpy(pszMethodName, szMethodString);
  1516. else
  1517. {
  1518. AddError("Method name too long", pStart);
  1519. hcErr = HTTP_ERROR(500, ISE_SUBERR_LONGMETHODNAME);
  1520. }
  1521. }
  1522. return hcErr;
  1523. }
  1524. virtual HTTP_CODE Render(
  1525. ITagReplacer *pReplacer,
  1526. IWriteStream *pWriteStream,
  1527. void* pState = NULL) const throw(...)
  1528. {
  1529. HTTP_CODE hcErrorCode = HTTP_SUCCESS;
  1530. DWORD dwIndex = 0;
  1531. DWORD dwArraySize = GetTokenCount();
  1532. CStencilState* _pState = reinterpret_cast<CStencilState*>(pState);
  1533. // set up locale info
  1534. CSaveThreadLocale lcidSave;
  1535. if (_pState)
  1536. {
  1537. dwIndex = _pState->dwIndex;
  1538. // restore the locale if we're restarting rendering
  1539. if (_pState->locale != CP_ACP)
  1540. SetThreadLocale(_pState->locale);
  1541. }
  1542. pReplacer->SetStream(pWriteStream);
  1543. while (dwIndex < dwArraySize)
  1544. {
  1545. // RenderToken advances dwIndex appropriately for us.
  1546. dwIndex = RenderToken(dwIndex, pReplacer, pWriteStream, &hcErrorCode, pState);
  1547. if (dwIndex == STENCIL_INVALIDINDEX ||
  1548. hcErrorCode != HTTP_SUCCESS)
  1549. break;
  1550. }
  1551. if (IsAsyncStatus(hcErrorCode))
  1552. {
  1553. ATLASSERT(_pState); // state is required for async
  1554. _pState->dwIndex = dwIndex;
  1555. }
  1556. // lcidSave destructor will restore the locale info in case it was changed
  1557. return hcErrorCode;
  1558. }
  1559. inline BOOL IsValidIndex(DWORD dwIndex) const throw()
  1560. {
  1561. if (dwIndex == STENCIL_INVALIDINDEX)
  1562. return FALSE;
  1563. if (dwIndex < GetTokenCount())
  1564. return TRUE;
  1565. else
  1566. return FALSE;
  1567. }
  1568. virtual DWORD RenderToken(
  1569. DWORD dwIndex,
  1570. ITagReplacer *pReplacer,
  1571. IWriteStream *pWriteStream,
  1572. HTTP_CODE *phcErrorCode,
  1573. void* pState = NULL) const throw(...)
  1574. {
  1575. const StencilToken* pToken = GetToken(dwIndex);
  1576. DWORD dwNextToken = 0;
  1577. HTTP_CODE hcErrorCode = HTTP_SUCCESS;
  1578. if (!pToken)
  1579. return STENCIL_INVALIDINDEX;
  1580. switch (pToken->type)
  1581. {
  1582. case STENCIL_ITERATORSTART:
  1583. {
  1584. HTTP_CODE hcErr = STENCIL_SUCCESS;
  1585. // A 'while' token has to at least be followed by an endwhile!
  1586. if (!IsValidIndex(dwIndex+1))
  1587. {
  1588. // This should have been caught at parse time
  1589. dwNextToken = STENCIL_INVALIDINDEX;
  1590. hcErrorCode = HTTP_ERROR(500, ISE_SUBERR_STENCIL_INVALIDINDEX);
  1591. ATLASSERT(FALSE);
  1592. break;
  1593. }
  1594. // End of loop should be valid
  1595. if (!IsValidIndex(pToken->dwLoopIndex))
  1596. {
  1597. // This should have been caught at parse time
  1598. dwNextToken = STENCIL_INVALIDINDEX;
  1599. hcErrorCode = HTTP_ERROR(500, ISE_SUBERR_STENCIL_MISMATCHWHILE);
  1600. ATLASSERT(FALSE);
  1601. break;
  1602. }
  1603. if (pToken->dwFnOffset == STENCIL_INVALIDOFFSET)
  1604. {
  1605. // This should have been caught at parse time
  1606. dwNextToken = STENCIL_INVALIDINDEX;
  1607. hcErrorCode = HTTP_ERROR(500, ISE_SUBERR_STENCIL_INVALIDFUNCOFFSET);
  1608. ATLASSERT(FALSE);
  1609. break;
  1610. }
  1611. DWORD dwLoopIndex = pToken->dwLoopIndex; // points to the end of the loop
  1612. // Call the replacement method
  1613. // if it returns HTTP_SUCCESS, enter the loop
  1614. // if it returns HTTP_S_FALSE, terminate the loop
  1615. hcErr = pReplacer->RenderReplacement(pToken->dwFnOffset,
  1616. pToken->dwObjOffset, pToken->dwMap, (void *) pToken->dwData);
  1617. if (hcErr == HTTP_SUCCESS)
  1618. {
  1619. dwNextToken = dwIndex+1;
  1620. hcErrorCode = HTTP_SUCCESS;
  1621. }
  1622. else if (hcErr == HTTP_S_FALSE)
  1623. {
  1624. dwNextToken = dwLoopIndex+1;
  1625. hcErrorCode = HTTP_SUCCESS;
  1626. }
  1627. else
  1628. {
  1629. dwNextToken = STENCIL_INVALIDINDEX;
  1630. hcErrorCode = hcErr;
  1631. break;
  1632. }
  1633. }
  1634. break;
  1635. case STENCIL_ITERATOREND:
  1636. {
  1637. dwNextToken = pToken->dwLoopIndex;
  1638. hcErrorCode = HTTP_SUCCESS;
  1639. ATLASSERT(GetToken(dwNextToken)->type == STENCIL_ITERATORSTART);
  1640. }
  1641. break;
  1642. case STENCIL_CONDITIONALSTART:
  1643. {
  1644. if (pToken->type == STENCIL_CONDITIONALSTART && pToken->dwFnOffset == STENCIL_INVALIDOFFSET)
  1645. {
  1646. // This should have been caught at parse time
  1647. ATLASSERT(FALSE);
  1648. dwNextToken = STENCIL_INVALIDINDEX;
  1649. hcErrorCode = HTTP_ERROR(500, ISE_SUBERR_STENCIL_INVALIDFUNCOFFSET);
  1650. break;
  1651. }
  1652. if (pToken->dwLoopIndex == STENCIL_INVALIDINDEX)
  1653. {
  1654. // This should have been caught at parse time
  1655. ATLASSERT(FALSE);
  1656. dwNextToken = STENCIL_INVALIDINDEX;
  1657. hcErrorCode = HTTP_ERROR(500, ISE_SUBERR_STENCIL_MISMATCHIF);
  1658. break;
  1659. }
  1660. DWORD dwLoopIndex = pToken->dwLoopIndex; // points to the end of the loop
  1661. HTTP_CODE hcErr;
  1662. // Call the replacement method.
  1663. // If it returns HTTP_SUCCESS, we render everything up to
  1664. // the end of the conditional.
  1665. // if it returns HTTP_S_FALSE, the condition is not met and we
  1666. // render the else part if it exists or jump past the endif otherwise
  1667. hcErr = pReplacer->RenderReplacement(pToken->dwFnOffset,
  1668. pToken->dwObjOffset, pToken->dwMap, (void *)pToken->dwData);
  1669. if (hcErr == HTTP_SUCCESS)
  1670. {
  1671. dwNextToken = dwIndex+1;
  1672. hcErrorCode = HTTP_SUCCESS;
  1673. }
  1674. else if (hcErr == HTTP_S_FALSE)
  1675. {
  1676. dwNextToken = dwLoopIndex+1;
  1677. hcErrorCode = HTTP_SUCCESS;
  1678. }
  1679. else
  1680. {
  1681. dwNextToken = STENCIL_INVALIDINDEX;
  1682. hcErrorCode = hcErr;
  1683. break;
  1684. }
  1685. }
  1686. break;
  1687. case STENCIL_CONDITIONALELSE:
  1688. {
  1689. if (pToken->dwLoopIndex == STENCIL_INVALIDINDEX)
  1690. {
  1691. // This should have been caught at parse time
  1692. ATLASSERT(FALSE);
  1693. dwNextToken = STENCIL_INVALIDINDEX;
  1694. hcErrorCode = HTTP_ERROR(500, ISE_SUBERR_STENCIL_MISMATCHIF);
  1695. break;
  1696. }
  1697. dwNextToken = pToken->dwLoopIndex+1;
  1698. hcErrorCode = HTTP_SUCCESS;
  1699. }
  1700. break;
  1701. case STENCIL_CONDITIONALEND:
  1702. {
  1703. dwNextToken = dwIndex+1;
  1704. hcErrorCode = HTTP_SUCCESS;
  1705. }
  1706. break;
  1707. case STENCIL_TEXTTAG:
  1708. {
  1709. pWriteStream->WriteStream(pToken->pStart,
  1710. (int)((pToken->pEnd-pToken->pStart)+1), NULL);
  1711. dwNextToken = dwIndex+1;
  1712. }
  1713. break;
  1714. case STENCIL_REPLACEMENT:
  1715. {
  1716. if (pToken->dwFnOffset == STENCIL_INVALIDOFFSET)
  1717. {
  1718. // This should have been caught at parse time
  1719. ATLASSERT(FALSE);
  1720. dwNextToken = STENCIL_INVALIDINDEX;
  1721. hcErrorCode = HTTP_ERROR(500, ISE_SUBERR_STENCIL_INVALIDFUNCOFFSET);
  1722. break;
  1723. }
  1724. hcErrorCode = pReplacer->RenderReplacement(pToken->dwFnOffset,
  1725. pToken->dwObjOffset, pToken->dwMap, (void *)pToken->dwData);
  1726. if (IsAsyncContinueStatus(hcErrorCode))
  1727. dwNextToken = dwIndex; // call the tag again after we get back
  1728. else
  1729. {
  1730. dwNextToken = dwIndex + 1;
  1731. // when returned from a handler, these indicate that the handler is done
  1732. // and that we should move on to the next handler when called back
  1733. if (hcErrorCode == HTTP_SUCCESS_ASYNC_DONE)
  1734. hcErrorCode = HTTP_SUCCESS_ASYNC;
  1735. else if (hcErrorCode == HTTP_SUCCESS_ASYNC_NOFLUSH_DONE)
  1736. hcErrorCode = HTTP_SUCCESS_ASYNC_NOFLUSH;
  1737. }
  1738. }
  1739. break;
  1740. case STENCIL_LOCALE:
  1741. {
  1742. if (pState)
  1743. {
  1744. CStencilState* _pState = reinterpret_cast<CStencilState*>(pState);
  1745. _pState->locale = (LCID) pToken->dwData;
  1746. }
  1747. SetThreadLocale((LCID) pToken->dwData);
  1748. dwNextToken = dwIndex + 1;
  1749. }
  1750. break;
  1751. default:
  1752. {
  1753. ATLASSERT(FALSE);
  1754. dwNextToken = STENCIL_INVALIDINDEX;
  1755. hcErrorCode = HTTP_ERROR(500, ISE_SUBERR_STENCIL_UNEXPECTEDTYPE);
  1756. break;
  1757. }
  1758. }
  1759. ATLASSERT(dwNextToken != dwIndex || IsAsyncContinueStatus(hcErrorCode));
  1760. if (phcErrorCode)
  1761. *phcErrorCode = hcErrorCode;
  1762. return dwNextToken;
  1763. }
  1764. DWORD GetTokenCount() const throw()
  1765. {
  1766. return (DWORD) m_arrTokens.GetCount();
  1767. }
  1768. const StencilToken* GetToken(DWORD dwIndex) const throw()
  1769. {
  1770. return &(m_arrTokens[dwIndex]);
  1771. }
  1772. StencilToken* GetToken(DWORD dwIndex) throw()
  1773. {
  1774. return &(m_arrTokens[dwIndex]);
  1775. }
  1776. LPSTR GetBufferStart() const throw()
  1777. {
  1778. return m_pBufferStart;
  1779. }
  1780. LPSTR GetBufferEnd() const throw()
  1781. {
  1782. return m_pBufferEnd;
  1783. }
  1784. WORD GetCodePage() const throw()
  1785. {
  1786. return m_nCodePage;
  1787. }
  1788. // IMemoryCacheClient
  1789. STDMETHOD(QueryInterface)(REFIID riid, void **ppv) throw()
  1790. {
  1791. if (!ppv)
  1792. return E_POINTER;
  1793. if (InlineIsEqualGUID(riid, __uuidof(IUnknown)) ||
  1794. InlineIsEqualGUID(riid, __uuidof(IMemoryCacheClient)))
  1795. {
  1796. *ppv = static_cast<void*>(this);
  1797. return S_OK;
  1798. }
  1799. return E_NOINTERFACE;
  1800. }
  1801. STDMETHOD_(ULONG, AddRef)() throw()
  1802. {
  1803. return 1;
  1804. }
  1805. STDMETHOD_(ULONG, Release)() throw()
  1806. {
  1807. return 1;
  1808. }
  1809. STDMETHOD(Free)(const void *pData) throw()
  1810. {
  1811. if (!pData)
  1812. return E_UNEXPECTED;
  1813. ATLASSERT(*((void **) pData) == static_cast<void*>(this));
  1814. Uninitialize();
  1815. delete this;
  1816. return S_OK;
  1817. }
  1818. }; // class CStencil
  1819. struct StencilIncludeInfo
  1820. {
  1821. public:
  1822. CHAR m_szQueryString[2048];
  1823. CHAR m_szFileName[MAX_PATH];
  1824. };
  1825. class CIncludeServerContext :
  1826. public CComObjectRootEx<CComMultiThreadModel>,
  1827. public CWrappedServerContext
  1828. {
  1829. public:
  1830. BEGIN_COM_MAP(CIncludeServerContext)
  1831. COM_INTERFACE_ENTRY(IHttpServerContext)
  1832. END_COM_MAP()
  1833. IWriteStream * m_pStream;
  1834. const StencilIncludeInfo * m_pIncludeInfo;
  1835. CIncludeServerContext() throw()
  1836. {
  1837. m_pStream = NULL;
  1838. m_pIncludeInfo = NULL;
  1839. }
  1840. void Initialize(
  1841. IWriteStream *pStream,
  1842. IHttpServerContext* pServerContext,
  1843. const StencilIncludeInfo * pIncludeInfo) throw()
  1844. {
  1845. m_pStream = pStream;
  1846. m_spParent = pServerContext;
  1847. m_pIncludeInfo = pIncludeInfo;
  1848. }
  1849. LPCSTR GetRequestMethod() throw()
  1850. {
  1851. return "GET";
  1852. }
  1853. LPCSTR GetQueryString() throw()
  1854. {
  1855. return m_pIncludeInfo->m_szQueryString;
  1856. }
  1857. LPCSTR GetPathTranslated() throw()
  1858. {
  1859. return m_pIncludeInfo->m_szFileName;
  1860. }
  1861. LPCSTR GetScriptPathTranslated() throw()
  1862. {
  1863. return m_pIncludeInfo->m_szFileName;
  1864. }
  1865. DWORD GetTotalBytes() throw()
  1866. {
  1867. return 0;
  1868. }
  1869. DWORD GetAvailableBytes() throw()
  1870. {
  1871. return 0;
  1872. }
  1873. BYTE *GetAvailableData() throw()
  1874. {
  1875. return NULL;
  1876. }
  1877. LPCSTR GetContentType() throw()
  1878. {
  1879. return 0;
  1880. }
  1881. BOOL WriteClient(void *pvBuffer, DWORD *pdwBytes) throw(...)
  1882. {
  1883. HRESULT hr = m_pStream->WriteStream((LPCSTR) pvBuffer, *pdwBytes, pdwBytes);
  1884. return SUCCEEDED(hr);
  1885. }
  1886. BOOL ReadClient(void * /*pvBuffer*/, DWORD * /*pdwSize*/) throw()
  1887. {
  1888. return FALSE;
  1889. }
  1890. BOOL AsyncReadClient(void * /*pvBuffer*/, DWORD * /*pdwSize*/) throw()
  1891. {
  1892. return FALSE;
  1893. }
  1894. BOOL SendRedirectResponse(LPCSTR /*pszRedirectURL*/) throw()
  1895. {
  1896. return FALSE;
  1897. }
  1898. BOOL SendResponseHeader(
  1899. LPCSTR /*pszHeader*/,
  1900. LPCSTR /*pszStatusCode*/,
  1901. BOOL /*fKeepConn*/) throw()
  1902. {
  1903. return TRUE;
  1904. }
  1905. BOOL DoneWithSession(DWORD /*dwHttpStatusCode*/) throw()
  1906. {
  1907. return TRUE;
  1908. }
  1909. BOOL RequestIOCompletion(PFN_HSE_IO_COMPLETION /*pfn*/, DWORD * /*pdwContext*/) throw()
  1910. {
  1911. return FALSE;
  1912. }
  1913. }; // class CIncludeServerContext
  1914. class CIDServerContext :
  1915. public CComObjectRootEx<CComMultiThreadModel>,
  1916. public CWrappedServerContext
  1917. {
  1918. public:
  1919. CHttpResponse *m_pResponse;
  1920. CHttpRequest *m_pRequest;
  1921. BEGIN_COM_MAP(CIDServerContext)
  1922. COM_INTERFACE_ENTRY(IHttpServerContext)
  1923. END_COM_MAP()
  1924. CIDServerContext() throw()
  1925. : m_pResponse(NULL), m_pRequest(NULL)
  1926. {
  1927. }
  1928. BOOL Initialize(
  1929. CHttpResponse *pResponse,
  1930. CHttpRequest *pRequest) throw()
  1931. {
  1932. m_pResponse = pResponse;
  1933. m_pRequest = pRequest;
  1934. HRESULT hr = m_pRequest->GetServerContext(&m_spParent);
  1935. return (SUCCEEDED(hr));
  1936. }
  1937. LPCSTR GetRequestMethod() throw()
  1938. {
  1939. ATLASSERT(m_pRequest != NULL);
  1940. return m_pRequest->GetMethodString();
  1941. }
  1942. LPCSTR GetQueryString() throw()
  1943. {
  1944. ATLASSERT(m_pRequest != NULL);
  1945. return m_pRequest->GetQueryString();
  1946. }
  1947. LPCSTR GetPathInfo() throw()
  1948. {
  1949. ATLASSERT(m_pRequest != NULL);
  1950. return m_pRequest->GetPathInfo();
  1951. }
  1952. LPCSTR GetPathTranslated() throw()
  1953. {
  1954. ATLASSERT(m_pRequest != NULL);
  1955. return m_pRequest->GetPathTranslated();
  1956. }
  1957. DWORD GetTotalBytes() throw()
  1958. {
  1959. ATLASSERT(m_pRequest != NULL);
  1960. return m_pRequest->GetTotalBytes();
  1961. }
  1962. DWORD GetAvailableBytes() throw()
  1963. {
  1964. ATLASSERT(m_pRequest != NULL);
  1965. return m_pRequest->GetAvailableBytes();
  1966. }
  1967. BYTE *GetAvailableData() throw()
  1968. {
  1969. ATLASSERT(m_pRequest != NULL);
  1970. return m_pRequest->GetAvailableData();
  1971. }
  1972. LPCSTR GetContentType() throw()
  1973. {
  1974. ATLASSERT(m_pRequest != NULL);
  1975. return m_pRequest->GetContentType();
  1976. }
  1977. LPCSTR GetScriptPathTranslated() throw()
  1978. {
  1979. ATLASSERT(m_pRequest != NULL);
  1980. return m_pRequest->GetScriptPathTranslated();
  1981. }
  1982. BOOL WriteClient(void *pvBuffer, DWORD *pdwBytes) throw()
  1983. {
  1984. ATLASSERT(m_pResponse != NULL);
  1985. return m_pResponse->WriteLen((LPCSTR)pvBuffer, *pdwBytes);
  1986. }
  1987. BOOL ReadClient(void *pvBuffer, DWORD *pdwSize) throw()
  1988. {
  1989. ATLASSERT(m_pRequest != NULL);
  1990. return m_pRequest->ReadData((LPSTR)pvBuffer, pdwSize);
  1991. }
  1992. BOOL SendRedirectResponse(LPCSTR pszRedirectURL) throw()
  1993. {
  1994. ATLASSERT(m_pResponse != NULL);
  1995. return m_pResponse->Redirect(pszRedirectURL);
  1996. }
  1997. BOOL TransmitFile(
  1998. HANDLE hFile,
  1999. PFN_HSE_IO_COMPLETION pfn,
  2000. void *pContext,
  2001. LPCSTR szStatusCode,
  2002. DWORD dwBytesToWrite,
  2003. DWORD dwOffset,
  2004. void *pvHead,
  2005. DWORD dwHeadLen,
  2006. void *pvTail,
  2007. DWORD dwTailLen,
  2008. DWORD dwFlags) throw(...)
  2009. {
  2010. ATLASSERT(m_pResponse != NULL);
  2011. ATLASSERT(m_spParent != NULL);
  2012. m_pResponse->Flush();
  2013. return m_spParent->TransmitFile(hFile, pfn, pContext, szStatusCode,
  2014. dwBytesToWrite, dwOffset, pvHead, dwHeadLen, pvTail, dwTailLen, dwFlags);
  2015. }
  2016. }; // class CIDServerContext
  2017. //
  2018. // CHtmlStencil
  2019. // CHtmlStencil is a specialization of CStencil. CHtmlStencil adds the following
  2020. // capabilities to CStencil:
  2021. //
  2022. // Support for rendering {{include }} tags
  2023. // The {{include }} tags specify another stencil to be included in-place during
  2024. // stencil rendering. The {{include }} tag takes a single parameter which is the
  2025. // URL of the stencil to include. That URL can optionally include parameters.
  2026. // An example:
  2027. // {{include mystencil.srf?param1=value1}}
  2028. //
  2029. // We also grab the handler name and the name of any subhandlers. A handler must be
  2030. // the first tag in the .srf file. The syntax for the handler specification is:
  2031. // {{handler MyDynamicHandler.dll/Default}}
  2032. // which would cause the MyDynamicHandler.dll to be loaded. Once loaded, the stencil
  2033. // processor will ask for the IReplacementHandler interface of the object named "Default".
  2034. //
  2035. // Additional handlers can be specified after the default handler. An example of an
  2036. // additional handler would be:
  2037. // {{subhandler OtherHandler MyOtherHandler.dll/Default}}
  2038. // would cause the MyOtherHandler.dll to be loaded. Once loaded, the stencil processor will
  2039. // ask for the IReplacementHandler interface of the object named "Default" and use it in
  2040. // processing the stencil anywhere it sees a stencil tag of the form
  2041. // {{OtherHandler.RenderReplacement}}
  2042. struct CStringPair
  2043. {
  2044. CStringA strDllPath;
  2045. CStringA strHandlerName;
  2046. CStringPair()throw()
  2047. {
  2048. }
  2049. CStringPair(CStringA &strDllPath_, CStringA &strHandlerName_) throw(...)
  2050. :strDllPath(strDllPath_), strHandlerName(strHandlerName_)
  2051. {
  2052. }
  2053. };
  2054. class CStringPairElementTraits :
  2055. public CElementTraitsBase< CStringPair >
  2056. {
  2057. public:
  2058. static ULONG Hash( INARGTYPE pair ) throw()
  2059. {
  2060. return CStringElementTraits<CStringA>::Hash( pair.strDllPath );
  2061. }
  2062. static bool CompareElements( INARGTYPE pair1, INARGTYPE pair2 ) throw()
  2063. {
  2064. return( (pair1.strDllPath == pair2.strDllPath) && (pair1.strHandlerName == pair2.strHandlerName) );
  2065. }
  2066. static int CompareElementsOrdered( INARGTYPE pair1, INARGTYPE pair2 ) throw()
  2067. {
  2068. return( pair1.strDllPath.Compare( pair2.strDllPath ) );
  2069. }
  2070. };
  2071. class CHtmlStencil : public CStencil
  2072. {
  2073. protected:
  2074. CAtlMap<CStringA, CStringPair,
  2075. CStringElementTraits<CStringA>, CStringPairElementTraits > m_arrExtraHandlers;
  2076. CHAR m_szBaseDir[MAX_PATH];
  2077. CComPtr<IServiceProvider> m_spServiceProvider;
  2078. CComPtr<IIsapiExtension> m_spExtension;
  2079. CComPtr<IStencilCache> m_spStencilCache;
  2080. CComPtr<IDllCache> m_spDllCache;
  2081. public:
  2082. typedef CAtlMap<CStringA, CStringPair,
  2083. CStringElementTraits<CStringA>, CStringPairElementTraits > mapType;
  2084. typedef CStencil baseType;
  2085. CHtmlStencil(IAtlMemMgr *pMemMgr=NULL) throw() :
  2086. CStencil(pMemMgr)
  2087. {
  2088. }
  2089. void Initialize(IServiceProvider *pProvider) throw(...)
  2090. {
  2091. ATLASSERT(pProvider);
  2092. if (m_spServiceProvider)
  2093. m_spServiceProvider.Release();
  2094. m_spServiceProvider = pProvider;
  2095. if (!m_spDllCache)
  2096. pProvider->QueryService(__uuidof(IDllCache), __uuidof(IDllCache), (void **) &m_spDllCache);
  2097. if (!m_spExtension)
  2098. pProvider->QueryInterface(__uuidof(IIsapiExtension), (void **) &m_spExtension);
  2099. }
  2100. BOOL GetIncludeInfo(LPCSTR szParamBegin, LPCSTR szParamEnd, StencilIncludeInfo *pInfo) const throw()
  2101. {
  2102. LPCSTR szQueryBegin = szParamBegin;
  2103. while (*szQueryBegin && *szQueryBegin != '?' && *szQueryBegin != '}')
  2104. {
  2105. LPSTR szNext = CharNextExA(GetCodePage(), szQueryBegin, 0);
  2106. if (szNext == szQueryBegin)
  2107. {
  2108. return FALSE;
  2109. }
  2110. szQueryBegin = szNext;
  2111. }
  2112. char szPath[MAX_PATH];
  2113. szPath[0] = '\0';
  2114. DWORD dwPrefixLen = 0;
  2115. if (*szParamBegin == '"')
  2116. {
  2117. szParamBegin++;
  2118. }
  2119. if (!IsFullPathA(szParamBegin))
  2120. {
  2121. if (*szParamBegin != '\\')
  2122. {
  2123. strcpy(szPath, m_szBaseDir);
  2124. }
  2125. else
  2126. {
  2127. LPCSTR szBackslash = strchr(m_szBaseDir, '\\');
  2128. if (szBackslash)
  2129. {
  2130. strncpy(szPath, m_szBaseDir, szBackslash-m_szBaseDir);
  2131. szPath[szBackslash-m_szBaseDir] = '\0';
  2132. }
  2133. else
  2134. {
  2135. strcpy(szPath, m_szBaseDir);
  2136. }
  2137. }
  2138. dwPrefixLen = (DWORD)strlen(szPath);
  2139. }
  2140. if (*szQueryBegin=='?')
  2141. {
  2142. size_t nMinus = (*(szQueryBegin-1) == '"') ? 1 : 0;
  2143. strncat(szPath, szParamBegin, szQueryBegin-szParamBegin-nMinus);
  2144. szPath[dwPrefixLen + szQueryBegin - szParamBegin] = '\0';
  2145. memcpy(pInfo->m_szQueryString, szQueryBegin + 1, szParamEnd - szQueryBegin);
  2146. pInfo->m_szQueryString[szParamEnd - szQueryBegin] = '\0';
  2147. }
  2148. else
  2149. {
  2150. pInfo->m_szQueryString[0] = '\0';
  2151. size_t nAdd = (*szParamEnd == '"') ? 0 : 1;
  2152. strncat(szPath, szParamBegin, szParamEnd - szParamBegin + nAdd);
  2153. szPath[dwPrefixLen + szParamEnd - szParamBegin + 1] = '\0';
  2154. }
  2155. PathCanonicalizeA(pInfo->m_szFileName, szPath);
  2156. return HTTP_SUCCESS;
  2157. }
  2158. int ParseInclude(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD * /*pBlockStack*/, DWORD * /*pdwTop*/) throw(...)
  2159. {
  2160. LPSTR szStart = szTokenStart;
  2161. LPSTR szEnd = szTokenEnd;
  2162. FindTagArgs(szStart, szEnd, 7);
  2163. CHeapPtr<char> szFileNameRelative;
  2164. CHeapPtr<TCHAR> szFileName;
  2165. ATLTRY(szFileNameRelative.AllocateBytes(max(MAX_PATH, szEnd-szStart+3)))
  2166. ATLTRY(szFileName.AllocateBytes(((szEnd-szStart)+MAX_PATH+3)*sizeof(TCHAR)))
  2167. if ((char*)szFileNameRelative == NULL ||
  2168. (TCHAR*)szFileName == NULL)
  2169. {
  2170. AddError("Out of memory", szTokenStart);
  2171. return AddToken(szTokenStart, szTokenEnd, STENCIL_TEXTTAG);
  2172. }
  2173. memcpy(szFileNameRelative, szStart, szEnd-szStart + 1);
  2174. szFileNameRelative[szEnd-szStart + 1] = '\0';
  2175. if (!IsFullPathA(szFileNameRelative))
  2176. {
  2177. CHeapPtr<CHAR> szTemp;
  2178. ATLTRY(szTemp.AllocateBytes((szEnd-szStart)+MAX_PATH+3));
  2179. if ((CHAR*)szTemp == NULL)
  2180. {
  2181. AddError("Out of memory", szTokenStart);
  2182. return AddToken(szTokenStart, szTokenEnd, STENCIL_TEXTTAG);
  2183. }
  2184. if (*szFileNameRelative != '\\')
  2185. {
  2186. strcpy(szTemp, m_szBaseDir);
  2187. }
  2188. else
  2189. {
  2190. LPCSTR szBackslash = strchr(m_szBaseDir, '\\');
  2191. if (szBackslash)
  2192. {
  2193. strncpy(szTemp, m_szBaseDir, szBackslash-m_szBaseDir);
  2194. szTemp[szBackslash-m_szBaseDir] = '\0';
  2195. }
  2196. else
  2197. {
  2198. strcpy(szTemp, m_szBaseDir);
  2199. }
  2200. }
  2201. strcat(szTemp, szFileNameRelative);
  2202. PathCanonicalize(szFileName, CA2CT(szTemp));
  2203. }
  2204. else
  2205. {
  2206. _tcscpy(szFileName, CA2CTEX<MAX_PATH>(szFileNameRelative));
  2207. }
  2208. LPTSTR szDot = NULL;
  2209. LPTSTR szExtra = _tcschr(szFileName, '?');
  2210. if (!szExtra)
  2211. {
  2212. szExtra = _tcschr(szFileName, '#');
  2213. if (!szExtra)
  2214. {
  2215. szDot = _tcsrchr(szFileName, '.');
  2216. }
  2217. }
  2218. if (szExtra != NULL)
  2219. {
  2220. // there is some extra information
  2221. LPTSTR szDotTmp = szFileName;
  2222. do
  2223. {
  2224. szDot = szDotTmp;
  2225. szDotTmp = _tcschr(szDotTmp+1, '.');
  2226. } while (szDotTmp && szDotTmp < szExtra);
  2227. }
  2228. if (!szDot || *szDot != '.')
  2229. {
  2230. AddError("Unexpected error", szTokenStart);
  2231. return AddToken(szTokenStart, szTokenEnd, STENCIL_TEXTTAG);
  2232. }
  2233. LPTSTR szExtEnd = szDot;
  2234. while (true)
  2235. {
  2236. szExtEnd++;
  2237. if (!*szExtEnd || *szExtEnd == '/' || *szExtEnd == '\\' || *szExtEnd == '?' || *szExtEnd == '#' || *szExtEnd == '"')
  2238. break;
  2239. }
  2240. if (szDot && szExtEnd-szDot == sizeof(".dll")-sizeof('\0') &&
  2241. !_tcsnicmp(szDot, _T(".dll"), sizeof(".dll")-sizeof('\0')))
  2242. {
  2243. // Do .dll stuff
  2244. DWORD dwIndex = AddToken(szStart, szEnd, STENCIL_STENCILINCLUDE);
  2245. StencilIncludeInfo *pInfo = (StencilIncludeInfo *)m_pMemMgr->Allocate(sizeof(StencilIncludeInfo));
  2246. if (!pInfo)
  2247. return -1;
  2248. GetIncludeInfo(szStart, szEnd, pInfo);
  2249. // m_arrTokens[dwIndex].pvParam = pInfo;
  2250. GetToken(dwIndex)->dwData = (DWORD_PTR) pInfo;
  2251. return dwIndex;
  2252. }
  2253. else if (szDot && (size_t)(szExtEnd-szDot) == _tcslen(c_tAtlSRFExtension) &&
  2254. !_tcsnicmp(szDot, c_tAtlSRFExtension, _tcslen(c_tAtlSRFExtension)))
  2255. {
  2256. // Do .srf stuff
  2257. DWORD dwIndex = AddToken(szStart, szEnd, STENCIL_STENCILINCLUDE);
  2258. StencilIncludeInfo *pInfo = (StencilIncludeInfo *)m_pMemMgr->Allocate(sizeof(StencilIncludeInfo));
  2259. if (!pInfo)
  2260. return -1;
  2261. GetIncludeInfo(szStart, szEnd, pInfo);
  2262. // m_arrTokens[dwIndex].pvParam = pInfo;
  2263. GetToken(dwIndex)->dwData = (DWORD_PTR) pInfo;
  2264. return dwIndex;
  2265. }
  2266. else
  2267. {
  2268. // Assume static content
  2269. CAtlFile file;
  2270. HRESULT hr = file.Create(szFileName, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING);
  2271. if (FAILED(hr) || GetFileType(file) != FILE_TYPE_DISK)
  2272. {
  2273. if (FAILED(hr))
  2274. AddError("Could not open included file", szTokenStart);
  2275. else
  2276. AddError("Included file is not a disk file", szTokenStart);
  2277. return AddToken(szTokenStart, szTokenEnd, STENCIL_TEXTTAG);
  2278. }
  2279. CAutoVectorPtr<CHAR> szBufferStart;
  2280. LPSTR szBufferEnd = NULL;
  2281. ULONGLONG dwLen = 0;
  2282. if (FAILED(file.GetSize(dwLen)))
  2283. return AddToken(szTokenStart, szTokenEnd, STENCIL_TEXTTAG);
  2284. if (!szBufferStart.Allocate((size_t) dwLen))
  2285. AtlThrow(E_OUTOFMEMORY);
  2286. DWORD dwRead;
  2287. if (FAILED(file.Read(szBufferStart, (DWORD) dwLen, dwRead)))
  2288. return AddToken(szTokenStart, szTokenEnd, STENCIL_TEXTTAG);
  2289. szBufferEnd = szBufferStart + dwRead-1;
  2290. DWORD dwIndex = AddToken(szBufferStart, szBufferEnd, STENCIL_STATICINCLUDE);
  2291. // m_arrTokens[dwIndex].bDynamicAlloc = TRUE;
  2292. GetToken(dwIndex)->bDynamicAlloc = TRUE;
  2293. szBufferStart.Detach();
  2294. return dwIndex;
  2295. }
  2296. }
  2297. PARSE_TOKEN_RESULT ParseSubhandler(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD * /*pBlockStack*/, DWORD * /*pdwTop*/) throw()
  2298. {
  2299. LPSTR szStart = szTokenStart;
  2300. LPSTR szEnd = szTokenEnd;
  2301. // move to the start of the arguments
  2302. // (the first char past 'subhandler'
  2303. FindTagArgs(szStart, szEnd, 10);
  2304. // skip any space to bring us to the start
  2305. // of the id for the subhandler.
  2306. szStart = SkipSpace(szStart, GetCodePage());
  2307. // id names cannot contain spaces. Mark the
  2308. // beginning and end if the subhandler id
  2309. LPCSTR szIdStart = szStart;
  2310. while (!isspace(*szStart) && *szStart != '}')
  2311. {
  2312. LPSTR szNext = CharNextExA(GetCodePage(), szStart, 0);
  2313. if (szNext == szStart)
  2314. {
  2315. // embedded null
  2316. AddError("Embedded null character in stencil", NULL);
  2317. return INVALID_TOKEN;
  2318. }
  2319. szStart = szNext;
  2320. }
  2321. LPCSTR szIdEnd = szStart;
  2322. // skip space to bring us to the beginning of the
  2323. // the dllpath/handlername
  2324. szStart = SkipSpace(szStart, GetCodePage());
  2325. // everything up to the end if the tag is
  2326. // part of the dllpath/handlername
  2327. LPSTR szHandlerStart = szStart;
  2328. while (*szStart != '}')
  2329. {
  2330. LPSTR szNext = CharNextExA(GetCodePage(), szStart, 0);
  2331. if (szNext == szStart)
  2332. {
  2333. // embedded null
  2334. AddError("Embedded null character in stencil", NULL);
  2335. return INVALID_TOKEN;
  2336. }
  2337. szStart = szNext;
  2338. }
  2339. LPCSTR szHandlerEnd = szStart;
  2340. _ATLTRY
  2341. {
  2342. CStringA strName(szIdStart, (int)(szIdEnd-szIdStart));
  2343. CStringA strPath(szHandlerStart, (int)(szHandlerEnd-szHandlerStart));
  2344. CStringA strDllPath;
  2345. CStringA strHandlerName;
  2346. DWORD dwDllPathLen = MAX_PATH+1;
  2347. DWORD dwHandlerNameLen = ATL_MAX_HANDLER_NAME_LEN+1;
  2348. LPSTR szDllPath = strDllPath.GetBuffer(dwDllPathLen);
  2349. LPSTR szHandlerName = strHandlerName.GetBuffer(dwHandlerNameLen);
  2350. if (!_AtlCrackHandler(strPath, szDllPath, &dwDllPathLen, szHandlerName, &dwHandlerNameLen))
  2351. {
  2352. strDllPath.ReleaseBuffer();
  2353. strHandlerName.ReleaseBuffer();
  2354. return INVALID_TOKEN;
  2355. }
  2356. strDllPath.ReleaseBuffer(dwDllPathLen);
  2357. strHandlerName.ReleaseBuffer(dwHandlerNameLen);
  2358. m_arrExtraHandlers.SetAt(strName, CStringPair(strDllPath, strHandlerName));
  2359. }
  2360. _ATLCATCHALL()
  2361. {
  2362. return INVALID_TOKEN;
  2363. }
  2364. return RESERVED_TOKEN;
  2365. }
  2366. virtual PARSE_TOKEN_RESULT ParseToken(LPSTR szTokenStart, LPSTR szTokenEnd, DWORD *pBlockStack, DWORD *pdwTop) throw()
  2367. {
  2368. LPSTR pStart = szTokenStart;
  2369. pStart += 2; //skip curlies
  2370. pStart = SkipSpace(pStart, GetCodePage());
  2371. DWORD dwLen = (DWORD)(szTokenEnd - szTokenStart);
  2372. int nIndex = -1;
  2373. if (CheckTag("include", 7, pStart, dwLen))
  2374. nIndex = ParseInclude(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  2375. else if (dwLen > 3 && !memcmp("!--", pStart, 3))
  2376. return RESERVED_TOKEN;
  2377. else if (dwLen > 2 && !memcmp("//", pStart, 2))
  2378. return RESERVED_TOKEN;
  2379. else if (CheckTag("subhandler", 10, pStart, dwLen))
  2380. {
  2381. return ParseSubhandler(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  2382. }
  2383. else
  2384. {
  2385. return CStencil::ParseToken(szTokenStart, szTokenEnd, pBlockStack, pdwTop);
  2386. }
  2387. if (nIndex < 0)
  2388. return INVALID_TOKEN;
  2389. return RESERVED_TOKEN;
  2390. }
  2391. mapType* GetExtraHandlers() throw()
  2392. {
  2393. return &m_arrExtraHandlers;
  2394. }
  2395. void SetBaseDirFromFile(LPCSTR szBaseDir) throw()
  2396. {
  2397. strcpy(m_szBaseDir, szBaseDir);
  2398. LPSTR szSlash = strrchr(m_szBaseDir, '\\');
  2399. if (szSlash)
  2400. {
  2401. szSlash++;
  2402. *szSlash = '\0';
  2403. }
  2404. else
  2405. {
  2406. *m_szBaseDir = '\0';
  2407. }
  2408. }
  2409. LPCSTR GetBaseDir() throw()
  2410. {
  2411. return m_szBaseDir;
  2412. }
  2413. // Any value returned from a replacement method other than HTTP_SUCCESS
  2414. // will stop the rendering of the stencil.
  2415. DWORD RenderToken(
  2416. DWORD dwIndex,
  2417. ITagReplacer* pReplacer,
  2418. IWriteStream *pWriteStream,
  2419. HTTP_CODE *phcErrorCode,
  2420. void* pState = NULL) const throw(...)
  2421. {
  2422. DWORD dwNextToken = STENCIL_INVALIDINDEX;
  2423. HTTP_CODE hcErrorCode = HTTP_SUCCESS;
  2424. const StencilToken* pToken = GetToken(dwIndex);
  2425. if (pToken)
  2426. {
  2427. if (pToken->type == STENCIL_STENCILINCLUDE)
  2428. {
  2429. ATLASSERT(m_spServiceProvider);
  2430. CComPtr<IHttpServerContext> spServerContext;
  2431. CComPtr<IHttpRequestLookup> spLookup;
  2432. if (FAILED(pReplacer->GetContext(__uuidof(IHttpServerContext), (VOID**) &spServerContext)))
  2433. return HTTP_ERROR(500, 0);
  2434. if (FAILED(pReplacer->GetContext(__uuidof(IHttpRequestLookup), (VOID**) &spLookup)))
  2435. return HTTP_ERROR(500, 0);
  2436. hcErrorCode = RenderInclude(m_spServiceProvider, pWriteStream,
  2437. (StencilIncludeInfo *)pToken->dwData, spServerContext, spLookup,
  2438. pState);
  2439. if (hcErrorCode == HTTP_SUCCESS || IsAsyncDoneStatus(hcErrorCode))
  2440. dwNextToken = dwIndex+1;
  2441. else if (IsAsyncContinueStatus(hcErrorCode))
  2442. dwNextToken = dwIndex;
  2443. }
  2444. else if (pToken->type == STENCIL_STATICINCLUDE)
  2445. {
  2446. pWriteStream->WriteStream(pToken->pStart,
  2447. (int)((pToken->pEnd-pToken->pStart)+1), NULL);
  2448. dwNextToken = dwIndex+1;
  2449. }
  2450. else
  2451. dwNextToken = baseType::RenderToken(dwIndex, pReplacer,
  2452. pWriteStream, &hcErrorCode, pState);
  2453. }
  2454. if (hcErrorCode == HTTP_SUCCESS_NO_CACHE)
  2455. {
  2456. hcErrorCode = HTTP_SUCCESS;
  2457. CComPtr<IHttpServerContext> spContext;
  2458. HRESULT hr = pReplacer->GetContext(__uuidof(IHttpServerContext), (void **)&spContext);
  2459. if (hr == S_OK && spContext)
  2460. {
  2461. CComQIPtr<IPageCacheControl> spControl;
  2462. spControl = spContext;
  2463. if (spControl)
  2464. spControl->Cache(FALSE);
  2465. }
  2466. }
  2467. if (phcErrorCode)
  2468. *phcErrorCode = hcErrorCode;
  2469. return dwNextToken;
  2470. }
  2471. ATL_NOINLINE HTTP_CODE RenderInclude(
  2472. IServiceProvider *pServiceProvider,
  2473. IWriteStream *pWriteStream,
  2474. const StencilIncludeInfo *pIncludeInfo,
  2475. IHttpServerContext *pServerContext,
  2476. IHttpRequestLookup *pLookup,
  2477. void* pState = NULL) const throw(...)
  2478. {
  2479. AtlServerRequest* pRequestInfo = NULL;
  2480. HTTP_CODE hcErr = HTTP_SUCCESS;
  2481. CComObjectStackEx<CIncludeServerContext> serverContext;
  2482. serverContext.Initialize(pWriteStream, pServerContext, pIncludeInfo);
  2483. #ifdef _DEBUG
  2484. bool bAsyncAllowed = false;
  2485. #endif
  2486. CStencilState* _pState = reinterpret_cast<CStencilState*>(pState);
  2487. if (_pState && _pState->pIncludeInfo)
  2488. {
  2489. pRequestInfo = _pState->pIncludeInfo;
  2490. _pState->pIncludeInfo = NULL;
  2491. #ifdef _DEBUG
  2492. bAsyncAllowed = true;
  2493. #endif
  2494. }
  2495. else
  2496. {
  2497. if (!m_spStencilCache)
  2498. m_spServiceProvider->QueryService(__uuidof(IStencilCache), __uuidof(IStencilCache), (void **) &m_spStencilCache);
  2499. ATLASSERT(m_spStencilCache);
  2500. if (!m_spDllCache)
  2501. pServiceProvider->QueryService(__uuidof(IDllCache), __uuidof(IDllCache), (void **) &m_spDllCache);
  2502. ATLASSERT(m_spDllCache);
  2503. pRequestInfo = m_spExtension->CreateRequest();
  2504. if (pRequestInfo == NULL)
  2505. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  2506. pRequestInfo->dwRequestState = ATLSRV_STATE_BEGIN;
  2507. pRequestInfo->dwRequestType = ATLSRV_REQUEST_STENCIL;
  2508. pRequestInfo->pDllCache = m_spDllCache;
  2509. pRequestInfo->pExtension = m_spExtension;
  2510. pRequestInfo->pServerContext = &serverContext;
  2511. if (_pState && _pState->pParentInfo)
  2512. pRequestInfo->pUserData = _pState->pParentInfo->pUserData;
  2513. // Extract the file extension of the included file by searching
  2514. // for the first '.' from the right.
  2515. // Can't use _tcsrchr because we have to use the stencil's codepage
  2516. LPCSTR szDot = NULL;
  2517. LPCSTR szMark = pIncludeInfo->m_szFileName;
  2518. while (*szMark)
  2519. {
  2520. if (*szMark == '.')
  2521. szDot = szMark;
  2522. LPCSTR szNext = CharNextExA(GetCodePage(), szMark, 0);
  2523. if (szNext == szMark)
  2524. {
  2525. // embedded null
  2526. return HTTP_FAIL;
  2527. }
  2528. szMark = szNext;
  2529. }
  2530. if (szDot && _stricmp(szDot, c_AtlSRFExtension) == 0)
  2531. {
  2532. hcErr = m_spExtension->LoadDispatchFile(pIncludeInfo->m_szFileName, pRequestInfo);
  2533. if (hcErr)
  2534. return hcErr;
  2535. }
  2536. else if (szDot && _stricmp(szDot, ".dll") == 0)
  2537. {
  2538. // Get the handler name if they used the asdf.dll?Handler=Default notation
  2539. // REVIEW : case sensitivity on the "Handler"?
  2540. char szHandlerName[ATL_MAX_HANDLER_NAME_LEN+1] = { '\0' };
  2541. LPSTR szStart = strstr(pIncludeInfo->m_szQueryString, "Handler=");
  2542. if (szStart &&
  2543. ((szStart == pIncludeInfo->m_szQueryString) ||
  2544. ((szStart > pIncludeInfo->m_szQueryString) && (*(szStart-1) == '&'))))
  2545. {
  2546. szStart += 8; // Skip past "Handler" and the "="
  2547. LPSTR szEnd = strchr(szStart, '&');
  2548. if (szEnd)
  2549. {
  2550. memcpy(szHandlerName, szStart, min((szEnd-szStart), ATL_MAX_HANDLER_NAME_LEN));
  2551. szHandlerName[min((szEnd-szStart), ATL_MAX_HANDLER_NAME_LEN)] = '\0';
  2552. }
  2553. else
  2554. {
  2555. strcpy(szHandlerName, szStart);
  2556. }
  2557. }
  2558. else
  2559. {
  2560. memcpy(szHandlerName, "Default", sizeof("Default"));
  2561. }
  2562. pRequestInfo->dwRequestType = ATLSRV_REQUEST_DLL;
  2563. hcErr = m_spExtension->LoadRequestHandler(pIncludeInfo->m_szFileName, szHandlerName, pRequestInfo->pServerContext,
  2564. &pRequestInfo->hInstDll, &pRequestInfo->pHandler);
  2565. if (hcErr)
  2566. return hcErr;
  2567. }
  2568. DWORD dwStatus;
  2569. hcErr = pRequestInfo->pHandler->GetFlags(&dwStatus);
  2570. if (hcErr)
  2571. return hcErr;
  2572. if (dwStatus & (ATLSRV_INIT_USEASYNC | ATLSRV_INIT_USEASYNC_EX))
  2573. {
  2574. #ifdef _DEBUG
  2575. bAsyncAllowed = true;
  2576. #endif
  2577. CComObjectNoLock<CIncludeServerContext>* pNewServerContext = NULL;
  2578. ATLTRY(pNewServerContext = new CComObjectNoLock<CIncludeServerContext>);
  2579. if (pNewServerContext == NULL)
  2580. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM);
  2581. pNewServerContext->Initialize(pWriteStream, pServerContext, pIncludeInfo);
  2582. pNewServerContext->AddRef();
  2583. pRequestInfo->pServerContext = pNewServerContext;
  2584. }
  2585. _ATLTRY
  2586. {
  2587. hcErr = pRequestInfo->pHandler->InitializeChild(pRequestInfo, m_spServiceProvider, pLookup);
  2588. if (hcErr)
  2589. return hcErr;
  2590. }
  2591. _ATLCATCHALL()
  2592. {
  2593. return HTTP_FAIL;
  2594. }
  2595. pRequestInfo->pfnHandleRequest = &IRequestHandler::HandleRequest;
  2596. }
  2597. if (pRequestInfo)
  2598. {
  2599. if (!hcErr)
  2600. {
  2601. if (pRequestInfo->pServerContext == NULL)
  2602. pRequestInfo->pServerContext = &serverContext;
  2603. _ATLTRY
  2604. {
  2605. ATLASSERT(pRequestInfo->pfnHandleRequest != NULL);
  2606. hcErr = (pRequestInfo->pHandler->*pRequestInfo->pfnHandleRequest)(pRequestInfo, pServiceProvider);
  2607. }
  2608. _ATLCATCHALL()
  2609. {
  2610. hcErr = HTTP_FAIL;
  2611. }
  2612. if (pRequestInfo->pServerContext == &serverContext)
  2613. pRequestInfo->pServerContext = NULL;
  2614. #ifdef _DEBUG
  2615. // must use ATLSRV_INIT_USEASYNC to use ASYNC returns
  2616. if (IsAsyncStatus(hcErr))
  2617. ATLASSERT(bAsyncAllowed);
  2618. #endif
  2619. if (IsAsyncStatus(hcErr))
  2620. {
  2621. ATLASSERT(pState); // state is required for async
  2622. if (IsAsyncContinueStatus(hcErr))
  2623. {
  2624. _pState->pIncludeInfo = pRequestInfo;
  2625. pRequestInfo->dwRequestState = ATLSRV_STATE_CONTINUE;
  2626. }
  2627. else if (IsAsyncDoneStatus(hcErr))
  2628. m_spExtension->FreeRequest(pRequestInfo);
  2629. }
  2630. else
  2631. m_spExtension->FreeRequest(pRequestInfo);
  2632. }
  2633. }
  2634. else
  2635. hcErr = HTTP_ERROR(500, ISE_SUBERR_UNEXPECTED);
  2636. return hcErr;
  2637. }
  2638. }; // class CHtmlStencil
  2639. __declspec(selectany) CCRTHeap CStencil::m_crtHeap;
  2640. //
  2641. // CHtmlTagReplacer
  2642. // This class manages CStencil based objects for HTTP requests. This class will retrieve
  2643. // CStencil based objects from the stencil cache, store CStencil based objects in the
  2644. // stencil cache and allocate and initialize CStencil based objects on a per reqeust
  2645. // basis. Typically, one instance of this class is created for each HTTP request. The
  2646. // instance is destroyed once the request has been completed.
  2647. template <class THandler, class StencilType=CHtmlStencil>
  2648. class CHtmlTagReplacer :
  2649. public ITagReplacerImpl<THandler>
  2650. {
  2651. protected:
  2652. typedef StencilType StencilType;
  2653. CSimpleArray<HINSTANCE> m_hInstHandlers;
  2654. typedef CAtlMap<CStringA, IRequestHandler*, CStringElementTraits<CStringA> > mapType;
  2655. mapType m_Handlers;
  2656. StencilType *m_pLoadedStencil;
  2657. WORD m_nCodePage;
  2658. CComPtr<IStencilCache> m_spStencilCache;
  2659. AtlServerRequest m_RequestInfo;
  2660. public:
  2661. // public members
  2662. CHtmlTagReplacer() throw() :
  2663. m_pLoadedStencil(NULL)
  2664. {
  2665. memset(&m_RequestInfo, 0x00, sizeof(m_RequestInfo));
  2666. m_nCodePage = CP_THREAD_ACP;
  2667. }
  2668. ~CHtmlTagReplacer() throw()
  2669. {
  2670. // you should call FreeHandlers before
  2671. // the object is destructed
  2672. ATLASSERT(m_hInstHandlers.GetSize() == 0);
  2673. }
  2674. HTTP_CODE Initialize(AtlServerRequest *pRequestInfo, IHttpServerContext *pSafeSrvCtx=NULL) throw(...)
  2675. {
  2676. CComPtr<IServiceProvider> spServiceProvider;
  2677. THandler *pT = static_cast<THandler*>(this);
  2678. HRESULT hr = pT->GetContext(__uuidof(IServiceProvider), (void **)&spServiceProvider);
  2679. if (FAILED(hr))
  2680. return HTTP_FAIL;
  2681. spServiceProvider->QueryService(__uuidof(IStencilCache), __uuidof(IStencilCache), (void **) &m_spStencilCache);
  2682. if (!m_spStencilCache)
  2683. {
  2684. ATLASSERT(FALSE);
  2685. return HTTP_FAIL;
  2686. }
  2687. m_RequestInfo.cbSize = sizeof(m_RequestInfo);
  2688. m_RequestInfo.pServerContext = pSafeSrvCtx;
  2689. m_RequestInfo.pUserData = pRequestInfo->pUserData;
  2690. return HTTP_SUCCESS;
  2691. }
  2692. HTTP_CODE LoadStencilResource(
  2693. HINSTANCE hInstResource,
  2694. LPCSTR szResourceID,
  2695. LPCSTR szResourceType = NULL, LPCSTR szStencilName=NULL) throw(...)
  2696. {
  2697. if (!szResourceType)
  2698. szResourceType = (LPCSTR) (RT_HTML);
  2699. // look up stencil in cache
  2700. HTTP_CODE hcErr = HTTP_SUCCESS;
  2701. // check the cache first
  2702. StencilType *pStencil = FindCacheStencil(szStencilName ? szStencilName : szResourceID);
  2703. if (!pStencil)
  2704. {
  2705. // create a new stencil
  2706. pStencil = GetNewCacheStencil();
  2707. THandler *pT = static_cast<THandler*>(this);
  2708. LPCSTR szFileName = pT->m_spServerContext->GetScriptPathTranslated();
  2709. if (!szFileName)
  2710. return HTTP_FAIL;
  2711. pStencil->SetBaseDirFromFile(szFileName);
  2712. if (!pStencil)
  2713. return HTTP_ERROR(500,ISE_SUBERR_OUTOFMEM);
  2714. // load the stencil and parse its replacements
  2715. if (HTTP_SUCCESS == pStencil->LoadFromResource(hInstResource,
  2716. szResourceID, szResourceType))
  2717. {
  2718. _ATLTRY
  2719. {
  2720. if (!pStencil->ParseReplacements(static_cast<ITagReplacer*>(this),
  2721. pStencil->GetBufferStart(), pStencil->GetBufferEnd()))
  2722. return HTTP_ERROR(500, ISE_SUBERR_BADSRF);
  2723. hcErr = FinishLoadStencil(pStencil, NULL);
  2724. if (!hcErr)
  2725. {
  2726. pStencil->FinishParseReplacements();
  2727. }
  2728. }
  2729. _ATLCATCHALL()
  2730. {
  2731. return HTTP_FAIL;
  2732. }
  2733. }
  2734. else
  2735. {
  2736. hcErr = HTTP_FAIL;
  2737. }
  2738. // if everything went OK, put the stencil in the stencil cache.
  2739. if (!hcErr)
  2740. {
  2741. hcErr = CacheStencil(szStencilName ? szStencilName : szResourceID, pStencil);
  2742. }
  2743. if (pStencil && hcErr) // something went wrong, free the stencil data
  2744. FreeCacheStencil(pStencil);
  2745. }
  2746. else
  2747. {
  2748. hcErr = FinishLoadStencil(pStencil);
  2749. }
  2750. return hcErr;
  2751. }
  2752. HTTP_CODE LoadStencilResource(HINSTANCE hInstResource, UINT nID, LPCSTR szResourceType = NULL) throw(...)
  2753. {
  2754. if (!szResourceType)
  2755. szResourceType = (LPCSTR) RT_HTML;
  2756. char szName[80];
  2757. sprintf(szName, "%p/%u", hInstResource, nID);
  2758. return LoadStencilResource(hInstResource, MAKEINTRESOURCEA(nID), szResourceType, szName);
  2759. }
  2760. HTTP_CODE LoadStencil(LPCSTR szFileName, IHttpRequestLookup * pLookup = NULL) throw(...)
  2761. {
  2762. if (!szFileName)
  2763. {
  2764. return HTTP_FAIL;
  2765. }
  2766. HTTP_CODE hcErr = HTTP_FAIL;
  2767. // try to find the stencil in the cache
  2768. StencilType *pStencil = FindCacheStencil(szFileName);
  2769. if (!pStencil)
  2770. {
  2771. // not in cache. Create a new one
  2772. pStencil = GetNewCacheStencil();
  2773. if (!pStencil)
  2774. {
  2775. return HTTP_ERROR(500, ISE_SUBERR_OUTOFMEM); // out of memory!
  2776. }
  2777. pStencil->SetBaseDirFromFile(szFileName);
  2778. // finish loading
  2779. hcErr = pStencil->LoadFile(szFileName);
  2780. if ( !hcErr )
  2781. {
  2782. _ATLTRY
  2783. {
  2784. if (!pStencil->ParseReplacements(static_cast<ITagReplacer*>(this),
  2785. pStencil->GetBufferStart(), pStencil->GetBufferEnd()))
  2786. return HTTP_ERROR(500, ISE_SUBERR_BADSRF);
  2787. hcErr = FinishLoadStencil(pStencil, pLookup);
  2788. if (!hcErr)
  2789. {
  2790. pStencil->FinishParseReplacements();
  2791. }
  2792. }
  2793. _ATLCATCHALL()
  2794. {
  2795. return HTTP_FAIL;
  2796. }
  2797. }
  2798. // if everything is OK, cache the stencil
  2799. if (!hcErr)
  2800. {
  2801. hcErr = CacheStencil(szFileName, pStencil);
  2802. }
  2803. if (pStencil && hcErr) // something went wrong, free stencil data
  2804. FreeCacheStencil(pStencil);
  2805. }
  2806. else
  2807. {
  2808. hcErr = FinishLoadStencil(pStencil, pLookup);
  2809. }
  2810. return hcErr;
  2811. }
  2812. HTTP_CODE RenderStencil(IWriteStream* pStream, void* pState = NULL) throw(...)
  2813. {
  2814. if (!m_pLoadedStencil)
  2815. return HTTP_ERROR(500, ISE_SUBERR_UNEXPECTED);
  2816. WORD nCodePage = m_pLoadedStencil->GetCodePage();
  2817. if (nCodePage != CP_ACP)
  2818. m_nCodePage = nCodePage;
  2819. HTTP_CODE hcErr = HTTP_FAIL;
  2820. hcErr = m_pLoadedStencil->Render(static_cast<ITagReplacer*>(this),
  2821. pStream, pState);
  2822. if (!IsAsyncStatus(hcErr) && m_pLoadedStencil->GetCacheItem())
  2823. m_spStencilCache->ReleaseStencil(m_pLoadedStencil->GetCacheItem());
  2824. return hcErr;
  2825. }
  2826. HTTP_CODE AddHandler(LPCSTR szName, IRequestHandler *pHandler, HINSTANCE hInstHandler) throw()
  2827. {
  2828. _ATLTRY
  2829. {
  2830. ATLASSERT(szName);
  2831. ATLASSERT(pHandler);
  2832. ATLASSERT(hInstHandler);
  2833. HTTP_CODE hcErr = HTTP_ERROR(500, ISE_SUBERR_UNEXPECTED);
  2834. if (szName && *szName && pHandler)
  2835. {
  2836. if (m_Handlers.SetAt(szName, pHandler))
  2837. {
  2838. if (hInstHandler && m_hInstHandlers.Add(hInstHandler))
  2839. hcErr = HTTP_SUCCESS;
  2840. }
  2841. }
  2842. return hcErr;
  2843. }
  2844. _ATLCATCHALL()
  2845. {
  2846. return HTTP_FAIL;
  2847. }
  2848. }
  2849. void SendHandlerError(LPCSTR szHandlerName) throw()
  2850. {
  2851. #ifndef _ATL_STENCIL_SLIENT_ERRORS
  2852. m_pStream->WriteStream("Handler ");
  2853. m_pStream->WriteStream(szHandlerName);
  2854. m_pStream->WriteStream(" was not found");
  2855. #endif
  2856. }
  2857. //Implementation
  2858. void FreeHandlers() throw(...)
  2859. {
  2860. POSITION pos = m_Handlers.GetStartPosition();
  2861. while (pos)
  2862. {
  2863. m_Handlers.GetNextValue(pos)->Release();
  2864. }
  2865. m_Handlers.RemoveAll();
  2866. int nLen = m_hInstHandlers.GetSize();
  2867. THandler *pT = static_cast<THandler *>(this);
  2868. CComPtr<IDllCache> spDllCache;
  2869. pT->m_spServiceProvider->QueryService(__uuidof(IDllCache), __uuidof(IDllCache),
  2870. (void **)&spDllCache);
  2871. for (int i=0; i<nLen; i++)
  2872. {
  2873. spDllCache->Free(m_hInstHandlers[i]);
  2874. }
  2875. m_hInstHandlers.RemoveAll();
  2876. }
  2877. StencilType* GetNewCacheStencil() throw(...)
  2878. {
  2879. StencilType *pStencil = NULL;
  2880. THandler *pT = static_cast<THandler *>(this);
  2881. IAtlMemMgr *pMemMgr;
  2882. if (FAILED(pT->m_spServiceProvider->QueryService(__uuidof(IAtlMemMgr), __uuidof(IAtlMemMgr), (void **)&pMemMgr)))
  2883. pMemMgr = NULL;
  2884. ATLTRY(pStencil = new StencilType(pMemMgr));
  2885. if (pStencil != NULL)
  2886. pStencil->Initialize(pT->m_spServiceProvider);
  2887. return pStencil;
  2888. }
  2889. HTTP_CODE CacheStencil(
  2890. LPCSTR szName,
  2891. StencilType* pStencilData) throw()
  2892. {
  2893. THandler *pT = static_cast<THandler *>(this);
  2894. HRESULT hr = E_FAIL;
  2895. HCACHEITEM hCacheItem = NULL;
  2896. hr = m_spStencilCache->CacheStencil(szName,
  2897. pStencilData,
  2898. sizeof(StencilType*),
  2899. &hCacheItem,
  2900. pT->m_hInstHandler,
  2901. static_cast<IMemoryCacheClient*>(pStencilData));
  2902. if (hr == S_OK && hCacheItem)
  2903. pStencilData->SetCacheItem(hCacheItem);
  2904. return (hr == S_OK) ? HTTP_SUCCESS : HTTP_FAIL;
  2905. }
  2906. StencilType *FindCacheStencil(LPCSTR szName) throw()
  2907. {
  2908. if (!szName || !m_spStencilCache)
  2909. return NULL;
  2910. StencilType *pStencilData = NULL;
  2911. HCACHEITEM hStencil;
  2912. if (m_spStencilCache->LookupStencil(szName, &hStencil) != S_OK)
  2913. return NULL;
  2914. m_spStencilCache->GetStencil(hStencil, reinterpret_cast<void **>(&pStencilData));
  2915. return pStencilData;
  2916. }
  2917. void FreeCacheStencil(StencilType* pStencilData) throw()
  2918. {
  2919. CComPtr<IMemoryCacheClient> spCacheClient;
  2920. if (m_spStencilCache->QueryInterface(__uuidof(IMemoryCacheClient), (void **) &spCacheClient) == S_OK)
  2921. spCacheClient->Free(pStencilData);
  2922. }
  2923. HTTP_CODE GetHandlerOffset(LPCSTR szHandlerName, DWORD* pdwOffset) throw()
  2924. {
  2925. if (!pdwOffset)
  2926. return HTTP_FAIL;
  2927. mapType::CPair *p = m_Handlers.Lookup(szHandlerName);
  2928. if (p)
  2929. {
  2930. DWORD dwIndex = 0;
  2931. POSITION pos = m_Handlers.GetStartPosition();
  2932. while (pos)
  2933. {
  2934. const mapType::CPair *p1 = m_Handlers.GetNext(pos);
  2935. if (p1 == p)
  2936. {
  2937. *pdwOffset = dwIndex;
  2938. return HTTP_SUCCESS;
  2939. }
  2940. dwIndex++;
  2941. }
  2942. ATLASSERT(FALSE);
  2943. return HTTP_SUCCESS;
  2944. }
  2945. *pdwOffset = 0;
  2946. return HTTP_FAIL;
  2947. }
  2948. HTTP_CODE GetReplacementObject(DWORD dwObjOffset, ITagReplacer **ppReplacer) throw(...)
  2949. {
  2950. HRESULT hr = E_FAIL;
  2951. POSITION pos = m_Handlers.GetStartPosition();
  2952. for (DWORD dwIndex=0; dwIndex < dwObjOffset; dwIndex++)
  2953. m_Handlers.GetNext(pos);
  2954. ATLASSERT(pos != NULL);
  2955. IRequestHandler *pHandler = NULL;
  2956. pHandler = m_Handlers.GetValueAt(pos);
  2957. ATLASSERT(pHandler != NULL);
  2958. hr = pHandler->QueryInterface(__uuidof(ITagReplacer), (void**)ppReplacer);
  2959. if (hr != S_OK)
  2960. return HTTP_FAIL;
  2961. return HTTP_SUCCESS;
  2962. }
  2963. // This is where we would actually load any extra request
  2964. // handlers the HTML stencil might have parsed for us.
  2965. HTTP_CODE FinishLoadStencil(StencilType *pStencil, IHttpRequestLookup * pLookup = NULL) throw(...)
  2966. {
  2967. THandler *pT = static_cast<THandler *>(this);
  2968. ATLASSERT(pStencil);
  2969. if (!pStencil)
  2970. return HTTP_ERROR(500, ISE_SUBERR_UNEXPECTED); // unexpected condition
  2971. m_pLoadedStencil = pStencil;
  2972. //load extra handlers if there are any
  2973. StencilType::mapType *pExtraHandlersMap =
  2974. pStencil->GetExtraHandlers();
  2975. if (pExtraHandlersMap)
  2976. {
  2977. POSITION pos = pExtraHandlersMap->GetStartPosition();
  2978. CStringA name;
  2979. CStringPair path;
  2980. IRequestHandler *pHandler;
  2981. HINSTANCE hInstHandler;
  2982. while(pos)
  2983. {
  2984. pExtraHandlersMap->GetNextAssoc(pos, name, path);
  2985. pHandler = NULL;
  2986. hInstHandler = NULL;
  2987. HTTP_CODE hcErr = pT->m_spExtension->LoadRequestHandler(path.strDllPath, path.strHandlerName,
  2988. pT->m_spServerContext,
  2989. &hInstHandler,
  2990. &pHandler);
  2991. if (!hcErr)
  2992. {
  2993. _ATLTRY
  2994. {
  2995. //map the name to the pointer to request handler
  2996. m_Handlers.SetAt(name, pHandler);
  2997. //store HINSTANCE of handler
  2998. m_hInstHandlers.Add(hInstHandler);
  2999. }
  3000. _ATLCATCHALL()
  3001. {
  3002. return HTTP_FAIL;
  3003. }
  3004. if (pLookup)
  3005. {
  3006. hcErr = pHandler->InitializeChild(&m_RequestInfo, pT->m_spServiceProvider, pLookup);
  3007. if (hcErr != HTTP_SUCCESS)
  3008. return hcErr;
  3009. }
  3010. }
  3011. else
  3012. return hcErr;
  3013. }
  3014. }
  3015. return HTTP_SUCCESS;
  3016. }
  3017. }; // class CHtmlTagReplacer
  3018. // CRequestHandlerT
  3019. // This is the base class for all user request handlers. This class implements
  3020. // the IReplacementHandler interface whose methods will be called to render HTML
  3021. // into a stream. The stream will be returned as the HTTP response upon completion
  3022. // of the HTTP request.
  3023. template < class THandler,
  3024. class ThreadModel=CComSingleThreadModel,
  3025. class TagReplacerType=CHtmlTagReplacer<THandler>
  3026. >
  3027. class CRequestHandlerT :
  3028. public TagReplacerType,
  3029. public CComObjectRootEx<ThreadModel>,
  3030. public IRequestHandlerImpl<THandler>
  3031. {
  3032. protected:
  3033. CStencilState m_state;
  3034. CComObjectStackEx<CIDServerContext> m_SafeSrvCtx;
  3035. typedef CRequestHandlerT<THandler, ThreadModel, TagReplacerType> _requestHandler;
  3036. public:
  3037. BEGIN_COM_MAP(_requestHandler)
  3038. COM_INTERFACE_ENTRY(IRequestHandler)
  3039. COM_INTERFACE_ENTRY(ITagReplacer)
  3040. END_COM_MAP()
  3041. // public CRequestHandlerT members
  3042. CHttpResponse m_HttpResponse;
  3043. CHttpRequest m_HttpRequest;
  3044. ATLSRV_REQUESTTYPE m_dwRequestType;
  3045. AtlServerRequest* m_pRequestInfo;
  3046. CRequestHandlerT() throw()
  3047. {
  3048. m_hInstHandler = NULL;
  3049. m_dwAsyncFlags = 0;
  3050. m_pRequestInfo = NULL;
  3051. }
  3052. ~CRequestHandlerT() throw()
  3053. {
  3054. FreeHandlers(); // free handlers held by CTagReplacer
  3055. }
  3056. void ClearResponse() throw()
  3057. {
  3058. m_HttpResponse.ClearResponse();
  3059. }
  3060. // Where user initialization should take place
  3061. HTTP_CODE ValidateAndExchange() throw()
  3062. {
  3063. return HTTP_SUCCESS; // continue processing request
  3064. }
  3065. // Where user Uninitialization should take place
  3066. HTTP_CODE Uninitialize(HTTP_CODE hcError) throw()
  3067. {
  3068. return hcError;
  3069. }
  3070. HTTP_CODE InitializeInternal(AtlServerRequest *pRequestInfo, IServiceProvider *pProvider) throw()
  3071. {
  3072. // Initialize our internal references to required services
  3073. m_pRequestInfo = pRequestInfo;
  3074. m_state.pParentInfo = pRequestInfo;
  3075. m_hInstHandler = pRequestInfo->hInstDll;
  3076. m_spServerContext = pRequestInfo->pServerContext;
  3077. m_spServiceProvider = pProvider;
  3078. return HTTP_SUCCESS;
  3079. }
  3080. HTTP_CODE InitializeHandler(
  3081. AtlServerRequest *pRequestInfo,
  3082. IServiceProvider *pProvider) throw(...)
  3083. {
  3084. HTTP_CODE hcErr = HTTP_FAIL;
  3085. ATLASSERT(pRequestInfo);
  3086. ATLASSERT(pProvider);
  3087. THandler* pT = static_cast<THandler*>(this);
  3088. hcErr = pT->InitializeInternal(pRequestInfo, pProvider);
  3089. if (!hcErr)
  3090. {
  3091. m_HttpResponse.Initialize(m_spServerContext);
  3092. hcErr = pT->CheckValidRequest();
  3093. if (!hcErr)
  3094. {
  3095. hcErr = HTTP_FAIL;
  3096. if (m_HttpRequest.Initialize(m_spServerContext,
  3097. pT->MaxFormSize(),
  3098. pT->FormFlags()))
  3099. {
  3100. if (m_SafeSrvCtx.Initialize(&m_HttpResponse, &m_HttpRequest))
  3101. {
  3102. hcErr = TagReplacerType::Initialize(pRequestInfo, &m_SafeSrvCtx);
  3103. if (!hcErr)
  3104. {
  3105. hcErr = pT->ValidateAndExchange();
  3106. }
  3107. }
  3108. }
  3109. }
  3110. }
  3111. return hcErr;
  3112. }
  3113. HTTP_CODE InitializeChild(
  3114. AtlServerRequest *pRequestInfo,
  3115. IServiceProvider *pProvider,
  3116. IHttpRequestLookup *pRequestLookup) throw(...)
  3117. {
  3118. ATLASSERT(pRequestInfo);
  3119. ATLASSERT(pProvider);
  3120. THandler *pT = static_cast<THandler*>(this);
  3121. HTTP_CODE hcErr = pT->InitializeInternal(pRequestInfo, pProvider);
  3122. if (hcErr)
  3123. return hcErr;
  3124. if (pRequestLookup)
  3125. {
  3126. // initialize with the pRequestLookup
  3127. m_HttpResponse.Initialize(pRequestLookup);
  3128. // REVIEW: Initialize with the IHttpServerContext if it exists
  3129. // the only time this is different than the previous call to
  3130. // initialize is if the user passes a different IHttpServerContext
  3131. // in pRequestInfo than the one extracted from pRequestLookup.
  3132. if (m_spServerContext)
  3133. m_HttpResponse.Initialize(m_spServerContext);
  3134. hcErr = pT->CheckValidRequest();
  3135. if (hcErr)
  3136. return hcErr;
  3137. // initialize with the pRequestLookup to chain query parameters
  3138. m_HttpRequest.Initialize(pRequestLookup);
  3139. // initialize with the m_spServerContext to get additional query params
  3140. // if they exist.
  3141. if (m_spServerContext)
  3142. m_HttpRequest.Initialize(m_spServerContext);
  3143. }
  3144. m_HttpResponse.SetBufferOutput(false); // child cannot buffer
  3145. // initialize the safe server context
  3146. // REVIEW: necessary?
  3147. if (!m_SafeSrvCtx.Initialize(&m_HttpResponse, &m_HttpRequest))
  3148. return HTTP_FAIL;
  3149. hcErr = TagReplacerType::Initialize(pRequestInfo, &m_SafeSrvCtx);
  3150. if (hcErr)
  3151. return hcErr;
  3152. return pT->ValidateAndExchange();
  3153. }
  3154. // HandleRequest is called to perform default processing of HTTP requests. Users
  3155. // can override this function in their derived classes if they need to perform
  3156. // specific initialization prior to processing this request or want to change the
  3157. // way the request is processed.
  3158. HTTP_CODE HandleRequest(
  3159. AtlServerRequest *pRequestInfo,
  3160. IServiceProvider* /*pServiceProvider*/) throw(...)
  3161. {
  3162. ATLASSERT(pRequestInfo);
  3163. THandler *pT = static_cast<THandler *>(this);
  3164. HTTP_CODE hcErr = HTTP_SUCCESS;
  3165. if (pRequestInfo->dwRequestState == ATLSRV_STATE_BEGIN)
  3166. {
  3167. m_dwRequestType = pRequestInfo->dwRequestType;
  3168. if (pRequestInfo->dwRequestType==ATLSRV_REQUEST_STENCIL)
  3169. {
  3170. LPCSTR szFileName = pRequestInfo->pServerContext->GetScriptPathTranslated();
  3171. hcErr = HTTP_FAIL;
  3172. if (szFileName)
  3173. hcErr = pT->LoadStencil(szFileName, static_cast<IHttpRequestLookup *>(&m_HttpRequest));
  3174. }
  3175. }
  3176. else if (pRequestInfo->dwRequestState == ATLSRV_STATE_CONTINUE)
  3177. m_HttpResponse.ClearContent();
  3178. #ifdef ATL_DEBUG_STENCILS
  3179. if (m_pLoadedStencil && !m_pLoadedStencil->ParseSuccessful())
  3180. {
  3181. // An error or series of errors occurred in parsing the stencil
  3182. m_pLoadedStencil->RenderErrors(static_cast<IWriteStream*>(&m_HttpResponse));
  3183. }
  3184. #endif
  3185. if (hcErr == HTTP_SUCCESS && m_pLoadedStencil)
  3186. {
  3187. // if anything other than HTTP_SUCCESS is returned during
  3188. // the rendering of replacement tags, we return that value
  3189. // here.
  3190. hcErr = pT->RenderStencil(static_cast<IWriteStream*>(&m_HttpResponse), &m_state);
  3191. if (hcErr == HTTP_SUCCESS && !m_HttpResponse.Flush(TRUE))
  3192. hcErr = HTTP_FAIL;
  3193. }
  3194. if (IsAsyncFlushStatus(hcErr))
  3195. {
  3196. pRequestInfo->pszBuffer = LPCSTR(m_HttpResponse.m_strContent);
  3197. pRequestInfo->dwBufferLen = m_HttpResponse.m_strContent.GetLength();
  3198. }
  3199. if (pRequestInfo->dwRequestState == ATLSRV_STATE_BEGIN || IsAsyncDoneStatus(hcErr))
  3200. return pT->Uninitialize(hcErr);
  3201. else if (!IsAsyncStatus(hcErr))
  3202. m_HttpResponse.ClearContent();
  3203. return hcErr;
  3204. }
  3205. HTTP_CODE ServerTransferRequest(LPCSTR szRequest, bool bContinueAfterTransfer=false,
  3206. int nCodePage = 0, void *pState = NULL) throw(...)
  3207. {
  3208. return m_spExtension->TransferRequest(
  3209. m_pRequestInfo,
  3210. m_spServiceProvider,
  3211. static_cast<IWriteStream*>(&m_HttpResponse),
  3212. static_cast<IHttpRequestLookup*>(&m_HttpRequest),
  3213. szRequest,
  3214. nCodePage == 0 ? m_nCodePage : nCodePage,
  3215. bContinueAfterTransfer,
  3216. pState);
  3217. }
  3218. inline DWORD MaxFormSize() throw()
  3219. {
  3220. return DEFAULT_MAX_FORM_SIZE;
  3221. }
  3222. inline DWORD FormFlags() throw()
  3223. {
  3224. return ATL_FORM_FLAG_IGNORE_FILES;
  3225. }
  3226. // Override this function to check if the request
  3227. // is valid. This function is called after m_HttpResponse
  3228. // has been initialized, so you can use it if you need
  3229. // to return an error to the client. This is also a
  3230. // good place to initialize any internal class data needed
  3231. // to handle the request. CRequestHandlerT::CheckValidRequest
  3232. // is called after CRequestHandlerT::InitializeInternal is
  3233. // called, so your override of this method will have access to
  3234. // m_pRequestInfo (this request's AtlServerRequest structure),
  3235. // m_hInstHandler (the HINSTANCE of this handler dll),
  3236. // m_spServerContext (the IHttpServerContext interface for this request),
  3237. // m_spServiceProvider (the IServiceProvider interface for this request).
  3238. // You should call CRequestHandlerT::CheckValidRequest in your override
  3239. // if you override this function.
  3240. //
  3241. // Note that m_HttpRequest has not been initialized, so
  3242. // you cannot use it. This function is intended to
  3243. // do simple checking throught IHttpServerContext to avoid
  3244. // expensive initialization of m_HttpRequest.
  3245. HTTP_CODE CheckValidRequest() throw()
  3246. {
  3247. LPCSTR szMethod = NULL;
  3248. ATLASSERT(m_pRequestInfo);
  3249. szMethod = m_pRequestInfo->pServerContext->GetRequestMethod();
  3250. if (strcmp(szMethod, "GET") && strcmp(szMethod, "POST") && strcmp(szMethod, "HEAD"))
  3251. return HTTP_NOT_IMPLEMENTED;
  3252. return HTTP_SUCCESS;
  3253. }
  3254. HRESULT GetContext(REFIID riid, void** ppv) throw()
  3255. {
  3256. if (!ppv)
  3257. return E_POINTER;
  3258. if (InlineIsEqualGUID(riid, __uuidof(IHttpServerContext)))
  3259. {
  3260. return m_spServerContext.CopyTo((IHttpServerContext **)ppv);
  3261. }
  3262. if (InlineIsEqualGUID(riid, __uuidof(IHttpRequestLookup)))
  3263. {
  3264. *ppv = static_cast<IHttpRequestLookup*>(&m_HttpRequest);
  3265. m_HttpRequest.AddRef();
  3266. return S_OK;
  3267. }
  3268. if (InlineIsEqualGUID(riid, __uuidof(IServiceProvider)))
  3269. {
  3270. *ppv = m_spServiceProvider;
  3271. m_spServiceProvider.p->AddRef();
  3272. return S_OK;
  3273. }
  3274. return E_NOINTERFACE;
  3275. }
  3276. template <typename Interface>
  3277. HRESULT GetContext(Interface** ppInterface) throw()
  3278. {
  3279. return GetContext(__uuidof(Interface), reinterpret_cast<void**>(ppInterface));
  3280. }
  3281. }; // class CRequestHandlerT
  3282. } // namespace ATL
  3283. #pragma warning( pop )
  3284. #endif // __ATLSTENCIL_H__