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

📄 httpclient.cpp

📁 MiniCA V2.0版本源码。《小型CA系统V2.1含源码》发表以来
💻 CPP
📖 第 1 页 / 共 5 页
字号:
/*
Module : HttpClient.cpp
Purpose: Implementation for the CHttpClient class
Created: PJN / 22-04-1999
History: None

Copyright (c) 1999 - 2005 by PJ Naughter.  (Web: www.naughter.com, Email: pjna@naughter.com)

All rights reserved.

Copyright / Usage Details:

You are allowed to include the source code in any product (commercial, shareware, freeware or otherwise) 
when your product is released in binary form. You are allowed to modify the source code in any way you want 
except you cannot modify the copyright details at the top of each module. If you want to distribute source 
code with your application, then you are only allowed to distribute versions released by the author. This is 
to maintain a single distribution point for the source code. 

*/



//////////////// Includes ////////////////////////////////////////////

#include "stdafx.h"
#ifndef __AFXPRIV_H__
#pragma message("To avoid this message please put afxpriv.h in your PCH (normally stdafx.h)")
#include <afxpriv.h>
#endif
#include "W3Mfc.h"
#include "HttpResponseHeader.h"
#include "Base64.h"
#include "HttpClient.h"
#include "Win32Handle.h"



//////////////// Macros / Defines ////////////////////////////////////

#ifndef RT_HTML
#define RT_HTML         MAKEINTRESOURCE(23)
#endif

#ifndef SEC_E_OK
#define SEC_E_OK                         ((SECURITY_STATUS)0x0000)
#endif

#ifndef SEC_I_CONTINUE_NEEDED
#define SEC_I_CONTINUE_NEEDED            ((SECURITY_STATUS)0x1012)
#endif

#ifndef INVALID_FILE_ATTRIBUTES
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#endif

#ifndef HSE_REQ_CLOSE_CONNECTION
#define HSE_REQ_CLOSE_CONNECTION                 (HSE_REQ_END_RESERVED+17)
#endif

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


//The local variable which handle the function pointers

_W3MFC_DATA _W3MFCData;



//////////////// Implementation //////////////////////////////////////

_W3MFC_DATA::_W3MFC_DATA()
{
  //Initialize the function pointers to sane defaults
  m_lpfnTransmitFile = NULL;
  m_lpfnTransmitPackets = NULL;

  //Only use the TransmitFile and TransmitPacket API's if we are running on 2000/XP/.NET Server
  OSVERSIONINFO osvi;
  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  BOOL bNT = (GetVersionEx(&osvi) && osvi.dwPlatformId == VER_PLATFORM_WIN32_NT);
  if (bNT && (osvi.dwMajorVersion > 4))
  {
    m_hMSWsock = LoadLibrary(_T("MSWSOCK.DLL"));
    if (m_hMSWsock)
    {
      m_lpfnTransmitFile = (LPTRANSMITFILE) GetProcAddress(m_hMSWsock, "TransmitFile");
      m_lpfnTransmitPackets = (LPTRANSMITPACKETS) GetProcAddress(m_hMSWsock, "TransmitPackets");
    }
  }
}

_W3MFC_DATA::~_W3MFC_DATA()
{
  if (m_hMSWsock)
  {
    FreeLibrary(m_hMSWsock);
    m_hMSWsock = NULL;
  }
}

#ifndef W3MFC_NO_ISAPI_SUPPORT
BOOL _W3MFC_DATA::TransmitFile(CHttpSocket& socket, CHttpResponseHeader& responseHdr, HSE_TF_INFO* pInfo)
{
  //Assume the worst
  BOOL bSuccess = FALSE;

  if (pInfo->pfnHseIO)
  {
    SetLastError(ERROR_INVALID_PARAMETER); //we do not support ascynchronous notifications
    return FALSE;
  }
  if (pInfo->Offset)
  {
    SetLastError(ERROR_INVALID_PARAMETER); //we do not support partials sens thro TransmitFile because that requires overlapped IO
    return FALSE;
  }

  if (pInfo->dwFlags & HSE_IO_SEND_HEADERS)
  {
    if (m_lpfnTransmitPackets && m_lpfnTransmitFile)
    {
      TRANSMIT_PACKETS_ELEMENT tpe[2];
      tpe[0].pBuffer = (void*) pInfo->pszStatusCode;
      tpe[0].dwElFlags = TP_ELEMENT_MEMORY;
      tpe[0].cLength = strlen(pInfo->pszStatusCode);

      tpe[1].pBuffer = responseHdr.GetData(tpe[1].cLength);
      tpe[1].dwElFlags = TP_ELEMENT_MEMORY;

      //Call the TransmitPackets function
      bSuccess = m_lpfnTransmitPackets(socket, tpe, 2, 0, NULL, TF_USE_KERNEL_APC);

      //And the TransmitFile function
      if (bSuccess)
        bSuccess = m_lpfnTransmitFile(socket, pInfo->hFile, pInfo->BytesToWrite, 0, NULL, NULL, TF_USE_KERNEL_APC);
    }
    else
      SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  }
  else
  {
    if (m_lpfnTransmitFile)
    {
      TRANSMIT_FILE_BUFFERS tfb;
      tfb.Head = pInfo->pHead;
      tfb.HeadLength = pInfo->HeadLength;
      tfb.Tail = pInfo->pTail;
      tfb.TailLength = pInfo->TailLength;

      //Call the TransmitFile function
      bSuccess = m_lpfnTransmitFile(socket, pInfo->hFile, pInfo->BytesToWrite, 0, NULL, &tfb, TF_USE_KERNEL_APC);
    }
    else
      SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  }

  return bSuccess;
}
#endif

BOOL _W3MFC_DATA::TransmitFile(CHttpSocket& socket, CHttpResponseHeader& responseHdr, HANDLE hFile, DWORD dwSize)
{
  ASSERT(m_lpfnTransmitFile);

  //Setup the TFB ready for the call to the "TransmitFile" function
  TRANSMIT_FILE_BUFFERS tfb;
  tfb.Head = responseHdr.GetData(tfb.HeadLength);
  tfb.Tail = NULL;
  tfb.TailLength = 0;

  //Call the TransmitFile function
  BOOL bSuccess = m_lpfnTransmitFile(socket, hFile, dwSize, 0, NULL, &tfb, TF_USE_KERNEL_APC);

  //Tidy up the heap memory we have used
  delete [] tfb.Head;

  return bSuccess;
}

BOOL _W3MFC_DATA::TransmitBuffer(CHttpSocket& socket, CHttpResponseHeader& responseHdr, BYTE* byData, DWORD dwSize)
{
  ASSERT(m_lpfnTransmitPackets);

  //Setup the TFB ready for the call to the "TransmitPackets" function
  TRANSMIT_PACKETS_ELEMENT tpe[2];
  tpe[0].pBuffer = responseHdr.GetData(tpe[0].cLength);
  tpe[0].dwElFlags = TP_ELEMENT_MEMORY;
  tpe[1].pBuffer = byData;
  tpe[1].cLength = dwSize;
  tpe[0].dwElFlags = TP_ELEMENT_MEMORY;

  //Call the TransmitPackets function
  return m_lpfnTransmitPackets(socket, tpe, 2, 0, NULL, TF_USE_KERNEL_APC);
}



IMPLEMENT_DYNCREATE(CHttpClient, CThreadPoolClient)

CHttpClient::CHttpClient()
{
  m_pServer = NULL;
#ifdef W3MFC_SSL_SUPPORT
  m_pSSLContext = NULL;
#endif
#ifndef W3MFC_NO_ISAPI_SUPPORT
  m_dwDataSentViaWriteClient = 0;
  m_nHttpStatusCodeSent = 0;
#endif
}

CHttpClient::~CHttpClient()
{
}

BOOL CHttpClient::AllowThisConnection()
{
  return TRUE;
}

#ifdef W3MFC_SSL_SUPPORT
BOOL CHttpClient::InitializeSSLConnection()
{
  SSL* pSSL = SSL_new(m_pSSLContext->operator SSL_CTX*());
  if (pSSL == NULL)
  {
    //Report the error
    CString sError;
    sError.Format(_T("CHttpClient::InitializeSSLConnection, Failed to create create SSL connection object"));
    ASSERT(m_pServer);
    m_pServer->OnError(sError);

    m_pServer->LogSSLErrors();

    return FALSE;
  }
  else
    m_SSL.Attach(pSSL);

  //Associate the raw socket with the SSL connection object
  if (SSL_set_fd(m_SSL, m_Socket) != 1)
  {
    //Report the error
    CString sError;
    sError.Format(_T("CHttpClient::InitializeSSLConnection, Failed to create create SSL connection object"));
    ASSERT(m_pServer);
    m_pServer->OnError(sError);

    m_pServer->LogSSLErrors();

    return FALSE;
  }

  return TRUE;
}

BOOL CHttpClient::DoSSLNegotiation()
{
  ASSERT(m_pServer);
  CHttpServerSettings* pSettings = m_pServer->GetSettings();
  ASSERT(pSettings);

  BOOL bNegotiationComplete = FALSE;
  while (!bNegotiationComplete)
  {
    int nSSLAccept = SSL_accept(m_SSL);
    if (nSSLAccept != 1)
    {
      BOOL bRetry = FALSE;
      int nSSL_get_error = SSL_get_error(m_SSL, nSSLAccept);
      if (nSSL_get_error == SSL_ERROR_WANT_READ)
      {
        if (m_Socket.IsReadible(pSettings->m_dwSSLNegotiationTimeout))
          bRetry = TRUE;
      }

      if (!bRetry)
      {
        //Report the error
        CString sError;
        sError.Format(_T("CHttpClient::DoSSLNegotiation, Failed to perform SSL handshake, SSL_accept:%d SSL_get_error:%d"), nSSLAccept, nSSL_get_error);
        m_pServer->OnError(sError);

        m_pServer->LogSSLErrors();

        return FALSE;
      }
    }
    else
      bNegotiationComplete = TRUE;
  }

  return TRUE;
}
#endif

BOOL CHttpClient::Run(const CThreadPoolRequest& request)
{
  //Validate our parameters
  ASSERT(request.m_pData);
  CHttpThreadPoolRequest* pHttpRequest = (CHttpThreadPoolRequest*) request.m_pData;

  //Hive away the parameters in member variables
  SOCKET clientSocket = pHttpRequest->m_ClientSocket.Detach();
  m_Socket.Attach(clientSocket);
  CopyMemory(&m_Request.m_ClientAddress, &pHttpRequest->m_ClientAddress, sizeof(sockaddr_in));
#ifdef W3MFC_SSL_SUPPORT
  m_pSSLContext = pHttpRequest->m_pSSLContext;
#endif

  //Call the helper function which does all of the work
  HandleClient();

#ifdef W3MFC_SSL_SUPPORT
  //Close the SSL connection
  m_SSL.Close();
#endif

  //Close down the connection
  m_Socket.Close();

  //Tidy up our heap memory after ourselves
  delete pHttpRequest;

  //Reset the request data
  m_Request = CHttpRequest();

  return TRUE;
}

int CHttpClient::ExitInstance()
{
  //Tidy up per thread SSL structures if we are using SSL
#ifdef W3MFC_SSL_SUPPORT
  ERR_remove_state(0);
#endif

  return CThreadPoolClient::ExitInstance();
}

void CHttpClient::HandleClient()
{
	//Validate our parameters
	ASSERT(m_pServer);
	CHttpServerSettings* pSettings = m_pServer->GetSettings();
	ASSERT(pSettings);
	
	//Do the reverse DNS lookup if configured to do so
	m_Request.m_sRemoteHost.Empty();
	if (pSettings->m_bDNSLookup)
	{
		HOSTENT* pHostEnt = gethostbyaddr((const char*) &m_Request.m_ClientAddress.sin_addr, sizeof(IN_ADDR), AF_INET);
		if (pHostEnt)
			m_Request.m_sRemoteHost = pHostEnt->h_name;
	}
	
	//Should we allow this client to connect
	if (!AllowThisConnection())
	{
		ReturnErrorMessage(400); //Bad Request
		return;    
	}
	
	//Create the SSL connection if required
#ifdef W3MFC_SSL_SUPPORT
	if (pSettings->m_SSLProtocol != CHttpServerSettings::SSL_NONE)
	{
		if (!InitializeSSLConnection())
			return;
		
		//Do the SSL negotiation
		if (!DoSSLNegotiation())
			return;
	}
#endif
	
	//Use a Win32 event notification on the socket
	CEvent dataEvent;
	int nError = WSAEventSelect(m_Socket, dataEvent, FD_READ | FD_CLOSE);
	if (nError == SOCKET_ERROR)
	{
		DWORD dwError = ::GetLastError();
		
		//Report the error
		CString sError;
		sError.Format(_T("CHttpClient::HandleClient, Failed in call to WSAEventSelect, GetLastError:%d"), dwError);
		m_pServer->OnError(sError);
		
		return;
	}
	
	//Also create a waitable timer if we can
	CWaitableTimer dataTimer;
	if (dataTimer.Create(TRUE))
		dataTimer.SetOnceOffRelative(pSettings->m_dwIdleClientTimeout);
	
	BOOL bMoreRequests = FALSE;
#ifndef W3MFC_NO_SSPI_SUPPORT
	BOOL bImpersonatedUsingSSPI = FALSE;
#endif
	do
	{
		m_bResponseKeepAlive = FALSE;
		
#ifdef W3MFC_SSL_SUPPORT
		//Read the client request
		BOOL bReadResponse = FALSE;
		if (dataTimer)
			bReadResponse = m_Socket.ReadResponse(m_Request, pSettings->m_dwIdleClientTimeout, 4096, m_SSL, *this, dataTimer, m_StopEvent, dataEvent);
		else
			bReadResponse = m_Socket.ReadResponse(m_Request, pSettings->m_dwIdleClientTimeout, 4096, m_SSL, *this);
#else
		BOOL bReadResponse = FALSE;
		if (dataTimer)
			bReadResponse = m_Socket.ReadResponse(m_Request, pSettings->m_dwIdleClientTimeout, 4096, *this, dataTimer, m_StopEvent, dataEvent);
		else
			bReadResponse = m_Socket.ReadResponse(m_Request, pSettings->m_dwIdleClientTimeout, 4096, *this);
#endif
		if (bReadResponse)
		{
			//Parse the client request
			if (ParseRequest())
			{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -