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

📄 extns.cpp

📁 Windows CE 6.0 Server 源码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
/*--
Module Name: ISAPI.CPP
Abstract: ISAPI handling code
--*/

#include "httpd.h"


// Amount of time before unloading an unused ISAPI
#define SCRIPT_TIMEOUT_DEFAULT   (1000*60*30)

const DWORD g_fIsapiExtensionModule = TRUE;

BOOL CGlobalVariables::InitExtensions(CReg *pWebsite) {
	DEBUGCHK(m_fRootSite);

	m_dwCacheSleep = pWebsite->ValueDW(RV_SCRIPTTIMEOUT,SCRIPT_TIMEOUT_DEFAULT);
	m_pISAPICache  = new CISAPICache();

	if (NULL == m_pISAPICache)
		return FALSE;

	InitScriptMapping(&m_scriptMap);
	InitScriptNoUnloadList(&m_scriptNoUnload);
	return TRUE;
}

void RemoveScriptNodes(PSCRIPT_MAP_NODE pScriptNodes, DWORD dwEntries);
void RemoveScriptNoUnloadList(WCHAR **szArray, DWORD dwEntries);

void CGlobalVariables::DeInitExtensions(void) {
	DEBUGCHK(m_fRootSite);
	RemoveScriptNodes(m_scriptMap.pScriptNodes,m_scriptMap.dwEntries);
	RemoveScriptNoUnloadList(m_scriptNoUnload.ppszNoUnloadEntry,m_scriptNoUnload.dwEntries);
}

BOOL CHttpRequest::ExecuteISAPI(WCHAR *wszExecutePath) {
	DWORD dwRet = HSE_STATUS_ERROR;
	EXTENSION_CONTROL_BLOCK ECB;
	CISAPI *pISAPIDLL = NULL;

	__try {
		if (! g_pVars->m_pISAPICache->Load(wszExecutePath,&pISAPIDLL))
			return FALSE;
		
		// create an ECB (this allocates no memory)
		FillECB(&ECB);
		
		// call the ISAPI
		dwRet = pISAPIDLL->CallExtension(&ECB);
		
		// grab log data if any
		if(ECB.lpszLogData[0]) {
			MyFree(m_pszLogParam);
			// silently fail on alloc failure.  ISAPI has sent all request
			// headers at this point anyway, we just lose log info.
			m_pszLogParam = MySzDupA(ECB.lpszLogData);
		}
	}
	__except(ReportFault(GetExceptionInformation(),0), EXCEPTION_EXECUTE_HANDLER) { // catch all exceptions
		DEBUGMSG(ZONE_ERROR, (L"HTTPD: ISAPI DLL caused exception 0x%08x and was terminated\r\n", GetExceptionCode()));
		g_pVars->m_pLog->WriteEvent(IDS_HTTPD_EXT_EXCEPTION,wszExecutePath,GetExceptionCode(),L"HttpExtensionProc",GetLastError());
	}

	g_pVars->m_pISAPICache->Unload(pISAPIDLL);

	// set keep-alive status based on return code
	m_fKeepAlive = (dwRet==HSE_STATUS_SUCCESS_AND_KEEP_CONN);
	
	DEBUGMSG(ZONE_ISAPI, (L"HTTPD: ISAPI ExtProc returned %d keep=%d\r\n", dwRet, m_fKeepAlive));
	DEBUGCHK(dwRet != HSE_STATUS_PENDING);
	return (dwRet!=HSE_STATUS_ERROR);
}

void CHttpRequest::FillECB(LPEXTENSION_CONTROL_BLOCK pECB) {
	ZEROMEM(pECB);
	pECB->cbSize = sizeof(*pECB);
	pECB->dwVersion = HSE_VERSION;
	pECB->ConnID = (HCONN)this;
	
	DEBUGCHK(m_pszMethod);

	// NOTE:  IIS examines dwHttpStatusCode on the return of HttpExtensionProc and 
	// uses this value for logging.  CE does not support this functionality.
	pECB->dwHttpStatusCode = 200;	
	pECB->lpszMethod = m_pszMethod;
	pECB->lpszQueryString = (PSTR)(m_pszQueryString ? m_pszQueryString : cszEmpty);
	pECB->lpszContentType = (PSTR)(m_pszContentType ? m_pszContentType : cszEmpty);
	pECB->lpszPathInfo = (PSTR) (m_pszPathInfo ? m_pszPathInfo : cszEmpty);	
	pECB->lpszPathTranslated = (PSTR) (m_pszPathTranslated ? m_pszPathTranslated : cszEmpty);

	pECB->cbTotalBytes = m_dwContentLength;
	pECB->cbAvailable = m_bufRequest.Count();
	DEBUGCHK(pECB->cbAvailable <= pECB->cbTotalBytes);
	
	pECB->lpbData = m_bufRequest.Data();

	pECB->GetServerVariable = ::GetServerVariable;
	pECB->WriteClient = ::WriteClient;
	pECB->ReadClient = ::ReadClient;
	pECB->ServerSupportFunction = ::ServerSupportFunction;
}

BOOL WINAPI GetServerVariable(HCONN hConn, PSTR psz, PVOID pv, PDWORD pdw) { 
	CHECKHCONN(hConn);
	CHECKPTRS2(psz, pdw);
	
	return ((CHttpRequest*)hConn)->GetServerVariable(psz, pv, pdw, FALSE);
}

int RecvToBuf(SOCKET socket, PVOID pv, DWORD dwReadBufSize, DWORD dwTimeout) {
	DEBUG_CODE_INIT;
	int iRecv = SOCKET_ERROR;
	DWORD dwAvailable;
	
	if (!MySelect(socket,dwTimeout)) {
		SetLastError(WSAETIMEDOUT);
		myleave(1400);
	}

	if(ioctlsocket(socket, FIONREAD, &dwAvailable)) {
		SetLastError(WSAETIMEDOUT);
		myleave(1401);
	}		

	iRecv = recv(socket, (PSTR) pv, (dwAvailable < dwReadBufSize) ? dwAvailable : dwReadBufSize, 0);
	if (iRecv == 0) {
		DEBUGMSG(ZONE_REQUEST,(L"HTTP: ReadBuffer call to recv() returns 0\r\n"));
		SetLastError(WSAETIMEDOUT); 
		myleave(1402);
	}
	if (iRecv == SOCKET_ERROR) {
		DEBUGMSG(ZONE_REQUEST,(L"HTTP: ReadBuffer call to recv() returns SOCKET_ERROR,GLE=0x%08x\r\n",GetLastError()));
		// recv() already has called SetLastError with appropriate message
		myleave(1403);
	}

done:
	DEBUGMSG_ERR(ZONE_REQUEST,(L"HTTPD: RecvToBuf returns error err = %d, GLE = 0x%08x\r\n",err,GetLastError()));
	return iRecv;
}

BOOL WINAPI ReadClient(HCONN hConn, PVOID pv, PDWORD pdw) {
	CHECKHCONN(hConn);
	CHECKPTRS2(pv, pdw);
	if ( *pdw == 0) {
		SetLastError(ERROR_INVALID_PARAMETER);
		return FALSE;
	}

	return ((CHttpRequest*)hConn)->ReadClient(pv,pdw);
}

BOOL CHttpRequest::ReadClient(PVOID pv, PDWORD pdw) {
	DEBUG_CODE_INIT;
	BOOL ret = FALSE;
	PVOID pvFilterModify = pv;
	DWORD dwBytesReceived;  
	DWORD dwBufferSize    = *pdw;

	m_bufRequest.InvalidateNextRequestIfAlreadyRead();

	if (!m_fHandleSSL)
		dwBytesReceived = RecvToBuf(m_socket,pv,*pdw,g_pVars->m_dwConnectionTimeout);
	else {
		DEBUGCHK(g_pVars->m_fSSL);

		// The buffer is designed so it will immediatly unencrypt a request sent to
		// it, so there's never encrypted data at end of buf.
		DWORD dwReadyBytes = m_bufRequest.UnaccessedCount();
		if (dwReadyBytes >= *pdw) {
			// We've already read in this data
			memcpy(pv,m_bufRequest.m_pszBuf+m_bufRequest.m_iNextInFollow,*pdw);
			m_bufRequest.m_iNextInFollow += (int) *pdw;
			dwBytesReceived = *pdw;
		}
		else {
			if (m_hrPreviousReadClient == INPUT_ERROR) {
				myleave(1395);
			}
			else if (m_hrPreviousReadClient == INPUT_TIMEOUT) {
				SetLastError(WSAETIMEDOUT);
				myleave(1396);
			}
		
			// copy what's in buf, reset where our read starts (we'll reuse
			// portion of buffer that's not in initial POST), and recv()
			PSTR  pszNextWrite = (PSTR)pv + dwReadyBytes;
			DWORD dwToRead     = *pdw-dwReadyBytes;

			if (dwReadyBytes)
				memcpy(pv,m_bufRequest.m_pszBuf+m_bufRequest.m_iNextInFollow,dwReadyBytes);
			m_bufRequest.m_iNextDecrypt = m_bufRequest.m_iNextInFollow = m_bufRequest.m_iNextIn = (int) m_dwInitialPostRead;

			// It's theoretically possible that the amount of bytes we have to read after
			// doing the above memcpy() is less than the size of an SSL header.  (ie if buf size=500,
			// we have 496 encrypted bytes, then we'd only be trying to read 4 bytes, which is bad if SSL header is 5 bytes long.)
			DWORD dwRecvOffWire = max(m_SSLInfo.m_Sizes.cbHeader,dwToRead);
			m_hrPreviousReadClient = m_bufRequest.RecvBody(m_socket,dwRecvOffWire,TRUE,FALSE,this,FALSE);

			if (m_hrPreviousReadClient == INPUT_TIMEOUT || m_hrPreviousReadClient == INPUT_ERROR) {
				// Only return FALSE in this case if there was no data in buffer, otherwise
				// we'll copy what we have and return FALSE next time client calls us.
				if (dwReadyBytes == 0) {
					if (m_hrPreviousReadClient == INPUT_ERROR)
						SetLastError(WSAETIMEDOUT);
					myleave(1398);
				}
			}

			DWORD dwToCopy = min(m_bufRequest.UnaccessedCount(),dwToRead);
			memcpy(pszNextWrite,m_bufRequest.m_pszBuf+m_bufRequest.m_iNextInFollow,dwToCopy);
			m_bufRequest.m_iNextInFollow += dwToCopy;
			dwBytesReceived = dwReadyBytes + dwToCopy;
		}
	}

	if (dwBytesReceived == 0 || dwBytesReceived == SOCKET_ERROR)
		myleave(1399);

	if (g_pVars->m_fFilters && !CallFilter(SF_NOTIFY_READ_RAW_DATA,(PSTR*) &pvFilterModify,(int*) &dwBytesReceived, NULL, (int *) &dwBufferSize))
		myleave(1404);

	// Check if filter modified pointer, copy if there's enough room for it.
	if (pvFilterModify != pv) 	{
		if (*pdw <= dwBufferSize) 		{
			memcpy(pv,pvFilterModify,dwBufferSize);
		}	
		else {
			DEBUGMSG(ZONE_ERROR,(L"HTTPD: An ISAPI read filter modified data buffer so it was too big for ISAPI ReadClient buf, no copy will be done\r\n"));
			SetLastError(ERROR_INSUFFICIENT_BUFFER);
			myleave(1405);
		}			
	}
	*pdw = dwBytesReceived;
	ret = TRUE;
done:
	DEBUGMSG_ERR(ZONE_ISAPI,(L"HTTPD:ReadClient failed, GLE = 0x%08x, err = % err\r\n",GetLastError(), err));
	return ret;
}

BOOL WINAPI WriteClient(HCONN hConn, PVOID pv, PDWORD pdw, DWORD dwFlags) {
	CHECKHCONN(hConn);
	CHECKPTRS2(pv, pdw);
	if(dwFlags & HSE_IO_ASYNC) { SetLastError(ERROR_INVALID_PARAMETER); return FALSE; }

	return ((CHttpRequest*)hConn)->WriteClient(pv, pdw,FALSE);
}

BOOL WINAPI ServerSupportFunction(HCONN hConn, DWORD dwReq, PVOID pvBuf, PDWORD pdwSize, PDWORD pdwType) {
	CHECKHCONN(hConn);
	return ((CHttpRequest*)hConn)->ServerSupportFunction(dwReq, pvBuf, pdwSize, pdwType);
}

BOOL CHttpRequest::ServerSupportFunction(DWORD dwReq, PVOID pvBuf, PDWORD pdwSize, PDWORD pdwType) {
	switch(dwReq)
	{
		// Can never support these
		//case HSE_REQ_ABORTIVE_CLOSE:  
		//case HSE_REQ_DONE_WITH_SESSION:	
		//case HSE_REQ_ASYNC_READ_CLIENT:
		//case HSE_REQ_GET_CERT_INFO_EX:	
		//case HSE_REQ_GET_IMPERSONATION_TOKEN:
		//case HSE_REQ_GET_SSPI_INFO:
		//case HSE_REQ_IO_COMPLETION:
		//case HSE_REQ_REFRESH_ISAPI_ACL:
		//case HSE_REQ_TRANSMIT_FILE:

		default:
		{
			SetLastError(ERROR_INVALID_PARAMETER);
			return FALSE;
		}

		case HSE_REQ_IS_KEEP_CONN: 
		{	
			CHECKPTR(pvBuf);
			*((BOOL *) pvBuf) = m_fKeepAlive;
			return TRUE;
		}

		case HSE_REQ_SEND_URL:
		case HSE_REQ_SEND_URL_REDIRECT_RESP:
		{
			CHECKPTR(pvBuf);

			// close connection, because ISAPI won't have a chance to add headers anyway
			CHttpResponse resp(this,STATUS_MOVED,CONN_CLOSE);
			resp.SendRedirect((PSTR)pvBuf); // send a special redirect body
			m_fKeepAlive = FALSE;
			return TRUE;
		}		

		case HSE_REQ_MAP_URL_TO_PATH_EX:
		case HSE_REQ_MAP_URL_TO_PATH:
		{	
			CHECKPTRS2(pvBuf,pdwSize);
			PSTR szURLToMap = (PSTR)pvBuf;
			if (!IsSlash(szURLToMap[0])) {
				DEBUGMSG(ZONE_ERROR,(L"HTTPD: ServerSupportFunction(HSE_REQ_MAP_URL_TO_PATH) returns failure because URL to map did not begin with a '/' or '\\'\r\n"));
				SetLastError(ERROR_INVALID_PARAMETER);
				return FALSE;
			}

			if (dwReq == HSE_REQ_MAP_URL_TO_PATH_EX) {
			 	if (!pdwType) {
					SetLastError(ERROR_INVALID_PARAMETER);
					return FALSE;
				}
				return MapURLToPath(szURLToMap,pdwSize,(LPHSE_URL_MAPEX_INFO) pdwType);				
			}
			else {
				// IIS docs are misleading here, but even if a valid param is passed in non-EX
				// case, ignore it.  (Like IIS.)	
				return MapURLToPath(szURLToMap,pdwSize);
			}
		}

		case HSE_REQ_SEND_RESPONSE_HEADER:
		{
			// no Connection header...let ISAPI send one if it wants
			CHttpResponse resp(this, STATUS_OK, CONN_NONE);
			// no body, default or otherwise (leave that to the ISAPI), but add default headers
			resp.SendResponse((PSTR) pdwType, (PSTR) pvBuf);
			return TRUE;
		}		

		case HSE_REQ_SEND_RESPONSE_HEADER_EX:
		{
			// Note:  We ignore cchStatus and cchHeader members.  
			CHECKPTR(pvBuf);
			HSE_SEND_HEADER_EX_INFO *pHeaderEx = (HSE_SEND_HEADER_EX_INFO *) pvBuf;

⌨️ 快捷键说明

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