📄 clientsocket.cpp
字号:
/********************************************************************/
/* */
/* 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 + -