⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isapi.cpp

📁 vc6.0完整版
💻 CPP
📖 第 1 页 / 共 4 页
字号:
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (C) 1992-1998 Microsoft Corporation
// All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.

// This module is unique -- no need for PCH

#include <limits.h>

#ifdef _AFXDLL
#include <afx.h>
#include <afxwin.h>
#include <afxdb.h>
#include <afxpriv.h>
#endif

#include <afxisapi.h>
#include <afxres.h>
#include <stdio.h>
#include <malloc.h>
#include "dispimpl.h"

///////////////////////////////////////////////////////////////////////
// Globals

// pointers to single global server and filter objects

static CHttpServer* pServer = NULL;
static CHttpFilter* pFilter = NULL;

// stock server extension strings

static const TCHAR szGet[] = _T("GET");
static const TCHAR szPost[] = _T("POST");
static const TCHAR szDecimalFormat[] = _T("%d");
static const TCHAR szFloatFormat[] = _T("%f");

// stock HTML tags

static const TCHAR szContentType[] = _T("Content-Type: text/html\r\n");
static const TCHAR szEndBody[] = _T("</body></html>");
static const TCHAR szStartTitle[] = _T("<html><head><title>");
static const TCHAR szEndTitle[] = _T("</title></head><body>");
static const TCHAR szDefaultTitle[] = _T("Default MFC Web Server Extension");

// error texts
// these aren't localized as they are part of the HTTP spec

typedef struct _httpstatinfo {
	DWORD   dwCode;
	LPCTSTR pstrString;
} HTTPStatusInfo;

static HTTPStatusInfo statusStrings[] = {
	{ HTTP_STATUS_OK,               _T("OK") },
	{ HTTP_STATUS_CREATED,          _T("Created") },
	{ HTTP_STATUS_ACCEPTED,         _T("Accepted") },
	{ HTTP_STATUS_NO_CONTENT,       _T("No Content") },
	{ HTTP_STATUS_TEMP_REDIRECT,    _T("Moved Temporarily") },
	{ HTTP_STATUS_REDIRECT,         _T("Moved Permanently") },
	{ HTTP_STATUS_NOT_MODIFIED,     _T("Not Modified") },
	{ HTTP_STATUS_BAD_REQUEST,      _T("Bad Request") },
	{ HTTP_STATUS_AUTH_REQUIRED,    _T("Unauthorized") },
	{ HTTP_STATUS_FORBIDDEN,        _T("Forbidden") },
	{ HTTP_STATUS_NOT_FOUND,        _T("Not Found") },
	{ HTTP_STATUS_REQUEST_TOO_LARGE,_T("Request entity was too large") },
	{ HTTP_STATUS_SERVER_ERROR,     _T("Internal Server Error") },
	{ HTTP_STATUS_NOT_IMPLEMENTED,  _T("Not Implemented") },
	{ HTTP_STATUS_BAD_GATEWAY,      _T("Bad Gateway") },
	{ HTTP_STATUS_SERVICE_NA,       _T("Service Unavailable") },
	{ 0, NULL }
};

/////////////////////////////////////////////////////////////////////////////
// Root of all parse maps

const AFXIS_DATADEF AFX_PARSEMAP CHttpServer::parseMap =
{
	&CHttpServer::GetNumMapEntries,
#ifdef _AFXDLL
	&CHttpServer::_GetBaseParseMap,
#else
	NULL,
#endif
	&CHttpServer::_parseEntries[0],
};

AFX_PARSEMAP_ENTRY CHttpServer::_parseEntries[] =
{
	{ NULL, NULL, NULL }    // nothing here
};

#ifdef _AFXDLL
const AFX_PARSEMAP* CHttpServer::_GetBaseParseMap()
{
	return NULL;
}
#endif

UINT PASCAL CHttpServer::GetNumMapEntries()
{
	return 0;
}

const AFX_PARSEMAP* CHttpServer::GetParseMap() const
{
	return NULL;
}

AFX_PARSEMAP::~AFX_PARSEMAP()
{
	// walk through parse map to find any dying parsed parameter entries

	UINT iEntry;
	UINT cEntries = (*pfnGetNumMapEntries)();
	AFX_PARSEMAP_ENTRY* pCurrent = (AFX_PARSEMAP_ENTRY*) lpEntries;

	for (iEntry = 0; iEntry < cEntries; iEntry++, pCurrent++)
	{
		if (pCurrent->pfn == NULL)
		{
			delete (AFX_PARSEMAP_ENTRY_PARAMS*) pCurrent->pszFnName;
			pCurrent->pszFnName = NULL;

			free(pCurrent->pszParamInfo);
			pCurrent->pszParamInfo = NULL;
		}
	}
}

AFX_PARSEMAP_ENTRY_PARAMS::~AFX_PARSEMAP_ENTRY_PARAMS()
{
	delete [] ppszInfo;
	delete [] ppszDefaults;
	delete [] ppszValues;
}

///////////////////////////////////////////////////////////////////////
// Entry points for HTTP Server Extensions

extern "C" DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
#ifdef _AFXDLL
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
	DWORD dwRet;

	ISAPIASSERT(pServer != NULL);
	if (pServer == NULL)
	{
		dwRet = HSE_STATUS_ERROR;
		pECB->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
	}
	else
		dwRet = pServer->HttpExtensionProc(pECB);

	return dwRet;
}

extern "C" BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
#ifdef _AFXDLL
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif
	BOOL bRet;

	ISAPIASSERT(pServer != NULL);
	if (pServer == NULL)
		bRet = FALSE;
	else
		bRet = pServer->GetExtensionVersion(pVer);

	return bRet;
}

extern "C" BOOL WINAPI TerminateExtension(DWORD dwFlags)
{
#ifdef _AFXDLL
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
#endif

	if (pServer == NULL)
		return TRUE;
	return pServer->TerminateExtension(dwFlags);
}

///////////////////////////////////////////////////////////////////////
// CHttpAsyncContext implementation

class CHttpAsyncContext
{
public:
	CHttpAsyncContext(HANDLE hFile, LPVOID pvHeader, DWORD dwHeaderLen,
					LPVOID pvTail, DWORD dwTailLen);
	virtual ~CHttpAsyncContext();

protected:
	LPVOID m_pvHeader;
	DWORD   m_dwHeaderLen;
	LPVOID m_pvTail;
	DWORD m_dwTailLen;
	HANDLE m_hFile;
};

CHttpAsyncContext::CHttpAsyncContext(HANDLE hFile, LPVOID pvHeader,
		DWORD dwHeaderLen, LPVOID pvTail, DWORD dwTailLen)
	: m_hFile(hFile)
{
	if (pvHeader == NULL || dwHeaderLen == 0)
	{
		m_pvHeader = NULL;
		dwHeaderLen = 0;
	}
	else
	{
		m_pvHeader = new BYTE[dwHeaderLen+1];
		memcpy(m_pvHeader, pvHeader, dwHeaderLen);
		reinterpret_cast<BYTE*>(m_pvHeader)[dwHeaderLen] = '\0';
		m_dwHeaderLen = dwHeaderLen;
	}

	if (pvTail == NULL || dwTailLen == 0)
	{
		m_pvTail = NULL;
		dwTailLen = 0;
	}
	else
	{
		m_pvTail = new BYTE[dwTailLen+1];
		memcpy(m_pvTail, pvTail, dwTailLen);
		reinterpret_cast<BYTE*>(m_pvTail)[dwTailLen] = '\0';
		m_dwTailLen = dwTailLen;
	}
}

CHttpAsyncContext::~CHttpAsyncContext()
{
	if (m_hFile != NULL && m_hFile != INVALID_HANDLE_VALUE)
		CloseHandle(m_hFile);

	delete [] m_pvTail;
	delete [] m_pvHeader;
}

///////////////////////////////////////////////////////////////////////
// CHttpServerContext implementation

void CHttpServerContext::Reset()
{
#ifdef _DEBUG
	m_dwOldEndOfHeaders = 0;
#endif
	m_pStream->Reset();
}

DWORD CHttpServerContext::SetChunkSize(DWORD dwNewSize)
{
	DWORD dwReturn = m_dwChunkSize;
	m_dwChunkSize = dwNewSize;
	return dwReturn;
}

DWORD CHttpServerContext::GetChunkSize() const
{
	return m_dwChunkSize;
}

VOID WINAPI AfxIOCallback(EXTENSION_CONTROL_BLOCK* pECB,
	PVOID pvContext, DWORD /* cbIO */, DWORD /* dwError */)
{
	if (!pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, NULL, NULL, NULL))
		ISAPITRACE("HttpExtensionProc io callback error\n");

	CHttpAsyncContext* pInfo = (CHttpAsyncContext*) pvContext;
	delete pInfo;
}

BOOL CHttpServerContext::TransmitFile(HANDLE hFile,
	DWORD dwFlags /* = HSE_IO_DISCONNECT_AFTER_SEND */,
	LPVOID pvHeader /* = NULL */, DWORD dwHeaderLen /* = 0 */,
	LPVOID pvTail /* = NULL */, DWORD dwTailLen /* = 0 */)
{
	if (hFile == INVALID_HANDLE_VALUE)
		return FALSE;

	ISAPIASSERT(dwHeaderLen == 0 || pvHeader != NULL);
	ISAPIASSERT(dwTailLen == 0 || pvTail != NULL);

	if (dwTailLen == 0 && pvTail != NULL)
		dwTailLen = lstrlen((LPCTSTR) pvTail);

	if (dwHeaderLen == 0 && pvHeader != NULL)
		dwHeaderLen = lstrlen((LPCTSTR) pvHeader);

	CHttpAsyncContext* pInfo =
		new CHttpAsyncContext(hFile, pvHeader, dwTailLen, pvTail, dwHeaderLen);

	HSE_TF_INFO info;

	info.pszStatusCode = NULL;
	info.hFile = hFile;
	info.dwFlags = dwFlags;
	info.BytesToWrite = 0;
	info.Offset = 0;
	info.pfnHseIO = AfxIOCallback;
	info.pContext = pInfo;
	info.pHead = pvHeader;
	info.HeadLength = dwHeaderLen;
	info.pTail = pvTail;
	info.TailLength = dwTailLen;

	BOOL bResult = ServerSupportFunction(HSE_REQ_TRANSMIT_FILE, &info, 0, 0);

	if (bResult)
	{
		m_dwStatusCode = HSE_STATUS_PENDING;
		m_bSendHeaders = FALSE;
	}
	else
		delete pInfo;

	return bResult;
}

///////////////////////////////////////////////////////////////////////
// CHttpServer implementation

BOOL CHttpServer::TerminateExtension(DWORD /* dwFlags */)
{
	// okay to unload at any time, by default
	return TRUE;
}

LPTSTR CHttpServer::GetQuery(CHttpServerContext* pCtxt, LPTSTR lpszQuery)
{
	// If the request is a POST, get all of the data.  First get what's
	// already available, then read any additional data via the
	// ReadClient() call.

	memcpy(lpszQuery, (LPCTSTR) pCtxt->m_pECB->lpbData, pCtxt->m_pECB->cbAvailable);
	lpszQuery[pCtxt->m_pECB->cbAvailable] = '\0';

	if (pCtxt->m_pECB->cbAvailable < pCtxt->m_pECB->cbTotalBytes)
	{
		LPTSTR pstrTarget = lpszQuery + pCtxt->m_pECB->cbAvailable;
		DWORD cbRemaining = pCtxt->m_pECB->cbTotalBytes - pCtxt->m_pECB->cbAvailable;
		DWORD cbRead;

		while (cbRemaining > 0)
		{
			cbRead = cbRemaining;
			if (!pCtxt->ReadClient(pstrTarget, &cbRead))
			{
				ISAPITRACE("Error: only %d of %d bytes read!\n",
					pCtxt->m_pECB->cbTotalBytes - cbRemaining,
					pCtxt->m_pECB->cbTotalBytes);
				return NULL;
			}

			if (cbRead == 0)
				break;

			pstrTarget += cbRead;
			cbRemaining -= cbRead;
		}

		*pstrTarget = '\0';
	}

	pCtxt->m_dwBytesReceived = pCtxt->m_pECB->cbTotalBytes;
	return lpszQuery;
}

BOOL CHttpServer::OnWriteBody(CHttpServerContext* pCtxt, LPBYTE pbContent,
								DWORD dwSize, DWORD dwReserved /* = 0 */)
{
	BOOL bRetVal;

	if (pCtxt->m_dwChunkSize == 0)
		bRetVal = pCtxt->WriteClient(pbContent, &dwSize, dwReserved);
	else
	{
		LPBYTE pbStart = pbContent;
		DWORD dwBytesLeft = dwSize;
		bRetVal = TRUE;

		while (bRetVal && (dwBytesLeft > 0))
		{
			DWORD dwThisChunk = min(dwBytesLeft, pCtxt->m_dwChunkSize);
			bRetVal = pCtxt->WriteClient(pbStart, &dwThisChunk, dwReserved);
			pbStart += dwThisChunk;
			dwBytesLeft -= dwThisChunk;
		}
	}

	return bRetVal;
}

DWORD CHttpServer::HttpExtensionProc(EXTENSION_CONTROL_BLOCK *pECB)
{
	DWORD dwRet = HSE_STATUS_SUCCESS;
	LPTSTR pszPostBuffer = NULL;
	LPTSTR pszQuery;
	LPTSTR pszCommand = NULL;
	int nMethodRet;
	LPTSTR pstrLastChar;
	DWORD cbStream = 0;
	BYTE* pbStream = NULL;
	CHttpServerContext ctxtCall(pECB);

	pECB->dwHttpStatusCode = 0;

	ISAPIASSERT(NULL != pServer);
	if (pServer == NULL)
	{
		dwRet = HSE_STATUS_ERROR;
		goto CleanUp;
	}

	// get the query

	if (lstrcmpi(pECB->lpszMethod, szGet) == 0)
	{
		pszQuery = pECB->lpszQueryString;
		ctxtCall.m_dwBytesReceived = lstrlen(pszQuery);
	}
	else if (lstrcmpi(pECB->lpszMethod, szPost) == 0)
	{
		if(pECB->cbTotalBytes == 0xffffffff)
		{
			dwRet = HSE_STATUS_ERROR ;
			pECB->dwHttpStatusCode = HTTP_STATUS_REQUEST_TOO_LARGE ;
			goto CleanUp;
		}
		
		if(pECB->cbTotalBytes < pECB->cbAvailable)
		{
			dwRet = HSE_STATUS_ERROR ;
			pECB->dwHttpStatusCode = HTTP_STATUS_BAD_REQUEST;
			goto CleanUp;
		}
		
		pszCommand = pECB->lpszQueryString;
		pszPostBuffer = new TCHAR[pECB->cbTotalBytes + 1];
		if( pszPostBuffer == NULL )
		{
			dwRet = HSE_STATUS_ERROR;
			goto CleanUp;
		}
		pszQuery =  GetQuery(&ctxtCall, pszPostBuffer);
		if (pszQuery == NULL)
		{
			dwRet = HSE_STATUS_ERROR;
			goto CleanUp;
		}
	}
	else
	{
		ISAPITRACE1("Error: Unrecognized method: %s\n", pECB->lpszMethod);
		dwRet = HSE_STATUS_ERROR;
		goto CleanUp;
	}

	// trim junk that some browsers put at the very end

	pstrLastChar = pszQuery + ctxtCall.m_dwBytesReceived -1;
	while ((*pstrLastChar == ' ' || *pstrLastChar == '\n' ||
		   *pstrLastChar == '\r') && pstrLastChar > pszQuery)
	{
		*pstrLastChar-- = '\0';
	}

	// do something about it

	if (!pServer->InitInstance(&ctxtCall))
		dwRet = HSE_STATUS_ERROR;
	else
	{
		pECB->dwHttpStatusCode = HTTP_STATUS_OK;
		try {
			nMethodRet = pServer->CallFunction(&ctxtCall, pszQuery, pszCommand);
		}
		catch (...)
		{
			ISAPITRACE1("Error: command %s caused an unhandled exception!\n",
				pszQuery);
			nMethodRet = callNoStackSpace;
		}

		// was an error caused by trying to dispatch?

		if (nMethodRet != callOK && pECB->dwHttpStatusCode == HTTP_STATUS_OK)
		{
			dwRet = HSE_STATUS_ERROR;
			switch (nMethodRet)
			{
			case callNoStream:
				pECB->dwHttpStatusCode = HTTP_STATUS_NO_CONTENT;
				break;

			case callParamRequired:
			case callBadParamCount:
			case callBadParam:
				pECB->dwHttpStatusCode = HTTP_STATUS_BAD_REQUEST;
				break;

			case callBadCommand:
				pECB->dwHttpStatusCode = HTTP_STATUS_NOT_IMPLEMENTED;
				break;

			case callNoStackSpace:
			default:
				pECB->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
				break;
			}
		}

		// if there was no error or the user said they handled
		// the error, prepare to spit out the generated HTML

		if (nMethodRet == callOK ||
			OnParseError(&ctxtCall, nMethodRet))
		{
			cbStream = ctxtCall.m_pStream->GetStreamSize();
			pbStream = ctxtCall.m_pStream->Detach();
		}
	}

CleanUp:
	// if there was an error, return an appropriate status
	TCHAR szResponse[64];
	BuildStatusCode(szResponse, pECB->dwHttpStatusCode);

	DWORD dwSize = cbStream - ctxtCall.m_dwEndOfHeaders;
	LPBYTE pbContent = NULL;
	BYTE cSaved = 0;

	if (pbStream != NULL && ctxtCall.m_bSendHeaders)
	{
		cSaved = pbStream[ctxtCall.m_dwEndOfHeaders];
		pbStream[ctxtCall.m_dwEndOfHeaders] = '\0';
		pbContent = &pbStream[ctxtCall.m_dwEndOfHeaders];
	}

	if (ctxtCall.m_bSendHeaders &&
		!ctxtCall.ServerSupportFunction(HSE_REQ_SEND_RESPONSE_HEADER,
			szResponse, 0, (LPDWORD) pbStream) &&
		::GetLastError() != 10054)  // WSAECONNRESET
	{
		pECB->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
		dwRet = HSE_STATUS_ERROR;
#ifdef _DEBUG
		DWORD dwCause = ::GetLastError();
		ISAPITRACE1("Error: Unable to write headers: 0x%8.8X!\n", dwCause);
#endif
	}
	else
	{
		if (pbContent != NULL)
		{
			BOOL bWorked = TRUE;

			// write a newline to separate content from headers

			if (ctxtCall.m_bSendHeaders)
			{
				*pbContent = cSaved;
				DWORD dwNewLineSize = 2;
				bWorked = ctxtCall.WriteClient(_T("\r\n"), &dwNewLineSize, 0);
			}

			if (!bWorked || !OnWriteBody(&ctxtCall, pbContent, dwSize))
			{
				dwRet = HSE_STATUS_ERROR;
				pECB->dwHttpStatusCode = HTTP_STATUS_SERVER_ERROR;
#ifdef _DEBUG

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -