253 lines
5.7 KiB
C++
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;
|
|
}
|