1
0

isapi.cpp 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298
  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10. // This module is unique -- no need for PCH
  11. #include <limits.h>
  12. #ifdef __BORLANDC__
  13. # include <afx.h>
  14. # ifdef _AFXDLL
  15. # include <afxwin.h>
  16. # include <afxdb.h>
  17. # endif
  18. #else
  19. # ifdef _AFXDLL
  20. # include <afx.h>
  21. # include <afxwin.h>
  22. # include <afxdb.h>
  23. # include <afxpriv.h>
  24. # endif
  25. #endif
  26. #include <afxisapi.h>
  27. #include <afxres.h>
  28. #include <stdio.h>
  29. #include <malloc.h>
  30. #include "dispimpl.h"
  31. ///////////////////////////////////////////////////////////////////////
  32. // Globals
  33. // pointers to single global server and filter objects
  34. static CHttpServer* pServer = NULL;
  35. static CHttpFilter* pFilter = NULL;
  36. // stock server extension strings
  37. static const TCHAR szGet[] = _T("GET");
  38. static const TCHAR szPost[] = _T("POST");
  39. static const TCHAR szDecimalFormat[] = _T("%d");
  40. static const TCHAR szFloatFormat[] = _T("%f");
  41. // stock HTML tags
  42. static const TCHAR szContentType[] = _T("Content-Type: text/html\r\n");
  43. static const TCHAR szEndBody[] = _T("</body></html>");
  44. static const TCHAR szStartTitle[] = _T("<html><head><title>");
  45. static const TCHAR szEndTitle[] = _T("</title></head><body>");
  46. static const TCHAR szDefaultTitle[] = _T("Default MFC Web Server Extension");
  47. // error texts
  48. // these aren't localized as they are part of the HTTP spec
  49. typedef struct _httpstatinfo {
  50. DWORD dwCode;
  51. LPCTSTR pstrString;
  52. } HTTPStatusInfo;
  53. static HTTPStatusInfo statusStrings[] = {
  54. { HTTP_STATUS_OK, _T("OK") },
  55. { HTTP_STATUS_CREATED, _T("Created") },
  56. { HTTP_STATUS_ACCEPTED, _T("Accepted") },
  57. { HTTP_STATUS_NO_CONTENT, _T("No Content") },
  58. { HTTP_STATUS_TEMP_REDIRECT, _T("Moved Temporarily") },
  59. { HTTP_STATUS_REDIRECT, _T("Moved Permanently") },
  60. { HTTP_STATUS_NOT_MODIFIED, _T("Not Modified") },
  61. { HTTP_STATUS_BAD_REQUEST, _T("Bad Request") },
  62. { HTTP_STATUS_AUTH_REQUIRED, _T("Unauthorized") },
  63. { HTTP_STATUS_FORBIDDEN, _T("Forbidden") },
  64. { HTTP_STATUS_NOT_FOUND, _T("Not Found") },
  65. { HTTP_STATUS_SERVER_ERROR, _T("Internal Server Error") },
  66. { HTTP_STATUS_NOT_IMPLEMENTED, _T("Not Implemented") },
  67. { HTTP_STATUS_BAD_GATEWAY, _T("Bad Gateway") },
  68. { HTTP_STATUS_SERVICE_NA, _T("Service Unavailable") },
  69. { 0, NULL }
  70. };
  71. /////////////////////////////////////////////////////////////////////////////
  72. // Root of all parse maps
  73. const AFXIS_DATADEF AFX_PARSEMAP CHttpServer::parseMap =
  74. {
  75. &CHttpServer::GetNumMapEntries,
  76. #ifdef _AFXDLL
  77. &CHttpServer::_GetBaseParseMap,
  78. #else
  79. NULL,
  80. #endif
  81. &CHttpServer::_parseEntries[0],
  82. };
  83. AFX_PARSEMAP_ENTRY CHttpServer::_parseEntries[] =
  84. {
  85. { NULL, NULL, NULL } // nothing here
  86. };
  87. #ifdef _AFXDLL
  88. const AFX_PARSEMAP* CHttpServer::_GetBaseParseMap()
  89. {
  90. return NULL;
  91. }
  92. #endif
  93. UINT PASCAL CHttpServer::GetNumMapEntries()
  94. {
  95. return 0;
  96. }
  97. const AFX_PARSEMAP* CHttpServer::GetParseMap() const
  98. {
  99. return NULL;
  100. }
  101. AFX_PARSEMAP::~AFX_PARSEMAP()
  102. {
  103. // walk through parse map to find any dying parsed parameter entries
  104. UINT iEntry;
  105. UINT cEntries = (*pfnGetNumMapEntries)();
  106. AFX_PARSEMAP_ENTRY* pCurrent = (AFX_PARSEMAP_ENTRY*) lpEntries;
  107. for (iEntry = 0; iEntry < cEntries; iEntry++, pCurrent++)
  108. {
  109. if (pCurrent->pfn == NULL)
  110. {
  111. delete (AFX_PARSEMAP_ENTRY_PARAMS*) pCurrent->pszFnName;
  112. pCurrent->pszFnName = NULL;
  113. free(pCurrent->pszParamInfo);
  114. pCurrent->pszParamInfo = NULL;
  115. }
  116. }
  117. }
  118. AFX_PARSEMAP_ENTRY_PARAMS::~AFX_PARSEMAP_ENTRY_PARAMS()
  119. {
  120. delete [] ppszInfo;
  121. delete [] ppszDefaults;
  122. delete [] ppszValues;
  123. }
  124. ///////////////////////////////////////////////////////////////////////
  125. // Entry points for HTTP Server Extensions
  126. extern "C" DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
  127. {
  128. #ifdef _AFXDLL
  129. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  130. #endif
  131. DWORD dwRet;
  132. ISAPIASSERT(pServer != NULL);
  133. if (pServer == NULL)
  134. {
  135. dwRet = HSE_STATUS_ERROR;
  136. pECB->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
  137. }
  138. else
  139. dwRet = pServer->HttpExtensionProc(pECB);
  140. return dwRet;
  141. }
  142. extern "C" BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
  143. {
  144. #ifdef _AFXDLL
  145. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  146. #endif
  147. BOOL bRet;
  148. ISAPIASSERT(pServer != NULL);
  149. if (pServer == NULL)
  150. bRet = FALSE;
  151. else
  152. bRet = pServer->GetExtensionVersion(pVer);
  153. return bRet;
  154. }
  155. extern "C" BOOL WINAPI TerminateExtension(DWORD dwFlags)
  156. {
  157. #ifdef _AFXDLL
  158. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  159. #endif
  160. if (pServer == NULL)
  161. return TRUE;
  162. return pServer->TerminateExtension(dwFlags);
  163. }
  164. ///////////////////////////////////////////////////////////////////////
  165. // CHttpAsyncContext implementation
  166. class CHttpAsyncContext
  167. {
  168. public:
  169. CHttpAsyncContext(HANDLE hFile, LPVOID pvHeader, DWORD dwHeaderLen,
  170. LPVOID pvTail, DWORD dwTailLen);
  171. virtual ~CHttpAsyncContext();
  172. protected:
  173. LPVOID m_pvHeader;
  174. DWORD m_dwHeaderLen;
  175. LPVOID m_pvTail;
  176. DWORD m_dwTailLen;
  177. HANDLE m_hFile;
  178. };
  179. CHttpAsyncContext::CHttpAsyncContext(HANDLE hFile, LPVOID pvHeader,
  180. DWORD dwHeaderLen, LPVOID pvTail, DWORD dwTailLen)
  181. : m_hFile(hFile)
  182. {
  183. if (pvHeader == NULL || dwHeaderLen == 0)
  184. {
  185. m_pvHeader = NULL;
  186. dwHeaderLen = 0;
  187. }
  188. else
  189. {
  190. m_pvHeader = new BYTE[dwHeaderLen+1];
  191. memcpy(m_pvHeader, pvHeader, dwHeaderLen);
  192. m_dwHeaderLen = dwHeaderLen;
  193. }
  194. if (pvTail == NULL || dwTailLen == 0)
  195. {
  196. m_pvTail = NULL;
  197. dwTailLen = 0;
  198. }
  199. else
  200. {
  201. m_pvTail = new BYTE[dwTailLen+1];
  202. memcpy(m_pvTail, pvTail, dwTailLen);
  203. m_dwTailLen = dwTailLen;
  204. }
  205. }
  206. CHttpAsyncContext::~CHttpAsyncContext()
  207. {
  208. if (m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
  209. CloseHandle(m_hFile);
  210. delete [] m_pvTail;
  211. delete [] m_pvHeader;
  212. }
  213. ///////////////////////////////////////////////////////////////////////
  214. // CHttpServerContext implementation
  215. void CHttpServerContext::Reset()
  216. {
  217. #ifdef _DEBUG
  218. m_dwOldEndOfHeaders = 0;
  219. #endif
  220. m_pStream->Reset();
  221. }
  222. DWORD CHttpServerContext::SetChunkSize(DWORD dwNewSize)
  223. {
  224. DWORD dwReturn = m_dwChunkSize;
  225. m_dwChunkSize = dwNewSize;
  226. return dwReturn;
  227. }
  228. DWORD CHttpServerContext::GetChunkSize() const
  229. {
  230. return m_dwChunkSize;
  231. }
  232. VOID WINAPI AfxIOCallback(EXTENSION_CONTROL_BLOCK* pECB,
  233. PVOID pvContext, DWORD /* cbIO */, DWORD /* dwError */)
  234. {
  235. if (!pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, NULL, NULL, NULL))
  236. ISAPITRACE("HttpExtensionProc io callback error\n");
  237. CHttpAsyncContext* pInfo = (CHttpAsyncContext*) pvContext;
  238. delete pInfo;
  239. }
  240. BOOL CHttpServerContext::TransmitFile(HANDLE hFile,
  241. DWORD dwFlags /* = HSE_IO_DISCONNECT_AFTER_SEND */,
  242. LPVOID pvHeader /* = NULL */, DWORD dwHeaderLen /* = 0 */,
  243. LPVOID pvTail /* = NULL */, DWORD dwTailLen /* = 0 */)
  244. {
  245. if (hFile == INVALID_HANDLE_VALUE)
  246. return FALSE;
  247. ISAPIASSERT(dwHeaderLen == 0 || pvHeader != NULL);
  248. ISAPIASSERT(dwTailLen == 0 || pvTail != NULL);
  249. if (dwTailLen == 0 && pvTail != NULL)
  250. dwTailLen = lstrlen((LPCTSTR) pvTail);
  251. if (dwHeaderLen == 0 && pvHeader != NULL)
  252. dwHeaderLen = lstrlen((LPCTSTR) pvHeader);
  253. CHttpAsyncContext* pInfo =
  254. new CHttpAsyncContext(hFile, pvHeader, dwTailLen, pvTail, dwHeaderLen);
  255. HSE_TF_INFO info;
  256. info.pszStatusCode = NULL;
  257. info.hFile = hFile;
  258. info.dwFlags = dwFlags;
  259. info.BytesToWrite = 0;
  260. info.Offset = 0;
  261. info.pfnHseIO = AfxIOCallback;
  262. info.pContext = pInfo;
  263. info.pHead = pvHeader;
  264. info.HeadLength = dwHeaderLen;
  265. info.pTail = pvTail;
  266. info.TailLength = dwTailLen;
  267. BOOL bResult = ServerSupportFunction(HSE_REQ_TRANSMIT_FILE, &info, 0, 0);
  268. if (bResult)
  269. {
  270. m_dwStatusCode = HSE_STATUS_PENDING;
  271. m_bSendHeaders = FALSE;
  272. }
  273. else
  274. delete pInfo;
  275. return bResult;
  276. }
  277. ///////////////////////////////////////////////////////////////////////
  278. // CHttpServer implementation
  279. BOOL CHttpServer::TerminateExtension(DWORD /* dwFlags */)
  280. {
  281. // okay to unload at any time, by default
  282. return TRUE;
  283. }
  284. LPTSTR CHttpServer::GetQuery(CHttpServerContext* pCtxt, LPTSTR lpszQuery)
  285. {
  286. // If the request is a POST, get all of the data. First get what's
  287. // already available, then read any additional data via the
  288. // ReadClient() call.
  289. memcpy(lpszQuery, (LPCTSTR) pCtxt->m_pECB->lpbData, pCtxt->m_pECB->cbAvailable);
  290. lpszQuery[pCtxt->m_pECB->cbAvailable] = '\0';
  291. if (pCtxt->m_pECB->cbAvailable < pCtxt->m_pECB->cbTotalBytes)
  292. {
  293. LPCTSTR pstrTarget = lpszQuery + pCtxt->m_pECB->cbAvailable;
  294. DWORD cbRemaining = pCtxt->m_pECB->cbTotalBytes - pCtxt->m_pECB->cbAvailable;
  295. DWORD cbRead;
  296. while (cbRemaining > 0)
  297. {
  298. cbRead = cbRemaining;
  299. if (!pCtxt->ReadClient((LPVOID) pstrTarget, &cbRead))
  300. {
  301. ISAPITRACE("Error: only %d of %d bytes read!\n",
  302. pCtxt->m_pECB->cbTotalBytes - cbRemaining,
  303. pCtxt->m_pECB->cbTotalBytes);
  304. return NULL;
  305. }
  306. if (cbRead == 0)
  307. break;
  308. pstrTarget += cbRead;
  309. cbRemaining -= cbRead;
  310. }
  311. }
  312. pCtxt->m_dwBytesReceived = pCtxt->m_pECB->cbTotalBytes;
  313. return lpszQuery;
  314. }
  315. BOOL CHttpServer::OnWriteBody(CHttpServerContext* pCtxt, LPBYTE pbContent,
  316. DWORD dwSize, DWORD dwReserved /* = 0 */)
  317. {
  318. BOOL bRetVal;
  319. if (pCtxt->m_dwChunkSize == 0)
  320. bRetVal = pCtxt->WriteClient(pbContent, &dwSize, dwReserved);
  321. else
  322. {
  323. LPBYTE pbStart = pbContent;
  324. DWORD dwBytesLeft = dwSize;
  325. bRetVal = TRUE;
  326. while (bRetVal && (dwBytesLeft > 0))
  327. {
  328. DWORD dwThisChunk = min(dwBytesLeft, pCtxt->m_dwChunkSize);
  329. bRetVal = pCtxt->WriteClient(pbStart, &dwThisChunk, dwReserved);
  330. pbStart += dwThisChunk;
  331. dwBytesLeft -= dwThisChunk;
  332. }
  333. }
  334. return bRetVal;
  335. }
  336. DWORD CHttpServer::HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
  337. {
  338. DWORD dwRet = HSE_STATUS_SUCCESS;
  339. LPTSTR pszPostBuffer = NULL;
  340. LPTSTR pszQuery;
  341. LPTSTR pszCommand = NULL;
  342. int nMethodRet;
  343. LPTSTR pstrLastChar;
  344. DWORD cbStream = 0;
  345. BYTE* pbStream = NULL;
  346. CHttpServerContext ctxtCall(pECB);
  347. pECB->dwHttpStatusCode = 0;
  348. ISAPIASSERT(NULL != pServer);
  349. if (pServer == NULL)
  350. {
  351. dwRet = HSE_STATUS_ERROR;
  352. goto CleanUp;
  353. }
  354. // get the query
  355. if (lstrcmpi(pECB->lpszMethod, szGet) == 0)
  356. {
  357. pszQuery = pECB->lpszQueryString;
  358. ctxtCall.m_dwBytesReceived = lstrlen(pszQuery);
  359. }
  360. else if (lstrcmpi(pECB->lpszMethod, szPost) == 0)
  361. {
  362. pszCommand = pECB->lpszQueryString;
  363. pszPostBuffer = new TCHAR[pECB->cbTotalBytes + 1];
  364. pszQuery = GetQuery(&ctxtCall, pszPostBuffer);
  365. if (pszQuery == NULL)
  366. {
  367. dwRet = HSE_STATUS_ERROR;
  368. goto CleanUp;
  369. }
  370. }
  371. else
  372. {
  373. ISAPITRACE1("Error: Unrecognized method: %s\n", pECB->lpszMethod);
  374. dwRet = HSE_STATUS_ERROR;
  375. goto CleanUp;
  376. }
  377. // trim junk that some browsers put at the very end
  378. pstrLastChar = pszQuery + ctxtCall.m_dwBytesReceived -1;
  379. while ((*pstrLastChar == ' ' || *pstrLastChar == '\n' ||
  380. *pstrLastChar == '\r') && pstrLastChar > pszQuery)
  381. {
  382. *pstrLastChar-- = '\0';
  383. }
  384. // do something about it
  385. if (!pServer->InitInstance(&ctxtCall))
  386. dwRet = HSE_STATUS_ERROR;
  387. else
  388. {
  389. pECB->dwHttpStatusCode = HTTP_STATUS_OK;
  390. try {
  391. nMethodRet = pServer->CallFunction(&ctxtCall, pszQuery, pszCommand);
  392. }
  393. catch (...)
  394. {
  395. ISAPITRACE1("Error: command %s caused an unhandled exception!\n",
  396. pszQuery);
  397. nMethodRet = callNoStackSpace;
  398. }
  399. // was an error caused by trying to dispatch?
  400. if (nMethodRet != callOK && pECB->dwHttpStatusCode == HTTP_STATUS_OK)
  401. {
  402. dwRet = HSE_STATUS_ERROR;
  403. switch (nMethodRet)
  404. {
  405. case callNoStream:
  406. pECB->dwHttpStatusCode = HTTP_STATUS_NO_CONTENT;
  407. break;
  408. case callParamRequired:
  409. case callBadParamCount:
  410. case callBadParam:
  411. pECB->dwHttpStatusCode = HTTP_STATUS_BAD_REQUEST;
  412. break;
  413. case callBadCommand:
  414. pECB->dwHttpStatusCode = HTTP_STATUS_NOT_IMPLEMENTED;
  415. break;
  416. case callNoStackSpace:
  417. default:
  418. pECB->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
  419. break;
  420. }
  421. }
  422. // if there was no error or the user said they handled
  423. // the error, prepare to spit out the generated HTML
  424. if (nMethodRet == callOK ||
  425. OnParseError(&ctxtCall, nMethodRet))
  426. {
  427. cbStream = ctxtCall.m_pStream->GetStreamSize();
  428. pbStream = ctxtCall.m_pStream->Detach();
  429. }
  430. }
  431. CleanUp:
  432. // if there was an error, return an appropriate status
  433. TCHAR szResponse[64];
  434. BuildStatusCode(szResponse, pECB->dwHttpStatusCode);
  435. DWORD dwSize = cbStream - ctxtCall.m_dwEndOfHeaders;
  436. LPBYTE pbContent = NULL;
  437. BYTE cSaved = 0;
  438. if (pbStream != NULL && ctxtCall.m_bSendHeaders)
  439. {
  440. cSaved = pbStream[ctxtCall.m_dwEndOfHeaders];
  441. pbStream[ctxtCall.m_dwEndOfHeaders] = '\0';
  442. pbContent = &pbStream[ctxtCall.m_dwEndOfHeaders];
  443. }
  444. if (ctxtCall.m_bSendHeaders &&
  445. !ctxtCall.ServerSupportFunction(HSE_REQ_SEND_RESPONSE_HEADER,
  446. szResponse, 0, (LPDWORD) pbStream) &&
  447. ::GetLastError() != 10054) // WSAECONNRESET
  448. {
  449. pECB->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
  450. dwRet = HSE_STATUS_ERROR;
  451. #ifdef _DEBUG
  452. DWORD dwCause = ::GetLastError();
  453. ISAPITRACE1("Error: Unable to write headers: 0x%8.8X!\n", dwCause);
  454. #endif
  455. }
  456. else
  457. {
  458. if (pbContent != NULL)
  459. {
  460. BOOL bWorked = TRUE;
  461. // write a newline to separate content from headers
  462. if (ctxtCall.m_bSendHeaders)
  463. {
  464. *pbContent = cSaved;
  465. DWORD dwNewLineSize = 2;
  466. bWorked = ctxtCall.WriteClient(_T("\r\n"), &dwNewLineSize, 0);
  467. }
  468. if (!bWorked || !OnWriteBody(&ctxtCall, pbContent, dwSize))
  469. {
  470. dwRet = HSE_STATUS_ERROR;
  471. pECB->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
  472. #ifdef _DEBUG
  473. DWORD dwCause = ::GetLastError();
  474. ISAPITRACE1("Error: Unable to write content body: 0x%8.8X!\n",
  475. dwCause);
  476. #endif
  477. }
  478. }
  479. else
  480. ISAPITRACE("Error: No body content!\n");
  481. }
  482. if (pbStream != NULL)
  483. ctxtCall.m_pStream->Free(pbStream);
  484. if (ctxtCall.m_dwStatusCode != DWORD(-1))
  485. dwRet = ctxtCall.m_dwStatusCode;
  486. if (dwRet == HSE_STATUS_SUCCESS)
  487. pECB->dwHttpStatusCode = HTTP_STATUS_OK;
  488. if (pszPostBuffer != NULL)
  489. delete [] pszPostBuffer;
  490. return dwRet;
  491. }
  492. void CHttpServer::BuildStatusCode(LPTSTR pszResponse, DWORD dwCode)
  493. {
  494. ISAPIASSERT(pszResponse != NULL);
  495. HTTPStatusInfo* pInfo = statusStrings;
  496. while (pInfo->pstrString != NULL)
  497. {
  498. if (dwCode == pInfo->dwCode)
  499. break;
  500. pInfo++;
  501. }
  502. if (pInfo->pstrString != NULL)
  503. wsprintf(pszResponse, _T("%d %s"), dwCode, pInfo->pstrString);
  504. else
  505. {
  506. ISAPIASSERT(dwCode != HTTP_STATUS_OK);
  507. ISAPITRACE1("Warning: Nonstandard status code %d\n", dwCode);
  508. BuildStatusCode(pszResponse, HTTP_STATUS_OK);
  509. }
  510. }
  511. BOOL CHttpServer::GetExtensionVersion(HSE_VERSION_INFO *pVer)
  512. {
  513. pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
  514. pVer->lpszExtensionDesc[0] = '\0';
  515. return TRUE;
  516. }
  517. CHttpServer::CHttpServer(TCHAR cDelimiter /* = '&' */)
  518. : m_cTokenDelimiter(cDelimiter)
  519. {
  520. ISAPIASSERT(pServer == NULL); // only one server instance
  521. pServer = this;
  522. // allocate our critical section directly to avoid bogus traces
  523. m_pCritSec = (LPCRITICAL_SECTION)
  524. LocalAlloc(LPTR, sizeof(CRITICAL_SECTION));
  525. ::InitializeCriticalSection(m_pCritSec);
  526. }
  527. CHttpServer::~CHttpServer()
  528. {
  529. if (m_pCritSec != NULL)
  530. {
  531. ::DeleteCriticalSection(m_pCritSec);
  532. LocalFree(m_pCritSec);
  533. }
  534. pServer = NULL;
  535. }
  536. BOOL CHttpServer::OnParseError(CHttpServerContext* pCtxt, int nMethodRet)
  537. {
  538. UNUSED(nMethodRet);
  539. UINT nResource = 0;
  540. if (pCtxt->m_pStream != NULL)
  541. {
  542. TCHAR szBuffer[132];
  543. TCHAR szTitle[256];
  544. TCHAR szFormat[256];
  545. LPCTSTR pszObject = NULL;
  546. switch (pCtxt->m_pECB->dwHttpStatusCode)
  547. {
  548. case HTTP_STATUS_BAD_REQUEST:
  549. nResource = AFX_IDS_HTTP_BAD_REQUEST;
  550. if (pCtxt->m_pECB->lpszQueryString)
  551. pszObject = pCtxt->m_pECB->lpszQueryString;
  552. else
  553. pszObject = pCtxt->m_pECB->lpszPathInfo;
  554. break;
  555. case HTTP_STATUS_AUTH_REQUIRED:
  556. nResource = AFX_IDS_HTTP_AUTH_REQUIRED;
  557. break;
  558. case HTTP_STATUS_FORBIDDEN:
  559. nResource = AFX_IDS_HTTP_FORBIDDEN;
  560. break;
  561. case HTTP_STATUS_NOT_FOUND:
  562. nResource = AFX_IDS_HTTP_NOT_FOUND;
  563. break;
  564. case HTTP_STATUS_SERVER_ERROR:
  565. nResource = AFX_IDS_HTTP_SERVER_ERROR;
  566. break;
  567. case HTTP_STATUS_NOT_IMPLEMENTED:
  568. nResource = AFX_IDS_HTTP_NOT_IMPLEMENTED;
  569. pszObject = pCtxt->m_pECB->lpszQueryString;
  570. break;
  571. default:
  572. nResource = AFX_IDS_HTTP_NO_TEXT;
  573. pszObject = (LPCTSTR) pCtxt->m_pECB->dwHttpStatusCode;
  574. break;
  575. }
  576. HINSTANCE hRes;
  577. hRes = AfxGetResourceHandle();
  578. #ifdef _AFXDLL
  579. if (AfxLoadString(nResource, szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0])) > 0)
  580. #else
  581. if (::LoadString(hRes, nResource, szBuffer,
  582. sizeof(szBuffer)/sizeof(szBuffer[0])) > 0)
  583. #endif
  584. {
  585. pCtxt->Reset();
  586. CHttpServer::StartContent(pCtxt);
  587. if (::LoadString(hRes, AFX_IDS_HTTP_TITLE,
  588. szTitle, sizeof(szTitle)/sizeof(szTitle[0])) > 0)
  589. {
  590. TCHAR szTitleCopy[64];
  591. wsprintf(szTitleCopy, szTitle, pCtxt->m_pECB->dwHttpStatusCode);
  592. *pCtxt << szTitleCopy;
  593. }
  594. if (pszObject != NULL)
  595. {
  596. wsprintf(szFormat, szBuffer, pszObject);
  597. *pCtxt << szFormat;
  598. }
  599. else
  600. *pCtxt << szBuffer;
  601. CHttpServer::EndContent(pCtxt);
  602. }
  603. else
  604. {
  605. ISAPITRACE1("Error: Couldn't load string %d\n", nResource);
  606. nResource = 0;
  607. }
  608. }
  609. if (nResource == 0)
  610. ISAPITRACE1("Error: Unhandled parsing error code %d\n", nMethodRet);
  611. return nResource != 0;
  612. }
  613. void CHttpServer::AddHeader(CHttpServerContext* pCtxt,
  614. LPCTSTR pszString) const
  615. {
  616. #ifdef _DEBUG
  617. // Can't call AddHeader() after writing directly to the stream.
  618. ISAPIASSERT(pCtxt->m_dwOldEndOfHeaders == pCtxt->m_pStream->GetStreamSize());
  619. #endif
  620. *pCtxt << pszString;
  621. pCtxt->m_dwEndOfHeaders = pCtxt->m_pStream->GetStreamSize();
  622. #ifdef _DEBUG
  623. pCtxt->m_dwOldEndOfHeaders = pCtxt->m_dwEndOfHeaders;
  624. #endif
  625. }
  626. void CHttpServer::StartContent(CHttpServerContext* pCtxt) const
  627. {
  628. AddHeader(pCtxt, szContentType);
  629. }
  630. void CHttpServer::WriteTitle(CHttpServerContext* pCtxt) const
  631. {
  632. *pCtxt << szStartTitle;
  633. *pCtxt << GetTitle();
  634. *pCtxt << szEndTitle;
  635. }
  636. LPCTSTR CHttpServer::GetTitle() const
  637. {
  638. return szDefaultTitle;
  639. }
  640. void CHttpServer::EndContent(CHttpServerContext* pCtxt) const
  641. {
  642. *pCtxt << szEndBody;
  643. }
  644. BOOL CHttpServer::InitInstance(CHttpServerContext*)
  645. {
  646. return TRUE;
  647. }
  648. int CHttpServer::CallFunction(CHttpServerContext* pCtxt,
  649. LPTSTR pszQuery, LPTSTR pszCommand)
  650. {
  651. int nRet;
  652. AFX_PARSEMAP_ENTRY* pParams;
  653. const AFX_PARSEMAP* pMap;
  654. const AFX_PARSEMAP_ENTRY* pFn;
  655. ISAPIASSERT(pCtxt->m_pStream == NULL);
  656. pCtxt->m_pStream = ConstructStream();
  657. if (pCtxt->m_pStream == NULL)
  658. nRet = callNoStream;
  659. else
  660. {
  661. ISAPIASSERT(pszQuery != NULL);
  662. if (pszQuery == NULL)
  663. nRet = callBadCommand;
  664. else
  665. {
  666. LPTSTR pszMethod;
  667. LPTSTR pszParams;
  668. // did the user specify a command via "MfcISAPICommand"?
  669. LPTSTR pszHiddenCommand = _tcschr(pszQuery, '=');
  670. if (pszHiddenCommand != NULL)
  671. {
  672. *pszHiddenCommand = '\0';
  673. // is it there?
  674. if (lstrcmpi(pszQuery, _T("MfcISAPICommand")) == 0)
  675. {
  676. // did they have a method, too?
  677. pszMethod = pszHiddenCommand+1;
  678. if (*pszMethod == '\0')
  679. pszParams = pszMethod;
  680. else
  681. {
  682. pszParams = _tcschr(pszMethod, m_cTokenDelimiter);
  683. if (pszParams != NULL && *pszParams != '\0')
  684. *pszParams++ = '\0';
  685. }
  686. // if we find it, we can call it
  687. pFn = LookUp(pszMethod, pMap, pParams);
  688. if (pFn != NULL)
  689. goto MakeTheCall;
  690. }
  691. // we didn't find the command, or we didn't have
  692. // "MfcISAPICommand", so we'll try and process things
  693. // normally...
  694. *pszHiddenCommand = '=';
  695. }
  696. if (pszCommand == NULL)
  697. {
  698. // got something via a GET method
  699. // is the first thing a parameter or a command?
  700. LPTSTR pszEquals;
  701. LPTSTR pszQMark;
  702. pszParams = _tcschr(pszQuery, m_cTokenDelimiter);
  703. pszQMark = _tcschr(pszQuery, '?');
  704. // Parameters start at the first delimiter
  705. if (pszParams == NULL || (pszQMark != NULL && (pszQMark < pszParams)))
  706. {
  707. pszParams = pszQMark;
  708. // if the command ends in question mark
  709. // and nothing else, ignore it
  710. if (pszQMark != NULL && pszQMark[1] == '\0')
  711. {
  712. *pszQMark = '\0';
  713. pszParams = NULL;
  714. }
  715. }
  716. // Does an equals sign show up before the first delimiter?
  717. pszEquals = _tcschr(pszQuery, '=');
  718. if (pszEquals == NULL || pszEquals > pszParams)
  719. {
  720. // It might be a command. If it isn't blank,
  721. // try and find it in the parameter map--if
  722. // we can't, then assume it is a parameter.
  723. pszMethod = pszQuery;
  724. if (*pszMethod != '\0')
  725. {
  726. TCHAR cTemp = 0;
  727. if (pszParams != NULL)
  728. {
  729. cTemp = *pszParams;
  730. *pszParams++ = '\0';
  731. }
  732. pFn = LookUp(pszMethod, pMap, pParams);
  733. if (pFn != NULL)
  734. goto MakeTheCall;
  735. if (pszParams != NULL)
  736. *--pszParams = cTemp;
  737. }
  738. }
  739. // we can be sure it's a parameter
  740. if (pszQMark == NULL || pszQMark >= pszParams)
  741. {
  742. // default command, params as supplied
  743. pszMethod = NULL;
  744. pszParams = pszQuery;
  745. }
  746. else
  747. {
  748. pszMethod = pszQuery;
  749. *pszQMark++ = '\0';
  750. pszParams = pszQMark;
  751. }
  752. }
  753. else
  754. {
  755. // with a POST, the verb arrives seperately
  756. pszMethod = pszCommand;
  757. pszParams = pszQuery;
  758. }
  759. // is it a default verb?
  760. if (pszMethod != NULL && lstrlen(pszMethod) == 0)
  761. pszMethod = NULL;
  762. // is it a useless parameter?
  763. if (pszParams != NULL && lstrlen(pszParams) == 0)
  764. pszParams = NULL;
  765. pFn = LookUp(pszMethod, pMap, pParams);
  766. MakeTheCall:
  767. if (pFn == NULL)
  768. nRet = callBadCommand;
  769. else
  770. {
  771. pCtxt->m_pStream->InitStream();
  772. nRet = CallMemberFunc(pCtxt, pFn, pParams, pszParams);
  773. }
  774. }
  775. }
  776. return nRet;
  777. }
  778. CHtmlStream* CHttpServer::ConstructStream()
  779. {
  780. return new CHtmlStream();
  781. }
  782. const AFX_PARSEMAP_ENTRY* CHttpServer::LookUp(LPCTSTR pszMethod,
  783. const AFX_PARSEMAP*& pMap, AFX_PARSEMAP_ENTRY*& pParams,
  784. AFX_PISAPICMD pCmdDefault /* = NULL */)
  785. {
  786. UINT iEntry;
  787. LPCTSTR pszFnName;
  788. const AFX_PARSEMAP* pParseMap = GetParseMap();
  789. const AFX_PARSEMAP* pBaseMap;
  790. const AFX_PARSEMAP_ENTRY* pRet = NULL;
  791. while (pParseMap != NULL && pRet == NULL)
  792. {
  793. UINT cEntries = (*pParseMap->pfnGetNumMapEntries)();
  794. const AFX_PARSEMAP_ENTRY* pCurrent = pParseMap->lpEntries;
  795. for (iEntry = 0; iEntry < cEntries && pRet == NULL; iEntry++, pCurrent++)
  796. {
  797. #ifdef _DEBUG
  798. // make sure not 2 parameter maps in a row
  799. if (pCurrent->pfn == NULL && (iEntry+1 < cEntries))
  800. ISAPIASSERT(pCurrent[1].pfn != NULL);
  801. #endif
  802. // skip parameter maps
  803. if (pCurrent->pfn == NULL)
  804. continue;
  805. pszFnName = pCurrent->pszFnName;
  806. // if the caller wants the default command, find that--
  807. // if the caller wants something specific, perform a compare
  808. // otherwise, see if we recursed to look up the default command
  809. if (pCmdDefault == NULL)
  810. {
  811. if (pszMethod == NULL && pCurrent->pszArgs == NULL)
  812. pRet = pCurrent;
  813. else if (pszMethod != NULL && pCurrent->pszArgs != NULL
  814. && lstrcmpi(pszFnName, pszMethod) == 0)
  815. pRet = pCurrent;
  816. }
  817. else if (pCurrent->pfn == pCmdDefault && pCurrent->pszArgs != NULL)
  818. pRet = pCurrent;
  819. if (pRet != NULL)
  820. {
  821. // if we need the default, recurse to find it by name
  822. if (pszMethod == NULL && pCmdDefault == NULL)
  823. return LookUp(NULL, pMap, pParams, pCurrent->pfn);
  824. // found it! see if there are parameters
  825. if (iEntry+1 >= cEntries || pCurrent[1].pfn != NULL)
  826. {
  827. pParams = NULL;
  828. pMap = NULL;
  829. }
  830. else
  831. {
  832. pParams = (AFX_PARSEMAP_ENTRY*) &(pCurrent[1]);
  833. pMap = pParseMap;
  834. }
  835. }
  836. }
  837. #ifdef _AFXDLL
  838. pBaseMap = (*pParseMap->pfnGetBaseMap)();
  839. #else
  840. pBaseMap = pParseMap->pBaseMap;
  841. #endif
  842. // catch simple mistake of BEGIN_PARSE_MAP(CMyClass, CMyClass)
  843. ISAPIASSERT(pBaseMap != pParseMap);
  844. pParseMap = pBaseMap;
  845. }
  846. // no matching entry ?
  847. if (pRet == NULL)
  848. ISAPITRACE1("Warning: no handler for command '%s'\n", pszMethod);
  849. return pRet;
  850. }
  851. UINT PASCAL CHttpServer::GetStackSize(const BYTE* pbParams)
  852. {
  853. // size of arguments on stack when pushed by value
  854. static const UINT rgnByValue[] =
  855. {
  856. sizeof(_STACK_INT), // ITS_I2
  857. sizeof(_STACK_LONG), // ITS_I4
  858. sizeof(_STACK_FLOAT), // ITS_R4
  859. sizeof(_STACK_DOUBLE), // ITS_R8
  860. sizeof(LPCTSTR), // ITS_PSTR
  861. 0, // ITS_EMPTY
  862. sizeof(LPCTSTR)+sizeof(_STACK_INT), // ITS_RAW
  863. };
  864. // sizeof 'this' pointer
  865. UINT nCount = sizeof(CHttpServer*);
  866. #ifdef _ALIGN_STACK
  867. nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  868. #endif
  869. // count arguments
  870. ISAPIASSERT(pbParams != NULL);
  871. while (*pbParams != 0 && *pbParams != IT_EMPTY)
  872. {
  873. // align if necessary
  874. // get and add appropriate byte count
  875. #ifdef _ALIGN_DOUBLES
  876. // align doubles on 8 byte for some platforms
  877. if (*pbParams == IT_R8)
  878. nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
  879. #endif
  880. // *pbParams must fit in the rgnByValue array
  881. ISAPIASSERT(*pbParams >= 1 && *pbParams <= sizeof(rgnByValue)/sizeof(UINT));
  882. nCount += rgnByValue[*pbParams-1];
  883. #ifdef _ALIGN_STACK
  884. nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
  885. #endif
  886. ++pbParams;
  887. }
  888. #if defined(_ALIGN_DOUBLES) && defined(_SHADOW_DOUBLES)
  889. // align doubles on 8 byte for some platforms
  890. nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
  891. #endif
  892. return nCount;
  893. }
  894. // indirect call helper (see OLECALL.CPP for implementation)
  895. extern "C" DWORD AFXISAPI
  896. _AfxParseCall(AFX_PISAPICMD pfn, void* pArgs, UINT nSizeArgs);
  897. // invoke standard method given IDispatch parameters/return value, etc.
  898. int CHttpServer::CallMemberFunc(CHttpServerContext* pCtxt,
  899. const AFX_PARSEMAP_ENTRY* pEntry,
  900. AFX_PARSEMAP_ENTRY* pParams, LPTSTR pszParams)
  901. {
  902. ISAPIASSERT(NULL != pEntry);
  903. AFX_PISAPICMD pFunc = pEntry->pfn;
  904. ISAPIASSERT(NULL != pFunc);
  905. int nRet = callOK;
  906. // get default function and parameters
  907. BYTE bNoParams = 0;
  908. ::EnterCriticalSection(m_pCritSec);
  909. const BYTE* pbParams = (const BYTE*)pEntry->pszArgs;
  910. if (NULL == pbParams)
  911. pbParams = &bNoParams;
  912. UINT nParams = lstrlenA((LPCSTR)pbParams);
  913. AFX_PARSEMAP_ENTRY_PARAMS *pDefaultParams = NULL;
  914. if (pParams != NULL)
  915. {
  916. if (pParams->pszFnName == NULL)
  917. nRet = ParseDefaultParams(pParams, nParams, pDefaultParams, pbParams);
  918. else
  919. pDefaultParams = (AFX_PARSEMAP_ENTRY_PARAMS*) pParams->pszFnName;
  920. }
  921. ::LeaveCriticalSection(m_pCritSec);
  922. if (nRet == callOK)
  923. {
  924. // get default function and return value information
  925. AFX_PISAPICMD pfn = pEntry->pfn;
  926. // determine size of arguments and allocate stack space
  927. // include space for our context pointer
  928. UINT nSizeArgs = GetStackSize(pbParams) + sizeof(_STACK_PTR);
  929. ISAPIASSERT(nSizeArgs != 0);
  930. if (nSizeArgs < _STACK_MIN)
  931. nSizeArgs = _STACK_MIN;
  932. BYTE* pStack = (BYTE*)_alloca(nSizeArgs + _SCRATCH_SIZE);
  933. if (pStack == NULL)
  934. {
  935. ISAPITRACE0("Error: stack overflow in CHttpServer::CallMemberFunc()!\n");
  936. return callNoStackSpace;
  937. }
  938. if (pDefaultParams != NULL)
  939. #ifndef _SHADOW_DOUBLES
  940. nRet = PushDefaultStackArgs(pStack, pCtxt, pbParams, pszParams,
  941. pDefaultParams);
  942. #else
  943. nRet = PushDefaultStackArgs(pStack, pCtxt, pbParams, pszParams,
  944. pDefaultParams, nSizeArgs);
  945. #endif
  946. else
  947. #ifndef _SHADOW_DOUBLES
  948. nRet = PushStackArgs(pStack, pCtxt, pbParams, pszParams);
  949. #else
  950. nRet = PushStackArgs(pStack, pCtxt, pbParams, pszParams, nSizeArgs);
  951. #endif
  952. pStack += _STACK_OFFSET;
  953. if (nRet == 0)
  954. {
  955. DWORD (AFXISAPI *pfnInet)(AFX_PISAPICMD, void*, UINT) =
  956. &_AfxParseCall;
  957. pfnInet(pfn, pStack, nSizeArgs);
  958. }
  959. }
  960. return nRet;
  961. }
  962. int CHttpServer::CountParams(LPCTSTR pszCommandLine, int& nCount)
  963. {
  964. BOOL bInQuote = FALSE;
  965. BOOL bInSpace = TRUE;
  966. LPCTSTR pszWalker = pszCommandLine;
  967. int nRetCode = callOK;
  968. nCount = 0;
  969. if (pszCommandLine != NULL)
  970. {
  971. while (*pszWalker != '\0')
  972. {
  973. if (bInSpace)
  974. {
  975. // this is invalid syntax
  976. ISAPIASSERT(*pszWalker != '\'');
  977. if (*pszWalker == '\'')
  978. {
  979. nRetCode = callMissingQuote;
  980. break;
  981. }
  982. if (!_istspace(*pszWalker))
  983. {
  984. nCount++;
  985. bInSpace = FALSE;
  986. }
  987. }
  988. else
  989. {
  990. if (*pszWalker == '\'')
  991. bInQuote = !bInQuote;
  992. else if (!bInQuote &&
  993. (_istspace(*pszWalker) || *pszWalker == m_cTokenDelimiter))
  994. bInSpace = TRUE;
  995. }
  996. pszWalker++;
  997. }
  998. // can't have only whitespace
  999. if (nCount == 0 && bInSpace)
  1000. {
  1001. nRetCode = callMissingParams;
  1002. ISAPIASSERT(nCount > 0 || !bInSpace);
  1003. }
  1004. // unclosed quoted string?
  1005. else if (bInQuote)
  1006. {
  1007. nRetCode = callMissingQuote;
  1008. ISAPIASSERT(!bInQuote);
  1009. }
  1010. }
  1011. return nRetCode;
  1012. }
  1013. int CHttpServer::ParseDefaultParams(AFX_PARSEMAP_ENTRY* pParams,
  1014. int nParams, AFX_PARSEMAP_ENTRY_PARAMS*& pBlock, const BYTE* pbParams)
  1015. {
  1016. int nRet = callOK;
  1017. LPSTR pszWalker;
  1018. BOOL bInQuote;
  1019. BOOL bInSpace;
  1020. BOOL bInEquals;
  1021. BOOL bMandatory = TRUE;
  1022. // only if we haven't done it already
  1023. if (pParams->pszFnName == NULL)
  1024. {
  1025. AFX_PARSEMAP_ENTRY_PARAMS* pParBlock = NULL;
  1026. ISAPIASSERT(pParams->pszParamInfo == NULL);
  1027. // can't have empty param string
  1028. ISAPIASSERT(*pParams->pszArgs != '\0');
  1029. if (*pParams->pszArgs != '\0')
  1030. {
  1031. pParBlock = new AFX_PARSEMAP_ENTRY_PARAMS;
  1032. pBlock = pParBlock;
  1033. memset(pParBlock, 0, sizeof(AFX_PARSEMAP_ENTRY_PARAMS));
  1034. pParams->pszFnName = (LPTSTR) pParBlock;
  1035. // start by finding how many parameters we have
  1036. nRet = CountParams(pParams->pszArgs, pParBlock->nParams);
  1037. if (nRet == callOK)
  1038. pParams->pszParamInfo = _tcsdup(pParams->pszArgs);
  1039. }
  1040. if (pParBlock == NULL || nRet != callOK)
  1041. {
  1042. if (nRet == callOK)
  1043. nRet = callMissingParams;
  1044. goto CleanUp;
  1045. }
  1046. // wrong number of parameters?
  1047. if (nParams != pParBlock->nParams)
  1048. {
  1049. nRet = callBadParamCount;
  1050. ISAPIASSERT(nParams == pParBlock->nParams);
  1051. }
  1052. // it's a winner!
  1053. else
  1054. {
  1055. pParBlock->ppszInfo =
  1056. new LPTSTR[pParBlock->nParams *2];
  1057. pParBlock->ppszDefaults =
  1058. new BYTE[pParBlock->nParams * sizeof(double)];
  1059. pParBlock->ppszValues =
  1060. new BYTE[pParBlock->nParams * sizeof(double)];
  1061. bInQuote = FALSE;
  1062. bInSpace = TRUE;
  1063. bInEquals = FALSE;
  1064. int nStorage = 0;
  1065. for (pszWalker = pParams->pszParamInfo;
  1066. *pszWalker != '\0'; pszWalker++)
  1067. {
  1068. if (bInSpace)
  1069. {
  1070. // this is invalid syntax
  1071. ISAPIASSERT(*pszWalker != '\'' && *pszWalker != '=');
  1072. if (*pszWalker == '\'' || *pszWalker == '=')
  1073. {
  1074. nRet = callMissingQuote;
  1075. break;
  1076. }
  1077. if (!_istspace(*pszWalker))
  1078. {
  1079. pParBlock->ppszInfo[nStorage++] = pszWalker;
  1080. bInSpace = FALSE;
  1081. }
  1082. }
  1083. else
  1084. {
  1085. if (bInEquals)
  1086. {
  1087. if (_istspace(*pszWalker) && bInQuote)
  1088. continue;
  1089. if (*pszWalker == '\'' || _istspace(*pszWalker))
  1090. {
  1091. if (bInQuote || _istspace(*pszWalker))
  1092. {
  1093. *pszWalker = '\0';
  1094. bInEquals = FALSE;
  1095. bInSpace = TRUE;
  1096. bInQuote = FALSE;
  1097. }
  1098. else
  1099. {
  1100. pParBlock->ppszInfo[nStorage-1]++;
  1101. bInQuote = TRUE;
  1102. }
  1103. }
  1104. }
  1105. else
  1106. {
  1107. // parameter with no default
  1108. if (_istspace(*pszWalker))
  1109. {
  1110. // can't have required param after optional params
  1111. ISAPIASSERT(bMandatory);
  1112. if (!bMandatory)
  1113. {
  1114. nRet = callBadParam;
  1115. goto CleanUp;
  1116. }
  1117. *pszWalker = '\0';
  1118. bInSpace = TRUE;
  1119. pParBlock->ppszInfo[nStorage++] = NULL;
  1120. }
  1121. // end of parameter name with default
  1122. else if (*pszWalker == '=')
  1123. {
  1124. bMandatory = FALSE;
  1125. bInEquals = TRUE;
  1126. *pszWalker = '\0';
  1127. pParBlock->ppszInfo[nStorage++] = pszWalker+1;
  1128. }
  1129. // bad syntax--quote in param name
  1130. else if (*pszWalker == '\'')
  1131. {
  1132. ISAPIASSERT(*pszWalker != '\'');
  1133. nRet = callMissingQuote;
  1134. break;
  1135. }
  1136. }
  1137. }
  1138. }
  1139. // handle case of no default for final param
  1140. if (nStorage & 1)
  1141. pParBlock->ppszInfo[nStorage] = NULL;
  1142. int nIndex;
  1143. for (nIndex = 0; nIndex < pParBlock->nParams; nIndex++)
  1144. {
  1145. if (pParBlock->ppszInfo[2*nIndex+1] != NULL)
  1146. #ifndef _SHADOW_DOUBLES
  1147. StoreStackParameter(
  1148. &pParBlock->ppszDefaults[sizeof(double) * nIndex],
  1149. pbParams[nIndex], pParBlock->ppszInfo[2*nIndex+1]);
  1150. #else
  1151. StoreStackParameter(
  1152. &pParBlock->ppszDefaults[sizeof(double) * nIndex],
  1153. pbParams[nIndex], pParBlock->ppszInfo[2*nIndex+1],
  1154. 0, FALSE);
  1155. #endif
  1156. else
  1157. pParBlock->nRequired++;
  1158. }
  1159. }
  1160. }
  1161. CleanUp:
  1162. return nRet;
  1163. }
  1164. // push arguments on stack appropriate for C++ call (compiler dependent)
  1165. #ifndef _SHADOW_DOUBLES
  1166. int CHttpServer::PushDefaultStackArgs(BYTE* pStack,
  1167. CHttpServerContext* pCtxt,
  1168. const BYTE* pbParams, LPTSTR pszParams,
  1169. AFX_PARSEMAP_ENTRY_PARAMS* pDefParams)
  1170. #else
  1171. int CHttpServer::PushDefaultStackArgs(BYTE* pStack,
  1172. CHttpServerContext* pCtxt,
  1173. const BYTE* pbParams, LPTSTR pszParams,
  1174. AFX_PARSEMAP_ENTRY_PARAMS* pDefParams, int nSizeArgs)
  1175. #endif
  1176. {
  1177. ISAPIASSERT(pStack != NULL);
  1178. LPTSTR pszCurParam = NULL;
  1179. int nExplicit = 0;
  1180. LPBYTE pFlags;
  1181. int nPushedExplicit = 0;
  1182. int nRetVal = callOK;
  1183. LPTSTR pszLineEnd;
  1184. // keep a list of flags to know what's pushed and what's not
  1185. pFlags = new BYTE[pDefParams->nParams];
  1186. memset(pFlags, 0, pDefParams->nParams);
  1187. // C++ member functions use the __thiscall convention, where parameters
  1188. // are pushed last to first. Assuming the stack grows down, this means
  1189. // that the first parameter is at the lowest memory address in the
  1190. // stack frame and the last parameter is at the highest address.
  1191. // push the 'this' pointer
  1192. *(_STACK_PTR*)pStack = (_STACK_PTR)this;
  1193. pStack += sizeof(_STACK_PTR);
  1194. // push our context pointer
  1195. *(_STACK_PTR*)pStack = (_STACK_PTR)pCtxt;
  1196. pStack += sizeof(_STACK_PTR);
  1197. // copy the default argument list to the usable argument list
  1198. memcpy(pDefParams->ppszValues, pDefParams->ppszDefaults,
  1199. sizeof(double) * pDefParams->nParams);
  1200. // push the arguments, if explicitly supplied
  1201. if (pszParams != NULL)
  1202. {
  1203. pszLineEnd = pszParams + lstrlen(pszParams);
  1204. TCHAR szTokens[2];
  1205. szTokens[0] = m_cTokenDelimiter;
  1206. szTokens[1] = '\0';
  1207. ISAPIASSERT(pbParams != NULL);
  1208. for (const BYTE* pb = pbParams; *pb != '\0'; ++pb)
  1209. {
  1210. if (*pb == IT_EMPTY)
  1211. {
  1212. // can't have ITS_EMPTY with other types!
  1213. ISAPIASSERT(pb == pbParams);
  1214. break;
  1215. }
  1216. if (pszParams == NULL)
  1217. break;
  1218. pszCurParam = _tcstok(pszParams, szTokens);
  1219. if (pszCurParam == NULL)
  1220. break;
  1221. // does this param have a name?
  1222. LPTSTR pszValue = _tcschr(pszCurParam, '=');
  1223. if (pszValue != NULL)
  1224. {
  1225. *pszValue++ = '\0';
  1226. // find the parameter in our param block
  1227. int nIndex;
  1228. BOOL bFound = FALSE;
  1229. for (nIndex = 0; nIndex < pDefParams->nParams; nIndex++)
  1230. {
  1231. if (lstrcmpi(pDefParams->ppszInfo[nIndex*2], pszCurParam) == 0)
  1232. {
  1233. bFound = TRUE;
  1234. break;
  1235. }
  1236. }
  1237. // something we don't recognize?
  1238. if (!bFound)
  1239. {
  1240. nRetVal = callBadParam;
  1241. goto CleanUp;
  1242. }
  1243. pszParams = pszValue + lstrlen(pszValue);
  1244. if (pszParams != pszLineEnd)
  1245. pszParams++;
  1246. // if this parameter has a default and there's
  1247. // no value for the parameter after the equal sign,
  1248. // let the default value prevail
  1249. if (*pszValue != '\0' ||
  1250. pDefParams->ppszInfo[2*nIndex+1] == NULL)
  1251. {
  1252. #ifndef _SHADOW_DOUBLES
  1253. StoreStackParameter(
  1254. &(pDefParams->ppszValues[nIndex*sizeof(double)]),
  1255. pbParams[nIndex], pszValue);
  1256. #else
  1257. StoreStackParameter(
  1258. &(pDefParams->ppszValues[nIndex*sizeof(double)]),
  1259. pbParams[nIndex], pszValue, 0, FALSE);
  1260. #endif
  1261. // if this has no default, it counts as explicit, too
  1262. if (pDefParams->ppszInfo[2*nIndex+1] == NULL)
  1263. nExplicit++;
  1264. }
  1265. // if we've already pushed this parameter, or if we've
  1266. // already pushed this many explicit params, make an error
  1267. if (pFlags[nIndex] != 0 || nIndex < nPushedExplicit)
  1268. {
  1269. nRetVal = callBadParam;
  1270. goto CleanUp;
  1271. }
  1272. pFlags[nIndex] = 1;
  1273. }
  1274. else
  1275. {
  1276. // not allowed to have optional params before required params
  1277. if (nExplicit != 0)
  1278. {
  1279. nRetVal = callBadParam;
  1280. goto CleanUp;
  1281. }
  1282. pszParams += lstrlen(pszCurParam);
  1283. if (pszParams != pszLineEnd)
  1284. pszParams++;
  1285. #ifndef _SHADOW_DOUBLES
  1286. pStack = StoreStackParameter(pStack, *pb, pszCurParam);
  1287. #else
  1288. pStack = StoreStackParameter(pStack, *pb, pszCurParam,
  1289. nSizeArgs, TRUE);
  1290. #endif
  1291. if (pFlags[nPushedExplicit] != 0)
  1292. {
  1293. nRetVal = callBadParam;
  1294. goto CleanUp;
  1295. }
  1296. pFlags[nPushedExplicit] = 1;
  1297. nPushedExplicit++;
  1298. }
  1299. }
  1300. // any unused parameters?
  1301. LPTSTR pszMoreParams;
  1302. pszMoreParams = _tcschr(pszParams, m_cTokenDelimiter);
  1303. if (*pb == '\0' && (pszMoreParams != NULL || *pszParams != '\0'))
  1304. {
  1305. nRetVal = callBadParamCount;
  1306. goto CleanUp;
  1307. }
  1308. }
  1309. // were any arguments without defaults missed?
  1310. if (nPushedExplicit + nExplicit < pDefParams->nRequired)
  1311. {
  1312. nRetVal = callBadParamCount;
  1313. }
  1314. else if (nPushedExplicit < pDefParams->nParams)
  1315. {
  1316. int nIndex;
  1317. for (nIndex = nPushedExplicit; nIndex < pDefParams->nParams; nIndex++)
  1318. {
  1319. #ifndef _SHADOW_DOUBLES
  1320. pStack = StoreRawStackParameter(pStack,
  1321. pbParams[nIndex],
  1322. &(pDefParams->ppszValues[nIndex*sizeof(double)]));
  1323. #else
  1324. pStack = StoreRawStackParameter(pStack,
  1325. pbParams[nIndex],
  1326. &(pDefParams->ppszValues[nIndex*sizeof(double)]), 0);
  1327. #endif
  1328. }
  1329. }
  1330. CleanUp:
  1331. if (pFlags != NULL)
  1332. delete [] pFlags;
  1333. return nRetVal;
  1334. }
  1335. // push arguments on stack appropriate for C++ call (compiler dependent)
  1336. #ifndef _SHADOW_DOUBLES
  1337. int CHttpServer::PushStackArgs(BYTE* pStack, CHttpServerContext* pCtxt,
  1338. const BYTE* pbParams, LPTSTR pszParams)
  1339. #else
  1340. int CHttpServer::PushStackArgs(BYTE* pStack, CHttpServerContext* pCtxt,
  1341. const BYTE* pbParams, LPTSTR pszParams, UINT nSizeArgs)
  1342. #endif
  1343. {
  1344. LPTSTR pszCurParam = NULL;
  1345. ISAPIASSERT(pStack != NULL);
  1346. // C++ member functions use the __thiscall convention, where parameters
  1347. // are pushed last to first. Assuming the stack grows down, this means
  1348. // that the first parameter is at the lowest memory address in the
  1349. // stack frame and the last parameter is at the highest address.
  1350. // push the 'this' pointer
  1351. *(_STACK_PTR*)pStack = (_STACK_PTR)this;
  1352. pStack += sizeof(_STACK_PTR);
  1353. // push our context pointer
  1354. *(_STACK_PTR*)pStack = (_STACK_PTR)pCtxt;
  1355. pStack += sizeof(_STACK_PTR);
  1356. // push the arguments (first to last, low address to high address)
  1357. TCHAR szTokens[2];
  1358. szTokens[0] = m_cTokenDelimiter;
  1359. szTokens[1] = '\0';
  1360. const BYTE* pb;
  1361. int nRetCode = callOK;
  1362. if (pszParams != NULL && *pbParams == IT_EMPTY)
  1363. nRetCode = callBadParamCount;
  1364. else if (pszParams != NULL)
  1365. {
  1366. LPTSTR pszLineEnd;
  1367. pszLineEnd = pszParams + lstrlen(pszParams);
  1368. ISAPIASSERT(pbParams != NULL);
  1369. for (pb = pbParams; *pb != '\0'; ++pb)
  1370. {
  1371. if (*pb == IT_EMPTY)
  1372. {
  1373. // can't have ITS_EMPTY with other types!
  1374. ISAPIASSERT(pb == pbParams);
  1375. if (pb != pbParams)
  1376. nRetCode = callBadParam;
  1377. break;
  1378. }
  1379. if (*pb == IT_RAW)
  1380. {
  1381. // can't have ITS_RAW with other types!
  1382. ISAPIASSERT(pb == pbParams);
  1383. if (pb != pbParams)
  1384. nRetCode = callBadParam;
  1385. else
  1386. {
  1387. BYTE* pbParam = (BYTE*) &pszParams;
  1388. #ifndef _SHADOW_DOUBLES
  1389. pStack = StoreRawStackParameter(pStack, IT_PSTR, pbParam);
  1390. pStack = StoreRawStackParameter(pStack, IT_I4,
  1391. (BYTE*) &(pCtxt->m_dwBytesReceived));
  1392. #else
  1393. pStack = StoreRawStackParameter(pStack, IT_PSTR, pbParam);
  1394. pStack = StoreRawStackParameter(pStack, IT_I4,
  1395. (BYTE*) &(pCtxt->m_dwBytesReceived));
  1396. #endif
  1397. }
  1398. return nRetCode;
  1399. }
  1400. if (pszParams == NULL)
  1401. break;
  1402. pszCurParam = _tcstok(pszParams, szTokens);
  1403. if (pszCurParam == NULL)
  1404. break;
  1405. pszParams = pszCurParam + lstrlen(pszCurParam);
  1406. if (pszParams != pszLineEnd)
  1407. pszParams++;
  1408. #ifndef _SHADOW_DOUBLES
  1409. pStack = StoreStackParameter(pStack, *pb, pszCurParam);
  1410. #else
  1411. pStack = StoreStackParameter(pStack, *pb, pszCurParam, nSizeArgs, TRUE);
  1412. #endif
  1413. }
  1414. // check that all source arguments were consumed
  1415. if (nRetCode == callOK)
  1416. {
  1417. LPTSTR pszMoreParams;
  1418. pszMoreParams = _tcschr(pszParams, m_cTokenDelimiter);
  1419. if (*pb != '\0' && pszMoreParams == NULL)
  1420. nRetCode = callBadParamCount;
  1421. else if (*pb == '\0' && (pszMoreParams != NULL || *pszParams != '\0'))
  1422. nRetCode = callBadParamCount;
  1423. }
  1424. }
  1425. else
  1426. {
  1427. if (*pbParams != IT_EMPTY)
  1428. nRetCode = callBadParamCount;
  1429. }
  1430. return nRetCode;
  1431. }
  1432. #ifndef _SHADOW_DOUBLES
  1433. BYTE* CHttpServer::StoreRawStackParameter(BYTE* pStack, BYTE nType,
  1434. BYTE* pRawParam)
  1435. #else
  1436. BYTE* CHttpServer::StoreRawStackParameter(BYTE* pStack, BYTE nType,
  1437. BYTE* pRawParam, int nSizeArgs)
  1438. #endif
  1439. {
  1440. ISAPIASSERT(pStack != NULL);
  1441. ISAPIASSERT(pRawParam != NULL);
  1442. #ifdef _SHADOW_DOUBLES
  1443. double* pDoubleShadow = (double*)(pStack + nSizeArgs);
  1444. double* pDoubleShadowMax = pDoubleShadow + _SHADOW_DOUBLES;
  1445. #endif
  1446. // push parameter value on the stack
  1447. switch (nType)
  1448. {
  1449. // by value parameters
  1450. case IT_I2:
  1451. *(_STACK_INT*)pStack = *((WORD*) pRawParam);
  1452. pStack += sizeof(_STACK_INT); // 'short' is passed as 'int'
  1453. break;
  1454. case IT_I4:
  1455. *(_STACK_LONG*)pStack = *((DWORD*) pRawParam);
  1456. pStack += sizeof(_STACK_LONG);
  1457. break;
  1458. case IT_R4:
  1459. *(_STACK_FLOAT*)pStack = *((_STACK_FLOAT*) pRawParam);
  1460. pStack += sizeof(_STACK_FLOAT);
  1461. #ifdef _SHADOW_DOUBLES
  1462. if (pDoubleShadow < pDoubleShadowMax)
  1463. *pDoubleShadow++ = *((_STACK_DOUBLE*) pRawParam);
  1464. #endif
  1465. break;
  1466. case IT_R8:
  1467. #ifdef _ALIGN_DOUBLES
  1468. // align doubles on 8 byte for some platforms
  1469. pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
  1470. ~(_ALIGN_DOUBLES-1));
  1471. #endif
  1472. *(_STACK_DOUBLE*)pStack = *((_STACK_DOUBLE*) pRawParam);
  1473. pStack += sizeof(_STACK_DOUBLE);
  1474. #ifdef _SHADOW_DOUBLES
  1475. if (pDoubleShadow < pDoubleShadowMax)
  1476. *pDoubleShadow++ = *((_STACK_DOUBLE*) pRawParam);
  1477. #endif
  1478. break;
  1479. case IT_PSTR:
  1480. *(_STACK_PTR*)pStack = *((_STACK_PTR*) pRawParam);
  1481. pStack += sizeof(_STACK_PTR);
  1482. break;
  1483. default:
  1484. ISAPIASSERT(FALSE);
  1485. }
  1486. #ifdef _ALIGN_STACK
  1487. // align stack as appropriate for next parameter
  1488. pStack = (BYTE*)(((DWORD)pStack + (_ALIGN_STACK-1)) &
  1489. ~(_ALIGN_STACK-1));
  1490. ISAPIASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  1491. #endif
  1492. return pStack;
  1493. }
  1494. #ifndef _SHADOW_DOUBLES
  1495. BYTE* CHttpServer::StoreStackParameter(BYTE* pStack, BYTE nType,
  1496. LPTSTR pszCurParam)
  1497. #else
  1498. BYTE* CHttpServer::StoreStackParameter(BYTE* pStack, BYTE nType,
  1499. LPTSTR pszCurParam, UINT nSizeArgs, BOOL bDoShadow)
  1500. #endif
  1501. {
  1502. ISAPIASSERT(pStack != NULL);
  1503. ISAPIASSERT(pszCurParam != NULL);
  1504. #ifdef _SHADOW_DOUBLES
  1505. double* pDoubleShadow = (double*)(pStack + nSizeArgs);
  1506. double* pDoubleShadowMax = pDoubleShadow + _SHADOW_DOUBLES;
  1507. #endif
  1508. // push parameter value on the stack
  1509. switch (nType)
  1510. {
  1511. // by value parameters
  1512. case IT_I2:
  1513. *(_STACK_INT*)pStack = (WORD) _ttoi(pszCurParam);
  1514. pStack += sizeof(_STACK_INT); // 'short' is passed as 'int'
  1515. break;
  1516. case IT_I4:
  1517. *(_STACK_LONG*)pStack = (DWORD) _ttol(pszCurParam);
  1518. pStack += sizeof(_STACK_LONG);
  1519. break;
  1520. case IT_R4:
  1521. *(_STACK_FLOAT*)pStack = (_STACK_FLOAT) atof(pszCurParam);
  1522. pStack += sizeof(_STACK_FLOAT);
  1523. #ifdef _SHADOW_DOUBLES
  1524. if (bDoShadow && pDoubleShadow < pDoubleShadowMax)
  1525. *pDoubleShadow++ = (double) atof(pszCurParam);
  1526. #endif
  1527. break;
  1528. case IT_R8:
  1529. #ifdef _ALIGN_DOUBLES
  1530. // align doubles on 8 byte for some platforms
  1531. pStack = (BYTE*)(((DWORD)pStack + _ALIGN_DOUBLES-1) &
  1532. ~(_ALIGN_DOUBLES-1));
  1533. #endif
  1534. *(_STACK_DOUBLE*)pStack = (_STACK_DOUBLE) atof(pszCurParam);
  1535. pStack += sizeof(_STACK_DOUBLE);
  1536. #ifdef _SHADOW_DOUBLES
  1537. if (bDoShadow && pDoubleShadow < pDoubleShadowMax)
  1538. *pDoubleShadow++ = atof(pszCurParam);
  1539. #endif
  1540. break;
  1541. case IT_PSTR:
  1542. *(_STACK_PTR*)pStack = (_STACK_PTR) PreprocessString(pszCurParam);
  1543. pStack += sizeof(_STACK_PTR);
  1544. break;
  1545. default:
  1546. ISAPIASSERT(FALSE);
  1547. }
  1548. #ifdef _ALIGN_STACK
  1549. // align stack as appropriate for next parameter
  1550. pStack = (BYTE*)(((DWORD)pStack + (_ALIGN_STACK-1)) &
  1551. ~(_ALIGN_STACK-1));
  1552. ISAPIASSERT(((DWORD)pStack & (_ALIGN_STACK-1)) == 0);
  1553. #endif
  1554. return pStack;
  1555. }
  1556. LPVOID CHttpServer::PreprocessString(LPTSTR psz)
  1557. {
  1558. LPTSTR pszSource = psz;
  1559. LPTSTR pszDest = psz;
  1560. static const TCHAR szHex[] = _T("0123456789ABCDEF");
  1561. // unescape special characters
  1562. while (*pszSource != '\0')
  1563. {
  1564. if (*pszSource == '+')
  1565. *pszDest++ = ' ';
  1566. else if (*pszSource == '%')
  1567. {
  1568. TCHAR nValue = '?';
  1569. LPCTSTR pszLow;
  1570. LPCTSTR pszHigh;
  1571. pszSource++;
  1572. *pszSource = (TCHAR) _totupper(*pszSource);
  1573. pszHigh = _tcschr(szHex, *pszSource);
  1574. if (pszHigh != NULL)
  1575. {
  1576. pszSource++;
  1577. *pszSource = (TCHAR) _totupper(*pszSource);
  1578. pszLow = _tcschr(szHex, *pszSource);
  1579. if (pszLow != NULL)
  1580. {
  1581. nValue = (TCHAR) (((pszHigh - szHex) << 4) +
  1582. (pszLow - szHex));
  1583. }
  1584. }
  1585. *pszDest++ = nValue;
  1586. }
  1587. else
  1588. *pszDest++ = *pszSource;
  1589. pszSource++;
  1590. }
  1591. *pszDest = '\0';
  1592. return (LPVOID) psz;
  1593. }
  1594. ///////////////////////////////////////////////////////////////////////
  1595. // in-memory HTML Stream
  1596. CHtmlStream::CHtmlStream(UINT nGrowBytes /* = 4096 */)
  1597. {
  1598. ISAPIASSERT(nGrowBytes <= UINT_MAX && nGrowBytes >= 0);
  1599. m_nGrowBytes = nGrowBytes;
  1600. m_nPosition = 0;
  1601. m_nBufferSize = 0;
  1602. m_lpBuffer = NULL;
  1603. m_bAutoDelete = TRUE;
  1604. m_nStreamSize = 0;
  1605. }
  1606. CHtmlStream::CHtmlStream(BYTE* lpBuffer, UINT nBufferSize,
  1607. UINT nGrowBytes /* = 0 */)
  1608. {
  1609. ISAPIASSERT(nGrowBytes <= UINT_MAX && nGrowBytes >= 0);
  1610. m_nGrowBytes = nGrowBytes;
  1611. m_nPosition = 0;
  1612. m_nBufferSize = nBufferSize;
  1613. // if the caller provides a grow-by size, use it;
  1614. // otherwise, incrememt by the initial buffer size
  1615. m_nStreamSize = nGrowBytes == 0 ? nBufferSize : 0;
  1616. m_lpBuffer = lpBuffer;
  1617. m_bAutoDelete = FALSE;
  1618. }
  1619. void CHtmlStream::Attach(BYTE* lpBuffer, UINT nBufferSize, UINT nGrowBytes)
  1620. {
  1621. ISAPIASSERT(m_lpBuffer == NULL);
  1622. m_nGrowBytes = nGrowBytes;
  1623. m_nPosition = 0;
  1624. m_nBufferSize = nBufferSize;
  1625. // if the caller provides a grow-by size, use it;
  1626. // otherwise, incrememt by the initial buffer size
  1627. m_nStreamSize = nGrowBytes == 0 ? nBufferSize : 0;
  1628. m_lpBuffer = lpBuffer;
  1629. m_bAutoDelete = FALSE;
  1630. }
  1631. BYTE* CHtmlStream::Detach()
  1632. {
  1633. BYTE* lpBuffer = NULL;
  1634. if (m_lpBuffer != NULL)
  1635. {
  1636. TCHAR chZero = 0;
  1637. Write(&chZero, sizeof(TCHAR));
  1638. lpBuffer = m_lpBuffer;
  1639. m_lpBuffer = NULL;
  1640. }
  1641. m_nBufferSize = 0;
  1642. m_nStreamSize = 0;
  1643. m_nPosition = 0;
  1644. return lpBuffer;
  1645. }
  1646. CHtmlStream::~CHtmlStream()
  1647. {
  1648. // Close should have already been called, but we check anyway
  1649. if (m_lpBuffer)
  1650. Close();
  1651. ISAPIASSERT(NULL == m_lpBuffer);
  1652. m_nGrowBytes = 0;
  1653. m_nPosition = 0;
  1654. m_nStreamSize = 0;
  1655. m_nBufferSize = 0;
  1656. }
  1657. BYTE* CHtmlStream::Alloc(DWORD nBytes)
  1658. {
  1659. return (BYTE*)malloc((UINT)nBytes);
  1660. }
  1661. BYTE* CHtmlStream::Realloc(BYTE* lpMem, DWORD nBytes)
  1662. {
  1663. return (BYTE*)realloc(lpMem, (UINT)nBytes);
  1664. }
  1665. #pragma intrinsic(memcpy)
  1666. BYTE* CHtmlStream::Memcpy(BYTE* lpMemTarget, const BYTE* lpMemSource,
  1667. UINT nBytes)
  1668. {
  1669. ISAPIASSERT(lpMemTarget != NULL);
  1670. ISAPIASSERT(lpMemSource != NULL);
  1671. return (BYTE*)memcpy(lpMemTarget, lpMemSource, nBytes);
  1672. }
  1673. #pragma function(memcpy)
  1674. void CHtmlStream::Free(BYTE* lpMem)
  1675. {
  1676. ISAPIASSERT(lpMem != NULL);
  1677. free(lpMem);
  1678. }
  1679. void CHtmlStream::GrowStream(DWORD dwNewLen)
  1680. {
  1681. if (dwNewLen > m_nBufferSize)
  1682. {
  1683. // grow the buffer
  1684. DWORD dwNewBufferSize = (DWORD)m_nBufferSize;
  1685. // watch out for buffers which cannot be grown!
  1686. ISAPIASSERT(m_nGrowBytes > 0);
  1687. if (m_nGrowBytes == 0)
  1688. throw;
  1689. // determine new buffer size
  1690. while (dwNewBufferSize < dwNewLen)
  1691. dwNewBufferSize += m_nGrowBytes;
  1692. // allocate new buffer
  1693. BYTE* lpNew;
  1694. if (m_lpBuffer == NULL)
  1695. lpNew = Alloc(dwNewBufferSize);
  1696. else
  1697. lpNew = Realloc(m_lpBuffer, dwNewBufferSize);
  1698. if (lpNew == NULL)
  1699. throw;
  1700. m_lpBuffer = lpNew;
  1701. m_nBufferSize = dwNewBufferSize;
  1702. }
  1703. }
  1704. CHtmlStream& CHtmlStream::operator<<(LPCTSTR psz)
  1705. {
  1706. Write(psz, lstrlen(psz));
  1707. return *this;
  1708. }
  1709. CHtmlStream& CHtmlStream::operator<<(short int w)
  1710. {
  1711. TCHAR sz[16];
  1712. int nLen = wsprintf(sz, szDecimalFormat, w);
  1713. Write(sz, nLen);
  1714. return *this;
  1715. }
  1716. CHtmlStream& CHtmlStream::operator<<(long int dw)
  1717. {
  1718. TCHAR sz[16];
  1719. int nLen = wsprintf(sz, szDecimalFormat, dw);
  1720. Write(sz, nLen);
  1721. return *this;
  1722. }
  1723. CHtmlStream& CHtmlStream::operator<<(float f)
  1724. {
  1725. TCHAR sz[64];
  1726. int nLen = _stprintf(sz, szFloatFormat, f);
  1727. Write(sz, nLen);
  1728. return *this;
  1729. }
  1730. CHtmlStream& CHtmlStream::operator<<(double d)
  1731. {
  1732. TCHAR sz[64];
  1733. int nLen = _stprintf(sz, szFloatFormat, d);
  1734. Write(sz, nLen);
  1735. return *this;
  1736. }
  1737. CHtmlStream& CHtmlStream::operator<<(const CHtmlStream& stream)
  1738. {
  1739. DWORD dwSourceLen = stream.GetStreamSize();
  1740. Write(stream.m_lpBuffer, dwSourceLen);
  1741. return *this;
  1742. }
  1743. void CHtmlStream::Close()
  1744. {
  1745. m_nGrowBytes = 0;
  1746. m_nPosition = 0;
  1747. m_nBufferSize = 0;
  1748. m_nStreamSize = 0;
  1749. if (m_lpBuffer && m_bAutoDelete)
  1750. Free(m_lpBuffer);
  1751. m_lpBuffer = NULL;
  1752. }
  1753. void CHtmlStream::Abort()
  1754. {
  1755. Close();
  1756. }
  1757. void CHtmlStream::Write(const void* lpBuf, UINT nCount)
  1758. {
  1759. if (nCount == 0)
  1760. return;
  1761. ISAPIASSERT(lpBuf != NULL);
  1762. if (m_nPosition + nCount > m_nBufferSize)
  1763. GrowStream(m_nPosition + nCount);
  1764. ISAPIASSERT(m_nPosition + nCount <= m_nBufferSize);
  1765. Memcpy((BYTE*)m_lpBuffer + m_nPosition, (BYTE*)lpBuf, nCount);
  1766. m_nPosition += nCount;
  1767. if (m_nPosition > m_nStreamSize)
  1768. m_nStreamSize = m_nPosition;
  1769. }
  1770. void CHtmlStream::Reset()
  1771. {
  1772. m_nPosition = 0;
  1773. m_nStreamSize = 0;
  1774. }
  1775. void CHtmlStream::InitStream()
  1776. {
  1777. // subclass can override for interesting applications
  1778. }
  1779. ///////////////////////////////////////////////////////////////////////
  1780. // HTTP Filter entry points
  1781. extern "C" DWORD WINAPI HttpFilterProc(PHTTP_FILTER_CONTEXT pfc,
  1782. DWORD dwNotificationType, LPVOID pvNotification)
  1783. {
  1784. #ifdef _AFXDLL
  1785. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1786. #endif
  1787. DWORD dwRet;
  1788. ISAPIASSERT(pFilter != NULL);
  1789. if (pFilter == NULL)
  1790. dwRet = SF_STATUS_REQ_NEXT_NOTIFICATION;
  1791. else
  1792. dwRet = pFilter->HttpFilterProc(pfc,
  1793. dwNotificationType, pvNotification);
  1794. return dwRet;
  1795. }
  1796. extern "C" BOOL WINAPI GetFilterVersion(PHTTP_FILTER_VERSION pVer)
  1797. {
  1798. #ifdef _AFXDLL
  1799. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  1800. #endif
  1801. BOOL bRet;
  1802. ISAPIASSERT(pFilter != NULL);
  1803. if (pFilter == NULL)
  1804. bRet = FALSE;
  1805. else
  1806. bRet = pFilter->GetFilterVersion(pVer);
  1807. return bRet;
  1808. }
  1809. ///////////////////////////////////////////////////////////////////////
  1810. // CHttpFilter implementation
  1811. CHttpFilter::CHttpFilter()
  1812. {
  1813. ISAPIASSERT(pFilter == NULL);
  1814. pFilter = this;
  1815. }
  1816. CHttpFilter::~CHttpFilter()
  1817. {
  1818. pFilter = NULL;
  1819. }
  1820. BOOL CHttpFilter::GetFilterVersion(PHTTP_FILTER_VERSION pVer)
  1821. {
  1822. pVer->dwFlags = SF_NOTIFY_ORDER_DEFAULT;
  1823. pVer->dwFilterVersion = HTTP_FILTER_REVISION;
  1824. pVer->lpszFilterDesc[0] = '\0';
  1825. return TRUE;
  1826. }
  1827. DWORD CHttpFilter::HttpFilterProc(PHTTP_FILTER_CONTEXT pfc,
  1828. DWORD dwNotificationType, LPVOID pvNotification)
  1829. {
  1830. DWORD dwRet = SF_STATUS_REQ_NEXT_NOTIFICATION;
  1831. CHttpFilterContext callCtxt(pfc);
  1832. switch (dwNotificationType)
  1833. {
  1834. case SF_NOTIFY_READ_RAW_DATA:
  1835. dwRet = OnReadRawData(&callCtxt, (PHTTP_FILTER_RAW_DATA) pvNotification);
  1836. break;
  1837. case SF_NOTIFY_PREPROC_HEADERS:
  1838. dwRet = OnPreprocHeaders(&callCtxt,
  1839. (PHTTP_FILTER_PREPROC_HEADERS) pvNotification);
  1840. break;
  1841. case SF_NOTIFY_AUTHENTICATION:
  1842. dwRet = OnAuthentication(&callCtxt,
  1843. (PHTTP_FILTER_AUTHENT) pvNotification);
  1844. break;
  1845. case SF_NOTIFY_URL_MAP:
  1846. dwRet = OnUrlMap(&callCtxt, (PHTTP_FILTER_URL_MAP) pvNotification);
  1847. break;
  1848. case SF_NOTIFY_SEND_RAW_DATA:
  1849. dwRet = OnSendRawData(&callCtxt, (PHTTP_FILTER_RAW_DATA) pvNotification);
  1850. break;
  1851. case SF_NOTIFY_LOG:
  1852. dwRet = OnLog(&callCtxt, (PHTTP_FILTER_LOG) pvNotification);
  1853. break;
  1854. case SF_NOTIFY_END_OF_NET_SESSION:
  1855. dwRet = OnEndOfNetSession(&callCtxt);
  1856. break;
  1857. case SF_NOTIFY_END_OF_REQUEST:
  1858. dwRet = OnEndOfRequest(&callCtxt);
  1859. break;
  1860. default:
  1861. ISAPITRACE1("Warning: unrecognized HTTP filter notification code %d\n", dwNotificationType);
  1862. break;
  1863. }
  1864. return dwRet;
  1865. }
  1866. // The user will override these. Here, the functions have no
  1867. // formal parameters to avoid warnings.
  1868. DWORD CHttpFilter::OnReadRawData(CHttpFilterContext*, PHTTP_FILTER_RAW_DATA)
  1869. {
  1870. return SF_STATUS_REQ_NEXT_NOTIFICATION;
  1871. }
  1872. DWORD CHttpFilter::OnPreprocHeaders(CHttpFilterContext*, PHTTP_FILTER_PREPROC_HEADERS)
  1873. {
  1874. return SF_STATUS_REQ_NEXT_NOTIFICATION;
  1875. }
  1876. DWORD CHttpFilter::OnAuthentication(CHttpFilterContext*, PHTTP_FILTER_AUTHENT)
  1877. {
  1878. return SF_STATUS_REQ_NEXT_NOTIFICATION;
  1879. }
  1880. DWORD CHttpFilter::OnUrlMap(CHttpFilterContext*, PHTTP_FILTER_URL_MAP)
  1881. {
  1882. return SF_STATUS_REQ_NEXT_NOTIFICATION;
  1883. }
  1884. DWORD CHttpFilter::OnSendRawData(CHttpFilterContext*, PHTTP_FILTER_RAW_DATA)
  1885. {
  1886. return SF_STATUS_REQ_NEXT_NOTIFICATION;
  1887. }
  1888. DWORD CHttpFilter::OnLog(CHttpFilterContext*, PHTTP_FILTER_LOG)
  1889. {
  1890. return SF_STATUS_REQ_NEXT_NOTIFICATION;
  1891. }
  1892. DWORD CHttpFilter::OnEndOfNetSession(CHttpFilterContext*)
  1893. {
  1894. return SF_STATUS_REQ_NEXT_NOTIFICATION;
  1895. }
  1896. DWORD CHttpFilter::OnEndOfRequest(CHttpFilterContext*)
  1897. {
  1898. return SF_STATUS_REQ_NEXT_NOTIFICATION;
  1899. }
  1900. ///////////////////////////////////////////////////////////////////////
  1901. // tracing helper function for linking without MFC
  1902. #ifndef _AFX
  1903. #ifdef _DEBUG
  1904. void AFXISAPI_CDECL AfxISAPITrace(LPCTSTR lpszFormat, ...)
  1905. {
  1906. va_list args;
  1907. va_start(args, lpszFormat);
  1908. // if the trace has been set to go to a window and the user
  1909. // presses RETRY, we will break to the debugger here
  1910. if (_CrtDbgReport(_CRT_WARN, NULL, 0, NULL, lpszFormat, args) == 1)
  1911. _CrtDbgBreak();
  1912. va_end(args);
  1913. }
  1914. #endif
  1915. #endif
  1916. ///////////////////////////////////////////////////////////////////////
  1917. // handle inline functions
  1918. #ifndef _AFX_ENABLE_INLINES
  1919. static const char _szAfxWinInl[] = "isapi.inl";
  1920. #undef THIS_FILE
  1921. #define THIS_FILE _szAfxWinInl
  1922. #define _AFXISAPI_INLINE
  1923. #include "afxisapi.inl"
  1924. #endif //!_AFX_ENABLE_INLINES