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

📄 reqsock.cpp

📁 一个网路服务器程序
💻 CPP
📖 第 1 页 / 共 3 页
字号:
{
	int ndx;
	// a local reference to the root....
	CString& strRoot = m_pDoc->m_strRoot;
	// change all SEPCHARs to forward slashes....
	while ( (ndx=strFile.Find( SEPCHAR )) != -1 )
		strFile = strFile.Left( ndx ) + '/' + strFile.Mid(ndx+1);
	// now add the prefix and server, and cut the root....
	CString strPort;
	UINT uPort = m_pDoc->m_uPort;
	if ( uPort != PORT_HTTP )
		strPort.Format( ":%d", uPort );

	strFile = CString("http://")
		+ m_pDoc->m_strServer
		+ strPort
		+ strFile.Mid(strRoot.GetLength());

	return TRUE;
}

int CRequestSocket::StuffString( const CString& strData )
{
	int nLen = strData.GetLength()*sizeof(TCHAR);
	// make sure there's enough room....
	if ( m_cbOut + nLen > m_buf.GetSize() )
	{
		int nChunks = nLen/1024 + 1;
		m_buf.SetSize( m_cbOut + nChunks*1024 );
	}
	// copy the data....
	MoveMemory( m_buf.GetData() + m_cbOut, (LPCSTR)strData, nLen );
	m_cbOut += nLen;
	// return amount of space left....
	return (int)(m_buf.GetSize() - m_cbOut);
}

int CRequestSocket::StuffString( UINT uId )
{
	CString str;
	BOOL bOk = str.LoadString( uId );
    ASSERT(bOk);
	return StuffString( str );
}

int CRequestSocket::StuffStatus( const CString& strStatus )
{
	CString strVer = "HTTP/1.0 ";
	StuffString( strVer );
	StuffString( strStatus );
	StuffString( CRLF );

	// stuff the server name....
	CString strServer;
	if ( strServer.LoadString( IDS_SERVER_NAME ) && !strServer.IsEmpty() )
		StuffHeader( "Server", strServer );

	// stuff the date....
	return StuffHeader( "Date", GetHttpDate() );
}

int CRequestSocket::StuffStatus( UINT uStatus )
{
	CString strStatus;
	BOOL bOk = strStatus.LoadString( uStatus );
    ASSERT(bOk);
	// save the status for this request....
	m_pRequest->m_uStatus = uStatus;
	// stuff the HTTP status line....
	return StuffStatus( strStatus );
}

int CRequestSocket::StuffError( UINT uMsg )
{
	StuffStatus( uMsg );
	return StuffString( CRLF );
}

int CRequestSocket::StuffHeader( CString strName, CString strValue )
{
	StuffString( strName );
	StuffString( ": " );
	StuffString( strValue );
	return StuffString( CRLF );
}

int CRequestSocket::StuffHeader( CString strName, int nValue )
{
	CString strValue;
	StuffString( strName );
	StuffString( ": " );
	strValue.Format( "%d", nValue );
	StuffString( strValue );
	return StuffString( CRLF );
}

BOOL CRequestSocket::StuffHeading( void )
{
	BOOL bContinue = FALSE;
	if ( m_pRequest->m_dwAttr & FILE_ATTRIBUTE_HIDDEN )
	{
		// never show hidden files....
		StuffError( IDS_STATUS_FORBIDDEN );
	}
	else if ( m_pRequest->m_dwAttr & FILE_ATTRIBUTE_DIRECTORY )
	{
		if ( m_pDoc->m_bAllowListing )
		{
			// create a directory listing....
			StuffStatus( IDS_STATUS_OK );
			StuffString( CRLF );
			bContinue = TRUE;
		}
		else
			StuffError( IDS_STATUS_FORBIDDEN );
	}
#ifdef IMPL_CGI
	else if ( m_hFile != INVALID_HANDLE_VALUE )
	{
		// cgi's output file will be opened already....
		CString strStatus, strHeaders;
		// loop until we find a blank line....
		DWORD dwRead = 0;
		CByteArray baFile;
		baFile.SetSize( 1024 );
		// read next chunk....
		if(!ReadFile( m_hFile, baFile.GetData(),
			(DWORD)baFile.GetSize(), &dwRead, NULL ))
		{
			BOOL bOk = strStatus.LoadString(IDS_STATUS_SVRERROR);
            ASSERT(bOk);
			dwRead = 0;
			CloseHandle( m_hFile );
			m_hFile = INVALID_HANDLE_VALUE;
		}

		while ( dwRead > 0 )
		{
			int ndx = 0;
			while( GetLine( baFile, dwRead, ndx ) == TRUE )
			{
				BOOL bSave = TRUE;
				// stuff any non-empty lines.....
				if ( m_strLine.IsEmpty() )
				{
					// we found our empty line;
					// back up to where we left off....
					DWORD dwPos = 0;
					dwPos = SetFilePointer( m_hFile,
						ndx - dwRead,
						NULL, FILE_CURRENT );

					// and we're off....
					bContinue = TRUE;
					break;
				}
				else
				{
					int nPos = m_strLine.Find( ':' );
					if ( nPos != -1 )
					{
						CString strName = m_strLine.Left( nPos );
						strName.TrimLeft();
						strName.TrimRight();
						CString strVal  = m_strLine.Mid( nPos+1 );
						strVal.TrimLeft();
						strVal.TrimRight();
						if ( strName.CompareNoCase("Status") == 0 )
						{
							strStatus = strVal;
							bSave = FALSE;
						}
						else if ( strName.CompareNoCase("Location") == 0 )
						{
							BOOL bOk = strStatus.LoadString( IDS_STATUS_MOVEDTEMP );
                            ASSERT(bOk);
						}
					}
				}

				// save the header (if we want to)....
				if ( bSave )
					strHeaders += m_strLine + CRLF;

				m_strLine.Empty();
			}
			// read next chunk if we're not done....
			if ( bContinue )
				break;
			else
				if(!ReadFile( m_hFile, baFile.GetData(),
					(DWORD)baFile.GetSize(), &dwRead, NULL ))
				{
					BOOL bOk = strStatus.LoadString(IDS_STATUS_SVRERROR);
                    ASSERT(bOk);
					CloseHandle( m_hFile );
					m_hFile = INVALID_HANDLE_VALUE;
				
				}
		}
		if ( strStatus.IsEmpty() )
			StuffStatus( IDS_STATUS_OK );
		else
			StuffStatus( strStatus );

		// stuff the headers....
		StuffString( strHeaders );
		// stuff the blank line....
		StuffString( CRLF );
	}
#endif // IMPL_CGI
	else
	{
		// open the file....
		m_hFile = CreateFile( m_pRequest->m_strFullPath,
			GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
			NULL );
		if ( m_hFile != INVALID_HANDLE_VALUE )
		{
			if ( m_reqStatus != REQ_SIMPLE )
			{
				CTime timeIfMod;
				CString strIfMod = m_pRequest->GetHeaderValue( "If-Modified-Since" );
				if ( strIfMod.GetLength() > 0 &&
					FromHttpTime( strIfMod, timeIfMod ) &&
					!IfModSince( timeIfMod ) )
				{
					// eh, it hasn't been modified....
					StuffStatus( IDS_STATUS_NOTMODIFIED );
					// don't need it anymore....
					CloseHandle( m_hFile );
					m_hFile = INVALID_HANDLE_VALUE;
				}
				else
				{
					// send it off....
					StuffStatus( IDS_STATUS_OK );
					// any other header info....
					StuffFileType();
					StuffHeader( "Content-length", GetFileSize( m_hFile, NULL ) );
					// get the last modified time....
					FILETIME ft;
					if ( GetFileTime( m_hFile, NULL, NULL, &ft ) )
					{
						StuffHeader( "Last-Modified", GetHttpDate( &ft ) );
					}
					bContinue = TRUE;
				}
				// blank line....
				StuffString( CRLF );
			}
			else
				bContinue = TRUE;
		}
		else
		{
			// couldn't open; try again later....
			StuffError( IDS_STATUS_SVCUNAVAIL );
		}
	}
	return bContinue;
}

void CRequestSocket::StartTargetStuff( void )
{
	if ( m_hFile != INVALID_HANDLE_VALUE)
	{
		DWORD dwRead = 0;
		// read the first chunk....
		if(ReadFile( m_hFile, m_buf.GetData() + m_cbOut,
			(DWORD)(m_buf.GetSize()-m_cbOut), &dwRead, NULL ) && dwRead > 0)
		{
			m_cbOut += dwRead;
		}
		else
		{
			// nothing read.... close the file....
			CloseHandle( m_hFile );
			m_hFile = INVALID_HANDLE_VALUE;
		}
	}
	else if ( m_pRequest->m_dwAttr & FILE_ATTRIBUTE_DIRECTORY )
		StuffListing();
	else
		StuffString( CRLF );
}

void CRequestSocket::StuffListing( void )
{
	BOOL bRoot = FALSE;
	BOOL bIcons = m_pDoc->m_bListIcon;
	CString strIcon;
	CString strLine = CString("http://")
		+ m_pDoc->m_strServer
		+ m_pRequest->m_strURL;
	CString strDir = m_pRequest->m_strURL;
	CString strMask = m_pRequest->m_strFullPath;

	// make sure URL ends in a slash....
	if ( strDir.GetAt( strDir.GetLength()-1 ) != '/' )
		strDir += '/';
	// is this the server's root folder?
	else if ( strDir.Compare( "/" ) == 0 )
		bRoot = TRUE;

	// create the file search mask....
	AddFile( strMask, IDS_DIRMASK );
	StuffString( IDS_CONTENTS_PRE );
	StuffString( strLine );
	StuffString( IDS_CONTENTS_POST );
	if ( bRoot )
		StuffString( IDS_CONTENTS_DESC );

    if ( bIcons )
    {
		BOOL bOk = strIcon.LoadString( IDS_ICON_BLANK );
        ASSERT(bOk);
    }
	strLine.Format( IDS_CONTENTS_HEADING, strIcon );
	StuffString( strLine );

	int nFiles = 0;

	WIN32_FIND_DATA fd;
	// find the first file that matches the mask....
	HANDLE fh = FindFirstFile( strMask, &fd );
	if ( fh != INVALID_HANDLE_VALUE )
	{
		// create a line for the found file....
		nFiles += StuffListingFile( &fd, strDir, bIcons );
		// loop through all other files....
		while ( FindNextFile( fh, &fd ) )
			nFiles += StuffListingFile( &fd, strDir, bIcons );
	}

	if ( nFiles == 0 )
		StuffString( IDS_CONTENTS_EMPTY );

	StuffString( IDS_CONTENTS_FOOTER );
	// only add the parent link if there is one....
	if ( !bRoot )
	{
		if ( bIcons )
        {
			BOOL bOk = strIcon.LoadString( IDS_ICON_PARENT );
            ASSERT(bOk);
        }
		strLine.Format( IDS_CONTENTS_PARENT, strIcon );
		StuffString( strLine );
	}
	// add the note and end it....
	StuffString( IDS_CONTENTS_NOTE );
	StuffString( CRLF );
}

int CRequestSocket::StuffListingFile( WIN32_FIND_DATA* pfd, const CString& strDir, BOOL bIcons )
{
	int nFile = 0;
	// don't include '.', '..' or hidden files....
	if ( lstrcmp( pfd->cFileName, "." ) && lstrcmp( pfd->cFileName, ".." )
		&& (pfd->dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) == 0 )
	{
		CString strSize, strIcon = "";
		CString strLine, strFile = pfd->cFileName;
		CTime timeFile( pfd->ftLastWriteTime );
		BOOL bFolder = ((pfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0);
        BOOL bOk = TRUE;
		if ( bIcons && bFolder )
			bOk = strIcon.LoadString( IDS_ICON_FOLDER );
		else if ( bIcons )
			bOk = strIcon.LoadString( IDS_ICON_FILE );
        ASSERT(bOk);

		// create the link string....
		CString strLink = strDir + strFile;
		// make sure spaces are replaced with '%20'...
		int ndx;
		while ( (ndx=strLink.Find(' ')) != -1 )
			strLink = strLink.Left(ndx) + "%20" + strLink.Mid( ndx+1 );

		// format the size string....
		if ( bFolder )
			strSize = "  Folder";
		else if ( pfd->nFileSizeHigh > 0 )
			strSize = "   > 4GB"; // yeah, right.
		else if ( pfd->nFileSizeLow < 1024 )
			strSize = "    &lt; 1K";
		else
			strSize.Format( "%7dK", pfd->nFileSizeLow/1024 );

		strLine.Format( IDS_CONTENTS_FORMAT,
			timeFile.Format( IDS_FILETIMEFMT ),
			strSize, strLink, strIcon, strFile );
		StuffString( strLine );
		nFile = 1;
	}
	return nFile;
}

BOOL CRequestSocket::StartSvrApp( void )
{
#ifdef IMPL_CGI
	if ( m_pRequest->m_dwExecute != CRequest::APP_ISAPI )
		return CGIStart();
	else
	{
		StuffError( IDS_STATUS_NOTIMPL );
		return FALSE;
	}
#else //  IMPL_CGI
	StuffError( IDS_STATUS_NOTIMPL );
	return FALSE;
#endif // IMPL_CGI
}

#ifdef IMPL_CGI
BOOL CRequestSocket::CGIStart( void )
{
	BOOL bOk = FALSE;
	// get the temp path...
	CString strTempPath;
	DWORD dwSize = 0;
	if((dwSize = GetTempPath( 0, NULL )) == 0) 
		return FALSE;
	
	GetTempPath(dwSize,strTempPath.GetBuffer(dwSize));
	strTempPath.ReleaseBuffer();
	// create a temporary file for the output....
	CString strTempName;
	
	GetTempFileName( strTempPath, "CGI", 0, strTempName.GetBuffer(dwSize+12) );
	strTempName.ReleaseBuffer();
	m_hFile = CreateFile( strTempName, GENERIC_READ|GENERIC_WRITE,
		FILE_SHARE_READ|FILE_SHARE_WRITE, &g_sa,
		CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE, NULL );
	if ( m_hFile != INVALID_HANDLE_VALUE )
	{
		// create the cancel event....
		m_pCancel = new CEvent;
		if ( m_pCancel )
		{
			// make sure the event is reset....
			m_pCancel->ResetEvent();
			// create the CGI thread suspended....
			m_pThread = AfxBeginThread( (AFX_THREADPROC)CGIThread,
				(LPVOID)this, THREAD_PRIORITY_NORMAL, 0,
				CREATE_SUSPENDED, NULL );
			if ( m_pThread )
			{
				// don't self-destruct (we must delete)....
				m_pThread->m_bAutoDelete = FALSE;
				// resume...
				m_pThread->ResumeThread();
				bOk = TRUE;
			}
		}
	}

	if ( bOk == FALSE )
	{
		StuffError( IDS_STATUS_SVRERROR );
		if( m_hFile != INVALID_HANDLE_VALUE )
		{ // JIC....
			CloseHandle( m_hFile );
			m_hFile = INVALID_HANDLE_VALUE;
		}
	}
	return bOk;
}

void AddEnvVar( CString& strEnv, CString strName, CString strVal )
{
	// add the name=val pair to the env in alphabetical order....
	strEnv += strName + '=' + strVal + '\a';
}

UINT CGIThread( LPVOID pvParam )
{
	CRequestSocket* pReqSock = (CRequestSocket*)pvParam;
	CRequest* pRequest = pReqSock->m_pRequest;
	BOOL bOk = FALSE;
	DWORD dwErr;
	HANDLE hWritePipe, hReadPipe;
	// create a pipe we'll use for STDIN....
	if ( CreatePipe( &hReadPipe, &hWritePipe, &g_sa, 0 ) )
	{
		// get the command line together....
		CString strCmdLine = pRequest->m_strFullPath
			+ ' '
			+ Decode( pRequest->m_strArgs, TRUE );
		// get the directory....
		CString strDir = pRequest->m_strFullPath;
		int ndx = strDir.ReverseFind( SEPCHAR );
		// assume we found it....
		strDir = strDir.Left( ndx+1 );

		// create an environment for the CGI process....
		DWORD dwCreateFlags = 0;
#ifdef UNICODE
		dwCreateFlags = CREATE_UNICODE_ENVIRONMENT;
#endif // UNICODE
		CEnvironment cEnv;

		CString strValue;
		BOOL bOk = strValue.LoadString( IDS_SERVER_NAME );
        ASSERT(bOk);
		cEnv.Add( "SERVER_SOFTWARE", strValue );

⌨️ 快捷键说明

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