Files
2026-06-01 12:46:52 +02:00

253 lines
5.7 KiB
C++

#include "XHttpAsyncDelegate.h"
#include "../../include/internet/XHttpResponseHeader.h"
#include "XHttpUtil.h"
namespace
{
void CALLBACK WinHttpSystemCallback( HINTERNET hHandle, DWORD_PTR dwContext, DWORD dwStatus, void* pInfo, DWORD dwLength )
{
XHttpAsyncDelegate* pDelegate = reinterpret_cast< XHttpAsyncDelegate* >( dwContext );
if( pDelegate != NULL )
{
pDelegate->OnSystemCallback( dwStatus, pInfo, dwLength );
}
}
};
XHttpAsyncDelegate::XHttpAsyncDelegate()
: m_hConnect( NULL )
, m_hRequest( NULL )
, m_pContent( NULL )
, m_pBuffer( NULL )
{
}
XHttpAsyncDelegate::~XHttpAsyncDelegate()
{
Close();
}
void XHttpAsyncDelegate::Close()
{
if( m_hRequest != NULL )
{
::WinHttpSetStatusCallback( m_hRequest, NULL, NULL, NULL );
::WinHttpCloseHandle( m_hRequest );
m_hRequest = NULL;
}
if( m_hConnect != NULL )
{
::WinHttpCloseHandle( m_hConnect );
m_hConnect = NULL;
}
m_pContent = NULL;
if( m_pBuffer != NULL )
{
delete m_pBuffer;
m_pBuffer = NULL;
}
}
bool XHttpAsyncDelegate::Execute( HINTERNET hSession,
const wchar_t* pVerb,
const XHttpRequest& Request,
XHttpContent* pContent,
size_t nMinBufferSize )
{
const XHttpURL& URL = Request.URL();
m_hConnect = ::WinHttpConnect( hSession, URL.Host().c_str(), URL.Port(), 0 );
if( m_hConnect == NULL )
{
return false;
}
DWORD dwFlag = URL.IsSecure() ? WINHTTP_FLAG_SECURE : 0;
m_hRequest = ::WinHttpOpenRequest(
m_hConnect,
pVerb,
URL.Path().c_str(),
NULL,
(Request.Referer().empty() == true) ? WINHTTP_NO_REFERER : Request.Referer().c_str(),
WINHTTP_DEFAULT_ACCEPT_TYPES,
dwFlag );
if( m_hRequest == NULL )
{
return false;
}
if( ::WinHttpSetStatusCallback(
m_hRequest,
WinHttpSystemCallback,
WINHTTP_CALLBACK_FLAG_ALL_COMPLETIONS,
0 )
== WINHTTP_INVALID_STATUS_CALLBACK )
{
return false;
}
const XHttpBuffer& Buffer = Request.GetData();
size_t nAllocSize = Buffer.Size();
if( nAllocSize < nMinBufferSize )
{
nAllocSize = nMinBufferSize;
}
m_pBuffer = new XHttpBuffer( nAllocSize );
m_pBuffer->Copy( Buffer.Buffer(), Buffer.Size() );
m_pContent = pContent;
XHttpUtil::XHttpSetRequestHeader Header( m_hRequest );
if( Header.Add( Request.GetHeader() ) == false )
{
return false;
}
m_pBuffer->TurnBack();
DWORD dwTotalSize = static_cast< DWORD >( m_pBuffer->Size() );
if( ::WinHttpSendRequest(
m_hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
WINHTTP_NO_REQUEST_DATA,
0,
dwTotalSize,
reinterpret_cast< DWORD_PTR >( this ) )
== FALSE )
{
return false;
}
return true;
}
void XHttpAsyncDelegate::OnSystemCallback( DWORD dwStatus, void* pInfo, DWORD dwLength )
{
try
{
if( DoSystemCallback( dwStatus, pInfo, dwLength ) == false )
{
delete this;
}
}
catch( const XHttpUtil::XHttpException& except )
{
XHttpContent* pContent = m_pContent;
if( pContent != NULL )
{
pContent->OnCallbackError( XHttpUtil::GetErrorFunction( except.m_dwWhere ), except.m_dwError,
except.m_szFunction, except.m_nLine );
}
delete this;
}
}
bool XHttpAsyncDelegate::DoSystemCallback( DWORD dwStatus, void* pInfo, DWORD dwLength )
{
switch( dwStatus )
{
case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
{
if( pInfo != NULL && dwLength == sizeof( DWORD ) )
{
DWORD dwWritten = *(static_cast< DWORD* >( pInfo ));
m_pBuffer->Flush( dwWritten );
}
if( m_pBuffer->Empty() == false )
{
if( ::WinHttpWriteData( m_hRequest, m_pBuffer->Buffer(), static_cast< DWORD >( m_pBuffer->Size() ), 0 ) == FALSE )
{
throw XHttpUtil::XHttpException( API_WRITE_DATA, ::GetLastError(), __FUNCTIONW__, __LINE__ );
}
}
else
{
if( ::WinHttpReceiveResponse( m_hRequest, NULL ) == FALSE )
{
throw XHttpUtil::XHttpException( API_RECEIVE_RESPONSE, ::GetLastError(), __FUNCTIONW__, __LINE__ );
}
}
}
break;
case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
{
XHttpResponseHeader Header( m_hRequest );
DWORD dwStatusCode = Header.StatusCode();
if( dwStatusCode != HTTP_STATUS_OK )
{
throw XHttpUtil::XHttpException( API_HEADER_STATUS_CODE, dwStatusCode, __FUNCTIONW__, __LINE__ );
}
XHttpContent* pContent = m_pContent;
if( pContent == NULL || pContent->OnCallbackHeader( Header ) == false )
{
return false;
}
m_pBuffer->Clear();
if( ::WinHttpReadData( m_hRequest, m_pBuffer->Buffer(), static_cast< DWORD >( m_pBuffer->MaxSize() ), NULL ) == FALSE )
{
throw XHttpUtil::XHttpException( API_READ_DATA, ::GetLastError(), __FUNCTIONW__, __LINE__ );
}
}
break;
case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
{
XHttpContent* pContent = m_pContent;
if( pContent == NULL )
{
return false;
}
if( dwLength > 0 )
{
m_pBuffer->HadCopied( dwLength );
if( pContent->OnCallbackBody( m_pBuffer->Buffer(), m_pBuffer->Size() ) == false )
{
return false;
}
m_pBuffer->Clear();
if( ::WinHttpReadData( m_hRequest, m_pBuffer->Buffer(), static_cast< DWORD >( m_pBuffer->MaxSize() ), NULL ) == FALSE )
{
throw XHttpUtil::XHttpException( API_READ_DATA, ::GetLastError(), __FUNCTIONW__, __LINE__ );
}
}
else
{
pContent->OnCallbackComplete();
return false;
}
}
break;
case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
{
WINHTTP_ASYNC_RESULT* pResult = static_cast< WINHTTP_ASYNC_RESULT* >( pInfo );
throw XHttpUtil::XHttpException( pResult->dwResult, pResult->dwError, __FUNCTIONW__, __LINE__ );
}
break;
case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING:
{
throw XHttpUtil::XHttpException( API_HANDLE_CLOSING, ::GetLastError(), __FUNCTIONW__, __LINE__ );
}
break;
}
return true;
}