📄 httpcgi.cpp
字号:
if (pSettings->m_sBindAddress.GetLength())
sLine.Format(_T("SERVER_NAME=%s\n"), pSettings->m_sBindAddress);
else
{
char pszHostName[256];
if (gethostname(pszHostName, 256) == 0)
{
CString sName(pszHostName);
sLine.Format(_T("SERVER_NAME=%s\n"), sName);
}
else
sLine = (_T("SERVER_NAME=\n"));
}
sEnvironment += sLine;
if (pClient->m_Request.m_nContentLength)
{
sLine.Format(_T("CONTENT_LENGTH=%d\n"), pClient->m_Request.m_nContentLength);
sEnvironment += sLine;
}
if (pClient->m_Request.m_sContentType.GetLength())
{
sLine.Format(_T("CONTENT_TYPE=%s\n"), pClient->m_Request.m_sContentType);
sEnvironment += sLine;
}
sLine.Format(_T("SERVER_PORT=%d\n"), pSettings->m_nPort);
sEnvironment += sLine;
#ifdef W3MFC_SSL_SUPPORT
if (pSettings->m_SSLProtocol == CHttpServerSettings::SSL_NONE)
sEnvironment += _T("SERVER_PROTOCOL=HTTP/1.0\n");
else
sEnvironment += _T("SERVER_PROTOCOL=HTTPS/1.0\n");
#else
sEnvironment += _T("SERVER_PROTOCOL=HTTP/1.0\n");
#endif
sLine.Format(_T("SERVER_SOFTWARE=%s\n"), pSettings->m_sServerName);
sEnvironment += sLine;
CString sScriptName = pClient->m_Request.m_sLocalFile;
sScriptName.Replace(_T('\\'), _T('/')); //Ensure we use unix directory separators
if (sScriptName.GetLength() && sScriptName.GetAt(0) != _T('/'))
sScriptName = _T("/") + sScriptName;
sLine.Format(_T("SCRIPT_NAME=%s\n"), sScriptName);
sEnvironment += sLine;
//Form the absolute path for PATH_TRANSLATED
LPTSTR pszFilePart;
TCHAR pszAbsolutePath[_MAX_PATH];
GetFullPathName(pClient->m_Request.m_sLocalFile, _MAX_PATH, pszAbsolutePath, &pszFilePart);
sLine.Format(_T("PATH_TRANSLATED=%s\n"), pszAbsolutePath);
sEnvironment += sLine;
sLine.Format(_T("REQUEST_LINE=%s\n"), pClient->m_Request.m_sRequest);
sEnvironment += sLine;
sLine.Format(_T("QUERY_STRING=%s\n"), pClient->m_Request.m_sRawExtra);
sEnvironment += sLine;
if (!pClient->m_Request.m_sRemoteHost.IsEmpty())
{
sLine.Format(_T("REMOTE_HOST=%s\n"), pClient->m_Request.m_sRemoteHost);
sEnvironment += sLine;
}
else
{
sLine.Format(_T("REMOTE_HOST=%d.%d.%d.%d\n"), pClient->m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b1,
pClient->m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b2, pClient->m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b3,
pClient->m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b4);
sEnvironment += sLine;
}
sLine.Format(_T("REMOTE_ADDR=%d.%d.%d.%d\n"), pClient->m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b1,
pClient->m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b2, pClient->m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b3,
pClient->m_Request.m_ClientAddress.sin_addr.S_un.S_un_b.s_b4);
sEnvironment += sLine;
sLine.Format(_T("PATH_INFO=%s\n"), pClient->m_Request.m_sPathInfo);
sEnvironment += sLine;
sLine.Format(_T("REQUEST_METHOD=%s\n"), pClient->m_Request.m_sVerb);
sEnvironment += sLine;
int nKeySize = 0;
if (pClient->GetKeySizeServerVariable(nKeySize))
{
sLine.Format(_T("HTTPS_KEYSIZE=%d\nCERT_KEYSIZE=%d\n"), nKeySize, nKeySize);
sEnvironment += sLine;
}
if (pClient->GetServerKeySizeServerVariable(nKeySize))
{
sLine.Format(_T("HTTPS_SECRETKEYSIZE=%d\nCERT_SECRETKEYSIZE=%d\n"), nKeySize, nKeySize);
sEnvironment += sLine;
}
sEnvironment += sLine;
#ifdef W3MFC_SSL_SUPPORT
if (pSettings->m_SSLProtocol == CHttpServerSettings::SSL_NONE)
sLine = _T("HTTPS=off\n");
else
sLine = _T("HTTPS=on\n");
#else
sLine = _T("HTTPS=off\n");
#endif
sEnvironment += sLine;
#ifdef W3MFC_SSL_SUPPORT
if (pSettings->m_SSLProtocol != CHttpServerSettings::SSL_NONE)
{
sLine.Format(_T("SERVER_PORT_SECURE=%d\n"), pSettings->m_nPort);
sEnvironment += sLine;
}
#endif
long nSerialNumber = 0;
if (pClient->GetCertSerialNumberServerVariable(nSerialNumber))
{
sLine.Format(_T("CERT_SERIALNUMBER=%d\n"), nSerialNumber);
sEnvironment += sLine;
}
sLine.Format(_T("REQUEST_URI=%s\n"), pClient->m_Request.m_sURL);
sEnvironment += sLine;
sLine.Format(_T("URL=%s\n"), pClient->m_Request.m_sURL);
sEnvironment += sLine;
if (pClient->m_Request.m_bLoggedOn)
{
sLine.Format(_T("LOGON_USER=%s\n"), pClient->m_Request.m_sUsername);
sEnvironment += sLine;
}
else if (pSettings->m_sUsername.GetLength())
{
sLine.Format(_T("LOGON_USER=%s\n"), pSettings->m_sUsername);
sEnvironment += sLine;
}
char* szIssuer = NULL;
if (pClient->GetCertIssuerServerVariable(szIssuer))
{
CString sIssuer(szIssuer);
sLine.Format(_T("CERT_SERVER_ISSUER=%s\nHTTPS_SERVER_ISSUER=%s\n"), sIssuer, sIssuer);
sEnvironment += sLine;
}
char* szSubject = NULL;
if (pClient->GetCertSubjectServerVariable(szSubject))
{
CString sSubject(szSubject);
sLine.Format(_T("CERT_SERVER_SUBJECT=%s\nHTTPS_SERVER_SUBJECT=%s\n"), sSubject, sSubject);
sEnvironment += sLine;
}
sLine.Format(_T("HTTP_VERSION=%d.%d\n"), HIWORD(pClient->m_Request.m_dwHttpVersion), LOWORD(pClient->m_Request.m_dwHttpVersion));
sEnvironment += sLine;
POSITION posMap = pClient->m_Request.m_HeaderMap.GetStartPosition();
while (posMap)
{
CString sKey;
CString sValue;
pClient->m_Request.m_HeaderMap.GetNextAssoc(posMap, sKey, sValue);
sLine.Format(_T("HTTP_%s=%s\n"), sKey, sValue);
sEnvironment += sLine;
}
return sEnvironment;
}
CString CHttpCGI::GetCGICommandLine(CHttpClient* pClient)
{
//What will be the return value
CString sCommandLine(pClient->m_Request.m_sLocalFile);
//First get the extension of the file
TCHAR sExt[_MAX_EXT];
_tsplitpath(pClient->m_Request.m_sLocalFile, NULL, NULL, NULL, sExt);
//Now get the command line for this extension from the registry
TCHAR pszValue[1024/sizeof(TCHAR)];
DWORD nData = 1024;
HKEY hExtKey = NULL;
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, sExt, 0, KEY_READ, &hExtKey) == ERROR_SUCCESS)
{
if (RegQueryValueEx(hExtKey, NULL, NULL, NULL, (LPBYTE)pszValue, &nData) == ERROR_SUCCESS)
{
//Close the registry key now that we are finished with it
RegCloseKey(hExtKey);
//pszValue is now the Extension File Subkey to use.
CString sValue;
sValue.Format(_T("%s\\Shell\\Open\\Command"), pszValue);
nData = 1024; //reset the size parameter
HKEY hExtensionFileKey = NULL;
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, sValue, 0, KEY_READ, &hExtensionFileKey) == ERROR_SUCCESS)
{
if (RegQueryValueEx(hExtensionFileKey, NULL, NULL, NULL, (LPBYTE)pszValue, &nData) == ERROR_SUCCESS)
{
//Expand the string with any environment variables it may contain
nData = 1024;
LPTSTR szBuf = sCommandLine.GetBuffer(nData);
DWORD dwRet = ExpandEnvironmentStrings(pszValue, szBuf, nData);
sCommandLine.ReleaseBuffer();
if (dwRet != 0)
{
sCommandLine.Replace(_T("%L"), pClient->m_Request.m_sLocalFile);
sCommandLine.Replace(_T("%1"), pClient->m_Request.m_sLocalFile);
sCommandLine.Replace(_T("%*"), _T(""));
}
}
//Close the registry key now that we are finished with it
RegCloseKey(hExtensionFileKey);
}
}
}
return sCommandLine;
}
void CHttpCGI::WriteToChildStdin(CHttpClient* pClient, HANDLE hChildStdin)
{
//Write the entity body to STDIN of the CGI child process
DWORD dwWritten;
ASSERT(pClient->m_Request.m_pRawEntity);
WriteFile(hChildStdin, pClient->m_Request.m_pRawEntity, pClient->m_Request.m_dwRawEntitySize, &dwWritten, NULL);
}
DWORD CHttpCGI::ReadFromClientStdout(CHttpClient* pClient, HANDLE hChildStdout, BOOL& bFoundKeepAlive)
{
//Validate our parameters
ASSERT(pClient);
ASSERT(pClient->m_pServer);
CHttpServerSettings* pSettings = pClient->m_pServer->GetSettings();
ASSERT(pSettings);
//Initialize the out parameters
bFoundKeepAlive = FALSE;
DWORD dwDataSent = 0;
//Allocate the receive / re transmit buffer
char* pszBuf = (char*) alloca(pSettings->m_dwCGIResponseBufferSize);
//Read output from the child process, and write to parent's STDOUT.
BOOL bMore = TRUE;
BOOL bFirstBuffer = TRUE;
while (bMore)
{
DWORD dwRead;
if (!ReadFile(hChildStdout, pszBuf, pSettings->m_dwCGIResponseBufferSize-1, &dwRead, NULL) || dwRead == 0)
bMore = FALSE;
else
{
//Used as a return value to indicate how much was sent to the client
dwDataSent += dwRead;
BOOL bFoundHTTPReturnCodeLine = FALSE;
if (bFirstBuffer)
{
//NULL terminate the data (so that we can use strstr)
pszBuf[dwRead] = '\0';
//See if the "Connection: Keep Alive" is being transmitted
bFoundKeepAlive = (strstr(pszBuf, "Connection: Keep-Alive") != NULL);
if (bFoundKeepAlive)
{
//Note it is important that "Content-Length" be also sent when using keep alives
//as otherwise client browsers do not know when to stop reading to get the end
//of the first response
bFoundKeepAlive = (strstr(pszBuf, "Content-Length: ") != NULL);
}
//Do we have a HTTP return code line
bFoundHTTPReturnCodeLine = (strstr(pszBuf,"HTTP/") != NULL);
//We only do this parse on the first buffer
bFirstBuffer = FALSE;
}
//Send the data back down the socket
try
{
char* pszTTPReturnCodeLine = "HTTP/1.0 200 OK\n";
#ifdef W3MFC_SSL_SUPPORT
if (!bFoundHTTPReturnCodeLine)
pClient->m_Socket.SendWithRetry(pszTTPReturnCodeLine, strlen(pszTTPReturnCodeLine), pSettings->m_dwWritableTimeout, pClient->m_SSL);
pClient->m_Socket.SendWithRetry(pszBuf, dwRead, pSettings->m_dwWritableTimeout, pClient->m_SSL);
#else
if (!bFoundHTTPReturnCodeLine)
pClient->m_Socket.SendWithRetry(pszTTPReturnCodeLine, strlen(pszTTPReturnCodeLine), pSettings->m_dwWritableTimeout);
pClient->m_Socket.SendWithRetry(pszBuf, dwRead, pSettings->m_dwWritableTimeout);
#endif
}
catch(CWSocketException* pEx)
{
//Report the error
CString sError;
sError.Format(_T("CHttpCGI::ReadFromClientStdout, Failed to send to socket, Error:%d"), pEx->m_nError);
pClient->m_pServer->OnError(sError);
pEx->Delete();
bMore = FALSE;
}
}
}
return dwDataSent;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -