📄 isapi.cpp
字号:
DWORD dwCause = ::GetLastError();
ISAPITRACE1("Error: Unable to write content body: 0x%8.8X!\n",
dwCause);
#endif
}
}
else
ISAPITRACE("Error: No body content!\n");
}
if (pbStream != NULL)
ctxtCall.m_pStream->Free(pbStream);
if (ctxtCall.m_dwStatusCode != DWORD(-1))
dwRet = ctxtCall.m_dwStatusCode;
if (dwRet == HSE_STATUS_SUCCESS)
pECB->dwHttpStatusCode = HTTP_STATUS_OK;
if (pszPostBuffer != NULL)
delete [] pszPostBuffer;
return dwRet;
}
void CHttpServer::BuildStatusCode(LPTSTR pszResponse, DWORD dwCode)
{
ISAPIASSERT(pszResponse != NULL);
HTTPStatusInfo* pInfo = statusStrings;
while (pInfo->pstrString != NULL)
{
if (dwCode == pInfo->dwCode)
break;
pInfo++;
}
if (pInfo->pstrString != NULL)
wsprintf(pszResponse, _T("%d %s"), dwCode, pInfo->pstrString);
else
{
ISAPIASSERT(dwCode != HTTP_STATUS_OK);
ISAPITRACE1("Warning: Nonstandard status code %d\n", dwCode);
BuildStatusCode(pszResponse, HTTP_STATUS_OK);
}
}
BOOL CHttpServer::GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
pVer->dwExtensionVersion = MAKELONG(HSE_VERSION_MINOR, HSE_VERSION_MAJOR);
pVer->lpszExtensionDesc[0] = '\0';
return TRUE;
}
CHttpServer::CHttpServer(TCHAR cDelimiter /* = '&' */)
: m_cTokenDelimiter(cDelimiter)
{
ISAPIASSERT(pServer == NULL); // only one server instance
pServer = this;
// allocate our critical section directly to avoid bogus traces
m_pCritSec = (LPCRITICAL_SECTION)
LocalAlloc(LPTR, sizeof(CRITICAL_SECTION));
::InitializeCriticalSection(m_pCritSec);
}
CHttpServer::~CHttpServer()
{
if (m_pCritSec != NULL)
{
::DeleteCriticalSection(m_pCritSec);
LocalFree(m_pCritSec);
}
pServer = NULL;
}
BOOL CHttpServer::OnParseError(CHttpServerContext* pCtxt, int nMethodRet)
{
UNUSED(nMethodRet);
UINT nResource = 0;
if (pCtxt->m_pStream != NULL)
{
TCHAR szBuffer[132];
TCHAR szTitle[256];
LPCTSTR pszObject = NULL;
switch (pCtxt->m_pECB->dwHttpStatusCode)
{
case HTTP_STATUS_BAD_REQUEST:
nResource = AFX_IDS_HTTP_BAD_REQUEST;
if (pCtxt->m_pECB->lpszQueryString)
pszObject = pCtxt->m_pECB->lpszQueryString;
else
pszObject = pCtxt->m_pECB->lpszPathInfo;
break;
case HTTP_STATUS_AUTH_REQUIRED:
nResource = AFX_IDS_HTTP_AUTH_REQUIRED;
break;
case HTTP_STATUS_FORBIDDEN:
nResource = AFX_IDS_HTTP_FORBIDDEN;
break;
case HTTP_STATUS_NOT_FOUND:
nResource = AFX_IDS_HTTP_NOT_FOUND;
break;
case HTTP_STATUS_SERVER_ERROR:
nResource = AFX_IDS_HTTP_SERVER_ERROR;
break;
case HTTP_STATUS_NOT_IMPLEMENTED:
nResource = AFX_IDS_HTTP_NOT_IMPLEMENTED;
pszObject = pCtxt->m_pECB->lpszQueryString;
break;
default:
nResource = AFX_IDS_HTTP_NO_TEXT;
pszObject = (LPCTSTR) pCtxt->m_pECB->dwHttpStatusCode;
break;
}
HINSTANCE hRes;
hRes = AfxGetResourceHandle();
#ifdef _AFXDLL
if (AfxLoadString(nResource, szBuffer, _countof(szBuffer)) > 0)
#else
if (::LoadString(hRes, nResource, szBuffer, _countof(szBuffer)) > 0)
#endif
{
pCtxt->Reset();
CHttpServer::StartContent(pCtxt);
if (::LoadString(hRes, AFX_IDS_HTTP_TITLE, szTitle, _countof(szTitle)) > 0)
{
TCHAR szTitleCopy[512];
_sntprintf(szTitleCopy, 512, szTitle, pCtxt->m_pECB->dwHttpStatusCode);
szTitleCopy[511] = 0;
*pCtxt << szTitleCopy;
}
if (pszObject != NULL)
{
TCHAR* pstrFormat = new TCHAR[lstrlen(szBuffer) + lstrlen(pszObject) + 1];
if (pstrFormat != NULL)
{
wsprintf(pstrFormat, szBuffer, pszObject);
*pCtxt << pstrFormat;
delete [] pstrFormat;
}
}
else
*pCtxt << szBuffer;
CHttpServer::EndContent(pCtxt);
}
else
{
ISAPITRACE1("Error: Couldn't load string %d\n", nResource);
nResource = 0;
}
}
if (nResource == 0)
ISAPITRACE1("Error: Unhandled parsing error code %d\n", nMethodRet);
return nResource != 0;
}
void CHttpServer::AddHeader(CHttpServerContext* pCtxt,
LPCTSTR pszString) const
{
#ifdef _DEBUG
// Can't call AddHeader() after writing directly to the stream.
ISAPIASSERT(pCtxt->m_dwOldEndOfHeaders == pCtxt->m_pStream->GetStreamSize());
#endif
*pCtxt << pszString;
pCtxt->m_dwEndOfHeaders = pCtxt->m_pStream->GetStreamSize();
#ifdef _DEBUG
pCtxt->m_dwOldEndOfHeaders = pCtxt->m_dwEndOfHeaders;
#endif
}
void CHttpServer::StartContent(CHttpServerContext* pCtxt) const
{
AddHeader(pCtxt, szContentType);
}
void CHttpServer::WriteTitle(CHttpServerContext* pCtxt) const
{
*pCtxt << szStartTitle;
*pCtxt << GetTitle();
*pCtxt << szEndTitle;
}
LPCTSTR CHttpServer::GetTitle() const
{
return szDefaultTitle;
}
void CHttpServer::EndContent(CHttpServerContext* pCtxt) const
{
*pCtxt << szEndBody;
}
BOOL CHttpServer::InitInstance(CHttpServerContext*)
{
return TRUE;
}
int CHttpServer::CallFunction(CHttpServerContext* pCtxt,
LPTSTR pszQuery, LPTSTR pszCommand)
{
int nRet;
AFX_PARSEMAP_ENTRY* pParams;
const AFX_PARSEMAP* pMap;
const AFX_PARSEMAP_ENTRY* pFn;
ISAPIASSERT(pCtxt->m_pStream == NULL);
pCtxt->m_pStream = ConstructStream();
if (pCtxt->m_pStream == NULL)
nRet = callNoStream;
else
{
ISAPIASSERT(pszQuery != NULL);
if (pszQuery == NULL)
nRet = callBadCommand;
else
{
LPTSTR pszMethod;
LPTSTR pszParams;
// did the user specify a command via "MfcISAPICommand"?
LPTSTR pszHiddenCommand = _tcschr(pszQuery, '=');
if (pszHiddenCommand != NULL)
{
*pszHiddenCommand = '\0';
// is it there?
if (lstrcmpi(pszQuery, _T("MfcISAPICommand")) == 0)
{
// did they have a method, too?
pszMethod = pszHiddenCommand+1;
if (*pszMethod == '\0')
pszParams = pszMethod;
else
{
pszParams = _tcschr(pszMethod, m_cTokenDelimiter);
if (pszParams != NULL && *pszParams != '\0')
*pszParams++ = '\0';
}
// if we find it, we can call it
pFn = LookUp(pszMethod, pMap, pParams);
if (pFn != NULL)
goto MakeTheCall;
}
// we didn't find the command, or we didn't have
// "MfcISAPICommand", so we'll try and process things
// normally...
*pszHiddenCommand = '=';
}
if (pszCommand == NULL)
{
// got something via a GET method
// is the first thing a parameter or a command?
LPTSTR pszEquals;
LPTSTR pszQMark;
pszParams = _tcschr(pszQuery, m_cTokenDelimiter);
pszQMark = _tcschr(pszQuery, '?');
// Parameters start at the first delimiter
if (pszParams == NULL || (pszQMark != NULL && (pszQMark < pszParams)))
{
pszParams = pszQMark;
// if the command ends in question mark
// and nothing else, ignore it
if (pszQMark != NULL && pszQMark[1] == '\0')
{
*pszQMark = '\0';
pszParams = NULL;
}
}
// Does an equals sign show up before the first delimiter?
pszEquals = _tcschr(pszQuery, '=');
if (pszEquals == NULL || pszEquals > pszParams)
{
// It might be a command. If it isn't blank,
// try and find it in the parameter map--if
// we can't, then assume it is a parameter.
pszMethod = pszQuery;
if (*pszMethod != '\0')
{
TCHAR cTemp = 0;
if (pszParams != NULL)
{
cTemp = *pszParams;
*pszParams++ = '\0';
}
pFn = LookUp(pszMethod, pMap, pParams);
if (pFn != NULL)
goto MakeTheCall;
if (pszParams != NULL)
*--pszParams = cTemp;
}
}
// we can be sure it's a parameter
if (pszQMark == NULL || pszQMark >= pszParams)
{
// default command, params as supplied
pszMethod = NULL;
pszParams = pszQuery;
}
else
{
pszMethod = pszQuery;
*pszQMark++ = '\0';
pszParams = pszQMark;
}
}
else
{
// with a POST, the verb arrives seperately
pszMethod = pszCommand;
pszParams = pszQuery;
}
// is it a default verb?
if (pszMethod != NULL && lstrlen(pszMethod) == 0)
pszMethod = NULL;
// is it a useless parameter?
if (pszParams != NULL && lstrlen(pszParams) == 0)
pszParams = NULL;
pFn = LookUp(pszMethod, pMap, pParams);
MakeTheCall:
if (pFn == NULL)
nRet = callBadCommand;
else
{
pCtxt->m_pStream->InitStream();
nRet = CallMemberFunc(pCtxt, pFn, pParams, pszParams);
}
}
}
return nRet;
}
CHtmlStream* CHttpServer::ConstructStream()
{
return new CHtmlStream();
}
const AFX_PARSEMAP_ENTRY* CHttpServer::LookUp(LPCTSTR pszMethod,
const AFX_PARSEMAP*& pMap, AFX_PARSEMAP_ENTRY*& pParams,
AFX_PISAPICMD pCmdDefault /* = NULL */)
{
UINT iEntry;
LPCTSTR pszFnName;
const AFX_PARSEMAP* pParseMap = GetParseMap();
const AFX_PARSEMAP* pBaseMap;
const AFX_PARSEMAP_ENTRY* pRet = NULL;
while (pParseMap != NULL && pRet == NULL)
{
UINT cEntries = (*pParseMap->pfnGetNumMapEntries)();
const AFX_PARSEMAP_ENTRY* pCurrent = pParseMap->lpEntries;
for (iEntry = 0; iEntry < cEntries && pRet == NULL; iEntry++, pCurrent++)
{
#ifdef _DEBUG
// make sure not 2 parameter maps in a row
if (pCurrent->pfn == NULL && (iEntry+1 < cEntries))
ISAPIASSERT(pCurrent[1].pfn != NULL);
#endif
// skip parameter maps
if (pCurrent->pfn == NULL)
continue;
pszFnName = pCurrent->pszFnName;
// if the caller wants the default command, find that--
// if the caller wants something specific, perform a compare
// otherwise, see if we recursed to look up the default command
if (pCmdDefault == NULL)
{
if (pszMethod == NULL && pCurrent->pszArgs == NULL)
pRet = pCurrent;
else if (pszMethod != NULL && pCurrent->pszArgs != NULL
&& lstrcmpi(pszFnName, pszMethod) == 0)
pRet = pCurrent;
}
else if (pCurrent->pfn == pCmdDefault && pCurrent->pszArgs != NULL)
pRet = pCurrent;
if (pRet != NULL)
{
// if we need the default, recurse to find it by name
if (pszMethod == NULL && pCmdDefault == NULL)
return LookUp(NULL, pMap, pParams, pCurrent->pfn);
// found it! see if there are parameters
if (iEntry+1 >= cEntries || pCurrent[1].pfn != NULL)
{
pParams = NULL;
pMap = NULL;
}
else
{
pParams = (AFX_PARSEMAP_ENTRY*) &(pCurrent[1]);
pMap = pParseMap;
}
}
}
#ifdef _AFXDLL
pBaseMap = (*pParseMap->pfnGetBaseMap)();
#else
pBaseMap = pParseMap->pBaseMap;
#endif
// catch simple mistake of BEGIN_PARSE_MAP(CMyClass, CMyClass)
ISAPIASSERT(pBaseMap != pParseMap);
pParseMap = pBaseMap;
}
// no matching entry ?
if (pRet == NULL)
ISAPITRACE1("Warning: no handler for command '%s'\n", pszMethod);
return pRet;
}
UINT PASCAL CHttpServer::GetStackSize(const BYTE* pbParams)
{
// size of arguments on stack when pushed by value
static const UINT rgnByValue[] =
{
sizeof(_STACK_INT), // ITS_I2
sizeof(_STACK_LONG), // ITS_I4
sizeof(_STACK_FLOAT), // ITS_R4
sizeof(_STACK_DOUBLE), // ITS_R8
sizeof(LPCTSTR), // ITS_PSTR
0, // ITS_EMPTY
sizeof(LPCTSTR)+sizeof(_STACK_INT), // ITS_RAW
};
// sizeof 'this' pointer
UINT nCount = sizeof(CHttpServer*);
#ifdef _ALIGN_STACK
nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
#endif
// count arguments
ISAPIASSERT(pbParams != NULL);
while (*pbParams != 0 && *pbParams != IT_EMPTY)
{
// align if necessary
// get and add appropriate byte count
#ifdef _ALIGN_DOUBLES
// align doubles on 8 byte for some platforms
if (*pbParams == IT_R8)
nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
#endif
// *pbParams must fit in the rgnByValue array
ISAPIASSERT(*pbParams >= 1 && *pbParams <= sizeof(rgnByValue)/sizeof(UINT));
nCount += rgnByValue[*pbParams-1];
#ifdef _ALIGN_STACK
nCount = (nCount + (_ALIGN_STACK-1)) & ~(_ALIGN_STACK-1);
#endif
++pbParams;
}
#if defined(_ALIGN_DOUBLES) && defined(_SHADOW_DOUBLES)
// align doubles on 8 byte for some platforms
nCount = (nCount + _ALIGN_DOUBLES-1) & ~(_ALIGN_DOUBLES-1);
#endif
return nCount;
}
// indirect call helper (see OLECALL.CPP for implementation)
extern "C" DWORD AFXISAPI
_AfxParseCall(AFX_PISAPICMD pfn, void* pArgs, UINT nSizeArgs);
// invoke standard method given IDispatch parameters/return value, etc.
int CHttpServer::CallMemberFunc(CHttpServerContext* pCtxt,
const AFX_PARSEMAP_ENTRY* pEntry,
AFX_PARSEMAP_ENTRY* pParams, LPTSTR pszParams)
{
ISAPIASSERT(NULL != pEntry);
AFX_PISAPICMD pFunc = pEntry->pfn;
ISAPIASSERT(NULL != pFunc);
int nRet = callOK;
// get default function and parameters
BYTE bNoParams = 0;
::EnterCriticalSection(m_pCritSec);
const BYTE* pbParams = (const BYTE*)pEntry->pszArgs;
if (NULL == pbParams)
pbParams = &bNoParams;
UINT nParams = lstrlenA((LPCSTR)pbParams);
AFX_PARSEMAP_ENTRY_PARAMS *pDefaultParams = NULL;
if (pParams != NULL)
{
if (pParams->pszFnName == NULL)
nRet = ParseDefaultParams(pParams, nParams, pDefaultParams, pbParams);
else
pDefaultParams = (AFX_PARSEMAP_ENTRY_PARAMS*) pParams->pszFnName;
}
::LeaveCriticalSection(m_pCritSec);
if (nRet == callOK)
{
// get default function and return value information
AFX_PISAPICMD pfn = pEntry->pfn;
// determine size of arguments and allocate stack space
// include space for our context pointer
UINT nSizeArgs = GetStackSize(pbParams) + sizeof(_STACK_PTR);
ISAPIASSERT(nSizeArgs != 0);
if (nSizeArgs < _STACK_MIN)
nSizeArgs = _STACK_MIN;
BYTE* pStack = (BYTE*)_alloca(nSizeArgs + _SCRATCH_SIZE);
if (pStack == NULL)
{
ISAPITRACE0("Error: stack overflow in CHttpServer::CallMemberFunc()!\n");
return callNoStackSpace;
}
if (pDefaultParams != NULL)
#ifndef _SHADOW_DOUBLES
nRet = PushDefaultStackArgs(pStack, pCtxt, pbParams, pszParams,
pDefaultParams);
#else
nRet = PushDefaultStackArgs(pStack, pCtxt, pbParams, pszParams,
pDefaultParams, nSizeArgs);
#endif
else
#ifndef _SHADOW_DOUBLES
nRet = PushStackArgs(pStack, pCtxt, pbParams, pszParams);
#else
nRet = PushStackArgs(pStack, pCtxt, pbParams, pszParams, nSizeArgs);
#endif
pStack += _STACK_OFFSET;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -