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

📄 httpclient.cpp

📁 MiniCA V2.0版本源码。《小型CA系统V2.1含源码》发表以来
💻 CPP
📖 第 1 页 / 共 5 页
字号:
				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 + -