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

📄 clientsocket.cpp

📁 vc++6.0开发网络典型应用实例导航 1. 本光盘提供了本书中所有的实例源程序文件。 2. 附录文件夹下是Winsock 函数参考以及错误码列表
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/********************************************************************/
/*																	*/
/*  CLIENTSOCKET.CPP												*/
/*																	*/
/*  Implementation of the Client Socket.							*/
/*	This class is a part of the CClientThread which handles			*/
/*  socket connections. Incomming data is processed in OnReceive	*/
/*																	*/
/*  Programmed by Pablo van der Meer								*/
/*																	*/
/*	This code is stolen from: http://www.pablovandermeer.nl			*/
/*																	*/
/*  Last updated: July 4, 2003										*/
/*																	*/
/********************************************************************/

#include "stdafx.h"
#include "Server.h"
#include "ServerDlg.h"
#include "ClientSocket.h"
#include "ClientThread.h"
#include "Cookie.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define PACKET_SIZE 4096
#define BUFFER_OVERFLOW 8192

#define REQUEST_METHOD_POST 0
#define REQUEST_METHOD_GET	1

CClientSocket::CClientSocket()
{
	m_nStatus = STATUS_REQUEST;
	
	// default request method is POST
	m_nRequestMethod = REQUEST_METHOD_POST;
	
	m_QueryParams = "";
	m_FormVars = "";
	m_RxBuffer = "";
}


CClientSocket::~CClientSocket()
{
}


// Do not edit the following lines, which are needed by ClassWizard.
#if 0
BEGIN_MESSAGE_MAP(CClientSocket, CSocket)
	//{{AFX_MSG_MAP(CClientSocket)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#endif	// 0


// send WM_QUIT message to the thread containing the socket
// to shutdown once the connection is closed.
void CClientSocket::OnClose(int nErrorCode) 
{
	m_pThread->PostThreadMessage(WM_QUIT,0,0);
	CSocket::OnClose(nErrorCode);
}


/********************************************************************/
/*																	*/
/* Function name : OnReceive										*/		
/* Description   : Called by the framework to notify this socket	*/
/*                 that there is data in the buffer.				*/
/*																	*/
/********************************************************************/
void CClientSocket::OnReceive(int nErrorCode) 
{
	try
	{
		TCHAR buff[PACKET_SIZE+1];

		int nRead = Receive(buff, PACKET_SIZE);
		switch (nRead)
		{
			case 0:
				Close();
				break;

			case SOCKET_ERROR:
				if (GetLastError() != WSAEWOULDBLOCK) 
				{
					TCHAR szError[256];
					wsprintf(szError, "ERROR in OnReceive(): %d", GetLastError());
					((CClientThread *)m_pThread)->PostStatusMessage(szError);
				}
				break;

			default:
				if (nRead != SOCKET_ERROR && nRead != 0)
				{
					// terminate the string
					buff[nRead] = 0; 

					m_RxBuffer += buff;

					GetRequests();
					// parse and execute requests
					ProcessRequests();
				}	
				break;
		}
	}
	catch(...)
	{
		// something bad happened... (DOS attack?)
		((CClientThread *)m_pThread)->PostStatusMessage("Exception occurred in CSocket::OnReceive()!");
		// close the connection.
		m_pThread->PostThreadMessage(WM_QUIT,0,0);
	}
	CSocket::OnReceive(nErrorCode);
}

/********************************************************************/
/*																	*/
/* Function name : GetLocalPath										*/		
/* Description   : Convert relative path (URL) to local path		*/
/*																	*/
/********************************************************************/
BOOL CClientSocket::GetLocalPath(LPCTSTR lpszRelativePath, CString &strLocalPath, BOOL &bIsDirectory)
{
	CString strOffset;
	CString strRelativePath = lpszRelativePath;

	// make unix style
	strRelativePath.Replace("\\","/");
	while(strRelativePath.Replace("//","/"));
	
	if (strRelativePath.Left(1) == '/')
	{
		// absolute path
		strOffset = m_strHomeDir;
	}
	else
	{
		// relative path
		strOffset = m_strCurrentDir;
	}

	if (strOffset.Right(1) != '\\')
		strOffset += "\\";

	strRelativePath.TrimLeft('/');
	strLocalPath = strOffset + strRelativePath;

	// make Windows style
	strLocalPath.Replace("/", "\\");

	CStringList partList;
	CString strSub;
	int nCount=0;

	// split path in parts
	while(AfxExtractSubString(strSub, strLocalPath, nCount++, '\\'))
	{
		// get rid of insignificant dots
		if (strSub != "..")
		{
			strSub.TrimLeft('.');
			strSub.TrimRight('.');
		}

		if (!strSub.IsEmpty())
			partList.AddTail(strSub);
	}
	
	strLocalPath.Empty();

	// fix dots
	while(!partList.IsEmpty())
	{
		CString strPart = partList.GetHead();
		partList.RemoveHead();

		if (strPart == "..")
		{
			// go back one level
			int nPos = strLocalPath.ReverseFind('\\');
			if (nPos != -1)
			{
				strLocalPath = strLocalPath.Left(nPos);
			}
		}
		else
		{
			if (!strLocalPath.IsEmpty())
			{
				strLocalPath += "\\";
			}
			strLocalPath += strPart;
		}
	}		

	// check if the file/directory exists
	DWORD dwAttributes = GetFileAttributes(strLocalPath);

	bIsDirectory = ((dwAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);

	return (dwAttributes != 0xFFFFFFFF);
}


/********************************************************************/
/*																	*/
/* Function name: GetRequests										*/		
/* Description  : Parse complete Request line						*/
/*																	*/
/********************************************************************/
void CClientSocket::GetRequests()
{
	CString strTemp;
	int nIndex;

	while(!m_RxBuffer.IsEmpty())
	{
		nIndex = m_RxBuffer.Find("\r\n");
		if (nIndex != -1)
		{
			strTemp = m_RxBuffer.Left(nIndex);
			m_RxBuffer = m_RxBuffer.Mid(nIndex + 2);
			m_strLines.AddTail(strTemp);
		}
		else
		{
			if (m_RxBuffer.GetLength() > BUFFER_OVERFLOW)
			{
				((CClientThread *)m_pThread)->PostStatusMessage("Buffer overflow: DOS attack?");

				// close the connection.
				Close();

				// buffer overflow (DOS attack ?)
				m_pThread->PostThreadMessage(WM_QUIT,0,0);
			}
			break;
		}
	}
}


/********************************************************************/
/*																	*/
/* Function name: ProcessRequests									*/		
/* Description  : Parse and execute commands from client.			*/
/*																	*/
/********************************************************************/
void CClientSocket::ProcessRequests()
{
	CString strMethod, strURL, strVersion;
	CString strBuff;

	while(!m_strLines.IsEmpty())
	{
		strBuff = m_strLines.RemoveHead();

		// post data ?
		if (strBuff.IsEmpty())
		{
			m_nStatus = STATUS_BODY;
			continue;
		}

		switch(m_nStatus)
		{
			case STATUS_REQUEST:
			{
				int nIndex = strBuff.Find(' ');
				if (nIndex != -1)
				{
					strMethod = strBuff.Left(nIndex);
					
					// strip URL + version
					strBuff = strBuff.Mid(nIndex + 1);
					
					strBuff.TrimLeft();
					strBuff.TrimRight();

					nIndex = strBuff.Find(' ');
				
					if(nIndex != -1)
					{
						// Change any %x's to the appropriate char
						strURL = URLDecode(strBuff.Left(nIndex));

						strBuff.TrimRight();

						// get HTTP version number
						strVersion = strBuff.Mid(nIndex + 1);
					}
					else
					{
						// simple request
						strURL = URLDecode(strBuff);
					}
				}

				// add url to header collection
				m_Headers.Add("url", strURL);

				// check for arguments
				nIndex = strURL.Find('?');
				if (nIndex != -1)
				{
					// save query params
					m_QueryParams = strURL.Mid(nIndex+1);
					// strip from file name....
					strURL = strURL.Left(nIndex);
				}
				
				// add scriptname to header collection
				m_Headers.Add("script_name", strURL);
				m_Headers.Add("path_info", strURL);

				m_nStatus = STATUS_HEADER;

				// log method
				((CClientThread *)m_pThread)->PostStatusMessage(strMethod + " " + strURL);

				break;
			}
			case STATUS_HEADER:
			{
				int nIndex = strBuff.Find(':');
				if(nIndex != -1)
				{
					CString strName = strBuff.Left(nIndex);
					CString strValue = strBuff.Mid(nIndex + 1);
					strBuff.Format("HEADER: Name: %s, Value: %s", strName, strValue);
					TRACE1("%s\n", strBuff);

					// add item to header collection
					m_Headers.Add(strName, strValue);
				}
				break;
			}
			case STATUS_BODY:
			{
				m_FormVars += strBuff;
				m_FormVars += "&";
				break;
			}
		}

		if (strMethod.IsEmpty())
			continue;
	}
	
	strMethod.MakeUpper();
		
	CString strFileName;

	if ((strMethod == "GET") || (strMethod == "POST"))
	{
		if (strMethod == "GET")
			m_nRequestMethod = REQUEST_METHOD_GET;
		else
			m_nRequestMethod = REQUEST_METHOD_POST;

		BOOL bIsDirectory = FALSE;

		// convert URL to local path
		if (GetLocalPath(strURL, strFileName, bIsDirectory))
		{
			// add path_translated to header collection
			m_Headers.Add("path_translated", strFileName);

			if (bIsDirectory)
			{
				int nLength = strFileName.GetLength();
				if(strFileName.GetAt(nLength-1) == '\\')
				{
					strFileName += m_strDefaultPage;
				}
				else
				{
					strFileName += '\\';
					strFileName += m_strDefaultPage;
				}
			}
			// valid filename ?
			if (FileExists(strFileName, FALSE))
			{
				// is it an asp page ?
				if (strFileName.Right(4).CompareNoCase(".asp") == 0)
				{
					if (ExecuteAspPage(strFileName))
						return;

					// fall through to return error
				}
				else
				{
					SendFile(strFileName);
					return;
				}
			}
			else
			{
				((CClientThread *)m_pThread)->PostStatusMessage("Sending listing...");

				// return directory listing
				SendListing(strURL);
				return;
			}
		}
		
		((CClientThread *)m_pThread)->PostStatusMessage("Error processing: " + strURL);

		SendError("400 Bad Request");
		return;
	}
	else
	if (strMethod == "HEAD")
	{
		// specified a filename ?
		if ((GetFileAttributes(strFileName) & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY)
		{
			int nLength = strFileName.GetLength();
			if(strFileName.GetAt(nLength-1) == '\\')
			{
				strFileName += "index.html";
			}
			else
			{
				strFileName += '\\';
				strFileName += "index.html";
			}
		}
		// valid filename ?
		if (FileExists(strFileName, FALSE))
		{
			// log command
			((CClientThread *)m_pThread)->PostStatusMessage("Sending file: " + strFileName);

			//SendHeader(strFileName);
			SendFile(strFileName);
			return;
		}

		// return error ...	
		((CClientThread *)m_pThread)->PostStatusMessage("Error processing: " + strURL);
	}
	else
	if (strMethod == "OPTIONS")
	{
	}
	else
	if (strMethod == "PUT")
	{
	}
	else
	if (strMethod == "DELETE")
	{
	}
	else
	if (strMethod == "TRACE")
	{
	}
}


/********************************************************************/
/*																	*/
/* Function name : SendListing										*/		
/* Description   : Send directory listing							*/
/*																	*/
/********************************************************************/
BOOL CClientSocket::SendListing(LPCTSTR lpszURL)
{
	CString strResult;
	CString strLocalPath;

	// if no directory is specified, use current dir
	if (lstrcmp(lpszURL, "") == 0)
	{
		strLocalPath = m_strCurrentDir;
	}
	else
	{
		BOOL bDummy;
		GetLocalPath(lpszURL, strLocalPath, bDummy);
	}

	// is path subdirectory of home ?
	if (!IsSubDirectory(m_strHomeDir, strLocalPath))
	{
		SendError("403 Forbidden");
		return FALSE;
	}

	// HTTP version
	strResult =	"HTTP/1.0 ";
	// status
	strResult += "200 OK\r\n";
	// servername
	strResult += "Server: Mini ASP Web Server\r\n";
	// content type
	strResult += "Content-Type: Text/html\r\n\r\n";
	
	// start of directory listing
	strResult = "<HTML><HEAD><TITLE>";
	strResult += "Listing of: ";
	strResult += lpszURL;
	strResult += "</TITLE></HEAD><BODY>\r\n";

    strResult += "<TABLE width=100%%><TR><TD><B>Name</B></TD>"
									   "<TD><B>Size (bytes)</B></TD>"

⌨️ 快捷键说明

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