📄 httpclient.cpp
字号:
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);
//And the year
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
time.wYear = (WORD) atoi(pszToken);
}
else //Must be a RFC 850 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 (2 Digits only, so make some intelligent assumptions)
pszToken = strtok(NULL, seps);
if (pszToken == NULL)
return FALSE;
time.wYear = (WORD) atoi(pszToken);
if (time.wYear < 50)
time.wYear += 2000;
else if (time.wYear < 100)
time.wYear += 1900;
//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);
}
}
return bSuccess;
}
BOOL CHttpClient::ParseAuthorizationLine(const CString& sField)
{
//Validate our parameters
ASSERT(m_pServer);
CHttpServerSettings* pSettings = m_pServer->GetSettings();
ASSERT(pSettings);
//By default assume the best
BOOL bSuccess = TRUE;
//For correct operation of the T2A macro, see MFC Tech Note 59
USES_CONVERSION;
//Make a local copy of the field we are going to parse
char* pszField = T2A((LPTSTR) (LPCTSTR) sField);
char seps[] = " ";
char* pszToken = strtok(pszField, seps);
if (pszToken)
{
//Parse out the base64 encoded username and password if we are doing Basic authentication
if ((strcmpi(pszToken, "Basic") == 0) && pSettings->m_bAllowBasicAuthentication)
{
//Move to the base64 encoded data after the text "Basic"
pszToken = strtok(NULL, seps);
if (pszToken)
{
//Decode the base64 string passed to us
CBase64 base64;
int nEncodedLength = strlen(pszToken);
int nDecodedLength = base64.DecodeGetRequiredLength(nEncodedLength);
BYTE* pszOutput = new BYTE[nDecodedLength + 1];
int nOutputLength = 0;
if (base64.Decode(pszToken, nEncodedLength, pszOutput, &nOutputLength))
{
//NULL terminate the decoded data
pszOutput[nOutputLength] = '\0';
CString sOutput(pszOutput);
int nColon = sOutput.Find(_T(":"));
if (nColon != -1)
{
m_Request.m_AuthorizationType = CHttpRequest::HTTP_AUTHORIZATION_PLAINTEXT;
m_Request.m_sUsername = sOutput.Left(nColon);
m_Request.m_sPassword = sOutput.Right(sOutput.GetLength() - nColon - 1);
}
}
else
bSuccess = FALSE;
//Tidy up the heap memory we have been using
delete [] pszOutput;
}
else
bSuccess = FALSE;
}
#ifndef W3MFC_NO_SSPI_SUPPORT
else if ((strcmpi(pszToken, "NTLM") == 0) && pSettings->m_bAllowNTLMAuthentication && !m_Request.m_bAuthenticationComplete)
{
//Move to the encoded data after the text "NTLM"
pszToken = strtok(NULL, seps);
if (pszToken)
{
CBase64 base64;
int nEncodedLength = strlen(pszToken);
int nDecodedLength = base64.DecodeGetRequiredLength(nEncodedLength);
BYTE* pszInput = new BYTE[nDecodedLength + 1];
int nInputLength = 0;
if (base64.Decode(pszToken, nEncodedLength, pszInput, &nInputLength))
{
//Get SSPI to act on the received data
//First setup the buffers
SecBuffer secBufferIn[1];
secBufferIn[0].BufferType = SECBUFFER_TOKEN;
secBufferIn[0].cbBuffer = nInputLength;
secBufferIn[0].pvBuffer = pszInput;
SecBufferDesc secbufDescriptorIn;
secbufDescriptorIn.ulVersion = SECBUFFER_VERSION;
secbufDescriptorIn.cBuffers = 1;
secbufDescriptorIn.pBuffers = secBufferIn;
SecBuffer secBufferOut[1];
secBufferOut[0].BufferType = SECBUFFER_TOKEN;
secBufferOut[0].cbBuffer = 0;
secBufferOut[0].pvBuffer = NULL;
SecBufferDesc secbufDescriptorOut;
secbufDescriptorOut.ulVersion = SECBUFFER_VERSION;
secbufDescriptorOut.cBuffers = 1;
secbufDescriptorOut.pBuffers = secBufferOut;
//Call SSPI
ULONG nContextAttributes;
SECURITY_STATUS ss = AcceptSecurityContext(m_pServer->GetCredentialHandle(), m_Request.m_bFirstAuthenticationRequest ? NULL : &m_Request.m_ContentHandle,
&secbufDescriptorIn, ASC_REQ_STREAM | ASC_REQ_ALLOCATE_MEMORY, SECURITY_NETWORK_DREP,
&m_Request.m_ContentHandle, &secbufDescriptorOut, &nContextAttributes, NULL);
//It's no longer the first request
m_Request.m_bFirstAuthenticationRequest = FALSE;
//Seup the output data (if any)
if (secBufferOut[0].cbBuffer)
{
nEncodedLength = base64.EncodeGetRequiredLength(secBufferOut[0].cbBuffer, BASE64_FLAG_NOCRLF);
char* pszOutput = new char[nEncodedLength + 1];
//Base 64 encode the data to be sent
base64.Encode((const BYTE*) secBufferOut[0].pvBuffer, secBufferOut[0].cbBuffer, pszOutput, &nEncodedLength, BASE64_FLAG_NOCRLF);
//Null terminate the data
pszOutput[nEncodedLength] = '\0';
//Set the data to return to the client
m_Request.m_sAuthenticationResponse = pszOutput;
//Tidy up the heap memory we have been using
delete [] pszOutput;
//Also free the data allocated by SSPI
FreeContextBuffer(secBufferOut[0].pvBuffer);
}
//Do we need more data from the client?
m_Request.m_bAuthenticationComplete = (ss != SEC_I_CONTINUE_NEEDED);
//Is the authentication handshake completed
if (ss == SEC_E_OK)
m_Request.m_AuthorizationType = CHttpRequest::HTTP_AUTHORIZATION_NTLM;
bSuccess = (ss == SEC_E_OK || ss == SEC_I_CONTINUE_NEEDED);
}
else
bSuccess = FALSE;
//Tidy up the heap memory we have been using
delete [] pszInput;
}
else
bSuccess = FALSE;
}
#endif //W3MFC_NO_SSPI_SUPPORT
}
return bSuccess;
}
BOOL CHttpClient::ParseRequestLine(const CString& sCurrentLine, BOOL bFirstLine, const CString& sField, const CString& sValue)
{
//Assume the worst
BOOL bSuccess = FALSE;
if (bFirstLine)
{
//Handle the first line
m_Request.m_sRequest = sCurrentLine;
bSuccess = ParseSimpleRequestLine(sCurrentLine);
}
else
{
bSuccess = TRUE;
//Also add the header line to the header map
CString sKey(sField);
sKey.MakeUpper();
m_Request.m_HeaderMap.SetAt(sKey, sValue);
//Handle any other request headers
if (sField.CompareNoCase(_T("If-Modified-Since")) == 0)
{
//Handle the If-Modified-Since header
SYSTEMTIME time;
if (ParseDate(sValue, time))
{
m_Request.m_bIfModifiedSincePresent = TRUE;
CopyMemory(&m_Request.m_IfModifiedSince, &time, sizeof(SYSTEMTIME));
}
}
else if (sField.CompareNoCase(_T("Authorization")) == 0)
{
//Handle the Authorization header
bSuccess = ParseAuthorizationLine(sValue);
}
else if (sField.CompareNoCase(_T("Content-Type")) == 0)
m_Request.m_sContentType = sValue;
else if (sField.CompareNoCase(_T("Content-Length")) == 0)
m_Request.m_nContentLength = _ttoi(sValue);
else if ((sField.CompareNoCase(_T("Connection")) == 0) && (sValue.CompareNoCase(_T("Keep-Alive")) == 0))
m_Request.m_bKeepAlive = TRUE;
}
return bSuccess;
}
LPSTR CHttpClient::FindNextTerminatorFromRequest(LPSTR pszLine)
{
LPSTR pszCurrentLine = pszLine;
while (TRUE)
{
++pszCurrentLine;
if (pszCurrentLine >= ((LPSTR) m_Request.m_pRawEntity))
return pszCurrentLine;
else if (*pszCurrentLine == '\n')
return pszCurrentLine;
}
return NULL;
}
BOOL CHttpClient::ParseRequest()
{
//By default assume the worst
BOOL bSuccess = FALSE;
//Also store a pointer to entity body.
LPSTR pszEntityTerminator = strstr((LPSTR) m_Request.m_pRawRequest, "\r\n\r\n");
if (pszEntityTerminator)
{
m_Request.m_pRawEntity = (BYTE*) (pszEntityTerminator+4);
m_Request.m_dwRawEntitySize = m_Request.m_dwRawRequestSize - (m_Request.m_pRawEntity - m_Request.m_pRawRequest);
}
else
{
m_Request.m_pRawEntity = NULL;
m_Request.m_dwRawEntitySize = 0;
}
//Process each line
BOOL bFirstLine = TRUE;
LPSTR pszLine = (LPSTR) m_Request.m_pRawRequest;
LPSTR pszTerminator = strstr(pszLine, "\n");
BOOL bMoreLines = TRUE;
do
{
CString sLine;
if (pszTerminator)
{
//Form the current line
int nCurSize = pszTerminator - pszLine;
char* pszCurrentLine = new char[nCurSize];
strncpy(pszCurrentLine, pszLine, nCurSize-1);
pszCurrentLine[nCurSize-1] = '\0';
//Transfer to the CString variable
sLine = pszCurrentLine;
//Tidy up the heap memory now that we are finished with it
delete [] pszCurrentLine;
//Parse each line using the virtual ParseRequestLine method
if (sLine.GetLength())
{
CString sField;
CString sValue;
if (!bFirstLine)
{
m_Socket.SplitRequestLine(sLine, sField, sValue);
bSuccess = ParseRequestLine(sLine, FALSE, sField, sValue);
}
else
{
bSuccess = ParseRequestLine(sLine, TRUE, sField, sValue);
bFirstLine = FALSE;
}
}
//Move onto the next line
if (pszTerminator)
{
pszLine = pszTerminator+1;
if (pszLine >= (LPSTR) m_Request.m_pRawEntity)
bMoreLines = FALSE;
else
pszTerminator = FindNextTerminatorFromRequest(pszLine);
}
}
else
bMoreLines = FALSE;
}
while (bMoreLines && bSuccess);
m_Request.m_hImpersonation = m_pServer->GetImpersonationHandle();
return bSuccess;
}
DWORD CHttpClient::ReturnErrorMessage(int nStatusCode)
{
//Validate our parameters
ASSERT(m_pServer);
CHttpServerSettings* pSettings = m_pServer->GetSettings();
ASSERT(pSettings);
//Form the body of the response
DWORD dwBodyLength = 0;
char* pszBody = m_pServer->LoadHTML(nStatusCode, dwBodyLength);
if (m_Request.m_dwHttpVersion > MAKELONG(9, 0))
{
//Form the header of the response
CHttpResponseHeader responseHdr;
responseHdr.AddStatusCode(nStatusCode);
SYSTEMTIME st;
GetSystemTime(&st);
responseHdr.AddDate(st);
responseHdr.AddServer(pSettings->m_sServerName);
responseHdr.AddW3MfcAllowFields(pSettings->m_bAllowDeleteRequest);
if (m_bResponseKeepAlive)
responseHdr.AddKeepAlive();
responseHdr.AddContentLength(dwBodyLength);
responseHdr.AddContentType(_T("text/html"));
//Send the header and body all in one
TransmitBuffer(m_Socket, responseHdr, (BYTE*)pszBody, dwBodyLength, pSettings->m_dwWritableTimeout);
}
else
{
//No header sent for HTTP v0.9
//so just send the body
try
{
#ifdef W3MFC_SSL_SUPPORT
m_Socket.SendWithRetry(pszBody, dwBodyLength, pSettings->m_dwWritableTimeout, m_SSL);
#else
m_Socket.SendWithRetry(pszBody, dwBodyLength, pSettings->m_dwWritableTimeout);
#endif
}
catch(CWSocketException* pEx)
{
//Report the error
CString sError;
sError.Format(_T("CHttpClient::ReturnErrorMessage, Failed to send to socket, Error:%d"), pEx->m_nError);
ASSERT(m_pServer);
m_pServer->OnError(sError);
pEx->Delete();
}
}
//Log the information
PostLog(nStatusCode, dwBodyLength);
//Return the body length
return dwBodyLength;
}
DWORD CHttpClient::ReturnRedirectMessage(const CString& sURL)
{
//Validate our parameters
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -