📄 httpdirectory.cpp
字号:
//Variable used to generate the header response
CHttpResponseHeader responseHdr;
//Open the file (use the FILE_FLAG_SEQUENTIAL_SCAN to improve performance)
HANDLE hFile = ::CreateFile(pClient->m_Request.m_sLocalFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
//Get the last modified time for the file / directory
FILETIME ftFile;
FILETIME ftRequest;
SYSTEMTIME stFile;
BOOL bHaveFileTime = ::GetFileTime(hFile, NULL, NULL, &ftFile);
if (bHaveFileTime)
{
::FileTimeToSystemTime(&ftFile, &stFile);
//deliberately remove the milliseconds as they do not appear in HTTP responses.
stFile.wMilliseconds = 0;
SystemTimeToFileTime(&stFile, &ftFile);
}
//Get the current system time in UTC
SYSTEMTIME stCurTime;
FILETIME ftCurTime;
::GetSystemTime(&stCurTime);
::SystemTimeToFileTime(&stCurTime, &ftCurTime);
//Ensure that the file time is not past the server time
if (CompareFileTime(&ftFile, &ftCurTime) == 1)
{
CopyMemory(&ftFile, &ftCurTime, sizeof(FILETIME));
CopyMemory(&stFile, &stCurTime, sizeof(SYSTEMTIME));
}
//Handle conditional GET of the file
if (pClient->m_Request.m_Verb == CHttpRequest::HTTP_VERB_GET &&
bHaveFileTime && pClient->m_Request.m_bIfModifiedSincePresent &&
::SystemTimeToFileTime(&pClient->m_Request.m_IfModifiedSince, &ftRequest) &&
::CompareFileTime(&ftFile, &ftRequest) != 1)
{
//Form the header
responseHdr.AddStatusCode(304); //File Not modified
responseHdr.AddDate(stCurTime);
responseHdr.AddServer(pSettings->m_sServerName);
responseHdr.AddW3MfcAllowFields(pSettings->m_bAllowDeleteRequest);
if (pSettings->m_bAutoExpire)
responseHdr.AddExpires(stFile);
if (pClient->m_bResponseKeepAlive)
responseHdr.AddKeepAlive();
responseHdr.AddLastModified(stFile);
responseHdr.AddContentLength(0);
responseHdr.AddContentType(_T("text/html"));
//Send the header
#ifdef W3MFC_SSL_SUPPORT
responseHdr.Send(pClient->m_Socket, pSettings->m_dwWritableTimeout, pClient->m_SSL);
#else
responseHdr.Send(pClient->m_Socket, pSettings->m_dwWritableTimeout);
#endif
//No body is sent for a 304 status
//Log the information
pClient->PostLog(304, 0);
}
else
{
//Get the length of the file
DWORD dwFileLength = GetFileSize(hFile, NULL);
if (pClient->m_Request.m_dwHttpVersion > MAKELONG(9, 0))
{
CString sMime = pSettings->m_pMimeManager->GetMimeType(pClient->m_Request);
//Form the header of the response
responseHdr.AddStatusCode(200);
responseHdr.AddDate(stCurTime);
responseHdr.AddServer(pSettings->m_sServerName);
responseHdr.AddW3MfcAllowFields(pSettings->m_bAllowDeleteRequest);
if (pSettings->m_bAutoExpire)
responseHdr.AddExpires(stFile);
if (pClient->m_bResponseKeepAlive)
responseHdr.AddKeepAlive();
if (bHaveFileTime)
responseHdr.AddLastModified(stFile);
responseHdr.AddContentLength(dwFileLength);
responseHdr.AddContentType(sMime);
//Send back the file contents (if not a HEAD request)
if (pClient->m_Request.m_Verb == CHttpRequest::HTTP_VERB_HEAD)
{
//Just send the header
#ifdef W3MFC_SSL_SUPPORT
responseHdr.Send(pClient->m_Socket, pSettings->m_dwWritableTimeout, pClient->m_SSL);
#else
responseHdr.Send(pClient->m_Socket, pSettings->m_dwWritableTimeout);
#endif
}
else
{
//Send the header and body all in one
pClient->TransmitFile(pClient->m_Socket, responseHdr, hFile, dwFileLength, pSettings->m_dwWritableTimeout);
}
}
else
{
//No header sent for Http 0.9
//Send back the file contents (if not a HEAD request)
if (pClient->m_Request.m_Verb != CHttpRequest::HTTP_VERB_HEAD)
{
try
{
char sBuf[4096];
DWORD dwBytesRead = 0;
do
{
if (::ReadFile(hFile, sBuf, 4096, &dwBytesRead, NULL) && dwBytesRead)
#ifdef W3MFC_SSL_SUPPORT
pClient->m_Socket.SendWithRetry(sBuf, dwBytesRead, pSettings->m_dwWritableTimeout, pClient->m_SSL);
#else
pClient->m_Socket.SendWithRetry(sBuf, dwBytesRead, pSettings->m_dwWritableTimeout);
#endif
}
while (dwBytesRead);
}
catch(CWSocketException* pEx)
{
//Report the error
CString sError;
sError.Format(_T("CHttpDirectory::TransmitFile, Failed to send to socket, Error:%d"), pEx->m_nError);
pClient->m_pServer->OnError(sError);
pEx->Delete();
}
}
}
//Log the information
pClient->PostLog(200, dwFileLength);
}
//Don't forget to close the file
CloseHandle(hFile);
}
else
{
DWORD dwLastError = ::GetLastError();
if (dwLastError == ERROR_ACCESS_DENIED && ((GetFileAttributes(pClient->m_Request.m_sLocalFile) & FILE_ATTRIBUTE_DIRECTORY) == 0) &&
(pSettings->m_bAllowBasicAuthentication ||
pSettings->m_bAllowNTLMAuthentication))
pClient->ReturnUnauthorizedMessage(pClient->m_Request.m_sURL);
else
pClient->ReturnErrorMessage(404); //File not found
}
}
void CHttpDirectory::HandleDirectory(CHttpClient* pClient, BOOL bDirectory)
{
//Validate the parameters
ASSERT(pClient);
ASSERT(pClient->m_pServer);
CHttpServerSettings* pSettings = pClient->m_pServer->GetSettings();
ASSERT(pSettings);
//Do the directory level authentication
if (!HandleDirectoryAuthorization(pClient))
return;
if (m_bScript)
{
BOOL bSentSomething = FALSE;
#ifndef W3MFC_NO_ISAPI_SUPPORT
CString sDLL = pSettings->m_pISAPIManager->GetISAPIExtension(pClient->m_Request);
if (sDLL.GetLength())
{
bSentSomething = TRUE;
TransmitISAPIRequest(pClient, sDLL); //Do our ISAPI implementation
}
#endif
#ifndef W3MFC_NO_CGI_SUPPORT
if (!bSentSomething)
{
bSentSomething = TRUE;
pSettings->m_pCGI->TransmitCGIResponse(pClient); //Do our CGI implementation
}
#endif
if (!bSentSomething)
{
//Report the error
CString sError;
sError.Format(_T("CHttpDirectory::HandleDirectoryAuthorization, Directory is a script directory but ISAPI and / or CGI is not supported in this configuration, All requests for this directory will fail!!, %s"), m_sAlias);
pClient->m_pServer->OnError(sError);
pClient->ReturnErrorMessage(500); //Internal server error
}
}
else if (bDirectory)
TransmitDirectory(pClient); //Return a directory listing back to the client
else
TransmitFile(pClient); //Return the file back to the client
}
#ifndef W3MFC_NO_ISAPI_SUPPORT
void CHttpDirectory::TransmitISAPIRequest(CHttpClient* pClient, const CString& sDLL)
{
//Validate the parameters
ASSERT(pClient);
ASSERT(pClient->m_pServer);
CHttpServerSettings* pSettings = pClient->m_pServer->GetSettings();
ASSERT(pSettings);
ASSERT(pSettings->m_pISAPI);
//Reset the data counter
pClient->m_dwDataSentViaWriteClient = 0;
pClient->m_nHttpStatusCodeSent = 0;
pClient->m_bResponseKeepAlive = FALSE;
//Assume the worst
BOOL bSuccess = FALSE;
if (pSettings->m_bCacheISAPI)
{
CHttpISAPIExtension* pISAPI = pSettings->m_pISAPI->CachedLoad(sDLL);
if (pISAPI)
bSuccess = pSettings->m_pISAPI->CallHttpExtensionProc(pClient, *pISAPI);
}
else
{
CHttpISAPIExtension isapi;
if (pSettings->m_pISAPI->UncachedLoad(sDLL, isapi))
bSuccess = pSettings->m_pISAPI->CallHttpExtensionProc(pClient, isapi);
}
if (!bSuccess)
{
//Report the error
CString sError;
sError.Format(_T("CHttpDirectory::TransmitISAPIRequest, Failed calling the function HttpExtensionProc in the ISAPI extension %s"), sDLL);
pClient->m_pServer->OnError(sError);
pClient->ReturnErrorMessage(500); //Internal server error
}
else
pClient->PostLog(pClient->m_nHttpStatusCodeSent, pClient->m_dwDataSentViaWriteClient);
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -