📄 httpclient.cpp
字号:
m_bResponseKeepAlive = pSettings->m_bKeepAlives && m_Request.m_bKeepAlive;
//Impersonate the client credentials if authorization type is PLAINTEXT
CW32Handle hImpersonation;
BOOL bLoggedOn = FALSE;
if (m_Request.m_AuthorizationType == CHttpRequest::HTTP_AUTHORIZATION_PLAINTEXT && pSettings->m_bPerformPassthroughAuthentication)
{
LPTSTR pszUser = m_Request.m_sUsername.GetBuffer(m_Request.m_sUsername.GetLength());
LPTSTR pszPassword = m_Request.m_sPassword.GetBuffer(m_Request.m_sPassword.GetLength());
bLoggedOn = LogonUser(pszUser, NULL, pszPassword, LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hImpersonation);
if (bLoggedOn)
{
ImpersonateLoggedOnUser(hImpersonation);
m_Request.m_bLoggedOn = TRUE;
}
else
{
//Report the error
CString sError;
sError.Format(_T("CHttpClient::HandleClient, Failed to logon using user name: %s, GetLastError:%d"), pszUser, ::GetLastError());
m_pServer->OnError(sError);
}
m_Request.m_sUsername.ReleaseBuffer();
m_Request.m_sPassword.ReleaseBuffer();
}
#ifndef W3MFC_NO_SSPI_SUPPORT
else if (m_Request.m_AuthorizationType == CHttpRequest::HTTP_AUTHORIZATION_NTLM && !bImpersonatedUsingSSPI)
{
bImpersonatedUsingSSPI = TRUE;
SECURITY_STATUS ss = ImpersonateSecurityContext(&m_Request.m_ContentHandle);
bLoggedOn = (ss == SEC_E_OK);
if (bLoggedOn)
{
//Pull out some values from the SSPI context handle and stuff them in the request object
SecPkgContext_Names names;
if (QueryContextAttributes(&m_Request.m_ContentHandle, SECPKG_ATTR_NAMES, &names) == SEC_E_OK)
{
m_Request.m_sUsername = names.sUserName;
FreeContextBuffer(names.sUserName);
}
SecPkgContext_Authority authority;
if (QueryContextAttributes(&m_Request.m_ContentHandle, SECPKG_ATTR_AUTHORITY, &authority) == SEC_E_OK)
{
m_Request.m_sAuthorityName = authority.sAuthorityName;
FreeContextBuffer(authority.sAuthorityName);
}
}
else
{
//Report the error
CString sError;
sError.Format(_T("CHttpClient::HandleClient, Failed to impersonate client credentials using SSPI: %s, Error:%d"), ss);
m_pServer->OnError(sError);
}
}
#endif
m_Request.m_hImpersonation = hImpersonation;
if (m_Request.m_AuthorizationType == CHttpRequest::HTTP_AUTHORIZATION_ANONYMOUS && !pSettings->m_bAllowAnonymous)
{
//Return an unauthorized message if some form of authentication is enabled
if (pSettings->m_bAllowBasicAuthentication || pSettings->m_bAllowNTLMAuthentication)
ReturnUnauthorizedMessage(m_Request.m_sURL);
else
{
//Report the error
m_pServer->OnError(_T("CHttpClient::HandleClient, Anonymous access is disabled in addition to all authentication mechanisms, All requests will Fail!!"));
ReturnErrorMessage(500); //Internal server error
}
}
else
{
if (m_Request.m_Verb == CHttpRequest::HTTP_VERB_GET || m_Request.m_Verb == CHttpRequest::HTTP_VERB_HEAD || m_Request.m_Verb == CHttpRequest::HTTP_VERB_POST)
{
if (!PreHandleGetPostHead()) //Allow derived classes to handle GET, HEAD or POST
{
BOOL bDirectory = FALSE;
CHttpDirectory* pDirectory = NULL;
DWORD dwMatchingURL = 0;
DWORD dwMatchingPath = 0;
if (MapURLToLocalFilename(m_Request.m_sURL, m_Request.m_sLocalFile, m_Request.m_sPathInfo, bDirectory, pDirectory, dwMatchingURL, dwMatchingPath))
{
ASSERT(pDirectory);
pDirectory->HandleDirectory(this, bDirectory);
}
else
ReturnErrorMessage(404); //Not Found
}
}
else if (pSettings->m_bAllowDeleteRequest && m_Request.m_Verb == CHttpRequest::HTTP_VERB_DELETE)
{
//By default, only allow deletion of a file if we are using authorization
if (m_Request.m_AuthorizationType != CHttpRequest::HTTP_AUTHORIZATION_ANONYMOUS)
{
CString sLocalFile;
BOOL bDirectory = FALSE;
CHttpDirectory* pDirectory = NULL;
DWORD dwMatchingURL = 0;
DWORD dwMatchingPath = 0;
if (MapURLToLocalFilename(m_Request.m_sURL, m_Request.m_sLocalFile, m_Request.m_sPathInfo, bDirectory, pDirectory, dwMatchingURL, dwMatchingPath) && !bDirectory && pDirectory->GetWritable())
{
if (DeleteFile(m_Request.m_sLocalFile))
ReturnFileDeletedOkMessage(m_Request.m_sLocalFile);
else
{
if (::GetLastError() == ERROR_ACCESS_DENIED && !bDirectory)
ReturnUnauthorizedMessage(m_Request.m_sURL);
else
ReturnErrorMessage(500); //Internal server error
}
}
else
ReturnErrorMessage(404); //Not Found
}
else if (pSettings->m_bAllowBasicAuthentication || pSettings->m_bAllowNTLMAuthentication)
ReturnUnauthorizedMessage(m_Request.m_sURL); //Not authorized
else
ReturnErrorMessage(404); //Not Found
}
else
ReturnErrorMessage(501); //Not implemented
}
//Restore our usual security priviledges
if (m_Request.m_AuthorizationType == CHttpRequest::HTTP_AUTHORIZATION_PLAINTEXT)
{
//Revert to the usual security settings
RevertToSelf();
}
}
else
ReturnErrorMessage(400); //Bad Request
}
//Should we service another request
bMoreRequests = m_bResponseKeepAlive;
//Remember some values from the old request
BOOL bAuthenticationCompleted = m_Request.m_bAuthenticationComplete;
CHttpRequest::HttpAuthorization Authorization = m_Request.m_AuthorizationType;
CString sRemoteHost = m_Request.m_sRemoteHost;
CString sUsername = m_Request.m_sUsername;
CString sAuthorityName = m_Request.m_sAuthorityName;
sockaddr_in clientAddress;
CopyMemory(&clientAddress, &m_Request.m_ClientAddress, sizeof(sockaddr_in));
//Reset the request data before we (potentially) loop around or exit
m_Request = CHttpRequest();
//Reinstate the Authentication completed flag. This prevents the need for reauthentications if the connection is keep alive
m_Request.m_bAuthenticationComplete = bAuthenticationCompleted;
//Reinstate the Authentication type and the Authority type and username (if it requires keep alives, which is only NTLM currently)
if (Authorization == CHttpRequest::HTTP_AUTHORIZATION_NTLM)
{
m_Request.m_AuthorizationType = Authorization;
m_Request.m_sUsername = sUsername;
m_Request.m_sAuthorityName = sAuthorityName;
}
//Reinstate the client connection details
CopyMemory(&m_Request.m_ClientAddress, &clientAddress, sizeof(sockaddr_in));
m_Request.m_sRemoteHost = sRemoteHost;
}
while (bMoreRequests);
//Undo the SSPI impersonation
#ifndef W3MFC_NO_SSPI_SUPPORT
if (bImpersonatedUsingSSPI)
RevertSecurityContext(&m_Request.m_ContentHandle);
//Free up the context handle
DeleteSecurityContext(&m_Request.m_ContentHandle);
#endif
}
BOOL CHttpClient::ParseSimpleRequestLine(const CString& sLine)
{
ASSERT(m_pServer);
CHttpServerSettings* pSettings = m_pServer->GetSettings();
ASSERT(pSettings);
//Make a local copy of the string for parsing purposes
TCHAR* pszLine = new TCHAR[sLine.GetLength() + 1];
_tcscpy(pszLine, sLine);
//Assume the worst
BOOL bSuccess = FALSE;
//First parse out the VERB
TCHAR seps[] = _T(" ");
TCHAR* pszVerb = _tcstok(pszLine, seps);
if (pszVerb)
{
m_Request.m_sVerb = pszVerb;
if (_tcsicmp(pszVerb, _T("GET")) == 0)
m_Request.m_Verb = CHttpRequest::HTTP_VERB_GET;
else if (_tcsicmp(pszVerb, _T("POST")) == 0)
m_Request.m_Verb = CHttpRequest::HTTP_VERB_POST;
else if (_tcsicmp(pszVerb, _T("HEAD")) == 0)
m_Request.m_Verb = CHttpRequest::HTTP_VERB_HEAD;
else if (_tcsicmp(pszVerb, _T("PUT")) == 0)
m_Request.m_Verb = CHttpRequest::HTTP_VERB_PUT;
else if (_tcsicmp(pszVerb, _T("LINK")) == 0)
m_Request.m_Verb = CHttpRequest::HTTP_VERB_LINK;
else if (_tcsicmp(pszVerb, _T("DELETE")) == 0)
m_Request.m_Verb = CHttpRequest::HTTP_VERB_DELETE;
else if (_tcsicmp(pszVerb, _T("UNLINK")) == 0)
m_Request.m_Verb = CHttpRequest::HTTP_VERB_UNLINK;
else
m_Request.m_Verb = CHttpRequest::HTTP_VERB_UNKNOWN;
//Parse out the URL
TCHAR* pszURL = _tcstok(NULL, seps);
if (pszURL)
{
m_Request.m_sRawURL = pszURL;
m_Request.m_sURL = UTF8ToCString(URLDecode(pszURL)); //Convert any embedded escape sequences to their unencoded format
//as well as handling UTF8 input data
//Handle the Search path i.e everything after the ?
int nQuestion = m_Request.m_sURL.Find(_T('?'));
if (nQuestion != -1)
{
m_Request.m_sExtra = m_Request.m_sURL.Right(m_Request.m_sURL.GetLength() - nQuestion - 1);
m_Request.m_sURL = m_Request.m_sURL.Left(nQuestion);
}
nQuestion = m_Request.m_sRawURL.Find(_T('?'));
if (nQuestion != -1)
m_Request.m_sRawExtra = m_Request.m_sRawURL.Right(m_Request.m_sRawURL.GetLength() - nQuestion - 1);
//Parse out the HTTP version
TCHAR* pszVersion = _tcstok(NULL, seps);
if (pszVersion)
{
if (_tcsstr(pszVersion, _T("HTTP/")) == pszVersion)
{
TCHAR sepsVer[] = _T(".");
TCHAR* pszMajorVersion = _tcstok(pszVersion+5, sepsVer);
if (pszMajorVersion)
{
WORD wMajorVersion = (WORD) _ttoi(pszMajorVersion);
TCHAR* pszMinorVersion = _tcstok(NULL, sepsVer);
if (pszMinorVersion)
{
WORD wMinorVersion = (WORD) _ttoi(pszMinorVersion);
m_Request.m_dwHttpVersion = MAKELONG(wMinorVersion, wMajorVersion);
bSuccess = TRUE;
}
}
}
}
else
{
//No version included in the request, so set it to HTTP v0.9
m_Request.m_dwHttpVersion = MAKELONG(9, 0);
bSuccess = m_Request.m_Verb == CHttpRequest::HTTP_VERB_GET; //"GET" is only allowed with HTTP v0.9
}
}
}
//Tidy up the heap memory we have used before we return
delete [] pszLine;
return bSuccess;
}
BOOL CHttpClient::ParseWeekDay(char* pszToken, int& nWeekDay)
{
BOOL bSuccess = TRUE;
if (strcmpi(pszToken, "Sun") == 0 || strcmpi(pszToken, "Sunday") == 0)
nWeekDay = 0;
else if (strcmpi(pszToken, "Mon") == 0 || strcmpi(pszToken, "Monday") == 0)
nWeekDay = 1;
else if (strcmpi(pszToken, "Tue") == 0 || strcmpi(pszToken, "Tuesday") == 0)
nWeekDay = 2;
else if (strcmpi(pszToken, "Wed") == 0 || strcmpi(pszToken, "Wednesday") == 0)
nWeekDay = 3;
else if (strcmpi(pszToken, "Thu") == 0 || strcmpi(pszToken, "Thursday") == 0)
nWeekDay = 4;
else if (strcmpi(pszToken, "Fri") == 0 || strcmpi(pszToken, "Friday") == 0)
nWeekDay = 5;
else if (strcmpi(pszToken, "Sat") == 0 || strcmpi(pszToken, "Saturday") == 0)
nWeekDay = 6;
else
bSuccess = FALSE;
return bSuccess;
}
BOOL CHttpClient::ParseMonth(char* pszToken, int& nMonth)
{
BOOL bSuccess = TRUE;
if (strcmpi(pszToken, "Jan") == 0)
nMonth = 1;
else if (strcmpi(pszToken, "Feb") == 0)
nMonth = 2;
else if (strcmpi(pszToken, "Mar") == 0)
nMonth = 3;
else if (strcmpi(pszToken, "Apr") == 0)
nMonth = 4;
else if (strcmpi(pszToken, "May") == 0)
nMonth = 5;
else if (strcmpi(pszToken, "Jun") == 0)
nMonth = 6;
else if (strcmpi(pszToken, "Jul") == 0)
nMonth = 7;
else if (strcmpi(pszToken, "Aug") == 0)
nMonth = 8;
else if (strcmpi(pszToken, "Sep") == 0)
nMonth = 9;
else if (strcmpi(pszToken, "Oct") == 0)
nMonth = 10;
else if (strcmpi(pszToken, "Nov") == 0)
nMonth = 11;
else if (strcmpi(pszToken, "Dec") == 0)
nMonth = 12;
else
bSuccess = FALSE;
return bSuccess;
}
BOOL CHttpClient::ParseDate(const CString& sField, SYSTEMTIME& time)
{
//This method understands RFC 1123, RFC 850 and asctime formats
//For correct operation of the T2A macro, see MFC Tech Note 59
USES_CONVERSION;
BOOL bSuccess = FALSE;
//Make a local copy of the field we are going to parse
char* pszField = T2A((LPTSTR) (LPCTSTR) sField);
//Http times never include a millisecond field, so just set it to zero
time.wMilliseconds = 0;
int nLength = strlen(pszField);
if (nLength > 5)
{
if (pszField[3] == ',') //Parsing a RFC 1123 format date
{
//First the weekday
char seps[] = ", :";
char* pszToken = strtok(pszField, seps);
if (pszToken == NULL)
return FALSE;
int nWeekDay;
bSuccess = ParseWeekDay(pszToken, nWeekDay);
if (bSuccess)
time.wDayOfWeek = (WORD) nWeekDay;
//Then the day of the month
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
time.wDay = (WORD) atoi(pszToken);
//Then the month
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
int nMonth = 0;
bSuccess = bSuccess && ParseMonth(pszToken, nMonth);
if (bSuccess)
time.wMonth = (WORD) nMonth;
//And the year
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
time.wYear = (WORD) atoi(pszToken);
//And the hour
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
time.wHour = (WORD) atoi(pszToken);
//And the minute
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
time.wMinute = (WORD) atoi(pszToken);
//And the second
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
time.wSecond = (WORD) atoi(pszToken);
}
else if (pszField[3] == ' ') //Parsing an asctime format date
{
//First the weekday
char seps[] = ", :";
char* pszToken = strtok(pszField, seps);
if (pszToken == NULL)
return FALSE;
int nWeekDay;
bSuccess = ParseWeekDay(pszToken, nWeekDay);
if (bSuccess)
time.wDayOfWeek = (WORD) nWeekDay;
//Then the month
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
int nMonth = 0;
bSuccess = bSuccess && ParseMonth(pszToken, nMonth);
if (bSuccess)
time.wMonth = (WORD) nMonth;
//Then the day of the month
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
time.wDay = (WORD) atoi(pszToken);
//And the hour
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
time.wHour = (WORD) atoi(pszToken);
//And the minute
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -