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

📄 httpclient.cpp

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