8627 lines
605 KiB
C++
8627 lines
605 KiB
C++
/* !
|
||
* \file RyeolHttpClient.cpp
|
||
* \brief Implementations of Ryeol's HTTP client classes.
|
||
* \author Jo Hyeong-ryeol
|
||
* \since 2004.04.12
|
||
* \version $LastChangedRevision: 103 $
|
||
* $LastChangedDate: 2006-02-05 00:38:41 +0900 (일, 05 2 2006) $
|
||
*
|
||
* <dl compact>
|
||
* <dt><b>Requirements:</b></dt>
|
||
* <dd>Requires Internet Explorer 4.0 or later.</dd><br>
|
||
* <dd>Unicode version class support on Windows Me/98/95 requires Microsoft Layer for Unicode.</dd><br>
|
||
* <dd>UTF-8 encoding support on Windows 95 requires Microsoft Layer for Unicode.</dd>
|
||
* </dl>
|
||
* This file contains implementations of Ryeol's HTTP client classes.
|
||
* \n\n\n
|
||
* Copyright © 2006 by <a href="mailto:hyeongryeol@gmail.com">Jo Hyeong-ryeol</a>\n
|
||
* Permission to copy, use, modify, sell and distribute this software is
|
||
* granted provided this copyright notice appears in all copies.
|
||
* This software is provided "as is" without express or implied warranty,
|
||
* and with no claim as to its suitability for any purpose.
|
||
*/
|
||
#include "stdafx.h"
|
||
#include "RyeolHttpClient.h"
|
||
|
||
#ifdef _DEBUG
|
||
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
|
||
#endif
|
||
|
||
#pragma warning (disable: 4290) // avoids 'C++ Exception Specification ignored' message
|
||
#pragma warning (disable: 4660)
|
||
#pragma warning (disable: 4996) // avoids 'This function or variable may be unsafe' message
|
||
#pragma comment (lib, "wininet.lib")
|
||
#pragma comment (lib, "urlmon.lib")
|
||
|
||
/*!
|
||
* \brief The namespace of the Ryeol's library
|
||
*
|
||
* This is the namespace for source codes written by Jo Hyeong-ryeol.
|
||
*/
|
||
namespace Ryeol {
|
||
|
||
/////////////////////////////// Global constant message table ////////////////////////////////////
|
||
#ifndef SAFEFREE
|
||
# define SAFEFREE(x) if(x){ ::free((void *)x); x = NULL; }
|
||
#endif
|
||
|
||
#ifndef INVALID_SET_FILE_POINTER
|
||
# define INVALID_SET_FILE_POINTER ((DWORD)-1)
|
||
#endif
|
||
|
||
#define HTTPCLIENT_POSTCNTX_BUFF_SIZE (1024 * 56)
|
||
|
||
|
||
// An assertion macro for the CHttpToolA and the CHttpToolW class
|
||
#define HTTPTOOL_ASSERT(expr, msg) \
|
||
\
|
||
if ( !(expr) ) { \
|
||
_ASSERTE ( expr ) ; ThrowException (msg) ; \
|
||
}
|
||
|
||
// An assertion macro for the CHttpClient related classes
|
||
#define HTTPCLIENT_ASSERT(expr, msg) \
|
||
\
|
||
if ( !(expr) ) { \
|
||
_ASSERTE ( expr ) ; \
|
||
if ( HttpTool::IsAnsi () ) \
|
||
CHttpToolA::ThrowException (msg) ; \
|
||
else \
|
||
CHttpToolW::ThrowException (L##msg) ; \
|
||
}
|
||
|
||
// An assertion macro for the CHttpClient related classes
|
||
#define HTTPCLIENT_ASSERTA(expr, msg) \
|
||
\
|
||
if ( !(expr) ) { \
|
||
_ASSERTE ( expr ) ; \
|
||
CHttpToolA::ThrowException (msg) ; \
|
||
}
|
||
|
||
// An assertion macro for the CHttpClient related classes
|
||
#define HTTPCLIENT_ASSERTW(expr, msg) \
|
||
\
|
||
if ( !(expr) ) { \
|
||
_ASSERTE ( expr ) ; \
|
||
CHttpToolW::ThrowException (L##msg) ; \
|
||
}
|
||
|
||
|
||
// not specified
|
||
static LPCSTR g_NotSpecifiedA[] = {
|
||
"Not specified"
|
||
} ;
|
||
|
||
static LPCWSTR g_NotSpecifiedW[] = {
|
||
L"Not specified"
|
||
} ;
|
||
|
||
// error messages
|
||
static LPCSTR g_NormalMsgA[] = {
|
||
"Unexpected error occurred."
|
||
, "The index is out of range."
|
||
, "Out of memory."
|
||
, "The requested URL is not a valid URL."
|
||
, "The post context is not started yet."
|
||
, "Couldn't read expected bytes from a file."
|
||
, "The post context has not been finished yet."
|
||
, "The port number is not valid."
|
||
, "std::exception occurred."
|
||
, "The encoded URL is not valid."
|
||
, "The UTF8 string contains an invalid character."
|
||
, "An unexpected arithmetic error has been occurred."
|
||
, "An arithmetic overflow error has been occurred."
|
||
, "An interger divide by zero exception has been occurred."
|
||
, "The file (%s) aleady exists."
|
||
} ;
|
||
|
||
static LPCWSTR g_NormalMsgW[] = {
|
||
L"Unexpected error occurred."
|
||
, L"The index is out of range."
|
||
, L"Out of memory."
|
||
, L"The requested URL is not a valid URL."
|
||
, L"The post context is not started yet."
|
||
, L"Couldn't read expected bytes from a file."
|
||
, L"The post context has not been finished yet."
|
||
, L"The port number is not valid."
|
||
, L"std::exception occurred."
|
||
, L"The encoded URL is not valid."
|
||
, L"The UTF8 string contains an invalid character."
|
||
, L"An unexpected arithmetic error has been occurred."
|
||
, L"An arithmetic overflow error has been occurred."
|
||
, L"An interger divide by zero exception has been occurred."
|
||
, L"The file (%s) aleady exists."
|
||
} ;
|
||
|
||
// error messages (which has a win32 error code) - Reserved
|
||
static LPCSTR g_NormalMsgWin32A[] = {""} ;
|
||
static LPCWSTR g_NormalMsgWin32W[] = {L""} ;
|
||
|
||
// WinInet error messages (which has a win32 error code)
|
||
static LPCSTR g_WinInetMsgWin32A[] = {
|
||
"::HttpQueryInfo failed."
|
||
, "::InternetReadFile failed."
|
||
, "::InternetOpen failed."
|
||
, "::InternetConnect failed."
|
||
, "::HttpOpenRequest failed."
|
||
, "::HttpAddRequestHeaders failed."
|
||
, "::HttpSendRequest failed."
|
||
, "::HttpSendRequestEx failed."
|
||
, "::InternetWriteFile failed."
|
||
, "::HttpEndRequest failed."
|
||
, "::InternetSetOption failed."
|
||
} ;
|
||
|
||
static LPCWSTR g_WinInetMsgWin32W[] = {
|
||
L"::HttpQueryInfo failed."
|
||
, L"::InternetReadFile failed."
|
||
, L"::InternetOpen failed."
|
||
, L"::InternetConnect failed."
|
||
, L"::HttpOpenRequest failed."
|
||
, L"::HttpAddRequestHeaders failed."
|
||
, L"::HttpSendRequest failed."
|
||
, L"::HttpSendRequestEx failed."
|
||
, L"::InternetWriteFile failed."
|
||
, L"::HttpEndRequest failed."
|
||
, L"::InternetSetOption failed."
|
||
} ;
|
||
|
||
// Win32 API error messages except the WinInet API (They have a win32 error code)
|
||
static LPCSTR g_Win32MsgWin32A[] = {
|
||
"::WideCharToMultiByte failed."
|
||
, "::MultiByteToWideChar failed."
|
||
, "::ReadFile failed."
|
||
, "OpenFile (::CreateFile) failed (\"%s\")."
|
||
, "::SetFilePointer failed."
|
||
, "::GetFileSize failed (\"%s\")."
|
||
, "::WriteFile failed (\"%s\")."
|
||
} ;
|
||
|
||
static LPCWSTR g_Win32MsgWin32W[] = {
|
||
L"::WideCharToMultiByte failed."
|
||
, L"::MultiByteToWideChar failed."
|
||
, L"::ReadFile failed."
|
||
, L"OpenFile (::CreateFile) failed (\"%s\")."
|
||
, L"::SetFilePointer failed."
|
||
, L"::GetFileSize failed (\"%s\")."
|
||
, L"::WriteFile failed (\"%s\")."
|
||
} ;
|
||
|
||
|
||
// user-defined error message
|
||
static LPCSTR g_UsrErrMsgA[] = {
|
||
"user-defined error message"
|
||
} ;
|
||
|
||
static LPCWSTR g_UsrErrMsgW[] = {
|
||
L"user-defined error message"
|
||
} ;
|
||
|
||
|
||
static LPCSTR HTTPCLIENT_DEF_MIMETYPE = "application/octet-stream" ;
|
||
|
||
// Constants in the CHttpToolT
|
||
LPCSTR CHttpToolA::szDefUsrAgent = "Ryeol HTTP Client Class" ;
|
||
LPCSTR CHttpToolA::szGET = "GET" ;
|
||
LPCSTR CHttpToolA::szPost = "POST" ;
|
||
LPCSTR CHttpToolA::szHTTP = "HTTP://" ;
|
||
LPCSTR CHttpToolA::szHTTPS = "HTTPS://" ;
|
||
LPCSTR CHttpToolA::szSlash = "/" ;
|
||
LPCSTR CHttpToolA::szCacheControl = "Cache-Control" ;
|
||
LPCSTR CHttpToolA::szNoCache = "no-cache" ;
|
||
LPCSTR CHttpToolA::szContentType = "Content-Type" ;
|
||
LPCSTR CHttpToolA::szMultipartFormDataBoundary = "multipart/form-data; boundary=" ;
|
||
LPCSTR CHttpToolA::szFormUrlEncoded = "application/x-www-form-urlencoded" ;
|
||
LPCSTR CHttpToolA::szDefBoundary = "----RYEOL-FB3B405B7EAE495aB0C0295C54D4E096-" ;
|
||
LPCSTR CHttpToolA::szDefUploadContType = "multipart/form-data; boundary=" "----RYEOL-FB3B405B7EAE495aB0C0295C54D4E096-" ;
|
||
LPCSTR CHttpToolA::szNULL = "NULL" ;
|
||
LPCSTR CHttpToolA::szEmptyString = "" ;
|
||
LPCSTR CHttpToolA::szColonSlashSlash = "://" ;
|
||
|
||
|
||
LPCWSTR CHttpToolW::szDefUsrAgent = L"Ryeol HTTP Client Class" ;
|
||
LPCWSTR CHttpToolW::szGET = L"GET" ;
|
||
LPCWSTR CHttpToolW::szPost = L"POST" ;
|
||
LPCWSTR CHttpToolW::szHTTP = L"HTTP://" ;
|
||
LPCWSTR CHttpToolW::szHTTPS = L"HTTPS://" ;
|
||
LPCWSTR CHttpToolW::szSlash = L"/" ;
|
||
LPCWSTR CHttpToolW::szCacheControl = L"Cache-Control" ;
|
||
LPCWSTR CHttpToolW::szNoCache = L"no-cache" ;
|
||
LPCWSTR CHttpToolW::szContentType = L"Content-Type" ;
|
||
LPCWSTR CHttpToolW::szMultipartFormDataBoundary = L"multipart/form-data; boundary=" ;
|
||
LPCWSTR CHttpToolW::szFormUrlEncoded = L"application/x-www-form-urlencoded" ;
|
||
LPCWSTR CHttpToolW::szDefBoundary = L"----RYEOL-FB3B405B7EAE495aB0C0295C54D4E096-" ;
|
||
LPCWSTR CHttpToolW::szDefUploadContType = L"multipart/form-data; boundary=" L"----RYEOL-FB3B405B7EAE495aB0C0295C54D4E096-" ;
|
||
LPCWSTR CHttpToolW::szNULL = L"NULL" ;
|
||
LPCWSTR CHttpToolW::szEmptyString = L"" ;
|
||
LPCWSTR CHttpToolW::szColonSlashSlash = L"://" ;
|
||
/////////////////////////////// Global constant message table ////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////// Explicit Instanciation /////////////////////////////////////////
|
||
template class CHttpClientMapT<CHttpToolA> ;
|
||
template class CHttpClientMapT<CHttpToolW> ;
|
||
template class CHttpResponseT<CHttpToolA> ;
|
||
template class CHttpResponseT<CHttpToolW> ;
|
||
template class CHttpPostStatT<CHttpToolA> ;
|
||
template class CHttpPostStatT<CHttpToolW> ;
|
||
template class CHttpUrlAnalyzerT<CHttpToolA> ;
|
||
template class CHttpUrlAnalyzerT<CHttpToolW> ;
|
||
template class CHttpClientT<CHttpToolA, CHttpEncoderA> ;
|
||
template class CHttpClientT<CHttpToolW, CHttpEncoderW> ;
|
||
///////////////////////////////////////// Explicit Instanciation /////////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////// httpclientexception /////////////////////////////////////////
|
||
/*!
|
||
* This is a default constructor with no argument.
|
||
*/
|
||
httpclientexceptionA::httpclientexceptionA (void)
|
||
throw ()
|
||
{
|
||
m_dwLastError = HTTPCLIENT_ERR_NOT_SPECIFIED ;
|
||
m_dwWin32LastError = NO_ERROR ;
|
||
}
|
||
|
||
/*!
|
||
* This is a constructor with an initial error message and initial error codes.
|
||
* If memory allocation failed for the error message, the error message will not be copied
|
||
* and Internal error message will point to NULL.
|
||
*
|
||
* \param szErrMsg [in] An initial error message.
|
||
* \param dwLastError [in] An error code.
|
||
* \param dwWin32LastError [in] A win32 error code.
|
||
*/
|
||
httpclientexceptionA::httpclientexceptionA (LPCSTR szErrMsg, DWORD dwLastError, DWORD dwWin32LastError)
|
||
throw ()
|
||
: errmsg_exceptionA (szErrMsg)
|
||
{
|
||
m_dwLastError = dwLastError ;
|
||
m_dwWin32LastError = dwWin32LastError ;
|
||
}
|
||
|
||
/*!
|
||
* This is a default constructor with no argument.
|
||
*/
|
||
httpclientexceptionW::httpclientexceptionW (void)
|
||
throw ()
|
||
{
|
||
m_dwLastError = HTTPCLIENT_ERR_NOT_SPECIFIED ;
|
||
m_dwWin32LastError = NO_ERROR ;
|
||
}
|
||
|
||
/*!
|
||
* This is a constructor with an initial error message and initial error codes.
|
||
* If memory allocation failed for the error message, the error message will not be copied
|
||
* and Internal error message will point to NULL.
|
||
*
|
||
* \param szErrMsg [in] An initial error message.
|
||
* \param dwLastError [in] An error code.
|
||
* \param dwWin32LastError [in] A win32 error code.
|
||
*/
|
||
httpclientexceptionW::httpclientexceptionW (LPCWSTR szErrMsg, DWORD dwLastError, DWORD dwWin32LastError)
|
||
throw ()
|
||
: errmsg_exceptionW (szErrMsg)
|
||
{
|
||
m_dwLastError = dwLastError ;
|
||
m_dwWin32LastError = dwWin32LastError ;
|
||
}
|
||
///////////////////////////////////////// httpclientexception /////////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////// CHttpToolA /////////////////////////////////////////
|
||
inline
|
||
LPCSTR CHttpToolA::GetConstMessage (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
// user-defined error message
|
||
if ( nIdx >= 1000 )
|
||
return g_UsrErrMsgA[0] ;
|
||
|
||
// Win32 API error (which has a win32 error code)
|
||
if ( nIdx >= 600 )
|
||
return g_Win32MsgWin32A[nIdx % 100] ;
|
||
|
||
// WinInet error (which has a win32 error code)
|
||
if ( nIdx >= 400 )
|
||
return g_WinInetMsgWin32A[nIdx % 100] ;
|
||
|
||
// Normal error (which has a win32 error code)
|
||
if ( nIdx >= 200 )
|
||
return g_NormalMsgWin32A[nIdx % 100] ;
|
||
|
||
// Normal error
|
||
if ( nIdx >= 100 )
|
||
return g_NormalMsgA[nIdx % 100] ;
|
||
|
||
return g_NotSpecifiedA[nIdx] ;
|
||
}
|
||
|
||
void CHttpToolA::ThrowException (DWORD nErrMsgIdx)
|
||
throw (Exception &)
|
||
{
|
||
throw Exception (GetConstMessage (nErrMsgIdx), nErrMsgIdx) ;
|
||
}
|
||
|
||
void CHttpToolA::ThrowException (LPCSTR szErrMsg, DWORD nErrMsgIdx)
|
||
throw (Exception &)
|
||
{
|
||
throw Exception (szErrMsg, nErrMsgIdx) ;
|
||
}
|
||
|
||
void CHttpToolA::ThrowException (DWORD nErrMsgIdx, DWORD dwErrCode, LPCSTR szStrArg)
|
||
throw (Exception &)
|
||
{
|
||
if ( szStrArg == NULL )
|
||
throw Exception (GetConstMessage (nErrMsgIdx), nErrMsgIdx, dwErrCode) ;
|
||
|
||
CHAR szErrMsg[512] ;
|
||
LPCSTR szFormat = GetConstMessage (nErrMsgIdx) ;
|
||
int cchWritten = SNPrintf (szErrMsg, 511, szFormat, szStrArg ? szStrArg : "NULL") ;
|
||
|
||
// if an error occurs
|
||
if ( cchWritten < -1 )
|
||
throw Exception (szFormat, nErrMsgIdx, dwErrCode) ;
|
||
|
||
if ( cchWritten == -1 )
|
||
cchWritten = 511 ;
|
||
|
||
szErrMsg[cchWritten] = NULL ;
|
||
throw Exception (szErrMsg, nErrMsgIdx, dwErrCode) ;
|
||
}
|
||
|
||
void CHttpToolA::ThrowException (LPCWSTR szErrMsg, DWORD nErrMsgIdx, DWORD dwErrCode)
|
||
throw (Exception &)
|
||
{
|
||
LPSTR szErrMsgA = NULL ;
|
||
|
||
try {
|
||
szErrMsgA = CHttpToolA::Unicode2Ansi (szErrMsg) ;
|
||
} catch (Exception &) {
|
||
szErrMsgA = NULL ;
|
||
}
|
||
|
||
Exception objException (szErrMsgA, nErrMsgIdx, dwErrCode) ;
|
||
SAFEFREE (szErrMsgA) ;
|
||
throw objException ;
|
||
}
|
||
|
||
void CHttpToolA::ThrowException (CHttpToolW::Exception & e)
|
||
throw (Exception &)
|
||
{
|
||
ThrowException (e.errmsg (), e.LastError (), e.Win32LastError ()) ;
|
||
}
|
||
|
||
void CHttpToolA::ThrowException (::SafeIntException & e)
|
||
throw (Exception &)
|
||
{
|
||
switch ( e.m_code ) {
|
||
case ERROR_ARITHMETIC_OVERFLOW:
|
||
ThrowException (HTTPCLIENT_ERR_ARITHMETIC_OVERFLOW) ;
|
||
break ;
|
||
|
||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||
ThrowException (HTTPCLIENT_ERR_INT_DIVIDE_BY_ZERO) ;
|
||
break ;
|
||
|
||
default:
|
||
ThrowException (HTTPCLIENT_ERR_UNEXPECTED_ARITHMETIC_ERROR) ;
|
||
break ;
|
||
}
|
||
}
|
||
|
||
// Conversion methods
|
||
// This method returns a converted ansi string from a unicode string.
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPSTR CHttpToolA::Unicode2Ansi (LPCWSTR szStr, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
// The unicode encodings are not allowed
|
||
HTTPTOOL_ASSERT ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpToolA::Unicode2Ansi: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
if ( szStr == NULL )
|
||
return NULL ;
|
||
|
||
int cchNeeded ;
|
||
|
||
if ( 0 == (cchNeeded = ::WideCharToMultiByte (CodePage, 0, szStr, -1, NULL, 0, NULL, NULL)) )
|
||
ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
|
||
PSTR szAnsi = (PSTR) ::malloc (sizeof (CHAR) * cchNeeded) ;
|
||
if ( szAnsi == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
if ( 0 == ::WideCharToMultiByte (CodePage, 0, szStr, -1, szAnsi, cchNeeded, NULL, NULL) ) {
|
||
SAFEFREE (szAnsi) ;
|
||
ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
return szAnsi ;
|
||
}
|
||
|
||
// This method returns a converted unicode string from a ansi string.
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPWSTR CHttpToolA::Ansi2Unicode (LPCSTR szStr, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
// The unicode encodings are not allowed
|
||
HTTPTOOL_ASSERT ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpToolA::Ansi2Unicode: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
if ( szStr == NULL )
|
||
return NULL ;
|
||
|
||
int cchNeeded ;
|
||
if ( 0 == (cchNeeded = ::MultiByteToWideChar (CodePage, 0, szStr, -1, NULL, 0)) )
|
||
ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
PWSTR szUni = (PWSTR) ::malloc (sizeof (WCHAR) * cchNeeded) ;
|
||
if ( szUni == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
if ( 0 == ::MultiByteToWideChar (CodePage, 0, szStr, -1, szUni, cchNeeded) ) {
|
||
SAFEFREE (szUni) ;
|
||
ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
return szUni ;
|
||
}
|
||
|
||
// comparison function (used by STL multimap)
|
||
bool CHttpToolA::operator () (LPCSTR szKey1, LPCSTR szKey2) const
|
||
throw ()
|
||
{
|
||
// return true if the two strings are null
|
||
if ( szKey1 == NULL && szKey2 == NULL )
|
||
return true ;
|
||
|
||
if ( szKey1 == NULL )
|
||
return true ;
|
||
|
||
if ( szKey2 == NULL )
|
||
return false ;
|
||
|
||
// case insensitive
|
||
return ::stricmp (szKey1, szKey2) < 0 ;
|
||
}
|
||
|
||
// Initializes a internet handle.
|
||
HINTERNET CHttpToolA::OpenInternet (LPCSTR szUserAgent, DWORD dwAccessType
|
||
, LPCSTR szProxyName, LPCSTR szProxyBypass, DWORD dwFlags)
|
||
throw (Exception &)
|
||
{
|
||
HINTERNET hInternet ;
|
||
|
||
if ( NULL == (hInternet = ::InternetOpenA (
|
||
szUserAgent // user agent
|
||
, dwAccessType // use direct connection or proxy connection
|
||
, szProxyName
|
||
, szProxyBypass
|
||
, dwFlags)
|
||
) )
|
||
ThrowException (HTTPCLIENT_ERR_INTERNETOPEN_FAILED, ::GetLastError ()) ;
|
||
|
||
return hInternet ;
|
||
}
|
||
|
||
// Closes a internet handle
|
||
void CHttpToolA::CloseInternet (HINTERNET & hInternet)
|
||
throw ()
|
||
{
|
||
if ( hInternet == NULL )
|
||
return ;
|
||
|
||
// Ignore any errors while closing the handle
|
||
::InternetCloseHandle (hInternet) ;
|
||
hInternet = NULL ;
|
||
}
|
||
|
||
// Returns a connection handle
|
||
// The hInternet must be a valid internet handle.
|
||
HINTERNET CHttpToolA::OpenConnection (HINTERNET hInternet, LPCSTR szServerAddr, INTERNET_PORT nPort
|
||
, LPCSTR szUsrName, LPCSTR szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hInternet != NULL, "CHttpToolA::OpenConnection: hInternet can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szServerAddr != NULL, "CHttpToolA::OpenConnection: szServerAddr can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (::strlen (szServerAddr) != 0, "CHttpToolA::OpenConnection: szServerAddr can not be an empty string.") ;
|
||
|
||
HINTERNET hConnection ;
|
||
|
||
if ( NULL == (hConnection = ::InternetConnectA (
|
||
hInternet
|
||
, szServerAddr
|
||
, nPort
|
||
, szUsrName
|
||
, szUsrPwd
|
||
, INTERNET_SERVICE_HTTP
|
||
, 0
|
||
, NULL)
|
||
) )
|
||
ThrowException (HTTPCLIENT_ERR_INTERNETCONNECT_FAILED, ::GetLastError ()) ;
|
||
|
||
return hConnection ;
|
||
}
|
||
|
||
// Closes a connection handle
|
||
void CHttpToolA::CloseConnection (HINTERNET & hConnection)
|
||
throw ()
|
||
{
|
||
if ( hConnection == NULL )
|
||
return ;
|
||
|
||
// Ignore any errors while closing the handle
|
||
::InternetCloseHandle (hConnection) ;
|
||
hConnection = NULL ;
|
||
}
|
||
|
||
// Returns a HTTP request handle
|
||
HINTERNET CHttpToolA::OpenRequest (HINTERNET hConnection, LPCSTR szMethod, LPCSTR szObjectName
|
||
, DWORD dwFlags, LPCSTR szReferer, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hConnection != NULL, "CHttpToolA::OpenRequest: hConnection can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szObjectName != NULL, "CHttpToolA::OpenRequest: szObjectName can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (::strlen (szObjectName) != 0, "CHttpToolA::OpenRequest: szObjectName can not be an empty string.") ;
|
||
|
||
static LPCSTR szAcceptedType[] = {
|
||
"*/*"
|
||
, NULL
|
||
} ;
|
||
|
||
HINTERNET hRequest = NULL ;
|
||
|
||
// Opens a HTTP request handle
|
||
if ( NULL == (hRequest = ::HttpOpenRequestA (
|
||
hConnection
|
||
, szMethod // HTTP Method
|
||
, szObjectName // Target object
|
||
, "HTTP/1.1" // HTTP/1.1
|
||
, szReferer // referer
|
||
, szAcceptedType // Accepts any type.
|
||
, dwFlags // Flags
|
||
, NULL // Doesn't use any context value.
|
||
)
|
||
) )
|
||
ThrowException (HTTPCLIENT_ERR_HTTPOPENREQUEST_FAILED, ::GetLastError ()) ;
|
||
|
||
return hRequest ;
|
||
}
|
||
|
||
// Closes a request handle
|
||
void CHttpToolA::CloseRequest (HINTERNET & hRequest)
|
||
throw ()
|
||
{
|
||
if ( hRequest == NULL )
|
||
return ;
|
||
|
||
// Ignore any errors while closing the handle
|
||
::InternetCloseHandle (hRequest) ;
|
||
hRequest = NULL ;
|
||
}
|
||
|
||
void CHttpToolA::AddHeader (HINTERNET hRequest, LPCSTR szName, LPCSTR szValue, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolA::AddHeader: hRequest can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szName != NULL, "CHttpToolA::AddHeader: szName can not be NULL.") ;
|
||
|
||
::SafeInt<size_t> cbHeader ;
|
||
::SafeInt<DWORD> cchHeader ;
|
||
|
||
try {
|
||
cbHeader = ::strlen (szName) ;
|
||
cbHeader += szValue ? ::strlen (szValue) : 0 ;
|
||
cbHeader += (4 + 1) ; // for ": ", "\r\n", '\0'
|
||
cchHeader = cbHeader - 1 ;
|
||
} catch (::SafeIntException & e) {
|
||
ThrowException (e) ;
|
||
}
|
||
|
||
PSTR szHeader = (PSTR) ::malloc (sizeof (CHAR) * (cbHeader.Value ())) ;
|
||
if ( szHeader == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
::strcpy (szHeader, szName) ;
|
||
::strcat (szHeader, ": ") ;
|
||
::strcat (szHeader, szValue ? szValue : "") ;
|
||
::strcat (szHeader, "\r\n") ;
|
||
|
||
// Adds a header
|
||
if ( !::HttpAddRequestHeadersA (
|
||
hRequest
|
||
, szHeader // headers to append to the request.
|
||
, cchHeader.Value () // header length
|
||
, HTTP_ADDREQ_FLAG_ADD // flags
|
||
)
|
||
) {
|
||
SAFEFREE (szHeader) ;
|
||
ThrowException (HTTPCLIENT_ERR_HTTPADDREQUESTHEADERS_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
SAFEFREE (szHeader) ;
|
||
}
|
||
|
||
void CHttpToolA::SendRequest (HINTERNET hRequest, LPCSTR szPosted, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolA::SendRequest: hRequest can not be NULL.") ;
|
||
|
||
::SafeInt<DWORD> cchPosted ;
|
||
|
||
try {
|
||
cchPosted = szPosted ? ::strlen (szPosted) : 0 ;
|
||
} catch (::SafeIntException & e) {
|
||
ThrowException (e) ;
|
||
}
|
||
|
||
if ( !::HttpSendRequestA (
|
||
hRequest
|
||
, NULL // Additional header
|
||
, 0 // The length of the additional header
|
||
, (void *) szPosted // A posted data
|
||
, cchPosted.Value () // The length of the posted data
|
||
) )
|
||
ThrowException (HTTPCLIENT_ERR_HTTPSENDREQUEST_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
void CHttpToolA::SendRequestEx (HINTERNET hRequest, DWORD dwPostedSize)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolA::SendRequestEx: hRequest can not be NULL.") ;
|
||
|
||
INTERNET_BUFFERSA BufferIn;
|
||
|
||
BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); // Must be set or error will occur
|
||
BufferIn.Next = NULL;
|
||
BufferIn.lpcszHeader = NULL;
|
||
BufferIn.dwHeadersLength = 0;
|
||
BufferIn.dwHeadersTotal = 0;
|
||
BufferIn.lpvBuffer = NULL;
|
||
BufferIn.dwBufferLength = 0;
|
||
BufferIn.dwBufferTotal = dwPostedSize; // This is the only member used other than dwStructSize
|
||
BufferIn.dwOffsetLow = 0;
|
||
BufferIn.dwOffsetHigh = 0;
|
||
|
||
if ( !::HttpSendRequestExA (
|
||
hRequest
|
||
, &BufferIn
|
||
, NULL
|
||
, 0
|
||
, 0
|
||
) )
|
||
ThrowException (HTTPCLIENT_ERR_HTTPSENDREQUESTEX_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
void CHttpToolA::InternetWriteFile (HINTERNET hRequest, const BYTE * pbyBuff, DWORD cbyBuff)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolA::InternetWriteFile: hRequest can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (pbyBuff != NULL, "CHttpToolA::InternetWriteFile: pbyBuff can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (cbyBuff != 0, "CHttpToolA::InternetWriteFile: cbyBuff can not be zero.") ;
|
||
|
||
DWORD dwTotalWritten = 0, dwWritten ;
|
||
|
||
while ( dwTotalWritten < cbyBuff ) {
|
||
if ( !::InternetWriteFile (
|
||
hRequest
|
||
, pbyBuff + dwTotalWritten
|
||
, cbyBuff - dwTotalWritten
|
||
, &dwWritten
|
||
)
|
||
)
|
||
ThrowException (HTTPCLIENT_ERR_INTERNETWRITEFILE_FAILED, ::GetLastError ()) ;
|
||
|
||
dwTotalWritten += dwWritten ;
|
||
}
|
||
}
|
||
|
||
void CHttpToolA::EndRequest (HINTERNET hRequest)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolA::EndRequest: hRequest can not be NULL.") ;
|
||
|
||
if ( !::HttpEndRequest (
|
||
hRequest
|
||
, NULL
|
||
, 0
|
||
, 0
|
||
)
|
||
)
|
||
ThrowException (HTTPCLIENT_ERR_HTTPENDREQUEST_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
// Checks whether the file exists.
|
||
// (Does not throw an exception)
|
||
BOOL CHttpToolA::FileExists (LPCSTR szFilePath)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (szFilePath != NULL, "CHttpToolA::FileExists: szFilePath can not be NULL.") ;
|
||
|
||
HANDLE hFile = ::CreateFileA (
|
||
szFilePath
|
||
, 0
|
||
, FILE_SHARE_READ
|
||
, NULL
|
||
, OPEN_EXISTING
|
||
, FILE_ATTRIBUTE_NORMAL
|
||
, NULL) ;
|
||
|
||
if ( hFile != INVALID_HANDLE_VALUE )
|
||
{
|
||
::CloseHandle (hFile) ;
|
||
return TRUE ;
|
||
}
|
||
|
||
return FALSE ;
|
||
}
|
||
|
||
// It returns a INVALID_HANDLE_VALUE if the specified file is not valid.
|
||
// (Does not throw an exception)
|
||
HANDLE CHttpToolA::OpenFile (LPCSTR szFilePath)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (szFilePath != NULL, "CHttpToolA::OpenFile: szFilePath can not be NULL.") ;
|
||
|
||
return ::CreateFileA (
|
||
szFilePath
|
||
, GENERIC_READ
|
||
, FILE_SHARE_READ
|
||
, NULL
|
||
, OPEN_EXISTING
|
||
, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN
|
||
, NULL) ;
|
||
}
|
||
|
||
// If it fails to create an file, it will return INVALID_HANDLE_VALUE.
|
||
// (Does not throw an exception)
|
||
HANDLE CHttpToolA::CreateFileAlwaysToWrite (LPCSTR szFilePath)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (szFilePath != NULL, "CHttpToolA::CreateFileAlwaysToWrite: szFilePath can not be NULL.") ;
|
||
|
||
return ::CreateFileA (
|
||
szFilePath
|
||
, GENERIC_WRITE
|
||
, 0
|
||
, NULL
|
||
, CREATE_ALWAYS
|
||
, FILE_ATTRIBUTE_NORMAL
|
||
, NULL) ;
|
||
}
|
||
|
||
|
||
|
||
|
||
DWORD CHttpToolA::GetFileSize (HANDLE hFile, LPCSTR szFilePath)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hFile != NULL, "CHttpToolA::GetFileSize: hFile can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szFilePath != NULL, "CHttpToolA::GetFileSize: szFilePath can not be NULL.") ;
|
||
|
||
DWORD dwFileSize = ::GetFileSize (hFile, NULL) ;
|
||
if ( dwFileSize == INVALID_FILE_SIZE )
|
||
ThrowException (HTTPCLIENT_ERR_GETFILESIZE_FAILED, ::GetLastError (), szFilePath) ;
|
||
|
||
return dwFileSize ;
|
||
}
|
||
|
||
// The file handle must point to BOF. If the file handle is INVALID_HANDLE_VALUE
|
||
// The default mime type is returned.
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPSTR CHttpToolA::GetMimeType (HANDLE hFile, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hFile != NULL, "CHttpToolA::GetMimeType: hFile can not be NULL.") ;
|
||
|
||
LPSTR szMimeType = NULL ;
|
||
try {
|
||
szMimeType = CHttpToolW::GetMimeType (hFile, CodePage) ;
|
||
} catch (CHttpToolW::Exception & e) {
|
||
ThrowException (e) ;
|
||
}
|
||
|
||
return szMimeType ;
|
||
}
|
||
|
||
// Returns the HTTP status text from the HTTP request handle.
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPSTR CHttpToolA::GetStatusText (HINTERNET hRequest)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolA::GetStatusText: hRequest can not be NULL.") ;
|
||
|
||
DWORD cbBuff = 0 ;
|
||
LPSTR szStatusText = NULL ;
|
||
|
||
// Get required buffer size
|
||
if ( !::HttpQueryInfoA (
|
||
hRequest
|
||
, HTTP_QUERY_STATUS_TEXT // Get the status text
|
||
, static_cast<void *> (szStatusText)
|
||
, &cbBuff // Required buffer size (byte)
|
||
, NULL // Don't use a header index
|
||
)
|
||
)
|
||
if ( ::GetLastError () != ERROR_INSUFFICIENT_BUFFER )
|
||
ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
|
||
_ASSERTE ( cbBuff != 0 ) ;
|
||
|
||
szStatusText = (LPSTR) ::malloc (cbBuff) ;
|
||
if ( szStatusText == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
// Get the status text
|
||
if ( !::HttpQueryInfoA (
|
||
hRequest
|
||
, HTTP_QUERY_STATUS_TEXT // Get the status text
|
||
, static_cast<void *> (szStatusText)
|
||
, &cbBuff // Allocated buffer size (byte)
|
||
, NULL // Don't use a header index
|
||
)
|
||
) {
|
||
::free (szStatusText) ;
|
||
ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
return szStatusText ;
|
||
}
|
||
|
||
// Get the HTTP header which has the name specified by szName from the HTTP request handle.
|
||
// If the header is not found, NULL is returned.
|
||
// The returned string must be freed by using the ::free () function.
|
||
// pnIdx exactly corresponds to the lpdwIndex parameter in the ::HttpQueryInfo function.
|
||
// For more information about this parameter, see microsoft's SDK documentation.
|
||
LPSTR CHttpToolA::GetHeader (HINTERNET hRequest, LPCSTR szName, DWORD * pnIdx)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolA::GetHeader: hRequest can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szName != NULL, "CHttpToolA::GetHeader: szName can not be NULL.") ;
|
||
|
||
DWORD nOrigIdx = 0 ;
|
||
if ( pnIdx ) nOrigIdx = *pnIdx ;
|
||
|
||
// Copy the header name
|
||
::SafeInt<DWORD> cbBuff ;
|
||
try {
|
||
cbBuff = ::strlen (szName) ;
|
||
cbBuff++ ;
|
||
cbBuff *= sizeof (CHAR) ;
|
||
} catch (::SafeIntException & e) {
|
||
ThrowException (e) ;
|
||
}
|
||
|
||
PSTR szHeader = (PSTR) ::malloc (cbBuff.Value ()) ;
|
||
if ( szHeader == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
::strcpy (szHeader, szName) ;
|
||
|
||
if ( ::HttpQueryInfoA (
|
||
hRequest
|
||
, HTTP_QUERY_CUSTOM // Get a custom header
|
||
, static_cast<void *> (szHeader)
|
||
, cbBuff.Ptr ()
|
||
, pnIdx
|
||
)
|
||
)
|
||
return szHeader ;
|
||
|
||
SAFEFREE (szHeader) ;
|
||
if ( pnIdx ) *pnIdx = nOrigIdx ;
|
||
|
||
// If the function failed
|
||
if ( ::GetLastError () != ERROR_INSUFFICIENT_BUFFER ) {
|
||
// If the header does not exist
|
||
if ( ::GetLastError () == ERROR_HTTP_HEADER_NOT_FOUND )
|
||
return NULL ;
|
||
|
||
ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
// Allocates required memory
|
||
szHeader = (LPSTR) ::malloc (cbBuff.Value ()) ;
|
||
if ( szHeader == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
::strcpy (szHeader, szName) ;
|
||
|
||
if ( !::HttpQueryInfoA (
|
||
hRequest
|
||
, HTTP_QUERY_CUSTOM // Get a custom header
|
||
, static_cast<void *> (szHeader)
|
||
, cbBuff.Ptr ()
|
||
, pnIdx
|
||
)
|
||
) {
|
||
SAFEFREE (szHeader) ;
|
||
ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
return szHeader ;
|
||
}
|
||
|
||
void CHttpToolA::InternetSetOption (HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength)
|
||
throw (Exception &)
|
||
{
|
||
if ( ::InternetSetOptionA (hInternet, dwOption, lpBuffer, dwBufferLength) )
|
||
return ;
|
||
|
||
ThrowException (HTTPCLIENT_ERR_INTERNETSETOPTION_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
// Generates a new upload boundary. If an error occurs, NULL is returned
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPSTR CHttpToolA::CreateUploadBoundary (void)
|
||
throw ()
|
||
{
|
||
GUID guid ;
|
||
|
||
if ( FAILED ( ::CoCreateGuid (&guid)) )
|
||
return NULL ;
|
||
|
||
PSTR szBoundary = (PSTR) ::malloc (sizeof (CHAR) * 44) ;
|
||
|
||
if ( szBoundary == NULL )
|
||
return NULL ;
|
||
|
||
::sprintf (szBoundary, "----LYOUL-%.08x%.04x%.04x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x-"
|
||
, guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1]
|
||
, guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
|
||
|
||
return szBoundary ;
|
||
}
|
||
///////////////////////////////////////// CHttpToolA /////////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////// CHttpToolW /////////////////////////////////////////
|
||
inline
|
||
LPCWSTR CHttpToolW::GetConstMessage (int nIdx)
|
||
throw ()
|
||
{
|
||
// user-defined error message
|
||
if ( nIdx >= 1000 )
|
||
return g_UsrErrMsgW[0] ;
|
||
|
||
// Win32 API error (which has a win32 error code)
|
||
if ( nIdx >= 600 )
|
||
return g_Win32MsgWin32W[nIdx % 100] ;
|
||
|
||
// WinInet error (which has a win32 error code)
|
||
if ( nIdx >= 400 )
|
||
return g_WinInetMsgWin32W[nIdx % 100] ;
|
||
|
||
// Normal error (which has a win32 error code)
|
||
if ( nIdx >= 200 )
|
||
return g_NormalMsgWin32W[nIdx % 100] ;
|
||
|
||
// Normal error
|
||
if ( nIdx >= 100 )
|
||
return g_NormalMsgW[nIdx % 100] ;
|
||
|
||
return g_NotSpecifiedW[nIdx] ;
|
||
}
|
||
|
||
void CHttpToolW::ThrowException (DWORD nErrMsgIdx)
|
||
throw (Exception &)
|
||
{
|
||
throw Exception (GetConstMessage (nErrMsgIdx), nErrMsgIdx) ;
|
||
}
|
||
|
||
void CHttpToolW::ThrowException (LPCWSTR szErrMsg, DWORD nErrMsgIdx)
|
||
throw (Exception &)
|
||
{
|
||
throw Exception (szErrMsg, nErrMsgIdx) ;
|
||
}
|
||
|
||
void CHttpToolW::ThrowException (DWORD nErrMsgIdx, DWORD dwErrCode, LPCWSTR szStrArg)
|
||
throw (Exception &)
|
||
{
|
||
if ( szStrArg == NULL )
|
||
throw Exception (GetConstMessage (nErrMsgIdx), nErrMsgIdx, dwErrCode) ;
|
||
|
||
WCHAR szErrMsg[512] ;
|
||
LPCWSTR szFormat = GetConstMessage (nErrMsgIdx) ;
|
||
int cchWritten = SNPrintf (szErrMsg, 511, szFormat, szStrArg ? szStrArg : L"NULL") ;
|
||
|
||
// if an error occurs
|
||
if ( cchWritten < -1 )
|
||
throw Exception (szFormat, nErrMsgIdx, dwErrCode) ;
|
||
|
||
if ( cchWritten == -1 )
|
||
cchWritten = 511 ;
|
||
|
||
szErrMsg[cchWritten] = NULL ;
|
||
throw Exception (szErrMsg, nErrMsgIdx, dwErrCode) ;
|
||
}
|
||
|
||
void CHttpToolW::ThrowException (LPCSTR szErrMsg, DWORD nErrMsgIdx, DWORD dwErrCode)
|
||
throw (Exception &)
|
||
{
|
||
LPWSTR szErrMsgW = NULL ;
|
||
|
||
try {
|
||
szErrMsgW = Ansi2Unicode (szErrMsg) ;
|
||
} catch (Exception &) {
|
||
;
|
||
}
|
||
|
||
Exception objException (szErrMsgW, nErrMsgIdx, dwErrCode) ;
|
||
SAFEFREE (szErrMsgW) ;
|
||
throw objException ;
|
||
}
|
||
|
||
void CHttpToolW::ThrowException (httpclientexceptionA & e)
|
||
throw (Exception &)
|
||
{
|
||
ThrowException (e.errmsg (), e.LastError (), e.Win32LastError ()) ;
|
||
}
|
||
|
||
void CHttpToolW::ThrowException (::SafeIntException & e)
|
||
throw (Exception &)
|
||
{
|
||
switch ( e.m_code ) {
|
||
case ERROR_ARITHMETIC_OVERFLOW:
|
||
ThrowException (HTTPCLIENT_ERR_ARITHMETIC_OVERFLOW) ;
|
||
break ;
|
||
|
||
case EXCEPTION_INT_DIVIDE_BY_ZERO:
|
||
ThrowException (HTTPCLIENT_ERR_INT_DIVIDE_BY_ZERO) ;
|
||
break ;
|
||
|
||
default:
|
||
ThrowException (HTTPCLIENT_ERR_UNEXPECTED_ARITHMETIC_ERROR) ;
|
||
break ;
|
||
}
|
||
}
|
||
|
||
|
||
// Conversion methods
|
||
// This function returns a converted ansi string from a unicode string.
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPSTR CHttpToolW::Unicode2Ansi (LPCWSTR szStr, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
// The unicode encodings are not allowed
|
||
HTTPTOOL_ASSERT ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpToolW::Unicode2Ansi: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
if ( szStr == NULL )
|
||
return NULL ;
|
||
|
||
int cchNeeded ;
|
||
|
||
if ( 0 == (cchNeeded = ::WideCharToMultiByte (CodePage, 0, szStr, -1, NULL, 0, NULL, NULL)) )
|
||
ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
|
||
PSTR szAnsi = (PSTR) ::malloc (sizeof (CHAR) * cchNeeded) ;
|
||
if ( szAnsi == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
if ( 0 == ::WideCharToMultiByte (CodePage, 0, szStr, -1, szAnsi, cchNeeded, NULL, NULL) ) {
|
||
SAFEFREE (szAnsi) ;
|
||
ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
return szAnsi ;
|
||
}
|
||
|
||
// This method returns a converted unicode string from a ansi string.
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPWSTR CHttpToolW::Ansi2Unicode (LPCSTR szStr, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
// The unicode encodings are not allowed
|
||
HTTPTOOL_ASSERT ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpToolW::Ansi2Unicode: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
if ( szStr == NULL )
|
||
return NULL ;
|
||
|
||
int cchNeeded ;
|
||
if ( 0 == (cchNeeded = ::MultiByteToWideChar (CodePage, 0, szStr, -1, NULL, 0)) )
|
||
ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
PWSTR szUni = (PWSTR) ::malloc (sizeof (WCHAR) * cchNeeded) ;
|
||
if ( szUni == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
if ( 0 == ::MultiByteToWideChar (CodePage, 0, szStr, -1, szUni, cchNeeded) ) {
|
||
SAFEFREE (szUni) ;
|
||
ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
return szUni ;
|
||
}
|
||
|
||
|
||
// comparison function (used by STL multimap)
|
||
bool CHttpToolW::operator () (LPCWSTR szKey1, LPCWSTR szKey2) const
|
||
throw ()
|
||
{
|
||
// return true if the two strings are null
|
||
if ( szKey1 == NULL && szKey2 == NULL )
|
||
return true ;
|
||
|
||
if ( szKey1 == NULL )
|
||
return true ;
|
||
|
||
if ( szKey2 == NULL )
|
||
return false ;
|
||
|
||
// case insensitive
|
||
return ::wcsicmp (szKey1, szKey2) < 0 ;
|
||
}
|
||
|
||
// Initializes a internet handle.
|
||
HINTERNET CHttpToolW::OpenInternet (LPCWSTR szUserAgent, DWORD dwAccessType
|
||
, LPCWSTR szProxyName, LPCWSTR szProxyBypass, DWORD dwFlags)
|
||
throw (Exception &)
|
||
{
|
||
HINTERNET hInternet ;
|
||
|
||
if ( NULL == (hInternet = InternetOpenW (
|
||
szUserAgent // user agent
|
||
, dwAccessType // use direct connection or proxy connection
|
||
, szProxyName
|
||
, szProxyBypass
|
||
, dwFlags)
|
||
) )
|
||
ThrowException (HTTPCLIENT_ERR_INTERNETOPEN_FAILED, ::GetLastError ()) ;
|
||
|
||
return hInternet ;
|
||
}
|
||
|
||
// Closes a internet handle
|
||
void CHttpToolW::CloseInternet (HINTERNET & hInternet)
|
||
throw ()
|
||
{
|
||
CHttpToolA::CloseInternet (hInternet) ;
|
||
}
|
||
|
||
// Returns a connection handle
|
||
// The hInternet must be a valid internet handle.
|
||
HINTERNET CHttpToolW::OpenConnection (HINTERNET hInternet, LPCWSTR szServerAddr, INTERNET_PORT nPort
|
||
, LPCWSTR szUsrName, LPCWSTR szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hInternet != NULL, "CHttpToolW::OpenConnection: hInternet can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szServerAddr != NULL, "CHttpToolW::OpenConnection: szServerAddr can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (::wcslen (szServerAddr) != 0, "CHttpToolW::OpenConnection: szServerAddr can not be an empty string.") ;
|
||
|
||
HINTERNET hConnection ;
|
||
|
||
if ( NULL == (hConnection = ::InternetConnectW (
|
||
hInternet
|
||
, szServerAddr
|
||
, nPort
|
||
, szUsrName
|
||
, szUsrPwd
|
||
, INTERNET_SERVICE_HTTP
|
||
, 0
|
||
, NULL)
|
||
) )
|
||
ThrowException (HTTPCLIENT_ERR_INTERNETCONNECT_FAILED, ::GetLastError ()) ;
|
||
|
||
return hConnection ;
|
||
}
|
||
|
||
// Closes a connection handle
|
||
void CHttpToolW::CloseConnection (HINTERNET & hConnection)
|
||
throw ()
|
||
{
|
||
CHttpToolA::CloseConnection (hConnection) ;
|
||
}
|
||
|
||
// Returns a HTTP request handle
|
||
HINTERNET CHttpToolW::OpenRequest (HINTERNET hConnection, LPCWSTR szMethod, LPCWSTR szObjectName
|
||
, DWORD dwFlags, LPCWSTR szReferer, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hConnection != NULL, "CHttpToolW::OpenRequest: hConnection can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szObjectName != NULL, "CHttpToolW::OpenRequest: szObjectName can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (::wcslen (szObjectName) != 0, "CHttpToolW::OpenRequest: szObjectName can not be an empty string.") ;
|
||
|
||
// The unicode encodings are not allowed
|
||
HTTPTOOL_ASSERT ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpToolW::OpenRequest: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
LPSTR szMethodA = NULL ;
|
||
LPSTR szObjectNameA = NULL ;
|
||
LPSTR szRefererA = NULL ;
|
||
|
||
HINTERNET hRequest = NULL ;
|
||
|
||
try {
|
||
szMethodA = Unicode2Ansi (szMethod, CodePage) ;
|
||
szObjectNameA = Unicode2Ansi (szObjectName, CodePage) ;
|
||
szRefererA = Unicode2Ansi (szReferer, CodePage) ;
|
||
|
||
hRequest = CHttpToolA::OpenRequest (hConnection, szMethodA, szObjectNameA
|
||
, dwFlags, szRefererA) ;
|
||
} catch (Exception &) {
|
||
SAFEFREE (szMethodA) ;
|
||
SAFEFREE (szObjectNameA) ;
|
||
SAFEFREE (szRefererA) ;
|
||
throw ;
|
||
} catch (CHttpToolA::Exception & e) {
|
||
SAFEFREE (szMethodA) ;
|
||
SAFEFREE (szObjectNameA) ;
|
||
SAFEFREE (szRefererA) ;
|
||
ThrowException (e) ;
|
||
}
|
||
|
||
SAFEFREE (szMethodA) ;
|
||
SAFEFREE (szObjectNameA) ;
|
||
SAFEFREE (szRefererA) ;
|
||
|
||
return hRequest ;
|
||
}
|
||
|
||
// Closes a request handle
|
||
void CHttpToolW::CloseRequest (HINTERNET & hRequest)
|
||
throw ()
|
||
{
|
||
CHttpToolA::CloseRequest (hRequest) ;
|
||
}
|
||
|
||
void CHttpToolW::AddHeader (HINTERNET hRequest, LPCWSTR szName, LPCWSTR szValue, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolW::AddHeader: hRequest can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szName != NULL, "CHttpToolW::AddHeader: szName can not be NULL.") ;
|
||
|
||
// The unicode encodings are not allowed
|
||
HTTPTOOL_ASSERT ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpToolW::AddHeader: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
LPSTR szNameA = NULL ;
|
||
LPSTR szValueA = NULL ;
|
||
|
||
try {
|
||
szNameA = Unicode2Ansi (szName, CodePage) ;
|
||
szValueA = Unicode2Ansi (szValue, CodePage) ;
|
||
|
||
CHttpToolA::AddHeader (hRequest, szNameA, szValueA) ;
|
||
} catch (Exception &) {
|
||
SAFEFREE (szNameA) ;
|
||
SAFEFREE (szValueA) ;
|
||
throw ;
|
||
} catch (CHttpToolA::Exception & e) {
|
||
SAFEFREE (szNameA) ;
|
||
SAFEFREE (szValueA) ;
|
||
ThrowException (e) ;
|
||
}
|
||
SAFEFREE (szNameA) ;
|
||
SAFEFREE (szValueA) ;
|
||
}
|
||
|
||
void CHttpToolW::SendRequest (HINTERNET hRequest, LPCWSTR szPosted, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolW::SendRequest: hRequest can not be NULL.") ;
|
||
|
||
// The unicode encodings are not allowed
|
||
HTTPTOOL_ASSERT ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpToolW::SendRequest: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
LPSTR szPostedA = Unicode2Ansi (szPosted, CodePage) ;
|
||
|
||
::SafeInt<DWORD> cchPosted ;
|
||
try {
|
||
cchPosted = szPostedA ? ::strlen (szPostedA) : 0 ;
|
||
} catch (::SafeIntException & e) {
|
||
SAFEFREE (szPostedA) ;
|
||
ThrowException (e) ;
|
||
}
|
||
|
||
if ( !::HttpSendRequestW (
|
||
hRequest
|
||
, NULL // Additional header
|
||
, 0 // The length of the additional header
|
||
, (void *) szPostedA // A posted data
|
||
, cchPosted.Value () // The length of the posted data
|
||
) ) {
|
||
SAFEFREE (szPostedA) ;
|
||
ThrowException (HTTPCLIENT_ERR_HTTPSENDREQUEST_FAILED, ::GetLastError ()) ;
|
||
}
|
||
SAFEFREE (szPostedA) ;
|
||
}
|
||
|
||
void CHttpToolW::SendRequestEx (HINTERNET hRequest, DWORD dwPostedSize)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolW::SendRequestEx: hRequest can not be NULL.") ;
|
||
|
||
INTERNET_BUFFERSW BufferIn;
|
||
|
||
BufferIn.dwStructSize = sizeof( INTERNET_BUFFERS ); // Must be set or error will occur
|
||
BufferIn.Next = NULL;
|
||
BufferIn.lpcszHeader = NULL;
|
||
BufferIn.dwHeadersLength = 0;
|
||
BufferIn.dwHeadersTotal = 0;
|
||
BufferIn.lpvBuffer = NULL;
|
||
BufferIn.dwBufferLength = 0;
|
||
BufferIn.dwBufferTotal = dwPostedSize; // This is the only member used other than dwStructSize
|
||
BufferIn.dwOffsetLow = 0;
|
||
BufferIn.dwOffsetHigh = 0;
|
||
|
||
if ( !::HttpSendRequestExW (
|
||
hRequest
|
||
, &BufferIn
|
||
, NULL
|
||
, 0
|
||
, 0
|
||
) )
|
||
ThrowException (HTTPCLIENT_ERR_HTTPSENDREQUESTEX_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
void CHttpToolW::InternetWriteFile (HINTERNET hRequest, const BYTE * pbyBuff, DWORD cbyBuff)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolW::InternetWriteFile: hRequest can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (pbyBuff != NULL, "CHttpToolW::InternetWriteFile: pbyBuff can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (cbyBuff != 0, "CHttpToolW::InternetWriteFile: cbyBuff can not be zero.") ;
|
||
|
||
DWORD dwTotalWritten = 0, dwWritten ;
|
||
|
||
while ( dwTotalWritten < cbyBuff ) {
|
||
if ( !::InternetWriteFile (
|
||
hRequest
|
||
, pbyBuff + dwTotalWritten
|
||
, cbyBuff - dwTotalWritten
|
||
, &dwWritten
|
||
)
|
||
)
|
||
ThrowException (HTTPCLIENT_ERR_INTERNETWRITEFILE_FAILED, ::GetLastError ()) ;
|
||
|
||
dwTotalWritten += dwWritten ;
|
||
}
|
||
}
|
||
|
||
void CHttpToolW::EndRequest (HINTERNET hRequest)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolW::EndRequest: hRequest can not be NULL.") ;
|
||
|
||
if ( !::HttpEndRequest (
|
||
hRequest
|
||
, NULL
|
||
, 0
|
||
, 0
|
||
)
|
||
)
|
||
ThrowException (HTTPCLIENT_ERR_HTTPENDREQUEST_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
// Checks whether the file exists.
|
||
// (Does not throw an exception)
|
||
BOOL CHttpToolW::FileExists (LPCWSTR szFilePath)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (szFilePath != NULL, "CHttpToolW::FileExists: szFilePath can not be NULL.") ;
|
||
|
||
HANDLE hFile = ::CreateFileW (
|
||
szFilePath
|
||
, 0
|
||
, FILE_SHARE_READ
|
||
, NULL
|
||
, OPEN_EXISTING
|
||
, FILE_ATTRIBUTE_NORMAL
|
||
, NULL) ;
|
||
|
||
if ( hFile != INVALID_HANDLE_VALUE )
|
||
{
|
||
::CloseHandle (hFile) ;
|
||
return TRUE ;
|
||
}
|
||
|
||
return FALSE ;
|
||
}
|
||
|
||
// It returns a INVALID_HANDLE_VALUE if the specified file is not valid.
|
||
// (Does not throw an exception)
|
||
HANDLE CHttpToolW::OpenFile (LPCWSTR szFilePath)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (szFilePath != NULL, "CHttpToolW::OpenFile: szFilePath can not be NULL.") ;
|
||
|
||
return ::CreateFileW (
|
||
szFilePath
|
||
, GENERIC_READ
|
||
, FILE_SHARE_READ
|
||
, NULL
|
||
, OPEN_EXISTING
|
||
, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN
|
||
, NULL) ;
|
||
}
|
||
|
||
// If it fails to create an file, it will return INVALID_HANDLE_VALUE.
|
||
// (Does not throw an exception)
|
||
HANDLE CHttpToolW::CreateFileAlwaysToWrite (LPCWSTR szFilePath)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (szFilePath != NULL, "CHttpToolW::CreateFileAlwaysToWrite: szFilePath can not be NULL.") ;
|
||
|
||
return ::CreateFileW (
|
||
szFilePath
|
||
, GENERIC_WRITE
|
||
, 0
|
||
, NULL
|
||
, CREATE_ALWAYS
|
||
, FILE_ATTRIBUTE_NORMAL
|
||
, NULL) ;
|
||
}
|
||
|
||
DWORD CHttpToolW::GetFileSize (HANDLE hFile, LPCWSTR szFilePath)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hFile != NULL, "CHttpToolW::GetFileSize: hFile can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szFilePath != NULL, "CHttpToolW::GetFileSize: szFilePath can not be NULL.") ;
|
||
|
||
DWORD dwFileSize = ::GetFileSize (hFile, NULL) ;
|
||
if ( dwFileSize == INVALID_FILE_SIZE )
|
||
ThrowException (HTTPCLIENT_ERR_GETFILESIZE_FAILED, ::GetLastError (), szFilePath) ;
|
||
|
||
return dwFileSize ;
|
||
}
|
||
|
||
// The file handle must point to BOF. If the file handle is INVALID_HANDLE_VALUE
|
||
// The default mime type is returned.
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPSTR CHttpToolW::GetMimeType (HANDLE hFile, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hFile != NULL, "CHttpToolW::GetMimeType: hFile can not be NULL.") ;
|
||
|
||
// The unicode encodings are not allowed
|
||
HTTPTOOL_ASSERT ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpToolW::GetMimeType: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
// If the file handle is not valid, just returns the default MimeType.
|
||
if ( hFile == INVALID_HANDLE_VALUE ) {
|
||
PSTR szMimeA = NULL ;
|
||
szMimeA = (PSTR) ::malloc (sizeof (CHAR) * (::strlen (HTTPCLIENT_DEF_MIMETYPE) + 1)) ;
|
||
if ( szMimeA == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
::strcpy (szMimeA, HTTPCLIENT_DEF_MIMETYPE) ;
|
||
return szMimeA ;
|
||
}
|
||
|
||
BYTE byBuff[256] ;
|
||
DWORD dwRead ;
|
||
|
||
if ( 0 == ::ReadFile (hFile
|
||
, byBuff
|
||
, 256
|
||
, &dwRead
|
||
, NULL) )
|
||
ThrowException (HTTPCLIENT_ERR_READFILE_FAILED, ::GetLastError ()) ;
|
||
|
||
// Moves the file pointer to the beginning of the file.
|
||
if ( INVALID_SET_FILE_POINTER == ::SetFilePointer (hFile, 0, NULL, FILE_BEGIN) )
|
||
ThrowException (HTTPCLIENT_ERR_SETFILEPOINTER_FAILED, ::GetLastError ()) ;
|
||
|
||
PWSTR szMimeW = NULL ;
|
||
PSTR szMimeA = NULL ;
|
||
HRESULT hResult ;
|
||
|
||
// If the ::FindMimeFromData function failed to get a appropriate MimeType,
|
||
// just returns the default MimeType.
|
||
if ( NOERROR != (hResult = ::FindMimeFromData (
|
||
NULL
|
||
, NULL
|
||
, byBuff
|
||
, dwRead
|
||
, NULL
|
||
, 0
|
||
, &szMimeW
|
||
, 0)) ) {
|
||
szMimeA = (PSTR) ::malloc (sizeof (CHAR) * (::strlen (HTTPCLIENT_DEF_MIMETYPE) + 1)) ;
|
||
if ( szMimeA == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
::strcpy (szMimeA, HTTPCLIENT_DEF_MIMETYPE) ;
|
||
return szMimeA ;
|
||
}
|
||
|
||
try {
|
||
szMimeA = Unicode2Ansi (szMimeW, CodePage) ;
|
||
} catch (Exception &) {
|
||
::CoTaskMemFree (szMimeW) ;
|
||
throw ;
|
||
}
|
||
|
||
::CoTaskMemFree (szMimeW) ;
|
||
return szMimeA ;
|
||
}
|
||
|
||
// Returns the HTTP status text from the HTTP request handle.
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPWSTR CHttpToolW::GetStatusText (HINTERNET hRequest)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolW::GetStatusText: hRequest can not be NULL.") ;
|
||
|
||
DWORD cbBuff = 0 ;
|
||
PWSTR szStatusText = NULL ;
|
||
|
||
// Get required buffer size
|
||
if ( !::HttpQueryInfoW (
|
||
hRequest
|
||
, HTTP_QUERY_STATUS_TEXT // Get the status text
|
||
, static_cast<void *> (szStatusText)
|
||
, &cbBuff // Required buffer size (byte)
|
||
, NULL // Don't use a header index
|
||
)
|
||
)
|
||
if ( ::GetLastError () != ERROR_INSUFFICIENT_BUFFER )
|
||
ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
|
||
_ASSERTE ( cbBuff != 0 ) ;
|
||
|
||
szStatusText = (PWSTR) ::malloc (cbBuff) ;
|
||
if ( szStatusText == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
// Get the status text
|
||
if ( !::HttpQueryInfoW (
|
||
hRequest
|
||
, HTTP_QUERY_STATUS_TEXT // Get the status text
|
||
, static_cast<void *> (szStatusText)
|
||
, &cbBuff // Required buffer size (byte)
|
||
, NULL // Don't use a header index
|
||
)
|
||
) {
|
||
::free (szStatusText) ;
|
||
ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
return szStatusText ;
|
||
}
|
||
|
||
// Get the HTTP header which has the name specified by szName from the HTTP request handle.
|
||
// If the header is not found, NULL is returned.
|
||
// The returned string must be freed by using the ::free () function.
|
||
// pnIdx exactly corresponds to the lpdwIndex parameter in the ::HttpQueryInfo function.
|
||
// For more information about this parameter, see microsoft's SDK documentation.
|
||
LPWSTR CHttpToolW::GetHeader (HINTERNET hRequest, LPCWSTR szName, DWORD * pnIdx)
|
||
throw (Exception &)
|
||
{
|
||
HTTPTOOL_ASSERT (hRequest != NULL, "CHttpToolW::GetHeader: hRequest can not be NULL.") ;
|
||
HTTPTOOL_ASSERT (szName != NULL, "CHttpToolW::GetHeader: szName can not be NULL.") ;
|
||
|
||
DWORD nOrigIdx = 0 ;
|
||
if ( pnIdx ) nOrigIdx = *pnIdx ;
|
||
|
||
|
||
// Copy the header name
|
||
::SafeInt<DWORD> cbBuff ;
|
||
try {
|
||
cbBuff = ::wcslen (szName) ;
|
||
cbBuff++ ; // for '\0' character
|
||
cbBuff *= sizeof (WCHAR) ;
|
||
} catch (::SafeIntException & e) {
|
||
ThrowException (e) ;
|
||
}
|
||
|
||
PWSTR szHeader = (PWSTR) ::malloc (cbBuff.Value ()) ;
|
||
if ( szHeader == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
::wcscpy (szHeader, szName) ;
|
||
|
||
if ( ::HttpQueryInfoW (
|
||
hRequest
|
||
, HTTP_QUERY_CUSTOM // Get a custom header
|
||
, static_cast<void *> (szHeader)
|
||
, cbBuff.Ptr ()
|
||
, pnIdx
|
||
)
|
||
)
|
||
return szHeader ;
|
||
|
||
SAFEFREE (szHeader) ;
|
||
if ( pnIdx ) *pnIdx = nOrigIdx ;
|
||
|
||
// If the function failed
|
||
if ( ::GetLastError () != ERROR_INSUFFICIENT_BUFFER ) {
|
||
// If the header does not exist
|
||
if ( ::GetLastError () == ERROR_HTTP_HEADER_NOT_FOUND )
|
||
return NULL ;
|
||
|
||
ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
// Allocates required memory
|
||
szHeader = (PWSTR) ::malloc (cbBuff.Value ()) ;
|
||
if ( szHeader == NULL )
|
||
ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
::wcscpy (szHeader, szName) ;
|
||
|
||
if ( !::HttpQueryInfoW (
|
||
hRequest
|
||
, HTTP_QUERY_CUSTOM // Get a custom header
|
||
, static_cast<void *> (szHeader)
|
||
, cbBuff.Ptr ()
|
||
, pnIdx
|
||
)
|
||
) {
|
||
SAFEFREE (szHeader) ;
|
||
ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
return szHeader ;
|
||
}
|
||
|
||
void CHttpToolW::InternetSetOption (HINTERNET hInternet, DWORD dwOption, LPVOID lpBuffer, DWORD dwBufferLength)
|
||
throw (Exception &)
|
||
{
|
||
if ( ::InternetSetOptionW (hInternet, dwOption, lpBuffer, dwBufferLength) )
|
||
return ;
|
||
|
||
ThrowException (HTTPCLIENT_ERR_INTERNETSETOPTION_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
// Generates a new upload boundary. If an error occurs, NULL is returned
|
||
// The returned string must be freed by using the ::free () function.
|
||
LPWSTR CHttpToolW::CreateUploadBoundary (void)
|
||
throw ()
|
||
{
|
||
GUID guid ;
|
||
|
||
if ( FAILED ( ::CoCreateGuid (&guid)) )
|
||
return NULL ;
|
||
|
||
PWSTR szBoundary = NULL ;
|
||
szBoundary = (PWSTR) ::malloc (sizeof (WCHAR) * 44) ;
|
||
|
||
if ( szBoundary == NULL )
|
||
return NULL ;
|
||
|
||
::swprintf (szBoundary, L"----LYOUL-%.08x%.04x%.04x%.02x%.02x%.02x%.02x%.02x%.02x%.02x%.02x-"
|
||
, guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1]
|
||
, guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
|
||
|
||
return szBoundary ;
|
||
}
|
||
///////////////////////////////////////// CHttpToolW /////////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////// CHttpClientMapT /////////////////////////////////////////
|
||
template <typename HttpTool>
|
||
CHttpClientMapT<HttpTool>::CHttpClientMapT (void)
|
||
throw ()
|
||
{
|
||
; // do nothing yet
|
||
}
|
||
|
||
template <typename HttpTool>
|
||
CHttpClientMapT<HttpTool>::~CHttpClientMapT (void)
|
||
throw ()
|
||
{
|
||
Clear () ;
|
||
}
|
||
|
||
// If some data cleared, it will return TRUE, otherwise return FALSE.
|
||
// If memory is exhausted, it can leak memory.
|
||
template <typename HttpTool>
|
||
BOOL CHttpClientMapT<HttpTool>::Clear (void)
|
||
throw ()
|
||
{
|
||
if ( m_map.empty () )
|
||
return FALSE ;
|
||
|
||
// Allocates memory to save pointers for key name.
|
||
// If an overflow exception or a memory allocation failure is occurs,
|
||
// The memory pointed by the key name pointer are leaked.
|
||
::SafeInt<MapSizeType> cKeys = m_map.size () ;
|
||
::SafeInt<size_t> cbRequired = 0 ;
|
||
PCSZ * arrKeys = NULL ;
|
||
|
||
try {
|
||
cbRequired = cKeys ;
|
||
cbRequired *= sizeof (PCSZ) ;
|
||
arrKeys = (PCSZ *) ::malloc (cbRequired.Value ()) ;
|
||
} catch (::SafeIntException &) {
|
||
arrKeys = NULL ;
|
||
}
|
||
|
||
MapSizeType nIdx = 0 ;
|
||
for (MapIter iter = m_map.begin (); iter != m_map.end (); ++iter) {
|
||
(iter->second).Delete () ;
|
||
|
||
// Saves the key name pointer
|
||
if ( arrKeys )
|
||
arrKeys[nIdx++] = iter->first ;
|
||
}
|
||
|
||
m_map.clear () ;
|
||
|
||
if ( arrKeys == NULL )
|
||
return TRUE ;
|
||
|
||
for (nIdx = 0; nIdx < cKeys; nIdx++)
|
||
SAFEFREE ( arrKeys[nIdx] ) ;
|
||
SAFEFREE ( arrKeys ) ;
|
||
|
||
return TRUE ;
|
||
}
|
||
|
||
// This function deletes an element in position nIdx from the map.
|
||
// If the element deleted, it will return TRUE, otherwise return FALSE.
|
||
template <typename HttpTool>
|
||
BOOL CHttpClientMapT<HttpTool>::Remove (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
if ( m_map.empty () )
|
||
return FALSE ;
|
||
|
||
// Find the item to delete
|
||
MapIter iter = m_map.begin () ;
|
||
for (DWORD i = 0; i < nIdx; i++) {
|
||
++iter ;
|
||
|
||
// If the nIdx is out of range.
|
||
if ( iter == m_map.end () )
|
||
return FALSE ;
|
||
}
|
||
|
||
(iter->second).Delete () ;
|
||
PCSZ szName = iter->first ;
|
||
m_map.erase (iter) ;
|
||
SAFEFREE (szName) ;
|
||
return TRUE ;
|
||
}
|
||
|
||
// This function erases all elements of which key name equals to szName.
|
||
// If some data cleared, it will return TRUE, otherwise return FALSE.
|
||
// If memory is exhausted, memory will be leaked.
|
||
template <typename HttpTool>
|
||
BOOL CHttpClientMapT<HttpTool>::RemoveAll (PCSZ szName)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpClientMapT::RemoveAll: szName can not be NULL.") ;
|
||
|
||
::SafeInt<MapSizeType> cKeys = m_map.count (szName) ;
|
||
|
||
// If the specified key name does not exist in the map
|
||
if ( cKeys.Value () == 0 )
|
||
return FALSE ;
|
||
|
||
// Allocates memory to save pointers to key name.
|
||
// If the allocation failed, the memory pointed by the key name pointer are leaked.
|
||
::SafeInt<size_t> cbRequired ;
|
||
PCSZ * arrKeys = NULL ;
|
||
try {
|
||
cbRequired = cKeys ;
|
||
cbRequired *= sizeof (PCSZ) ;
|
||
arrKeys = (PCSZ *) ::malloc (cbRequired.Value ()) ;
|
||
} catch (::SafeIntException &) {
|
||
arrKeys = NULL ;
|
||
}
|
||
|
||
std::pair<MapIter, MapIter> pairIter = m_map.equal_range (szName) ;
|
||
|
||
MapSizeType nIdx = 0 ;
|
||
for (MapIter iter = pairIter.first; iter != pairIter.second; ++iter) {
|
||
(iter->second).Delete () ;
|
||
|
||
// Saves the key name pointer
|
||
if ( arrKeys )
|
||
arrKeys[nIdx++] = iter->first ;
|
||
}
|
||
|
||
m_map.erase (pairIter.first, pairIter.second) ;
|
||
|
||
if ( arrKeys == NULL )
|
||
return TRUE ;
|
||
|
||
for (nIdx = 0; nIdx < cKeys; nIdx++)
|
||
SAFEFREE ( arrKeys[nIdx] ) ;
|
||
SAFEFREE ( arrKeys ) ;
|
||
|
||
return TRUE ;
|
||
}
|
||
|
||
// This function deletes an element of which the key name equals to szName and the index is nIdx.
|
||
// If some data cleared, it will return TRUE, otherwise return FALSE.
|
||
template <typename HttpTool>
|
||
BOOL CHttpClientMapT<HttpTool>::Remove (PCSZ szName, DWORD nIdx)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpClientMapT::Remove: szName can not be NULL.") ;
|
||
|
||
std::pair<MapIter, MapIter> pairIter = m_map.equal_range (szName) ;
|
||
|
||
// If the specified key name does not exist in the map
|
||
if ( pairIter.first == pairIter.second )
|
||
return FALSE ;
|
||
|
||
MapIter iter = pairIter.first ;
|
||
for (DWORD i = 0; i < nIdx; i++) {
|
||
++iter ;
|
||
|
||
// If the nIdx is out of range.
|
||
if ( iter == pairIter.second )
|
||
return FALSE ;
|
||
}
|
||
|
||
// Deletes the element
|
||
(iter->second).Delete () ;
|
||
PCSZ szKeyName = iter->first ;
|
||
m_map.erase (iter) ;
|
||
SAFEFREE (szKeyName) ;
|
||
|
||
return TRUE ;
|
||
}
|
||
|
||
template <typename HttpTool>
|
||
BOOL CHttpClientMapT<HttpTool>::Exists (PCSZ szName, DWORD nIdx)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpClientMapT::Exists: szName can not be NULL.") ;
|
||
|
||
::SafeInt<MapSizeType> cKeys = m_map.count (szName) ;
|
||
return (cKeys > nIdx) ;
|
||
}
|
||
|
||
// If the szName is NULL, it will return the count of elements.
|
||
template <typename HttpTool>
|
||
DWORD CHttpClientMapT<HttpTool>::Count (PCSZ szName)
|
||
throw ()
|
||
{
|
||
::SafeInt<DWORD> cKeys ;
|
||
try {
|
||
cKeys = szName ? m_map.count (szName) : m_map.size () ;
|
||
} catch (::SafeIntException &) {
|
||
cKeys = cKeys.MaxInt () ; // This statement is never executed.
|
||
}
|
||
return cKeys.Value () ;
|
||
}
|
||
|
||
template <typename HttpTool>
|
||
BOOL CHttpClientMapT<HttpTool>::Empty (void) const
|
||
throw ()
|
||
{
|
||
return m_map.empty () ? TRUE : FALSE ;
|
||
}
|
||
|
||
// If the nIdx is not valid, it will return NULL.
|
||
template <typename HttpTool>
|
||
typename CHttpClientMapT<HttpTool>::PCSZ
|
||
CHttpClientMapT<HttpTool>::GetKey (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
if ( m_map.empty () )
|
||
return NULL ;
|
||
|
||
MapIter iter = m_map.begin () ;
|
||
for (DWORD i = 0; i < nIdx; i++) {
|
||
++iter ;
|
||
|
||
// If the nIdx is not valid.
|
||
if ( iter == m_map.end () )
|
||
return NULL ;
|
||
}
|
||
return iter->first ;
|
||
}
|
||
|
||
// If the specified element is not found in position nIdx,
|
||
// returns MapValue of which szValue is NULL.
|
||
template <typename HttpTool>
|
||
typename CHttpClientMapT<HttpTool>::MapValue
|
||
CHttpClientMapT<HttpTool>::Get (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
MapValue mapValue = { NULL, 0 } ;
|
||
|
||
if ( m_map.empty () )
|
||
return mapValue ;
|
||
|
||
MapIter iter = m_map.begin () ;
|
||
for (DWORD i = 0; i < nIdx; i++) {
|
||
++iter ;
|
||
|
||
// If the nIdx is not valid.
|
||
if ( iter == m_map.end () )
|
||
return mapValue ;
|
||
}
|
||
|
||
mapValue = iter->second ;
|
||
if ( mapValue.szValue == NULL )
|
||
mapValue.szValue = HttpTool::szEmptyString ;
|
||
|
||
return mapValue ;
|
||
}
|
||
|
||
// If the specified element is not found, it will return NULL.
|
||
template <typename HttpTool>
|
||
typename CHttpClientMapT<HttpTool>::PCSZ
|
||
CHttpClientMapT<HttpTool>::GetValue (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return Get (nIdx).szValue ;
|
||
}
|
||
|
||
// Returns 0 if the specified element is not found.
|
||
// (If the dwFlag in MapValue is 0, it also returns 0)
|
||
template <typename HttpTool>
|
||
DWORD CHttpClientMapT<HttpTool>::GetFlag (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return Get (nIdx).dwFlag ;
|
||
}
|
||
|
||
// If the specified element is not found, returns MapValue of which szValue is NULL.
|
||
template <typename HttpTool>
|
||
typename CHttpClientMapT<HttpTool>::MapValue
|
||
CHttpClientMapT<HttpTool>::Get (PCSZ szName, DWORD nIdx)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpClientMapT::Get: szName can not be NULL.") ;
|
||
|
||
MapValue mapValue = { NULL, 0 } ;
|
||
std::pair<MapIter, MapIter> pairIter ;
|
||
pairIter = m_map.equal_range (szName) ;
|
||
|
||
// If the key is not found.
|
||
if ( pairIter.first == pairIter.second )
|
||
return mapValue ;
|
||
|
||
MapIter iter = pairIter.first ;
|
||
for (DWORD i = 0; i < nIdx; i++) {
|
||
++iter ;
|
||
|
||
// If the nIdx is not valid
|
||
if ( iter == pairIter.second )
|
||
return mapValue ;
|
||
}
|
||
|
||
mapValue = iter->second ;
|
||
if ( mapValue.szValue == NULL )
|
||
mapValue.szValue = HttpTool::szEmptyString ;
|
||
|
||
return mapValue ;
|
||
}
|
||
|
||
// Returns NULL if the specified element is not found.
|
||
template <typename HttpTool>
|
||
typename CHttpClientMapT<HttpTool>::PCSZ
|
||
CHttpClientMapT<HttpTool>::GetValue (PCSZ szName, DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return Get (szName, nIdx).szValue ;
|
||
}
|
||
|
||
// Returns 0 if the specified element is not found.
|
||
// (If the dwFlag in MapValue is 0, it also returns 0)
|
||
template <typename HttpTool>
|
||
DWORD CHttpClientMapT<HttpTool>::GetFlag (PCSZ szName, DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return Get (szName, nIdx).dwFlag ;
|
||
}
|
||
|
||
// Adds a new MapValue. It also receives the ownership of memory pointed by szName and szValue.
|
||
// The szName and szValue must be allocated by using ::malloc.
|
||
// The szValue could be NULL.
|
||
template <typename HttpTool>
|
||
void CHttpClientMapT<HttpTool>::AddPointerDirectly (PSZ szName, PSZ szValue, BOOL dwFlag)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpClientMapT::AddPointerDirectly: szName can not be NULL.") ;
|
||
|
||
try {
|
||
// Checks the arithmetic overflow exception
|
||
::SafeInt<MapSizeType> cKeys = Count () ;
|
||
::SafeInt<DWORD> cdwKeys = cKeys ;
|
||
cKeys++ ;
|
||
cdwKeys++ ;
|
||
|
||
MapValue newValue = { (PCSZ) szValue, dwFlag } ;
|
||
m_map.insert (MapItem ((PCSZ) szName, newValue)) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
} catch (std::exception & e) {
|
||
HttpTool::ThrowException (e.what (), HTTPCLIENT_ERR_STD_EXCEPTION) ;
|
||
} catch (...) {
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_UNEXPECTED_ERROR) ;
|
||
}
|
||
}
|
||
|
||
// The szValue could be NULL.
|
||
template <typename HttpTool>
|
||
void CHttpClientMapT<HttpTool>::Add (PCSZ szName, PCSZ szValue, BOOL dwFlag)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpClientMapT::Add: szName can not be NULL.") ;
|
||
|
||
PSZ szNewName = NULL ;
|
||
PSZ szNewValue = NULL ;
|
||
::SafeInt<size_t> cbName, cbValue ;
|
||
|
||
try {
|
||
cbName = HttpTool::StringLen (szName) ;
|
||
cbName++ ;
|
||
cbName *= sizeof (CharType) ;
|
||
|
||
szNewName = (PSZ) ::malloc (cbName.Value ()) ;
|
||
if ( szNewName == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
HttpTool::StringCopy (szNewName, szName) ;
|
||
|
||
if ( szValue != NULL ) {
|
||
cbValue = HttpTool::StringLen (szValue) ;
|
||
cbValue++ ;
|
||
cbValue *= sizeof (CharType) ;
|
||
|
||
szNewValue = (PSZ) ::malloc (cbValue.Value ()) ;
|
||
if ( szNewValue == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
HttpTool::StringCopy (szNewValue, szValue) ;
|
||
}
|
||
AddPointerDirectly (szNewName, szNewValue, dwFlag) ;
|
||
|
||
} catch (::SafeIntException & e) {
|
||
SAFEFREE (szNewName) ;
|
||
SAFEFREE (szNewValue) ;
|
||
HttpTool::ThrowException (e) ;
|
||
} catch (Exception &) {
|
||
SAFEFREE (szNewName) ;
|
||
SAFEFREE (szNewValue) ;
|
||
throw ;
|
||
}
|
||
}
|
||
|
||
// If the specified element is not found, it will add a new value.
|
||
// otherwise it will modifiy the existing value.
|
||
// The szValue could be NULL.
|
||
template <typename HttpTool>
|
||
void CHttpClientMapT<HttpTool>::Set (PCSZ szName, PCSZ szValue, BOOL dwFlag, DWORD nIdx)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpClientMapT::Set: szName can not be NULL.") ;
|
||
|
||
std::pair<MapIter, MapIter> pairIter ;
|
||
pairIter = m_map.equal_range (szName) ;
|
||
|
||
// Adds a new value if the specified element is not found.
|
||
if ( pairIter.first == pairIter.second ) {
|
||
// The nIdx must be 0
|
||
_ASSERTE ( nIdx == 0 ) ;
|
||
Add (szName, szValue, dwFlag) ;
|
||
return ;
|
||
}
|
||
|
||
MapIter iter = pairIter.first ;
|
||
for (DWORD i = 0; i < nIdx; i++) {
|
||
++iter ;
|
||
|
||
// The nIdx must be valid
|
||
_ASSERTE ( iter != pairIter.second ) ;
|
||
}
|
||
|
||
MapValue newValue = { NULL, dwFlag } ;
|
||
if ( szValue ) {
|
||
::SafeInt<size_t> cbValue ;
|
||
|
||
try {
|
||
cbValue = HttpTool::StringLen (szValue) ;
|
||
cbValue++ ;
|
||
cbValue *= sizeof (CharType) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
newValue.szValue = (PCSZ) ::malloc (cbValue.Value ()) ;
|
||
if ( newValue.szValue == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
HttpTool::StringCopy ((PSZ) newValue.szValue, szValue) ;
|
||
}
|
||
|
||
MapValue oldValue = iter->second ;
|
||
iter->second = newValue ;
|
||
oldValue.Delete () ;
|
||
}
|
||
|
||
template <typename HttpTool>
|
||
typename CHttpClientMapT<HttpTool>::ConstMapIter
|
||
CHttpClientMapT<HttpTool>::Begin (void) const
|
||
throw ()
|
||
{
|
||
return m_map.begin () ;
|
||
}
|
||
|
||
template <typename HttpTool>
|
||
typename CHttpClientMapT<HttpTool>::ConstMapIter
|
||
CHttpClientMapT<HttpTool>::End (void) const
|
||
throw ()
|
||
{
|
||
return m_map.end () ;
|
||
}
|
||
///////////////////////////////////////// CHttpClientMapT /////////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////// CHttpEncoder /////////////////////////////////////////
|
||
/*!
|
||
* This method has no meaning because the input string is an Ansi string.
|
||
* It just returns the length of the input string.
|
||
*
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param CodePage [in] Ignored.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderA::AnsiEncodeLen (PCSTR szStr, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
if ( szStr == NULL || szStr[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> dwLen ;
|
||
try {
|
||
dwLen = ::strlen (szStr) ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolA::ThrowException (e) ;
|
||
}
|
||
return dwLen.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method has no meaning because the input string is an Ansi string.
|
||
* It just returns the copy of the input string.
|
||
*
|
||
* \param szBuff [out] A buffer to save the encoded string. The buffer can not be NULL.
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param CodePage [in] Ignored.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderA::AnsiEncode (PSTR szBuff, PCSTR szStr, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szBuff != NULL, "CHttpEncoderA::AnsiEncode: szBuff can not be NULL.") ;
|
||
|
||
if ( (szStr == NULL) || (szStr[0] == '\0') ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
return ::strcpy (szBuff, szStr) ;
|
||
}
|
||
|
||
/*!
|
||
* This method has no meaning because the decoded string is an Ansi string.
|
||
* It just returns the length of the input string.
|
||
*
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param CodePage [in] Ignored.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderA::AnsiDecodeLen (PCSTR szEncoded, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> dwLen ;
|
||
try {
|
||
dwLen = ::strlen (szEncoded) ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolA::ThrowException (e) ;
|
||
}
|
||
return dwLen.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method has no meaning because the decoded string is an Ansi string.
|
||
* It just returns the copy of the input string.
|
||
*
|
||
* \param szBuff [out] A buffer to save the decoded string. The buffer can not be NULL.
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param CodePage [in] Ignored.
|
||
* \return A decoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderA::AnsiDecode (PSTR szBuff, PCSTR szEncoded, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szBuff != NULL, "CHttpEncoderA::AnsiDecode: szBuff can not be NULL.") ;
|
||
|
||
if ( (szEncoded == NULL) || (szEncoded[0] == '\0') ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
return ::strcpy (szBuff, szEncoded) ;
|
||
}
|
||
|
||
// Checks whether the character is a valid hexadecimal.
|
||
template <typename CharType>
|
||
static BOOL _HexIsValid(CharType chHex)
|
||
{
|
||
if ( chHex >= '0' && chHex <= '9' )
|
||
return TRUE ;
|
||
|
||
if ( chHex >= 'A' && chHex <= 'F' )
|
||
return TRUE ;
|
||
|
||
if ( chHex >= 'a' && chHex <= 'f' )
|
||
return TRUE ;
|
||
|
||
return FALSE ;
|
||
}
|
||
|
||
template <typename CharType>
|
||
static CharType _HexToNum(CharType chHex)
|
||
{
|
||
if ( chHex >= '0' && chHex <= '9' )
|
||
return chHex - '0' ;
|
||
|
||
if ( chHex >= 'A' && chHex <= 'F' )
|
||
return chHex - 'A' + 10 ;
|
||
|
||
if ( chHex >= 'a' && chHex <= 'f' )
|
||
return chHex - 'a' + 10 ;
|
||
|
||
return 0 ;
|
||
}
|
||
|
||
template <typename CharType>
|
||
static BOOL _IsAlNum (CharType chChr)
|
||
{
|
||
if (chChr >= 'A' && chChr <= 'Z')
|
||
return TRUE ;
|
||
|
||
if (chChr >= 'a' && chChr <= 'z')
|
||
return TRUE ;
|
||
|
||
if (chChr >= '0' && chChr <= '9')
|
||
return TRUE ;
|
||
|
||
return FALSE ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method returns the number of characters required to make a URL-encoded string.
|
||
*
|
||
* \param szEncoded [in] An Ansi string or a UTF-8 string. The string can not be NULL.
|
||
* \return The number of characters required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
static DWORD _UrlEncodeLen (PCSTR szStr)
|
||
throw (typename HttpTool::Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szStr != NULL, "_UrlEncodeLen: szStr can not be NULL.") ;
|
||
|
||
::SafeInt<DWORD> cchEncoded = 0 ;
|
||
PCSTR pchStr = szStr ;
|
||
try {
|
||
while ( *pchStr ) {
|
||
cchEncoded++ ;
|
||
if ( !_IsAlNum (*pchStr) && *pchStr != ' ' )
|
||
cchEncoded += 2 ;
|
||
pchStr++ ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
return cchEncoded.Value () ;
|
||
}
|
||
|
||
template <typename CharType>
|
||
static CharType _ToHex (CharType chChr)
|
||
{
|
||
_ASSERTE ( chChr < 16 ) ;
|
||
return chChr > 9 ? 'A' + (chChr - 10) : '0' + chChr ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method makes a URL-encoded string.
|
||
*
|
||
* \param szBuff [out] A buffer to save the encoded string. The buffer can not be NULL.
|
||
* \param szEncoded [in] An Ansi string or a UTF-8 string. The string can not be NULL.
|
||
* \return An URL-encoded string.
|
||
*/
|
||
template <typename StringType>
|
||
static StringType _UrlEncode (StringType szBuff, PCSTR szStr)
|
||
{
|
||
_ASSERTE ( szBuff != NULL && szStr != NULL ) ;
|
||
|
||
const CHAR * pchStr = szStr ;
|
||
StringType pchOut = szBuff ;
|
||
|
||
// do encoding
|
||
for (; *pchStr != NULL; pchStr++) {
|
||
if ( _IsAlNum (*pchStr) ) {
|
||
*pchOut++ = *pchStr ;
|
||
continue ;
|
||
}
|
||
|
||
if ( *pchStr == ' ' ) {
|
||
*pchOut++ = '+' ;
|
||
continue ;
|
||
}
|
||
|
||
*pchOut++ = '%';
|
||
*pchOut++ = _ToHex (((*pchStr) & 0xF0) >> 4);
|
||
*pchOut++ = _ToHex ((*pchStr) & 0x0F);
|
||
}
|
||
*pchOut = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method converts an Ansi character into an UTF-8 character.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szUtf8Char [out] A buffer to save the converted UTF-8 character. The buffer can not be NULL.
|
||
* The buffer must be allocated at least 7 characters.
|
||
* \param szAnsiChar [in] A string which contains an Ansi character. The string can not be NULL.
|
||
* \param CodePage [in] A code page of the Ansi character.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
void CHttpEncoderA::_AnsiCharToUtf8Char (PSTR szUtf8Char, PCSTR szAnsiChar, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szUtf8Char != NULL && szAnsiChar != NULL
|
||
, "CHttpEncoderA::_AnsiCharToUtf8Char: szUtf8Char and szAnsiChar can not be NULL.") ;
|
||
|
||
WCHAR wszUnicode[2] ;
|
||
|
||
// Get a unicode character
|
||
if ( 0 == ::MultiByteToWideChar (CodePage, 0, szAnsiChar, -1, wszUnicode, 2) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
// Get a UTF-8 character sequence
|
||
if ( 0 == ::WideCharToMultiByte (CP_UTF8, 0, wszUnicode, 2, szUtf8Char, 7, NULL, NULL) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method converts an UTF-8 character into an Ansi character.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szAnsiChar [out] A buffer to save the converted Ansi character. The buffer can not be NULL.
|
||
* The buffer must be allocated at least 3 characters.
|
||
* \param szUtf8Char [in] A string which contains an UTF-8 character. The string can not be NULL.
|
||
* \param CodePage [in] A code page of the converted Ansi character.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
void CHttpEncoderA::_Utf8CharToAnsiChar (PSTR szAnsiChar, PCSTR szUtf8Char, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szAnsiChar != NULL && szUtf8Char != NULL
|
||
, "CHttpEncoderA::_Utf8CharToAnsiChar: szAnsiChar and szUtf8Char can not be NULL.") ;
|
||
|
||
WCHAR wszUnicode[2] ;
|
||
|
||
// Get a unicode character
|
||
if ( 0 == ::MultiByteToWideChar (CP_UTF8, 0, szUtf8Char, -1, wszUnicode, 2) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
// Get a Ansi character sequence
|
||
if ( 0 == ::WideCharToMultiByte (CodePage, 0, wszUnicode, 2, szAnsiChar, 3, NULL, NULL) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of bytes required to encode an Ansi string using UTF-8 encoding.
|
||
* The returned value does not include the terminating NULL character.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param CodePage [in] A code page of the szStr parameter.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderA::Utf8EncodeLen (PCSTR szStr, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
if ( szStr == NULL || szStr[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchEncoded = 0 ;
|
||
PCSTR pchStr = szStr ;
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
PSTR pchUtf8 ;
|
||
|
||
try {
|
||
while ( *pchStr ) {
|
||
szAnsi[0] = *pchStr ;
|
||
if ( ::IsDBCSLeadByteEx (CodePage, *pchStr) ) {
|
||
szAnsi[1] = *(++pchStr) ;
|
||
szAnsi[2] = '\0' ;
|
||
} else
|
||
szAnsi[1] = '\0' ;
|
||
|
||
_AnsiCharToUtf8Char (szUtf8, szAnsi, CodePage) ;
|
||
for (pchUtf8 = szUtf8; *pchUtf8 != '\0'; pchUtf8++, cchEncoded++) ;
|
||
pchStr++ ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolA::ThrowException (e) ;
|
||
}
|
||
return cchEncoded.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method encodes an Ansi string using UTF-8 encoding.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the encoded string. The buffer can not be NULL.
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param CodePage [in] A code page of the szStr parameter.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderA::Utf8Encode (PSTR szBuff, PCSTR szStr, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szBuff != NULL, "CHttpEncoderA::Utf8Encode: szBuff can not be NULL.") ;
|
||
|
||
if ( szStr == NULL || szStr[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
PSTR pchBuff = szBuff ;
|
||
PCSTR pchStr = szStr ;
|
||
|
||
while ( *pchStr ) {
|
||
szAnsi[0] = *pchStr ;
|
||
if ( ::IsDBCSLeadByteEx (CodePage, *pchStr) ) {
|
||
szAnsi[1] = *(++pchStr) ;
|
||
szAnsi[2] = '\0' ;
|
||
} else
|
||
szAnsi[1] = '\0' ;
|
||
|
||
_AnsiCharToUtf8Char (szUtf8, szAnsi, CodePage) ;
|
||
::strcpy (pchBuff, szUtf8) ;
|
||
for (; *pchBuff != NULL; pchBuff++) ;
|
||
pchStr++ ;
|
||
}
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method saves an UTF-8 character into the buffer.
|
||
* The pszSrc parameter is modified to point to the next UTF-8 character.
|
||
*
|
||
* \param szUtf8Char [out] A buffer to save an UTF-8 character. The buffer can not be NULL.
|
||
* The buffer must be allocated at least 7 characters.
|
||
* \param pszSrc [in] A pointer to a UTF-8 string. The pointer can not be NULL.
|
||
* \return Returns FALSE if the UTF-8 string contains an invalid byte.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
static BOOL _GetNextUtf8Char (PSTR szUtf8Char, PCSTR * pszSrc)
|
||
{
|
||
_ASSERTE ( szUtf8Char != NULL ) ;
|
||
_ASSERTE ( pszSrc != NULL && *pszSrc != NULL ) ;
|
||
|
||
if ( '\0' == (szUtf8Char[0] = **pszSrc) )
|
||
return TRUE ;
|
||
|
||
(*pszSrc)++ ;
|
||
|
||
// An ASCII character
|
||
if ( szUtf8Char[0] >= 0 && szUtf8Char[0] <= 0x7F ) {
|
||
szUtf8Char[1] = '\0' ;
|
||
return TRUE ;
|
||
}
|
||
|
||
BYTE cchUtf8, byChar ;
|
||
|
||
byChar = static_cast<BYTE> (szUtf8Char[0]) ;
|
||
|
||
// Following values are not allowed in UTF-8 encoding
|
||
if ( byChar == 0xFE || byChar == 0xFF )
|
||
return FALSE ;
|
||
|
||
// It must be the first byte of the UTF-8 character sequence
|
||
if ( !(byChar >= 0xC0 && byChar <= 0xFD) )
|
||
return FALSE ;
|
||
|
||
// Counts the number of bytes of the UTF-8 character sequence
|
||
if ( (byChar & 0xFE) == 0xFC ) cchUtf8 = 6 ;
|
||
else if ( (byChar & 0xFC) == 0xF8 ) cchUtf8 = 5 ;
|
||
else if ( (byChar & 0xF8) == 0xF0 ) cchUtf8 = 4 ;
|
||
else if ( (byChar & 0xF0) == 0xE0 ) cchUtf8 = 3 ;
|
||
else if ( (byChar & 0xE0) == 0xC0 ) cchUtf8 = 2 ;
|
||
else return FALSE ;
|
||
|
||
for (BYTE i = 1; i < cchUtf8; i++) {
|
||
szUtf8Char[i] = *((*pszSrc)++) ;
|
||
byChar = static_cast<BYTE> (szUtf8Char[i]) ;
|
||
|
||
// It must be a valid byte of the UTF-8 multibyte sequence.
|
||
if ( !(byChar >=0x80 && byChar <= 0xBF) )
|
||
return FALSE ;
|
||
}
|
||
szUtf8Char[cchUtf8] = '\0' ;
|
||
return TRUE ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of bytes required to decode an UTF-8 string in ANSI.
|
||
* The returned value does not include the terminating NULL character.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param CodePage [in] A code page of the returned Ansi string.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderA::Utf8DecodeLen (PCSTR szEncoded, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchDecoded = 0 ;
|
||
PCSTR pchEncoded = szEncoded ;
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
PSTR pchAnsi ;
|
||
|
||
try {
|
||
while ( *pchEncoded ) {
|
||
if ( !_GetNextUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_INVALID_UTF8_CHARACTER) ;
|
||
|
||
_Utf8CharToAnsiChar (szAnsi, szUtf8, CodePage) ;
|
||
for (pchAnsi = szAnsi; *pchAnsi != '\0'; pchAnsi++, cchDecoded++) ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolA::ThrowException (e) ;
|
||
}
|
||
return cchDecoded.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method decodes an UTF-8 string using Ansi encoding.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the decoded string. The buffer can not be NULL.
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param CodePage [in] A code page of the returned Ansi string.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderA::Utf8Decode (PSTR szBuff, PCSTR szEncoded, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szBuff != NULL, "CHttpEncoderA::Utf8Decode: szBuff can not be NULL.") ;
|
||
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
PCSTR pchEncoded = szEncoded ;
|
||
CHAR szUtf8[7] ;
|
||
PSTR pchBuff = szBuff ;
|
||
|
||
while ( *pchEncoded ) {
|
||
if ( !_GetNextUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_INVALID_UTF8_CHARACTER) ;
|
||
|
||
_Utf8CharToAnsiChar (pchBuff, szUtf8, CodePage) ;
|
||
for (; *pchBuff != '\0'; pchBuff++) ;
|
||
}
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of bytes required to make a URL-encoded string
|
||
* (in Ansi character set) from an Ansi string.
|
||
* The URL-encoded string is a string that is safe to transmit from the Web server to a client.
|
||
* The returned value does not include the terminating NULL character.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the string is encoded using UTF-8 encoding
|
||
* and that string is used to make a URL-encoded string.
|
||
* \param CodePage [in] A code page of the szStr parameter.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderA::UrlEncodeLenA (PCSTR szStr, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
if ( szStr == NULL || szStr[0] == '\0' )
|
||
return 0 ;
|
||
|
||
if ( !bUtf8Encoding )
|
||
return _UrlEncodeLen<CHttpToolA> (szStr) ;
|
||
|
||
::SafeInt<DWORD> cchEncoded = 0 ;
|
||
PCSTR pchStr = szStr ;
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
|
||
try {
|
||
while ( *pchStr ) {
|
||
szAnsi[0] = *pchStr ;
|
||
if ( ::IsDBCSLeadByteEx (CodePage, *pchStr) ) {
|
||
szAnsi[1] = *(++pchStr) ;
|
||
szAnsi[2] = '\0' ;
|
||
} else
|
||
szAnsi[1] = '\0' ;
|
||
|
||
_AnsiCharToUtf8Char (szUtf8, szAnsi, CodePage) ;
|
||
cchEncoded += _UrlEncodeLen<CHttpToolA> (szUtf8) ;
|
||
pchStr++ ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolA::ThrowException (e) ;
|
||
}
|
||
return cchEncoded.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method encodes a Ansi string to make a URL-encoded string (in Ansi character set).
|
||
* The URL-encoded string is a string that is safe to transmit from the Web server to a client.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the encoded string. The buffer can not be NULL.
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the string is encoded using UTF-8 encoding
|
||
* and that string is used to make a URL-encoded string.
|
||
* \param CodePage [in] A code page of the szStr parameter.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderA::UrlEncodeA (PSTR szBuff, PCSTR szStr, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szBuff != NULL, "CHttpEncoderA::UrlEncodeA: szBuff can not be NULL.") ;
|
||
|
||
if ( szStr == NULL || szStr[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
if ( !bUtf8Encoding )
|
||
return _UrlEncode (szBuff, szStr) ;
|
||
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
PSTR pchBuff = szBuff ;
|
||
PCSTR pchStr = szStr ;
|
||
|
||
while ( *pchStr ) {
|
||
szAnsi[0] = *pchStr ;
|
||
if ( ::IsDBCSLeadByteEx (CodePage, *pchStr) ) {
|
||
szAnsi[1] = *(++pchStr) ;
|
||
szAnsi[2] = '\0' ;
|
||
} else
|
||
szAnsi[1] = '\0' ;
|
||
|
||
_AnsiCharToUtf8Char (szUtf8, szAnsi, CodePage) ;
|
||
_UrlEncode (pchBuff, szUtf8) ;
|
||
for (; *pchBuff != NULL; pchBuff++) ;
|
||
pchStr++ ;
|
||
}
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method encodes a Ansi string to make a URL-encoded string (in Unicode character set).
|
||
* The URL-encoded string is a string that is safe to transmit from the Web server to a client.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the encoded string. The buffer can not be NULL.
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the string is encoded using UTF-8 encoding
|
||
* and that string is used to make a URL-encoded string.
|
||
* \param CodePage [in] A code page of the szStr parameter.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PWSTR CHttpEncoderA::UrlEncodeW (PWSTR szBuff, PCSTR szStr, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szBuff != NULL, "CHttpEncoderA::UrlEncodeW: szBuff can not be NULL.") ;
|
||
|
||
if ( szStr == NULL || szStr[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
if ( !bUtf8Encoding )
|
||
return _UrlEncode (szBuff, szStr) ;
|
||
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
PWSTR pchBuff = szBuff ;
|
||
PCSTR pchStr = szStr ;
|
||
|
||
while ( *pchStr ) {
|
||
szAnsi[0] = *pchStr ;
|
||
if ( ::IsDBCSLeadByteEx (CodePage, *pchStr) ) {
|
||
szAnsi[1] = *(++pchStr) ;
|
||
szAnsi[2] = '\0' ;
|
||
} else
|
||
szAnsi[1] = '\0' ;
|
||
|
||
_AnsiCharToUtf8Char (szUtf8, szAnsi, CodePage) ;
|
||
_UrlEncode (pchBuff, szUtf8) ;
|
||
for (; *pchBuff != NULL; pchBuff++) ;
|
||
pchStr++ ;
|
||
}
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
// [out] pchDecoded A pointer to a character to save the next URL decoded character.
|
||
// [in] pszSrc A pointer to a URL Encoded string.
|
||
// Returns TRUE if the operation success
|
||
template <typename StringType>
|
||
static BOOL _GetNextUrlDecodedChar (CHAR * pchDecoded, StringType * pszSrc)
|
||
{
|
||
_ASSERTE ( pchDecoded != NULL && pszSrc != NULL && *pszSrc != NULL ) ;
|
||
|
||
if ( **pszSrc == NULL ) {
|
||
*pchDecoded = '\0' ;
|
||
return TRUE ;
|
||
}
|
||
|
||
if ( **pszSrc == '+' ) {
|
||
*pchDecoded = ' ' ;
|
||
(*pszSrc)++ ;
|
||
return TRUE ;
|
||
}
|
||
|
||
if ( **pszSrc != '%' ) {
|
||
*pchDecoded = static_cast<CHAR> (*((*pszSrc)++)) ;
|
||
return FALSE ;
|
||
}
|
||
|
||
(*pszSrc)++ ;
|
||
|
||
if ( !_HexIsValid (**pszSrc) )
|
||
return FALSE ;
|
||
|
||
*pchDecoded = _HexToNum (**pszSrc) * 16 ;
|
||
(*pszSrc)++ ;
|
||
|
||
if ( !_HexIsValid (**pszSrc) )
|
||
return FALSE ;
|
||
|
||
*pchDecoded += _HexToNum (**pszSrc) ;
|
||
(*pszSrc)++ ;
|
||
|
||
return TRUE ;
|
||
}
|
||
|
||
// [out] szAnsiChar a buffer to save the next URL decoded Ansi character sequence.
|
||
// The buffer must be allocated at least 3 characters.
|
||
// [in] pszSrc A pointer to a URL Encoded string.
|
||
// [in] CodePage codepage
|
||
// Returns TRUE if the operation success
|
||
template <typename StringType>
|
||
static BOOL _GetNextUrlDecodedAnsiChar (PSTR szAnsiChar, StringType * pszSrc, UINT CodePage = CP_ACP)
|
||
{
|
||
_ASSERTE ( szAnsiChar != NULL ) ;
|
||
_ASSERTE ( pszSrc != NULL && *pszSrc != NULL ) ;
|
||
|
||
if ( !_GetNextUrlDecodedChar (szAnsiChar, pszSrc) )
|
||
return FALSE ;
|
||
|
||
if ( szAnsiChar[0] == '\0' )
|
||
return TRUE ;
|
||
|
||
if ( !::IsDBCSLeadByteEx (CodePage, szAnsiChar[0]) ) {
|
||
szAnsiChar[1] = '\0' ;
|
||
return TRUE ;
|
||
}
|
||
|
||
if ( !_GetNextUrlDecodedChar (szAnsiChar + 1, pszSrc) )
|
||
return FALSE ;
|
||
|
||
// It can not be '\0'
|
||
if ( szAnsiChar[1] == '\0' )
|
||
return FALSE ;
|
||
|
||
szAnsiChar[2] = '\0' ;
|
||
return TRUE ;
|
||
}
|
||
|
||
// [out] szUtf8Char a buffer to save a returned UTF-8 character sequence.
|
||
// The buffer must be allocated at least 7 characters.
|
||
// [in] pszSrc A pointer to a URL Encoded string.
|
||
// Returns TRUE if the operation success
|
||
template <typename StringType>
|
||
static BOOL _GetNextUrlDecodedUtf8Char (PSTR szUtf8Char, StringType * pszSrc)
|
||
{
|
||
_ASSERTE ( szUtf8Char != NULL ) ;
|
||
_ASSERTE ( pszSrc != NULL && *pszSrc != NULL ) ;
|
||
|
||
if ( !_GetNextUrlDecodedChar (szUtf8Char, pszSrc) )
|
||
return FALSE ;
|
||
|
||
if ( szUtf8Char[0] == '\0' )
|
||
return TRUE ;
|
||
|
||
// An ASCII character
|
||
if ( szUtf8Char[0] >= 0 && szUtf8Char[0] <= 0x7F ) {
|
||
szUtf8Char[1] = '\0' ;
|
||
return TRUE ;
|
||
}
|
||
|
||
BYTE cchUtf8, byChar ;
|
||
|
||
byChar = static_cast<BYTE> (szUtf8Char[0]) ;
|
||
|
||
// following values are not allowed in UTF-8 encoding
|
||
if ( byChar == 0xFE || byChar == 0xFF )
|
||
return FALSE ; // Invalid UTF-8 byte
|
||
|
||
// It must be the first character of a UTF-8 character sequence
|
||
if ( !(byChar >= 0xC0 && byChar <= 0xFD) )
|
||
return FALSE ;
|
||
|
||
// Counts the number of bytes of the UTF-8 character sequence
|
||
if ( (byChar & 0xFE) == 0xFC ) cchUtf8 = 6 ;
|
||
else if ( (byChar & 0xFC) == 0xF8 ) cchUtf8 = 5 ;
|
||
else if ( (byChar & 0xF8) == 0xF0 ) cchUtf8 = 4 ;
|
||
else if ( (byChar & 0xF0) == 0xE0 ) cchUtf8 = 3 ;
|
||
else if ( (byChar & 0xE0) == 0xC0 ) cchUtf8 = 2 ;
|
||
else return FALSE ;
|
||
|
||
for (BYTE i = 1; i < cchUtf8; i++) {
|
||
if ( !_GetNextUrlDecodedChar (szUtf8Char + i, pszSrc) )
|
||
return FALSE ;
|
||
|
||
byChar = static_cast<BYTE> (szUtf8Char[i]) ;
|
||
|
||
// It must be a byte of the UTF-8 multibyte sequence.
|
||
if ( !(byChar >=0x80 && byChar <= 0xBF) )
|
||
return FALSE ;
|
||
}
|
||
szUtf8Char[cchUtf8] = '\0' ;
|
||
return TRUE ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of bytes required to decode an URL-encoded string. (Ansi version)
|
||
* The returned value does not include the terminating NULL character.
|
||
* This method does not support the URL-encoded string which contains a unicode character by using the %u or %x prefix.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the decoded string is assumed an UTF-8 string.
|
||
* So the decoded string is converted into an Ansi string.
|
||
* \param CodePage [in] A code page of the decoded string.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderA::UrlDecodeLenA (PCSTR szEncoded, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchDecoded = 0 ;
|
||
PCSTR pchEncoded = szEncoded ;
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
CHAR * pchAnsi ;
|
||
|
||
try {
|
||
do {
|
||
if ( bUtf8Encoding ) {
|
||
if ( !_GetNextUrlDecodedUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
// Converts into Ansi
|
||
_Utf8CharToAnsiChar (szAnsi, szUtf8, CodePage) ;
|
||
} else {
|
||
if ( !_GetNextUrlDecodedAnsiChar (szAnsi, &pchEncoded, CodePage) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
}
|
||
|
||
for (pchAnsi = szAnsi; *pchAnsi != NULL; pchAnsi++, cchDecoded++) ;
|
||
|
||
} while ( szAnsi[0] != '\0' ) ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolA::ThrowException (e) ;
|
||
}
|
||
return cchDecoded.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of unicode characters required to decode an URL-encoded string.
|
||
* The returned value does not include the terminating NULL character.
|
||
* This method does not support the URL-encoded string which contains a unicode character by using the %u or %x prefix.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the decoded string is assumed an UTF-8 string.
|
||
* So the decoded string is converted into an Unicode string.
|
||
* \param CodePage [in] A code page of the decoded string.
|
||
* \return The number of unicode characters required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderA::UrlDecodeLenW (PCSTR szEncoded, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchDecoded = 0 ;
|
||
PCSTR pchEncoded = szEncoded ;
|
||
|
||
try {
|
||
if ( bUtf8Encoding ) {
|
||
CHAR szUtf8[7] ;
|
||
|
||
while ( true ) {
|
||
if ( !_GetNextUrlDecodedUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
if ( szUtf8[0] == '\0' )
|
||
break ;
|
||
|
||
cchDecoded++ ;
|
||
}
|
||
return cchDecoded.Value () ;
|
||
}
|
||
|
||
CHAR szAnsi[3] ;
|
||
while ( true ) {
|
||
if ( !_GetNextUrlDecodedAnsiChar (szAnsi, &pchEncoded, CodePage) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
if ( szAnsi[0] == '\0' )
|
||
break ;
|
||
|
||
cchDecoded++ ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolA::ThrowException (e) ;
|
||
}
|
||
return cchDecoded.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method decodes an URL-encoded string.
|
||
* This method does not support the URL-encoded string which contains a unicode character by using the %u or %x prefix.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the decoded string. The buffer can not be NULL.
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the decoded string is assumed an UTF-8 string.
|
||
* So the decoded string is converted into an Ansi string.
|
||
* \param CodePage [in] A code page of the decoded string.
|
||
* \return A decoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderA::UrlDecodeA (PSTR szBuff, PCSTR szEncoded, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szBuff != NULL, "CHttpEncoderA::UrlDecodeA: szBuff can not be NULL.") ;
|
||
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
PCSTR pchEncoded = szEncoded ;
|
||
PSTR pchBuff = szBuff ;
|
||
PSTR pchAnsi ;
|
||
|
||
do {
|
||
if ( bUtf8Encoding ) {
|
||
if ( !_GetNextUrlDecodedUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
// Converts into a Ansi character
|
||
_Utf8CharToAnsiChar (szAnsi, szUtf8, CodePage) ;
|
||
} else {
|
||
if ( !_GetNextUrlDecodedAnsiChar (szAnsi, &pchEncoded, CodePage) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
}
|
||
|
||
for (pchAnsi = szAnsi; *pchAnsi != '\0'; *(pchBuff++) = *pchAnsi, pchAnsi++) ;
|
||
|
||
} while ( szAnsi[0] != '\0' ) ;
|
||
|
||
*pchBuff = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method decodes an URL-encoded string.
|
||
* This method does not support the URL-encoded string which contains a unicode character by using the %u or %x prefix.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the decoded string. The buffer can not be NULL.
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the decoded string is assumed an UTF-8 string.
|
||
* So the decoded string is converted into an Unicode string.
|
||
* \param CodePage [in] A code page of the decoded string.
|
||
* \return A decoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PWSTR CHttpEncoderA::UrlDecodeW (PWSTR szBuff, PCSTR szEncoded, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTA (szBuff != NULL, "CHttpEncoderA::UrlDecodeW: szBuff can not be NULL.") ;
|
||
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
PCSTR pchEncoded = szEncoded ;
|
||
PWSTR pchBuff = szBuff ;
|
||
|
||
if ( bUtf8Encoding ) {
|
||
CHAR szUtf8[7] ;
|
||
|
||
while ( true ) {
|
||
if ( !_GetNextUrlDecodedUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
if ( szUtf8[0] == '\0' )
|
||
break ;
|
||
|
||
// Converts into a unicode character
|
||
if ( 0 == ::MultiByteToWideChar (CP_UTF8, 0, szUtf8, -1, pchBuff, 2) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
pchBuff++ ;
|
||
}
|
||
} else {
|
||
CHAR szAnsi[3] ;
|
||
|
||
while ( true ) {
|
||
if ( !_GetNextUrlDecodedAnsiChar (szAnsi, &pchEncoded, CodePage) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
if ( szAnsi[0] == '\0' )
|
||
break ;
|
||
|
||
// Converts into a unicode character
|
||
if ( 0 == ::MultiByteToWideChar (CodePage, 0, szAnsi, -1, pchBuff, 2) )
|
||
CHttpToolA::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
pchBuff++ ;
|
||
}
|
||
}
|
||
|
||
*pchBuff = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
|
||
/*!
|
||
* This method returns the number of bytes required to convert an Unicode string into an Ansi string.
|
||
* The returned value does not include the terminating NULL character.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param CodePage [in] A code page of the encoded string.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderW::AnsiEncodeLen (PCWSTR szStr, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
// The unicode encodings are not allowed
|
||
HTTPCLIENT_ASSERTW ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpEncoderW::AnsiEncodeLen: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
if ( szStr == NULL || szStr[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchAnsiLen ;
|
||
try {
|
||
if ( 0 == (cchAnsiLen = ::WideCharToMultiByte (CodePage, 0, szStr, -1, NULL, 0, NULL, NULL)) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
cchAnsiLen-- ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
return cchAnsiLen.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method converts an Unicode string into an Ansi string.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the encoded string. The buffer can not be NULL.
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param CodePage [in] A code page of the encoded string.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderW::AnsiEncode (PSTR szBuff, PCWSTR szStr, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
// The unicode encodings are not allowed
|
||
HTTPCLIENT_ASSERTW ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpEncoderW::AnsiEncode: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
HTTPCLIENT_ASSERTW (szBuff != NULL, "CHttpEncoderW::AnsiEncode: szBuff can not be NULL.") ;
|
||
|
||
if ( (szStr == NULL) || (szStr[0] == '\0') ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
::SafeInt<int> cbAnsiLen ;
|
||
try {
|
||
cbAnsiLen = AnsiEncodeLen (szStr, CodePage) ;
|
||
cbAnsiLen++ ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
|
||
if ( 0 == ::WideCharToMultiByte (CodePage, 0, szStr, -1, szBuff, cbAnsiLen.Value (), NULL, NULL) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of unicode characters required to convert an Ansi string into an Unicode string.
|
||
* The returned value does not include the terminating NULL character.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param CodePage [in] A code page of the szEncoded parameter.
|
||
* \return The number of unicode characters required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderW::AnsiDecodeLen (PCSTR szEncoded, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
// The unicode encodings are not allowed
|
||
HTTPCLIENT_ASSERTW ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpEncoderW::AnsiDecodeLen: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchUnicodeLen ;
|
||
try {
|
||
if ( 0 == (cchUnicodeLen = ::MultiByteToWideChar (CodePage, 0, szEncoded, -1, NULL, 0)) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
cchUnicodeLen-- ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
return cchUnicodeLen.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method converts an Ansi string into an Unicode string.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the decoded string. The buffer can not be NULL.
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param CodePage [in] A code page of the szEncoded parameter.
|
||
* \return A decoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PWSTR CHttpEncoderW::AnsiDecode (PWSTR szBuff, PCSTR szEncoded, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
// The unicode encodings are not allowed
|
||
HTTPCLIENT_ASSERTW ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpEncoderW::AnsiDecode: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
HTTPCLIENT_ASSERTW (szBuff != NULL, "CHttpEncoderW::AnsiDecode: szBuff can not be NULL.") ;
|
||
|
||
if ( (szEncoded == NULL) || (szEncoded[0] == '\0') ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
::SafeInt<int> cchUnicode ;
|
||
try {
|
||
cchUnicode = AnsiDecodeLen (szEncoded, CodePage) ;
|
||
cchUnicode++ ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
if ( 0 == ::MultiByteToWideChar (CodePage, 0, szEncoded, -1, szBuff, cchUnicode.Value ()) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of characters required to encode an Unicode string using UTF-8 encoding.
|
||
* The returned value does not include the terminating NULL character.
|
||
*
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param CodePage [in] Ignored.
|
||
* \return The number of characters required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderW::Utf8EncodeLen (PCWSTR szStr, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
if ( szStr == NULL || szStr[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchRequired ;
|
||
try {
|
||
if ( 0 == (cchRequired = ::WideCharToMultiByte (CP_UTF8, 0, szStr, -1, NULL, 0, NULL, NULL)) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
cchRequired-- ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
return cchRequired.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method encodes an Unicode string using UTF-8 encoding.
|
||
*
|
||
* \param szBuff [out] A buffer to save the encoded string. The buffer can not be NULL.
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param CodePage [in] Ignored.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderW::Utf8Encode (PSTR szBuff, PCWSTR szStr, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTW (szBuff != NULL, "CHttpEncoderW::Utf8Encode: szBuff can not be NULL.") ;
|
||
|
||
if ( szStr == NULL || szStr[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
::SafeInt<int> cchRequired ;
|
||
try {
|
||
cchRequired = Utf8EncodeLen (szStr) ;
|
||
cchRequired++ ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
if ( 0 == ::WideCharToMultiByte (CP_UTF8, 0, szStr, -1, szBuff, cchRequired.Value (), NULL, NULL) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of unicode characters required to decode an UTF-8 string in unicode.
|
||
* The returned value does not include the terminating NULL character.
|
||
*
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param CodePage [in] Ignored.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderW::Utf8DecodeLen (PCSTR szEncoded, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchRequired ;
|
||
try {
|
||
if ( 0 == (cchRequired = ::MultiByteToWideChar (CP_UTF8, 0, szEncoded, -1, NULL, 0)) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
cchRequired-- ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
return cchRequired.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method decodes an UTF-8 string in unicode.
|
||
*
|
||
* \param szBuff [out] A buffer to save the decoded string. The buffer can not be NULL.
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param CodePage [in] Ignored.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PWSTR CHttpEncoderW::Utf8Decode (PWSTR szBuff, PCSTR szEncoded, UINT /* CodePage */)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTW (szBuff != NULL, "CHttpEncoderW::Utf8Decode: szBuff can not be NULL.") ;
|
||
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
::SafeInt<int> cchRequired ;
|
||
try {
|
||
cchRequired = Utf8DecodeLen (szEncoded) ;
|
||
cchRequired++ ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
|
||
if ( 0 == ::MultiByteToWideChar (CP_UTF8, 0, szEncoded, -1, szBuff, cchRequired.Value ()) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of bytes required to make a URL-encoded string
|
||
* (in Ansi character set) from an Unicode string.
|
||
* The URL-encoded string is a string that is safe to transmit from the Web server to a client.
|
||
* The returned value does not include the terminating NULL character.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the string is encoded using UTF-8 encoding
|
||
* and that string is used to make a URL-encoded string.
|
||
* \param CodePage [in] A code page of the encoded string.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderW::UrlEncodeLenA (PCWSTR szStr, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
if ( szStr == NULL || szStr[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchEncoded = 0 ;
|
||
PCWSTR pchStr = szStr ;
|
||
WCHAR szUnicode[2] = {'\0', '\0'} ;
|
||
CHAR szAnsiOrUtf8[7] ;
|
||
UINT nActualCodePage = bUtf8Encoding ? CP_UTF8 : CodePage ;
|
||
|
||
try {
|
||
while ( *pchStr ) {
|
||
szUnicode[0] = *(pchStr++) ;
|
||
|
||
if ( 0 == ::WideCharToMultiByte (nActualCodePage, 0, szUnicode, 2, szAnsiOrUtf8, 7, NULL, NULL) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
cchEncoded += _UrlEncodeLen<CHttpToolW> (szAnsiOrUtf8) ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
return cchEncoded.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method encodes a Unicode string to make a URL-encoded string (in Ansi character set).
|
||
* The URL-encoded string is a string that is safe to transmit from the Web server to a client.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the encoded string. The buffer can not be NULL.
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the string is encoded using UTF-8 encoding
|
||
* and that string is used to make a URL-encoded string.
|
||
* \param CodePage [in] A code page of the encoded string.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderW::UrlEncodeA (PSTR szBuff, PCWSTR szStr, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTW (szBuff != NULL, "CHttpEncoderW::UrlEncodeA: szBuff can not be NULL.") ;
|
||
|
||
if ( szStr == NULL || szStr[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
PCWSTR pchStr = szStr ;
|
||
PSTR pchBuff = szBuff ;
|
||
WCHAR szUnicode[2] = {'\0', '\0'} ;
|
||
CHAR szAnsiOrUtf8[7] ;
|
||
UINT nActualCodePage = bUtf8Encoding ? CP_UTF8 : CodePage ;
|
||
|
||
while ( *pchStr ) {
|
||
szUnicode[0] = *(pchStr++) ;
|
||
|
||
if ( 0 == ::WideCharToMultiByte (nActualCodePage, 0, szUnicode, 2, szAnsiOrUtf8, 7, NULL, NULL) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
_UrlEncode (pchBuff, szAnsiOrUtf8) ;
|
||
for (; *pchBuff != NULL; pchBuff++) ;
|
||
}
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method encodes a Unicode string to make a URL-encoded string (in Unicode character set).
|
||
* The URL-encoded string is a string that is safe to transmit from the Web server to a client.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the encoded string. The buffer can not be NULL.
|
||
* \param szStr [in] A string which is encoded.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the string is encoded using UTF-8 encoding
|
||
* and that string is used to make a URL-encoded string.
|
||
* \param CodePage [in] A code page of the encoded string.
|
||
* \return An encoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PWSTR CHttpEncoderW::UrlEncodeW (PWSTR szBuff, PCWSTR szStr, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTW (szBuff != NULL, "CHttpEncoderW::UrlEncodeW: szBuff can not be NULL.") ;
|
||
|
||
if ( szStr == NULL || szStr[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
PCWSTR pchStr = szStr ;
|
||
PWSTR pchBuff = szBuff ;
|
||
WCHAR szUnicode[2] = {'\0', '\0'} ;
|
||
CHAR szAnsiOrUtf8[7] ;
|
||
UINT nActualCodePage = bUtf8Encoding ? CP_UTF8 : CodePage ;
|
||
|
||
while ( *pchStr ) {
|
||
szUnicode[0] = *(pchStr++) ;
|
||
|
||
if ( 0 == ::WideCharToMultiByte (nActualCodePage, 0, szUnicode, 2, szAnsiOrUtf8, 7, NULL, NULL) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
_UrlEncode (pchBuff, szAnsiOrUtf8) ;
|
||
for (; *pchBuff != NULL; pchBuff++) ;
|
||
}
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
// [out] szAnsiChar a buffer to save a returned Ansi character sequence.
|
||
// The buffer must be allocated at least 3 characters.
|
||
// [in] szUtf8Char An Utf8 character
|
||
void CHttpEncoderW::_Utf8CharToAnsiChar (PSTR szAnsiChar, PCSTR szUtf8Char, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTW (szAnsiChar != NULL && szUtf8Char != NULL
|
||
, "CHttpEncoderW::_Utf8CharToAnsiChar: szAnsiChar and szUtf8Char can not be NULL.") ;
|
||
|
||
WCHAR wszUnicode[2] ;
|
||
|
||
// Get a unicode character
|
||
if ( 0 == ::MultiByteToWideChar (CP_UTF8, 0, szUtf8Char, -1, wszUnicode, 2) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
// Get a Ansi character sequence
|
||
if ( 0 == ::WideCharToMultiByte (CodePage, 0, wszUnicode, 2, szAnsiChar, 3, NULL, NULL) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_WIDECHARTOMULTIBYTE_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of bytes required to decode an URL-encoded string. (Ansi version)
|
||
* The returned value does not include the terminating NULL character.
|
||
* This method does not support the URL-encoded string which contains a unicode character by using the %u or %x prefix.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the decoded string is assumed an UTF-8 string.
|
||
* So the decoded string is converted into an Ansi string.
|
||
* \param CodePage [in] A code page of the decoded string.
|
||
* \return The number of bytes required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderW::UrlDecodeLenA (PCWSTR szEncoded, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchDecoded = 0 ;
|
||
PCWSTR pchEncoded = szEncoded ;
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
CHAR * pchAnsi ;
|
||
|
||
try {
|
||
do {
|
||
if ( bUtf8Encoding ) {
|
||
if ( !_GetNextUrlDecodedUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
// Converts into Ansi
|
||
_Utf8CharToAnsiChar (szAnsi, szUtf8, CodePage) ;
|
||
} else {
|
||
if ( !_GetNextUrlDecodedAnsiChar (szAnsi, &pchEncoded, CodePage) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
}
|
||
|
||
for (pchAnsi = szAnsi; *pchAnsi != NULL; pchAnsi++, cchDecoded++) ;
|
||
|
||
} while ( szAnsi[0] != '\0' ) ;
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
|
||
return cchDecoded.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of unicode characters required to decode an URL-encoded string.
|
||
* The returned value does not include the terminating NULL character.
|
||
* This method does not support the URL-encoded string which contains a unicode character by using the %u or %x prefix.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the decoded string is assumed an UTF-8 string.
|
||
* So the decoded string is converted into an Unicode string.
|
||
* \param CodePage [in] A code page of the decoded string.
|
||
* \return The number of unicode characters required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
DWORD CHttpEncoderW::UrlDecodeLenW (PCWSTR szEncoded, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' )
|
||
return 0 ;
|
||
|
||
::SafeInt<DWORD> cchDecoded = 0 ;
|
||
PCWSTR pchEncoded = szEncoded ;
|
||
|
||
try {
|
||
if ( bUtf8Encoding ) {
|
||
CHAR szUtf8[7] ;
|
||
|
||
while ( true ) {
|
||
if ( !_GetNextUrlDecodedUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
if ( szUtf8[0] == '\0' )
|
||
break ;
|
||
|
||
cchDecoded++ ;
|
||
}
|
||
return cchDecoded.Value () ;
|
||
}
|
||
|
||
CHAR szAnsi[3] ;
|
||
while ( true ) {
|
||
if ( !_GetNextUrlDecodedAnsiChar (szAnsi, &pchEncoded, CodePage) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
if ( szAnsi[0] == '\0' )
|
||
break ;
|
||
|
||
cchDecoded++ ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
CHttpToolW::ThrowException (e) ;
|
||
}
|
||
|
||
return cchDecoded.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method decodes an URL-encoded string.
|
||
* This method does not support the URL-encoded string which contains a unicode character by using the %u or %x prefix.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the decoded string. The buffer can not be NULL.
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the decoded string is assumed an UTF-8 string.
|
||
* So the decoded string is converted into an Ansi string.
|
||
* \param CodePage [in] A code page of the decoded string.
|
||
* \return A decoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PSTR CHttpEncoderW::UrlDecodeA (PSTR szBuff, PCWSTR szEncoded, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTW (szBuff != NULL, "CHttpEncoderW::UrlDecodeA: szBuff can not be NULL.") ;
|
||
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
CHAR szAnsi[3], szUtf8[7] ;
|
||
PCWSTR pchEncoded = szEncoded ;
|
||
PSTR pchBuff = szBuff ;
|
||
PSTR pchAnsi ;
|
||
|
||
do {
|
||
if ( bUtf8Encoding ) {
|
||
if ( !_GetNextUrlDecodedUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
// Converts into a Ansi character
|
||
_Utf8CharToAnsiChar (szAnsi, szUtf8, CodePage) ;
|
||
} else {
|
||
if ( !_GetNextUrlDecodedAnsiChar (szAnsi, &pchEncoded, CodePage) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
}
|
||
|
||
for (pchAnsi = szAnsi; *pchAnsi != '\0'; *(pchBuff++) = *pchAnsi, pchAnsi++) ;
|
||
|
||
} while ( szAnsi[0] != '\0' ) ;
|
||
|
||
*pchBuff = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method decodes an URL-encoded string.
|
||
* This method does not support the URL-encoded string which contains a unicode character by using the %u or %x prefix.
|
||
* The detailed infomation about the Code-Page Identifiers is described in the MSDN documentation.
|
||
*
|
||
* \param szBuff [out] A buffer to save the decoded string. The buffer can not be NULL.
|
||
* \param szEncoded [in] A string to decode.
|
||
* \param bUtf8Encoding [in] If this is TRUE, the decoded string is assumed an UTF-8 string.
|
||
* So the decoded string is converted into an Unicode string.
|
||
* \param CodePage [in] A code page of the decoded string.
|
||
* \return A decoded string.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
PWSTR CHttpEncoderW::UrlDecodeW (PWSTR szBuff, PCWSTR szEncoded, BOOL bUtf8Encoding, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERTW (szBuff != NULL, "CHttpEncoderW::UrlDecodeW: szBuff can not be NULL.") ;
|
||
|
||
if ( szEncoded == NULL || szEncoded[0] == '\0' ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
PCWSTR pchEncoded = szEncoded ;
|
||
PWSTR pchBuff = szBuff ;
|
||
|
||
if ( bUtf8Encoding ) {
|
||
CHAR szUtf8[7] ;
|
||
|
||
while ( true ) {
|
||
if ( !_GetNextUrlDecodedUtf8Char (szUtf8, &pchEncoded) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
if ( szUtf8[0] == '\0' )
|
||
break ;
|
||
|
||
// Converts into a unicode character
|
||
if ( 0 == ::MultiByteToWideChar (CP_UTF8, 0, szUtf8, -1, pchBuff, 2) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
pchBuff++ ;
|
||
}
|
||
} else {
|
||
CHAR szAnsi[3] ;
|
||
|
||
while ( true ) {
|
||
if ( !_GetNextUrlDecodedAnsiChar (szAnsi, &pchEncoded, CodePage) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_ENCODED_URL_NOT_VALID) ;
|
||
|
||
if ( szAnsi[0] == '\0' )
|
||
break ;
|
||
|
||
// Converts into a unicode character
|
||
if ( 0 == ::MultiByteToWideChar (CodePage, 0, szAnsi, -1, pchBuff, 2) )
|
||
CHttpToolW::ThrowException (HTTPCLIENT_ERR_MULTIBYTETOWIDECHAR_FAILED, ::GetLastError ()) ;
|
||
|
||
pchBuff++ ;
|
||
}
|
||
}
|
||
|
||
*pchBuff = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
///////////////////////////////////////// CHttpEncoder /////////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////// CHttpResponseT /////////////////////////////////////////
|
||
/*!
|
||
* This is the constructor which has three parameters which are the WinInet internet handles.
|
||
* The handles are owned by the CHttpResponseT and the lifetime of the handles are managed by the CHttpResponseT.
|
||
* If you pass NULL for hInternet or hConnection parameter, user has to manage the lifetime of the handles
|
||
* which are not passed to the CHttpResponseT until the CHttpResponseT is destoried.
|
||
*
|
||
* \param hInternet [in] An internet handle returned by ::InternetOpen.
|
||
* \param hConnection [in] A connection handle returned by ::InternetConnect.
|
||
* \param hRequest [in] A request handle returned by ::HttpSendRequest or ::HttpEndRequest function.
|
||
* The hRequest parameter can not be NULL.
|
||
*/
|
||
template <typename HttpTool>
|
||
CHttpResponseT<HttpTool>::CHttpResponseT (HINTERNET hInternet, HINTERNET hConnection, HINTERNET hRequest)
|
||
throw ()
|
||
{
|
||
_Initialize (hInternet, hConnection, hRequest) ;
|
||
}
|
||
|
||
/*!
|
||
* This is the constructor which has two parameters which are the WinInet internet handles.
|
||
* The handles are owned by the CHttpResponseT and the lifetime of the handles are managed by the CHttpResponseT.
|
||
* If you pass NULL for hConnection parameter, user has to manage the lifetime of the hConnection handle
|
||
* which is not passed to the CHttpResponseT until the CHttpResponseT is destoried.
|
||
* The user also has to manage the lifetime of the internet handle returned by ::InternetOpen
|
||
* until the CHttpResponseT is destoried.
|
||
*
|
||
* \param hConnection [in] A connection handle returned by ::InternetConnect.
|
||
* \param hRequest [in] A request handle returned by ::HttpSendRequest or ::HttpEndRequest function.
|
||
* The hRequest parameter can not be NULL.
|
||
*/
|
||
template <typename HttpTool>
|
||
CHttpResponseT<HttpTool>::CHttpResponseT (HINTERNET hConnection, HINTERNET hRequest)
|
||
throw ()
|
||
{
|
||
_Initialize (NULL, hConnection, hRequest) ;
|
||
}
|
||
|
||
/*!
|
||
* This is the constructor which has a parameter which is the WinInet internet handle.
|
||
* The handle is owned by the CHttpResponseT and the lifetime of the handle is managed by the CHttpResponseT.
|
||
* user has to manage the lifetime of the internet handles returned by ::InternetOpen and ::InternetConnect
|
||
* until the CHttpResponseT is destoried.
|
||
*
|
||
* \param hRequest [in] A request handle returned by ::HttpSendRequest or ::HttpEndRequest function.
|
||
* The hRequest parameter can not be NULL.
|
||
*/
|
||
template <typename HttpTool>
|
||
CHttpResponseT<HttpTool>::CHttpResponseT (HINTERNET hRequest)
|
||
throw ()
|
||
{
|
||
_Initialize (NULL, NULL, hRequest) ;
|
||
}
|
||
|
||
/*!
|
||
* This is a default destructor. It closes all internet handles saved in this object.
|
||
*/
|
||
template <typename HttpTool>
|
||
CHttpResponseT<HttpTool>::~CHttpResponseT (void)
|
||
throw ()
|
||
{
|
||
HttpTool::CloseRequest (m_hRequest) ;
|
||
HttpTool::CloseConnection (m_hConnection) ;
|
||
HttpTool::CloseInternet (m_hInternet) ;
|
||
SAFEFREE (m_szStatusText) ;
|
||
}
|
||
|
||
/*!
|
||
* This method initializes the internal member variables.
|
||
*
|
||
* \param hInternet [in] An internet handle returned by ::InternetOpen.
|
||
* \param hConnection [in] A connection handle returned by ::InternetConnect.
|
||
* \param hRequest [in] A request handle returned by ::HttpSendRequest or ::HttpEndRequest function.
|
||
* The hRequest parameter can not be NULL.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpResponseT<HttpTool>::_Initialize (HINTERNET hInternet, HINTERNET hConnection, HINTERNET hRequest)
|
||
throw ()
|
||
{
|
||
_ASSERTE ( hRequest != NULL ) ;
|
||
|
||
m_hInternet = hInternet ;
|
||
m_hConnection = hConnection ;
|
||
m_hRequest = hRequest ;
|
||
|
||
m_dwStatus = 0 ;
|
||
m_szStatusText = NULL ;
|
||
m_cbContLen = 0 ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method caches all HTTP headers of which name is the szName.
|
||
*
|
||
* \param szName [in] The case-insensitive name of the header. NULL is not allowed.
|
||
* \return The number of cached headers.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
DWORD CHttpResponseT<HttpTool>::_LoadHeader (PCSZ szName)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_hRequest != NULL, "CHttpResponseT::_LoadHeader: m_hRequest can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpResponseT::_LoadHeader: szName can not be NULL.") ;
|
||
|
||
PSZ szHeader = NULL ;
|
||
PSZ szCopiedName = NULL ;
|
||
::SafeInt<DWORD> cHeader = 0 ;
|
||
|
||
try {
|
||
try {
|
||
DWORD nIdx = 0 ;
|
||
::SafeInt<size_t> cbName = 1 ;
|
||
cbName += HttpTool::StringLen (szName) ;
|
||
cbName *= sizeof (CharType) ;
|
||
|
||
while ( true ) {
|
||
if ( NULL == (szHeader = HttpTool::GetHeader (m_hRequest, szName, &nIdx)) )
|
||
break ;
|
||
|
||
cHeader++ ;
|
||
|
||
// Copy the header name
|
||
if ( NULL == (szCopiedName = (PSZ) ::malloc (cbName.Value ())) )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
HttpTool::StringCopy (szCopiedName, szName) ;
|
||
m_mapHeader.AddPointerDirectly (szCopiedName, szHeader) ;
|
||
szCopiedName = szHeader = NULL ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
} catch (Exception &) {
|
||
m_mapHeader.RemoveAll (szName) ; // All or nothing
|
||
SAFEFREE (szHeader) ;
|
||
SAFEFREE (szCopiedName) ;
|
||
throw ;
|
||
}
|
||
|
||
return cHeader.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of headers of which name is szName.
|
||
*
|
||
* \param szName [in] A case-insensitive header name. NULL is not allowed.
|
||
* \return The number of headers of which name is bstrName.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
DWORD CHttpResponseT<HttpTool>::GetHeaderCount (PCSZ szName)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpResponseT::GetHeaderCount: szName can not be NULL.") ;
|
||
|
||
DWORD cHeader = m_mapHeader.Count (szName) ;
|
||
|
||
// Tries to load headers if the header does not exist
|
||
if ( cHeader == 0 )
|
||
cHeader = _LoadHeader (szName) ;
|
||
|
||
return cHeader ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the header of which name is the szName.
|
||
* If a header name has multiple values, you can specify a zero-based index for a specific value.
|
||
* If a header specified by szName is not found or the index is out of range, it will return NULL.
|
||
* Otherwise it always returns a null-terminated string. The returned string is owned by
|
||
* the CHttpResponseT. So you can not free it.
|
||
*
|
||
* \param szName [in] A case-insensitive header name. NULL is not allowed.
|
||
* \param nIdx [in] A zero-based index for a header which has multiple values.
|
||
* \return The requested header.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
typename CHttpResponseT<HttpTool>::PCSZ
|
||
CHttpResponseT<HttpTool>::GetHeader (PCSZ szName, DWORD nIdx = 0)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpResponseT::GetHeader: szName can not be NULL.") ;
|
||
|
||
// Tries to load headers if the header does not exist
|
||
if ( !m_mapHeader.Count (szName) && !_LoadHeader (szName) )
|
||
return NULL ;
|
||
|
||
return m_mapHeader.GetValue (szName, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the HTTP status code of a HTTP response.
|
||
*
|
||
* \return The HTTP status code.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
DWORD CHttpResponseT<HttpTool>::GetStatus (void)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_hRequest != NULL, "CHttpResponseT::GetStatus: m_hRequest can not be NULL.") ;
|
||
|
||
// If the cached one exists
|
||
if ( m_dwStatus != 0 )
|
||
return m_dwStatus ;
|
||
|
||
DWORD dwBuffSize = sizeof (DWORD) ;
|
||
|
||
if ( !::HttpQueryInfo (
|
||
m_hRequest
|
||
, HTTP_QUERY_STATUS_CODE // Get the HTTP status code
|
||
| HTTP_QUERY_FLAG_NUMBER
|
||
, static_cast<void *> (&m_dwStatus)
|
||
, &dwBuffSize // Buffer size (byte)
|
||
, NULL // Does not use a header index
|
||
)
|
||
)
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
|
||
return m_dwStatus ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the HTTP status text of a HTTP response.
|
||
* It always returns a null-terminated string. The returned string is owned by
|
||
* the CHttpResponse. So you can not free it.
|
||
*
|
||
* \return The HTTP status text returned by a HTTP server.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
typename CHttpResponseT<HttpTool>::PCSZ
|
||
CHttpResponseT<HttpTool>::GetStatusText (void)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_hRequest != NULL, "CHttpResponseT::GetStatusText: m_hRequest can not be NULL.") ;
|
||
|
||
// If the cached one exists
|
||
if ( m_szStatusText != NULL )
|
||
return m_szStatusText ;
|
||
|
||
return (m_szStatusText = HttpTool::GetStatusText (m_hRequest)) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the content length of a returned HTTP response.
|
||
* The content is the data stream except the HTTP headers. If the length is retrieved,
|
||
* it will return TRUE, otherwise return FALSE.
|
||
*
|
||
* \param cbContLen [out] A reference variable to save the content length.
|
||
* \return TRUE if the content length is available, otherwise FALSE.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
BOOL CHttpResponseT<HttpTool>::GetContentLength (DWORD & cbContLen)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_hRequest != NULL, "CHttpResponseT::GetContentLength: m_hRequest can not be NULL.") ;
|
||
|
||
DWORD dwBuffSize = sizeof (DWORD) ;
|
||
|
||
if ( !::HttpQueryInfo (
|
||
m_hRequest
|
||
, HTTP_QUERY_CONTENT_LENGTH // Reads the 'content-length' header
|
||
| HTTP_QUERY_FLAG_NUMBER
|
||
, static_cast<void *> (&cbContLen)
|
||
, &dwBuffSize // Buffer size (byte)
|
||
, NULL // Does not use a header index
|
||
)
|
||
) {
|
||
|
||
if ( ::GetLastError () == ERROR_HTTP_HEADER_NOT_FOUND )
|
||
return FALSE ;
|
||
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_QUERYINFO_FAILED, ::GetLastError ()) ;
|
||
}
|
||
|
||
return TRUE ;
|
||
}
|
||
|
||
/*!
|
||
* This method reads the content (the data stream except headers) of a returned HTTP response.
|
||
*
|
||
* \param pbyBuff [out] A buffer to save the read content.
|
||
* \param cbBuff [in] A buffer size in byte.
|
||
* \return Returns the number of bytes read. Returns zero if all content is read.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
DWORD CHttpResponseT<HttpTool>::ReadContent (BYTE * pbyBuff, DWORD cbBuff)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_hRequest != NULL, "CHttpResponseT::ReadContent: m_hRequest can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (pbyBuff != NULL, "CHttpResponseT::ReadContent: pbyBuff can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (cbBuff != 0, "CHttpResponseT::ReadContent: cbBuff can not be zero.") ;
|
||
|
||
DWORD cbRead = 0 ;
|
||
if ( !::InternetReadFile (
|
||
m_hRequest
|
||
, pbyBuff
|
||
, cbBuff
|
||
, &cbRead
|
||
)
|
||
)
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_INTERNETREADFILE_FAILED, ::GetLastError ()) ;
|
||
|
||
return cbRead ;
|
||
}
|
||
|
||
/*!
|
||
* This method saves the content (the data stream except headers) of a returned HTTP response
|
||
* to a file which is specified by szFilePath.
|
||
*
|
||
* \param szFilePath [in] A file path to save the return content.
|
||
* \param bOverwrite [in] If this is TRUE, a file is overwritten if aleady exists. otherwise an exception is thrown.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpResponseT<HttpTool>::SaveContent (PCSZ szFilePath, BOOL bOverwrite)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szFilePath != NULL, "CHttpResponseT::SaveContent: szFilePath can not be NULL.") ;
|
||
|
||
// Checks whether the target file aleady exists.
|
||
if ( !bOverwrite )
|
||
{
|
||
if ( HttpTool::FileExists (szFilePath) )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_FILE_ALEADY_EXISTS, NO_ERROR, szFilePath) ;
|
||
}
|
||
|
||
// Create a file to save content stream
|
||
HANDLE hFile = HttpTool::CreateFileAlwaysToWrite (szFilePath) ;
|
||
|
||
if ( hFile == INVALID_HANDLE_VALUE )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OPENFILE_FAILED, ::GetLastError (), szFilePath) ;
|
||
|
||
const DWORD cbBuff = 1024 * 10 ; // use 10k buffer
|
||
BYTE byBuff[cbBuff] ;
|
||
DWORD cbRead, cbWritten, cbRemain ;
|
||
|
||
// Reads the data stream returned by the HTTP server.
|
||
while ( cbRead = ReadContent (byBuff, cbBuff) ) {
|
||
cbRemain = cbRead ;
|
||
|
||
do {
|
||
if ( !::WriteFile (hFile, byBuff + (cbRead - cbRemain) , cbRemain, &cbWritten, NULL) ) {
|
||
DWORD dwLastError = ::GetLastError () ;
|
||
::CloseHandle (hFile) ;
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_WRITEFILE_FAILED, dwLastError, szFilePath) ;
|
||
}
|
||
cbRemain -= cbWritten ;
|
||
} while ( cbRemain > 0 ) ;
|
||
}
|
||
::CloseHandle (hFile) ;
|
||
}
|
||
|
||
|
||
///////////////////////////////////////// CHttpResponseT /////////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////// CHttpPostStatT /////////////////////////////////////////
|
||
/*!
|
||
* This is a default constructor with no argument.
|
||
*/
|
||
template <typename HttpTool>
|
||
CHttpPostStatT<HttpTool>::CHttpPostStatT (void)
|
||
throw ()
|
||
{
|
||
// Initialize member variables
|
||
_InitMemberVariables () ;
|
||
}
|
||
|
||
/*!
|
||
* This is a copy constructor.
|
||
* If memory allocation failed, the messages contained in the objPostStat object will
|
||
* not be copied and the internal string pointers will point to NULL.
|
||
*
|
||
* \param objPostStat [in] An CHttpPostStat object.
|
||
*/
|
||
template <typename HttpTool>
|
||
CHttpPostStatT<HttpTool>::CHttpPostStatT (const CHttpPostStatT & objPostStat)
|
||
throw ()
|
||
{
|
||
operator= (objPostStat) ;
|
||
}
|
||
|
||
/*!
|
||
* This is a default destructor.
|
||
*/
|
||
template <typename HttpTool>
|
||
CHttpPostStatT<HttpTool>::~CHttpPostStatT (void)
|
||
throw ()
|
||
{
|
||
_MakeUnActive () ;
|
||
}
|
||
|
||
// Initialize member variables
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_InitMemberVariables (void)
|
||
throw ()
|
||
{
|
||
m_bIsActive = FALSE ;
|
||
|
||
m_cbActualTotal = 0 ;
|
||
m_cbActualPosted = 0 ;
|
||
|
||
m_cbTotal = 0 ;
|
||
m_cbPosted = 0 ;
|
||
|
||
m_cParam = 0 ;
|
||
m_cParamPosted = 0 ;
|
||
m_cFile = 0 ;
|
||
m_cFilePosted = 0 ;
|
||
|
||
m_szCurrParam = NULL ;
|
||
m_szCurrFile = NULL ;
|
||
m_cbCurrParam = 0 ;
|
||
m_cbCurrParamPosted = 0 ;
|
||
}
|
||
|
||
// Copy a string.
|
||
// The destination pointer will point to NULL if memory allocation failed.
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_SetString (PSZ * pszDest, PCSZ szSrc)
|
||
throw ()
|
||
{
|
||
_ASSERTE ( pszDest != NULL ) ;
|
||
|
||
if ( szSrc == NULL ) {
|
||
SAFEFREE ( (*pszDest) ) ;
|
||
return ;
|
||
}
|
||
|
||
// If the source and destination string are the same, just return.
|
||
if ( *pszDest != NULL ) {
|
||
if ( 0 == HttpTool::StringCmp (*pszDest, szSrc) )
|
||
return ;
|
||
|
||
SAFEFREE ( (*pszDest) ) ;
|
||
}
|
||
|
||
*pszDest = (PSZ) ::malloc (sizeof (CharType) * (HttpTool::StringLen (szSrc) + 1)) ;
|
||
|
||
// If memory allocation failed, just return.
|
||
if ( *pszDest == NULL )
|
||
return ;
|
||
|
||
HttpTool::StringCopy (*pszDest, szSrc) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a boolean which indicates whether the POST is in progress or not.
|
||
*
|
||
* \return TRUE if the POST is in progress, otherwise FALSE
|
||
*/
|
||
template <typename HttpTool>
|
||
BOOL CHttpPostStatT<HttpTool>::IsActive (void) const
|
||
throw ()
|
||
{
|
||
return m_bIsActive ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the actual number of bytes to send to a HTTP web server.
|
||
* The returned size includes the size of boundaries, parameter names, and other elements.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The actual number of bytes which is going to be sent to a HTTP web server
|
||
*/
|
||
template <typename HttpTool>
|
||
size_t CHttpPostStatT<HttpTool>::ActualTotalByte (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::ActualTotalByte: The post context is not active.") ;
|
||
return m_cbActualTotal ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the actual number of bytes posted to a HTTP web server.
|
||
* The returned size includes the size of boundaries, parameter names, and other elements.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The actual number of bytes posted to a HTTP web server
|
||
*/
|
||
template <typename HttpTool>
|
||
size_t CHttpPostStatT<HttpTool>::ActualPostedByte (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::ActualPostedByte: The post context is not active.") ;
|
||
return m_cbActualPosted ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of bytes to send to a HTTP web server.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The number of bytes to send to a HTTP web server
|
||
*/
|
||
template <typename HttpTool>
|
||
size_t CHttpPostStatT<HttpTool>::TotalByte (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::TotalByte: The post context is not active.") ;
|
||
return m_cbTotal ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of bytes posted to a HTTP web server.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The number of bytes posted to a HTTP web server
|
||
*/
|
||
template <typename HttpTool>
|
||
size_t CHttpPostStatT<HttpTool>::PostedByte (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::PostedByte: The post context is not active.") ;
|
||
return m_cbPosted ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the total number of parameters to send to a HTTP web server.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The total number of parameters
|
||
*/
|
||
template <typename HttpTool>
|
||
DWORD CHttpPostStatT<HttpTool>::TotalCount (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::TotalCount: The post context is not active.") ;
|
||
return m_cParam ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of posted parameters.
|
||
* The count includes the current parameter which is being sent to the server.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The number of posted parameters
|
||
*/
|
||
template <typename HttpTool>
|
||
DWORD CHttpPostStatT<HttpTool>::PostedCount (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::PostedCount: The post context is not active.") ;
|
||
return m_cParamPosted ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of file parameters.
|
||
* The file parameter is a parameter which contains a file path to upload.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The number of file parameters
|
||
*/
|
||
template <typename HttpTool>
|
||
DWORD CHttpPostStatT<HttpTool>::FileCount (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::FileCount: The post context is not active.") ;
|
||
return m_cFile ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of posted file parameters.
|
||
* The file parameter is a parameter which contains a file path to upload.
|
||
* If the current parameter is a file parameter, then the count includes the current parameter.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The number of posted file parameters
|
||
*/
|
||
template <typename HttpTool>
|
||
DWORD CHttpPostStatT<HttpTool>::PostedFileCount (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::PostedFileCount: The post context is not active.") ;
|
||
return m_cFilePosted ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the current parameter name.
|
||
* The current parameter is a parameter which is being sent to the server.
|
||
* It always returns a null-terminated string. The returned string is owned by
|
||
* the CHttpPostStat. So you can not free it.
|
||
* If the system fails to allocate memory for the current parameter name,
|
||
* it will return "NULL" instead of NULL.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The current parameter name
|
||
*/
|
||
template <typename HttpTool>
|
||
typename CHttpPostStatT<HttpTool>::PCSZ
|
||
CHttpPostStatT<HttpTool>::CurrParam (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::CurrParam: The post context is not active.") ;
|
||
|
||
// If the string of the current parameter is NULL,
|
||
// returns "NULL" instead of NULL
|
||
if ( m_szCurrParam == NULL )
|
||
return HttpTool::szNULL ;
|
||
|
||
return m_szCurrParam ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the file path which is currently being uploaded.
|
||
* It always returns a null-terminated string. The returned string is owned by
|
||
* the CHttpPostStat. So you can not free it.
|
||
* If the current parameter is not a file parameter or the system fails to allocate
|
||
* memory for the current file path, it will return "NULL".
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The current file path
|
||
*/
|
||
template <typename HttpTool>
|
||
typename CHttpPostStatT<HttpTool>::PCSZ
|
||
CHttpPostStatT<HttpTool>::CurrFile (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::CurrFile: The post context is not active.") ;
|
||
|
||
// If the string of the current file is NULL,
|
||
// returns "NULL" instead of NULL
|
||
if ( m_szCurrFile == NULL )
|
||
return HttpTool::szNULL ;
|
||
|
||
return m_szCurrFile ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of bytes of the current parameter.
|
||
* The current parameter is a parameter which is being sent to the server.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The number of bytes of the current parameter
|
||
*/
|
||
template <typename HttpTool>
|
||
size_t CHttpPostStatT<HttpTool>::CurrParamTotalByte (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::CurrParamTotalByte: The post context is not active.") ;
|
||
return m_cbCurrParam ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of posted bytes of the current parameter.
|
||
* The current parameter is a parameter which is being sent to the server.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The number of posted bytes of the current parameter
|
||
*/
|
||
template <typename HttpTool>
|
||
size_t CHttpPostStatT<HttpTool>::CurrParamPostedByte (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::CurrParamPostedByte: The post context is not active.") ;
|
||
return m_cbCurrParamPosted ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of remained bytes of the current parameter.
|
||
* The current parameter is a parameter which is being sent to the server.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return The number of remained bytes of the current parameter
|
||
*/
|
||
template <typename HttpTool>
|
||
size_t CHttpPostStatT<HttpTool>::CurrParamRemainByte (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::CurrParamRemainByte: The post context is not active.") ;
|
||
return m_cbCurrParam - m_cbCurrParamPosted ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns TRUE if the current parameter is a file parameter,
|
||
* otherwise it will return FALSE.
|
||
* The current parameter is a parameter which is being sent to the server.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return TRUE if the current parameter is a file parameter, otherwise FALSE
|
||
*/
|
||
template <typename HttpTool>
|
||
BOOL CHttpPostStatT<HttpTool>::CurrParamIsFile (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::CurrParamIsFile: The post context is not active.") ;
|
||
return (m_szCurrFile != NULL) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns TRUE if the current parameter is completely posted,
|
||
* otherwise it will return FALSE.
|
||
* The current parameter is a parameter which is being sent to the server.
|
||
* If the IsActive is FALSE, you shouldn't call this method.
|
||
*
|
||
* \return TRUE if the current parameter is completely posted, otherwise FALSE
|
||
*/
|
||
template <typename HttpTool>
|
||
BOOL CHttpPostStatT<HttpTool>::CurrParamIsComplete (void) const
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::CurrParamIsComplete: The post context is not active.") ;
|
||
return (CurrParamTotalByte () == CurrParamPostedByte ()) ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method returns TRUE if all bytes are sent.
|
||
*
|
||
* \return Returns TRUE if all bytes are sent
|
||
*/
|
||
template <typename HttpTool>
|
||
BOOL CHttpPostStatT<HttpTool>::_IsComplete (void) const
|
||
throw ()
|
||
{
|
||
_ASSERTE ( m_bIsActive ) ;
|
||
return (ActualTotalByte () == ActualPostedByte ()) ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method tests whether the m_cbActualPosted is safe to increase.
|
||
*
|
||
* \param nBytes [in] The number of bytes to add to the m_cbActualPosted.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_TestAddActualPostedBytes (size_t nBytes)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::_TestAddActualPostedBytes: The post context is not active.") ;
|
||
|
||
try {
|
||
::SafeInt<size_t> cbActualPosted = m_cbActualPosted ;
|
||
|
||
_ASSERTE ( (cbActualPosted + nBytes) <= m_cbActualTotal ) ;
|
||
cbActualPosted += nBytes ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method increases the m_cbActualPosted member variable.
|
||
*
|
||
* \param nBytes [in] The number of bytes to add to the m_cbActualPosted.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_AddActualPostedBytes (size_t nBytes)
|
||
throw (Exception &)
|
||
{
|
||
_TestAddActualPostedBytes (nBytes) ;
|
||
m_cbActualPosted += nBytes ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method cleans all internal states and closes the POST state.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_MakeUnActive (void)
|
||
throw ()
|
||
{
|
||
SAFEFREE (m_szCurrParam) ;
|
||
SAFEFREE (m_szCurrFile) ;
|
||
|
||
_InitMemberVariables () ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method starts a new state of the HTTP POST.
|
||
*
|
||
* \param cbActualTotal [in] The actual total number of bytes of the request.
|
||
* \param cbTotal [in] The total number of bytes of the request.
|
||
* \param cParam [in] The number of parameters.
|
||
* \param cFile [in] The number of file parameters.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_MakeActive (size_t cbActualTotal, size_t cbTotal, DWORD cParam
|
||
, DWORD cFile)
|
||
throw ()
|
||
{
|
||
_MakeUnActive () ;
|
||
|
||
m_bIsActive = TRUE ;
|
||
m_cbActualTotal = cbActualTotal ;
|
||
m_cbTotal = cbTotal ;
|
||
m_cParam = cParam ;
|
||
m_cFile = cFile ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method tests whether a new current parameter is safely set.
|
||
*
|
||
* \param szCurrParam [in] The name of the current parameter.
|
||
* \param cbCurrParam [in] The number of bytes of the current parameter.
|
||
* \param bIsFile [in] TRUE if the current parameter is a file parameter.
|
||
* \param szCurrFile [in] The file path of the current parameter.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_TestStartNewEntry (PCSZ /* szCurrParam */, size_t /* cbCurrParam */
|
||
, BOOL bIsFile, PCSZ /* szCurrFile */)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::_TestStartNewEntry: The post context is not active.") ;
|
||
|
||
try {
|
||
::SafeInt<DWORD> cParamPosted = m_cParamPosted ;
|
||
_ASSERTE ( (cParamPosted + 1) <= m_cParam ) ;
|
||
cParamPosted++ ;
|
||
|
||
if ( bIsFile ) {
|
||
::SafeInt<DWORD> cFilePosted = m_cFilePosted ;
|
||
_ASSERTE ( (cFilePosted + 1) <= m_cFile ) ;
|
||
cFilePosted++ ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method sets a new current parameter.
|
||
* If memory allocation is failed for strings (szCurrParam, szCurrFile),
|
||
* NULL is saved. (and "NULL" is returned when the user requests these values)
|
||
*
|
||
* \param szCurrParam [in] The name of the current parameter.
|
||
* \param cbCurrParam [in] The number of bytes of the current parameter.
|
||
* \param bIsFile [in] TRUE if the current parameter is a file parameter.
|
||
* \param szCurrFile [in] The file path of the current parameter.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_StartNewEntry (PCSZ szCurrParam, size_t cbCurrParam
|
||
, BOOL bIsFile, PCSZ szCurrFile)
|
||
throw (Exception &)
|
||
{
|
||
_TestStartNewEntry (szCurrParam, cbCurrParam, bIsFile, szCurrFile) ;
|
||
|
||
if ( bIsFile ) {
|
||
m_cFilePosted++ ;
|
||
_SetString (&m_szCurrFile, szCurrFile) ;
|
||
} else {
|
||
_SetString (&m_szCurrFile, NULL) ;
|
||
}
|
||
|
||
m_cParamPosted++ ;
|
||
_SetString (&m_szCurrParam, szCurrParam) ;
|
||
|
||
m_cbCurrParam = cbCurrParam ;
|
||
m_cbCurrParamPosted = 0 ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method tests whether the counters related to the number of posted bytes is safe to increase.
|
||
* (m_cbPosted, m_cbCurrParamPosted, m_cbActualPosted)
|
||
*
|
||
* \param nBytes [in] The number of bytes to add.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_TestAddPostedBytes (size_t nBytes)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_bIsActive, "CHttpPostStatT::_TestAddPostedBytes: The post context is not active.") ;
|
||
|
||
try {
|
||
_TestAddActualPostedBytes (nBytes) ;
|
||
|
||
::SafeInt<size_t> cbPosted = m_cbPosted ;
|
||
::SafeInt<size_t> cbCurrParamPosted = m_cbCurrParamPosted ;
|
||
|
||
_ASSERTE ( (cbPosted + nBytes) <= m_cbTotal ) ;
|
||
_ASSERTE ( (cbCurrParamPosted + nBytes) <= m_cbCurrParam ) ;
|
||
|
||
cbPosted += nBytes ;
|
||
cbCurrParamPosted += nBytes ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method increases all counters related to the number of posted bytes.
|
||
* (m_cbPosted, m_cbCurrParamPosted, m_cbActualPosted)
|
||
*
|
||
* \param nBytes [in] The number of bytes to add.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpPostStatT<HttpTool>::_AddPostedBytes (size_t nBytes)
|
||
throw (Exception &)
|
||
{
|
||
_TestAddPostedBytes (nBytes) ;
|
||
|
||
m_cbPosted += nBytes ;
|
||
m_cbCurrParamPosted += nBytes ;
|
||
_AddActualPostedBytes (nBytes) ;
|
||
}
|
||
|
||
/*!
|
||
* This operator copies the state information from the source object.
|
||
* All strings contained in the targeted object can be NULL if memory allocation failed.
|
||
* (and "NULL" is returned when the user requests these values)
|
||
*
|
||
* \param objPostStat [in] A CHttpPostStat object.
|
||
* \return The targeted object.
|
||
*/
|
||
template <typename HttpTool>
|
||
CHttpPostStatT<HttpTool> &
|
||
CHttpPostStatT<HttpTool>::operator= (const CHttpPostStatT<HttpTool> & objPostStat)
|
||
throw ()
|
||
{
|
||
if ( this == &objPostStat )
|
||
return *this ;
|
||
|
||
_MakeUnActive () ;
|
||
|
||
m_bIsActive = objPostStat.m_bIsActive ;
|
||
|
||
m_cbActualTotal = objPostStat.m_cbActualTotal ;
|
||
m_cbActualPosted = objPostStat.m_cbActualPosted ;
|
||
|
||
m_cbTotal = objPostStat.m_cbTotal ;
|
||
m_cbPosted = objPostStat.m_cbPosted ;
|
||
|
||
m_cParam = objPostStat.m_cParam ;
|
||
m_cParamPosted = objPostStat.m_cParamPosted ;
|
||
m_cFile = objPostStat.m_cFile ;
|
||
m_cFilePosted = objPostStat.m_cFilePosted ;
|
||
|
||
_SetString (&m_szCurrParam, objPostStat.m_szCurrParam) ;
|
||
_SetString (&m_szCurrFile, objPostStat.m_szCurrFile) ;
|
||
|
||
m_cbCurrParam = objPostStat.m_cbCurrParam ;
|
||
m_cbCurrParamPosted = objPostStat.m_cbCurrParamPosted ;
|
||
|
||
return *this ;
|
||
}
|
||
///////////////////////////////////////// CHttpPostStatT /////////////////////////////////////////
|
||
|
||
///////////////////////////////////////// CHttpUrlAnalyzer /////////////////////////////////////////
|
||
/*!
|
||
* This is the default constructor. If you pass a URL to the constructor,
|
||
* It analyzes a URL using Analyze method.
|
||
*
|
||
* \param szUrl [in] An URL to analyze.
|
||
* \param CodePage [in] A code page of the URL. If the URL is a unicode string,
|
||
* this parameter is ignored.
|
||
* CP_UTF8, CP_UTF7 are not allowed.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Analyze
|
||
*/
|
||
template <typename HttpTool>
|
||
CHttpUrlAnalyzerT<HttpTool>::CHttpUrlAnalyzerT (PCSZ szUrl, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
Analyze (szUrl, CodePage) ;
|
||
}
|
||
|
||
/*!
|
||
* This method clears all saved information and sets to 0.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpUrlAnalyzerT<HttpTool>::Reset (void)
|
||
throw ()
|
||
{
|
||
m_nProtocolIdx = m_cchProtocol = m_nServerAddrIdx = m_cchServerAddr
|
||
= m_nServerPortIdx = m_cchServerPort = m_nUrlPathIdx = m_cchUrlPath
|
||
= m_nSearchIdx = m_cchSearch = m_nBookmarkIdx = m_cchBookmark = 0 ;
|
||
}
|
||
|
||
/*!
|
||
* This method analyzes a URL and saves information about its component parts.
|
||
* It does not check whether the URL is valid. The URL itself is not saved.
|
||
*
|
||
* \param szUrl [in] An URL to analyze.
|
||
* \param CodePage [in] A code page of the URL. If the URL is a unicode string,
|
||
* this parameter is ignored.
|
||
* CP_UTF8, CP_UTF7 are not allowed.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool>
|
||
void CHttpUrlAnalyzerT<HttpTool>::Analyze (PCSZ szUrl, UINT CodePage)
|
||
throw (Exception &)
|
||
{
|
||
// The unicode encodings are not allowed
|
||
HTTPCLIENT_ASSERT ((CodePage != CP_UTF8) && (CodePage != CP_UTF7)
|
||
, "CHttpUrlAnalyzerT::Analyze: CP_UTF8 and CP_UTF7 can not be used for the CodePage parameter.") ;
|
||
|
||
Reset () ;
|
||
|
||
if ( szUrl == NULL || szUrl[0] == '\0' )
|
||
return ;
|
||
|
||
// Checks overflow
|
||
try {
|
||
::SafeInt<DWORD> dw = HttpTool::StringLen (szUrl) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
PCSZ pchNextUrl = szUrl ;
|
||
DWORD nNextUrlCharIdx = 0 ;
|
||
|
||
{
|
||
// Get the protocol
|
||
PCSZ pchColonSlashSlash = NULL ;
|
||
|
||
{
|
||
// Finds "://" in the URL
|
||
for (pchColonSlashSlash = pchNextUrl; *pchColonSlashSlash != '\0'; pchColonSlashSlash++) {
|
||
|
||
// If the character is a leadbyte of the double byte character set
|
||
if ( HttpTool::IsDBCSLeadByteEx (CodePage, *pchColonSlashSlash) ) {
|
||
// Ignores a trailing byte
|
||
if ( *(pchColonSlashSlash + 1) != '\0' )
|
||
pchColonSlashSlash++ ;
|
||
continue ;
|
||
}
|
||
|
||
if ( (*pchColonSlashSlash == ':')
|
||
&& (*(pchColonSlashSlash + 1) != '\0') && (*(pchColonSlashSlash + 1) == '/')
|
||
&& (*(pchColonSlashSlash + 2) != '\0') && (*(pchColonSlashSlash + 2) == '/') )
|
||
break ;
|
||
}
|
||
}
|
||
|
||
if ( *pchColonSlashSlash != '\0' ) {
|
||
for (; pchNextUrl != pchColonSlashSlash; pchNextUrl++, m_cchProtocol++, nNextUrlCharIdx++) ;
|
||
|
||
pchNextUrl += 3/* == strlen (szColonSlashSlash)*/ ;
|
||
nNextUrlCharIdx += 3 ;
|
||
}
|
||
}
|
||
|
||
{
|
||
// Get server address and server port
|
||
BOOL bFoundColon = FALSE ;
|
||
|
||
m_nServerAddrIdx = nNextUrlCharIdx ;
|
||
for (; *pchNextUrl != '/' && *pchNextUrl != '?' && *pchNextUrl != '#' && *pchNextUrl != '\0';
|
||
pchNextUrl++, nNextUrlCharIdx++) {
|
||
|
||
// If the character is a leadbyte of the double byte character set
|
||
if ( HttpTool::IsDBCSLeadByteEx (CodePage, *pchNextUrl) ) {
|
||
m_cchServerPort += (bFoundColon ? 1 : 0) ;
|
||
m_cchServerAddr += (bFoundColon ? 0 : 1) ;
|
||
|
||
// Ignores a trailing byte
|
||
if ( *(pchNextUrl + 1) != '\0' ) {
|
||
pchNextUrl++ ;
|
||
nNextUrlCharIdx++ ;
|
||
m_cchServerPort += (bFoundColon ? 1 : 0) ;
|
||
m_cchServerAddr += (bFoundColon ? 0 : 1) ;
|
||
}
|
||
continue ;
|
||
}
|
||
|
||
if ( bFoundColon ) {
|
||
m_cchServerPort++ ;
|
||
continue ;
|
||
}
|
||
|
||
if ( *pchNextUrl == ':' ) {
|
||
m_nServerPortIdx = nNextUrlCharIdx + 1 ;
|
||
bFoundColon = TRUE ;
|
||
continue ;
|
||
}
|
||
|
||
m_cchServerAddr++ ;
|
||
}
|
||
|
||
if ( !bFoundColon )
|
||
m_nServerPortIdx = nNextUrlCharIdx ;
|
||
}
|
||
|
||
{
|
||
// Get path and search string
|
||
BOOL bFoundQuestionMark = FALSE ;
|
||
|
||
m_nUrlPathIdx = nNextUrlCharIdx ;
|
||
for (; *pchNextUrl != '#' && *pchNextUrl != '\0'; pchNextUrl++, nNextUrlCharIdx++) {
|
||
|
||
// If the character is a leadbyte of the double byte character set
|
||
if ( HttpTool::IsDBCSLeadByteEx (CodePage, *pchNextUrl) ) {
|
||
m_cchSearch += (bFoundQuestionMark ? 1 : 0) ;
|
||
m_cchUrlPath += (bFoundQuestionMark ? 0 : 1) ;
|
||
|
||
// Ignores a trailing byte
|
||
if ( *(pchNextUrl + 1) != '\0' ) {
|
||
pchNextUrl++ ;
|
||
nNextUrlCharIdx++ ;
|
||
m_cchSearch += (bFoundQuestionMark ? 1 : 0) ;
|
||
m_cchUrlPath += (bFoundQuestionMark ? 0 : 1) ;
|
||
}
|
||
continue ;
|
||
}
|
||
|
||
if ( bFoundQuestionMark ) {
|
||
m_cchSearch++ ;
|
||
continue ;
|
||
}
|
||
|
||
if ( *pchNextUrl == '?' ) {
|
||
m_nSearchIdx = nNextUrlCharIdx ;
|
||
m_cchSearch++ ;
|
||
bFoundQuestionMark = TRUE ;
|
||
continue ;
|
||
}
|
||
|
||
m_cchUrlPath++ ;
|
||
}
|
||
|
||
if ( !bFoundQuestionMark )
|
||
m_nSearchIdx = nNextUrlCharIdx ;
|
||
}
|
||
|
||
{
|
||
// Get bookmark
|
||
m_nBookmarkIdx = nNextUrlCharIdx ;
|
||
for (; *pchNextUrl != '\0'; pchNextUrl++, nNextUrlCharIdx++, m_cchBookmark++) ;
|
||
}
|
||
}
|
||
///////////////////////////////////////// CHttpUrlAnalyzer /////////////////////////////////////////
|
||
|
||
|
||
///////////////////////////////////////// CHttpClientT /////////////////////////////////////////
|
||
/*!
|
||
* This is a default constructor with no argument.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
CHttpClientT<HttpTool, HttpEncoder>::CHttpClientT (void)
|
||
throw ()
|
||
{
|
||
// Initializes member variables
|
||
m_bStrictFileCheck = FALSE ;
|
||
m_bUseUtf8 = FALSE ;
|
||
m_nAnsiCodePage = CP_ACP ;
|
||
|
||
m_RefCount = 0;
|
||
|
||
// variables related to the WinInet API
|
||
m_szInternetUserAgent = NULL ;
|
||
m_dwInternetAccessType = INTERNET_OPEN_TYPE_PRECONFIG ;
|
||
m_szInternetProxyName = NULL ;
|
||
m_szInternetProxyBypass = NULL ;
|
||
m_dwInternetFlags = 0 ;
|
||
m_szProxyUserName = NULL ;
|
||
m_szProxyPassword = NULL ;
|
||
|
||
|
||
// Initializes a boundary
|
||
m_szBoundary = NULL ;
|
||
m_szUploadContType = NULL ;
|
||
m_szBoundaryA = NULL ;
|
||
m_bNeedToFreeBoundaryA = FALSE ;
|
||
try {
|
||
m_szBoundary = HttpTool::CreateUploadBoundary () ;
|
||
if ( m_szBoundary ) {
|
||
m_szUploadContType =
|
||
(PSZ) ::malloc (sizeof (CharType)
|
||
* (30 /* ::strlen (szMultipartFormDataBoundary) */
|
||
+ HttpTool::StringLen (m_szBoundary)
|
||
+ 1)
|
||
) ;
|
||
if ( m_szUploadContType == NULL )
|
||
throw "Out of memory" ;
|
||
|
||
HttpTool::StringCopy (m_szUploadContType, HttpTool::szMultipartFormDataBoundary) ;
|
||
HttpTool::StringCat (m_szUploadContType, m_szBoundary) ;
|
||
m_szBoundaryA = _String2Ansi (m_szBoundary, m_bNeedToFreeBoundaryA) ;
|
||
}
|
||
} catch (...) {
|
||
SAFEFREE (m_szBoundary) ;
|
||
SAFEFREE (m_szUploadContType) ;
|
||
}
|
||
|
||
// Initializes the context related to the POST context
|
||
_InitPostContext () ;
|
||
}
|
||
|
||
/*!
|
||
* This is a default destructor.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
CHttpClientT<HttpTool, HttpEncoder>::~CHttpClientT (void)
|
||
throw ()
|
||
{
|
||
// Releases the POST context
|
||
_EndPostContext () ;
|
||
|
||
// Releases the Boundary
|
||
SAFEFREE (m_szBoundary) ;
|
||
SAFEFREE (m_szUploadContType) ;
|
||
if ( m_bNeedToFreeBoundaryA )
|
||
SAFEFREE (m_szBoundaryA) ;
|
||
|
||
// Releases the variables related to the WinInet API
|
||
SAFEFREE (m_szInternetUserAgent) ;
|
||
SAFEFREE (m_szInternetProxyName) ;
|
||
SAFEFREE (m_szInternetProxyBypass) ;
|
||
SAFEFREE (m_szProxyUserName) ;
|
||
SAFEFREE (m_szProxyPassword) ;
|
||
}
|
||
|
||
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::_String2AnsiLen (PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
return HttpEncoder::AnsiEncodeLen (szStr, m_nAnsiCodePage) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
PCSTR CHttpClientT<HttpTool, HttpEncoder>::_String2Ansi (PCSZ szStr, BOOL & bNeedToFree)
|
||
throw (Exception &)
|
||
{
|
||
if ( HttpTool::IsAnsi () ) {
|
||
bNeedToFree = FALSE ;
|
||
return reinterpret_cast<PCSTR> (szStr) ;
|
||
}
|
||
|
||
DWORD cchAnsi = HttpEncoder::AnsiEncodeLen (szStr, m_nAnsiCodePage) ;
|
||
::SafeInt<size_t> cbRequired = 0 ;
|
||
|
||
try {
|
||
cbRequired += cchAnsi ;
|
||
cbRequired += 1 ;
|
||
cbRequired *= sizeof (CHAR) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
PSTR szBuff = (PSTR) ::malloc (cbRequired.Value ()) ;
|
||
if ( szBuff == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
try {
|
||
HttpEncoder::AnsiEncode (szBuff, szStr, m_nAnsiCodePage) ;
|
||
} catch (Exception &) {
|
||
SAFEFREE (szBuff) ;
|
||
throw ;
|
||
}
|
||
|
||
bNeedToFree = TRUE ;
|
||
return szBuff ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::_UrlEncodeLenA (PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
return HttpEncoder::UrlEncodeLenA (szStr, m_bUseUtf8, m_nAnsiCodePage) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
PCSTR CHttpClientT<HttpTool, HttpEncoder>::_UrlEncodeA (PSTR szBuff, PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
return HttpEncoder::UrlEncodeA (szBuff, szStr, m_bUseUtf8, m_nAnsiCodePage) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
PCSTR CHttpClientT<HttpTool, HttpEncoder>::_UrlEncodeA (PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
DWORD cchEncoded = _UrlEncodeLenA (szStr) ;
|
||
::SafeInt<size_t> cbRequired = 0 ;
|
||
try {
|
||
cbRequired += cchEncoded ;
|
||
cbRequired += 1 ;
|
||
cbRequired *= sizeof (CHAR) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
PSTR szBuff = (PSTR) ::malloc (cbRequired.Value ()) ;
|
||
if ( szBuff == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
try {
|
||
_UrlEncodeA (szBuff, szStr) ;
|
||
} catch (Exception &) {
|
||
SAFEFREE (szBuff) ;
|
||
throw ;
|
||
}
|
||
return szBuff ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::_UrlEncodeLen (PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
return HttpEncoder::UrlEncodeLen (szStr, m_bUseUtf8, m_nAnsiCodePage) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::_UrlEncode (PSZ szBuff, PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
return HttpEncoder::UrlEncode (szBuff, szStr, m_bUseUtf8, m_nAnsiCodePage) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::_UrlEncode (PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
DWORD cchEncoded = _UrlEncodeLen (szStr) ;
|
||
::SafeInt<size_t> cbRequired = 0 ;
|
||
try {
|
||
cbRequired += cchEncoded ;
|
||
cbRequired += 1 ;
|
||
cbRequired *= sizeof (CharType) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
PSZ szBuff = (PSZ) ::malloc (cbRequired.Value ()) ;
|
||
if ( szBuff == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
try {
|
||
_UrlEncode (szBuff, szStr) ;
|
||
} catch (Exception &) {
|
||
SAFEFREE (szBuff) ;
|
||
throw ;
|
||
}
|
||
return szBuff ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::_Utf8EncodeLen (PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
return HttpEncoder::Utf8EncodeLen (szStr, m_nAnsiCodePage) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
PCSTR CHttpClientT<HttpTool, HttpEncoder>::_Utf8Encode (PSTR szBuff, PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
return HttpEncoder::Utf8Encode (szBuff, szStr, m_nAnsiCodePage) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
PCSTR CHttpClientT<HttpTool, HttpEncoder>::_Utf8Encode (PCSZ szStr)
|
||
throw (Exception &)
|
||
{
|
||
DWORD cchEncoded = _Utf8EncodeLen (szStr) ;
|
||
::SafeInt<size_t> cbRequired = 0 ;
|
||
try {
|
||
cbRequired += cchEncoded ;
|
||
cbRequired += 1 ;
|
||
cbRequired *= sizeof (CHAR) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
PSTR szBuff = (PSTR) ::malloc (cbRequired.Value ()) ;
|
||
if ( szBuff == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
try {
|
||
_Utf8Encode (szBuff, szStr) ;
|
||
} catch (Exception &) {
|
||
SAFEFREE (szBuff) ;
|
||
throw ;
|
||
}
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method allocates memory and copies the target string if the szTargetString and the szOldString
|
||
* are not the same. If the szTargetString and the szOldString are the same, it returns szOldString.
|
||
*
|
||
* \param szTargetString [in] A target string to compare.
|
||
* \param szOldString [in] An original string to compare.
|
||
* \return A copied target string or szOldString.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::_AllocNCopyIfNewString (PCSZ szTargetString, PSZ szOldString)
|
||
throw (Exception &)
|
||
{
|
||
if ( szTargetString == szOldString )
|
||
return szOldString ;
|
||
|
||
if ( szTargetString == NULL )
|
||
return NULL ;
|
||
|
||
if ( szOldString && !HttpTool::StringCmp (szTargetString, szOldString) )
|
||
return szOldString ;
|
||
|
||
::SafeInt<size_t> cbRequired = 0 ;
|
||
try {
|
||
cbRequired = HttpTool::StringLen (szTargetString) ;
|
||
cbRequired++ ;
|
||
cbRequired *= sizeof (CharType) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
PSZ szNewString = (PSZ) ::malloc (cbRequired.Value ()) ;
|
||
if ( szNewString == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
HttpTool::StringCopy (szNewString, szTargetString) ;
|
||
return szNewString ;
|
||
}
|
||
|
||
/*!
|
||
* This method sets the current StrictFileCheck property.
|
||
* If the StrictFileCheck is TRUE, an exception will be thrown
|
||
* when it fails to open a file which is going to be uploaded.
|
||
* If FALSE, it does nothing. The default is FALSE.
|
||
*
|
||
* \param bStrict [in] A boolean value which specifies StrictFileCheck.
|
||
* \return Previously set value.
|
||
*
|
||
* The following code snippet demonstrates the usage of this property.
|
||
* \code
|
||
...
|
||
CHttpClient objHttpReq ;
|
||
|
||
// CHttpClient will throw a httpclientexception if it fails to open a file.
|
||
objHttpReq.SetStrictFileCheck (TRUE) ;
|
||
|
||
try {
|
||
// Adds HTTP parameters
|
||
objHttpReq.AddParam (_T ("title"), _T ("The memory of K-NET")) ;
|
||
objHttpReq.AddParam (_T ("photo"), _T ("C:\\myphoto\\k-net.jpg"), ParamFile) ;
|
||
|
||
// Starts a new HTTP UPLOAD
|
||
objHttpReq.RequestUpload (...) or objHttpReq.BeginUpload (...) ;
|
||
...
|
||
|
||
} catch (httpclientexception & e) {
|
||
// If it failed to open the file (C:\myphoto\k-net.jpg)
|
||
if ( e.LastError () == HTTPCLIENT_ERR_OPENFILE_FAILED ) {
|
||
... // Place error handling codes here.
|
||
}
|
||
...
|
||
}
|
||
* \endcode
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::SetStrictFileCheck (BOOL bStrict)
|
||
throw ()
|
||
{
|
||
BOOL bOldStrictFileCheck = m_bStrictFileCheck ;
|
||
m_bStrictFileCheck = bStrict ;
|
||
return bOldStrictFileCheck ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the current StrictFileCheck property.
|
||
* If the StrictFileCheck is TRUE, an exception will be thrown
|
||
* when it fails to open a file which is going to be uploaded.
|
||
* If FALSE, it does nothing. The default is FALSE.
|
||
*
|
||
* \return StrictFileCheck property.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::GetStrictFileCheck (void) const
|
||
throw ()
|
||
{
|
||
return m_bStrictFileCheck ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the current StrictFileCheck property.
|
||
* If the StrictFileCheck is TRUE, an exception will be thrown
|
||
* when it fails to open a file which is going to be uploaded.
|
||
* If FALSE, it does nothing. The default is FALSE.
|
||
*
|
||
* \return StrictFileCheck property.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::StrictFileCheck (void) const
|
||
throw ()
|
||
{
|
||
return GetStrictFileCheck () ;
|
||
}
|
||
|
||
|
||
/*!
|
||
* This method sets the current UseUtf8 property.
|
||
* If the UseUtf8 is TRUE, all request will be sent in UTF-8 encoding,
|
||
* otherwise, all request will be sent in ANSI encoding.
|
||
* If a web server uses UTF-8 encoding, you should set TRUE.
|
||
* It is not allowed to call this method if the BeginPost or BeginUpload method is not finished.
|
||
* The default is FALSE.
|
||
*
|
||
* \param bUseUtf8 [in] A boolean value which specifies UseUtf8.
|
||
* \return previously set value.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::SetUseUtf8 (BOOL bUseUtf8)
|
||
throw (Exception &)
|
||
{
|
||
// It is not allowed to call this method if the POST context is active.
|
||
if( _PostContextIsActive () ) {
|
||
OutputDebugString (L"CHttpClientT::SetUseUtf8: It is not allowed to call this method if the POST context is active.") ;
|
||
}
|
||
|
||
BOOL bOldUseUtf8 = m_bUseUtf8 ;
|
||
m_bUseUtf8 = bUseUtf8 ;
|
||
return bOldUseUtf8 ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the current UseUtf8 property.
|
||
* If the UseUtf8 is TRUE, all request will be sent in UTF-8 encoding,
|
||
* otherwise, all request will be sent in ANSI encoding.
|
||
* If a web server uses UTF-8 encoding, you should set TRUE.
|
||
* The default is FALSE.
|
||
*
|
||
* \return UseUtf8 property.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::GetUseUtf8 (void) const
|
||
throw ()
|
||
{
|
||
return m_bUseUtf8 ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the current UseUtf8 property.
|
||
* If the UseUtf8 is TRUE, all request will be sent in UTF-8 encoding,
|
||
* otherwise, all request will be sent in ANSI encoding.
|
||
* If a web server uses UTF-8 encoding, you should set TRUE.
|
||
* The default is FALSE.
|
||
*
|
||
* \return UseUtf8 property.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::UseUtf8 (void) const
|
||
throw ()
|
||
{
|
||
return GetUseUtf8 () ;
|
||
}
|
||
|
||
/*!
|
||
* This method sets the current ANSI code page which is used for all non-unicode strings.
|
||
* If a web server uses an ANSI character set, you should set an appropriate ANSI code page.
|
||
* It is not allowed to call this method if the BeginPost or BeginUpload method is not finished.
|
||
* For more infomation about the Code-Page Identifiers, see the MSDN documentation.
|
||
* The default is CP_ACP (which is the system's ANSI code page).
|
||
*
|
||
* \param nAnsiCodePage [in] An ANSI code page to set.
|
||
* \return previously set value.
|
||
*
|
||
* \sa ::WideCharToMultiByte, ::MultiByteToWideChar
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
UINT CHttpClientT<HttpTool, HttpEncoder>::SetAnsiCodePage (UINT nAnsiCodePage)
|
||
throw (Exception &)
|
||
{
|
||
// It is not allowed to call this method if the POST context is active.
|
||
HTTPCLIENT_ASSERT (!_PostContextIsActive ()
|
||
, "CHttpClientT::SetAnsiCodePage: It is not allowed to call this method if the POST context is active.") ;
|
||
|
||
// It is not allowed to set the unicode encodings
|
||
HTTPCLIENT_ASSERT ((nAnsiCodePage != CP_UTF8) && (nAnsiCodePage != CP_UTF7)
|
||
, "CHttpClientT::SetAnsiCodePage: CP_UTF8 and CP_UTF7 can not be used for the nAnsiCodePage parameter.") ;
|
||
|
||
UINT nOldAnsiCodePage = m_nAnsiCodePage ;
|
||
m_nAnsiCodePage = nAnsiCodePage ;
|
||
return nOldAnsiCodePage ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the current ANSI code page which is used for all non-unicode strings.
|
||
* If a web server uses an ANSI character set, you should set an appropriate ANSI code page.
|
||
* For more infomation about the Code-Page Identifiers, see the MSDN documentation.
|
||
* The default is CP_ACP (which is the system's ANSI code page).
|
||
*
|
||
* \return The current ANSI code page.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
UINT CHttpClientT<HttpTool, HttpEncoder>::GetAnsiCodePage (void) const
|
||
throw ()
|
||
{
|
||
return m_nAnsiCodePage ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the current ANSI code page which is used for all non-unicode strings.
|
||
* If a web server uses an ANSI character set, you should set an appropriate ANSI code page.
|
||
* For more infomation about the Code-Page Identifiers, see the MSDN documentation.
|
||
* The default is CP_ACP (which is the system's ANSI code page).
|
||
*
|
||
* \return The current ANSI code page.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
UINT CHttpClientT<HttpTool, HttpEncoder>::AnsiCodePage (void) const
|
||
throw ()
|
||
{
|
||
return GetAnsiCodePage () ;
|
||
}
|
||
|
||
/*!
|
||
* This method erases all HTTP headers which is sent to a web server.
|
||
*
|
||
* \return FALSE if all header is aleady erased, otherwise TRUE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::ClearHeader (void)
|
||
throw ()
|
||
{
|
||
return m_mapHeader.Clear () ;
|
||
}
|
||
|
||
/*!
|
||
* This method erases a HTTP header at the given index specified by nIdx.
|
||
*
|
||
* \param nIdx [in] A header index to remove.
|
||
* \return TRUE if the header is found and removed, otherwise FALSE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::RemoveHeader (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapHeader.Remove (nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method erases a HTTP header of which name is szName.
|
||
* If the header has multiple values, you can specify a zero-based index for a specific value.
|
||
*
|
||
* \param szName [in] A case-insensitive header name to remove. NULL is not allowed.
|
||
* \param nIdx [in] A zero-based value index if the header has multiple values. The default is zero.
|
||
* \return TRUE if the header is found and removed, otherwise FALSE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::RemoveHeader (PCSZ szName, DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapHeader.Remove (szName, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method erases all HTTP headers of which name is szName.
|
||
*
|
||
* \param szName [in] A case-insensitive header name to remove. NULL is not allowed.
|
||
* \return TRUE if the header is found and removed, otherwise FALSE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::RemoveAllHeader (PCSZ szName)
|
||
throw ()
|
||
{
|
||
return m_mapHeader.RemoveAll (szName) ;
|
||
}
|
||
|
||
/*!
|
||
* This method adds a new HTTP header.
|
||
* The header's name and the header's value can not be NULL or an empty string.
|
||
*
|
||
* \param szName [in] A case-insensitive header name. NULL or an empty string is not allowed.
|
||
* \param szValue [in] A header value. NULL or an empty string is not allowed.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::AddHeader (PCSZ szName, PCSZ szValue)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpClientT::AddHeader: szName can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (szName[0] != '\0', "CHttpClientT::AddHeader: szName can not be an empty string.") ;
|
||
HTTPCLIENT_ASSERT (szValue != NULL, "CHttpClientT::AddHeader: szValue can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (szValue[0] != '\0', "CHttpClientT::AddHeader: szValue can not be an empty string.") ;
|
||
m_mapHeader.Add (szName, szValue) ;
|
||
}
|
||
|
||
/*!
|
||
* This method modifies the HTTP header value of which name is szName.
|
||
* If the header has multiple values, you can specify a zero-based index for a specific value.
|
||
* If the header is not found and the nIdx is zero, it will add a new header.
|
||
* The header's name and the header's value can not be NULL or an empty string.
|
||
*
|
||
* \param szName [in] A case-insensitive header name. NULL or an empty string is not allowed.
|
||
* \param szValue [in] A header value. NULL or an empty string is not allowed.
|
||
* \param nIdx [in] A zero-based value index if the header has multiple values. The default is zero.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::SetHeader (PCSZ szName, PCSZ szValue, DWORD nIdx)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szName != NULL, "CHttpClientT::SetHeader: szName can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (szName[0] != '\0', "CHttpClientT::SetHeader: szName can not be an empty string.") ;
|
||
HTTPCLIENT_ASSERT (szValue != NULL, "CHttpClientT::SetHeader: szValue can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (szValue[0] != '\0', "CHttpClientT::SetHeader: szValue can not be an empty string.") ;
|
||
m_mapHeader.Set (szName, szValue, 0, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a HTTP header name at the given index specified by nIdx.
|
||
* If the index is out of range, it will return NULL. Otherwise it always returns a null-terminated string.
|
||
* The returned string is owned by the CHttpClientT. So you can not free it.
|
||
*
|
||
* \param nIdx [in] A zero-based header index.
|
||
* \return A header name.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetHeaderName (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapHeader.GetKey (nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a HTTP header at the given index specified by nIdx.
|
||
* If the index is out of range, it will return NULL. Otherwise it always returns a null-terminated string.
|
||
* The returned string is owned by the CHttpClient. So you can not free it.
|
||
*
|
||
* \param nIdx [in] A zero-based header index.
|
||
* \return A header.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetHeader (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapHeader.GetValue (nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a HTTP header of which name is szName.
|
||
* If the header has multiple values, you can specify a zero-based index for a specific value.
|
||
* If the header is not found, it will return NULL. Otherwise it always returns a null-terminated string.
|
||
* The returned string is owned by the CHttpClient. So you can not free it.
|
||
*
|
||
* \param szName [in] A case-insensitive header name to find. NULL is not allowed.
|
||
* \param nIdx [in] A zero-based value index if the header has multiple values. The default is zero.
|
||
* \return A header.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetHeader (PCSZ szName, DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapHeader.GetValue (szName, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns whether the HTTP header of which name is szName exists.
|
||
* If the header has multiple values, you can specify a zero-based index for a specific value.
|
||
*
|
||
* \param szName [in] A case-insensitive header name to find. NULL is not allowed.
|
||
* \param nIdx [in] A zero-based value index if the header has multiple values. The default is zero.
|
||
* \return TRUE if the header is found, otherwise FALSE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::HeaderExists (PCSZ szName, DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapHeader.Exists (szName, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of HTTP headers of which name is szName.
|
||
* If the szName is NULL, it will return the number of all headers.
|
||
*
|
||
* \param szName [in] A case-insensitive header name to find.
|
||
* \return The number of headers.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::GetHeaderCount (PCSZ szName)
|
||
throw ()
|
||
{
|
||
return m_mapHeader.Count (szName) ;
|
||
}
|
||
|
||
/*!
|
||
* This method erases all HTTP parameters.
|
||
* It is not allowed to call this method if the BeginPost or BeginUpload method is not finished.
|
||
*
|
||
* \return FALSE if all parameter is aleady erased, otherwise TRUE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::ClearParam (void)
|
||
throw (Exception &)
|
||
{
|
||
// It is not allowed to call this method if the POST context is active.
|
||
HTTPCLIENT_ASSERT (!_PostContextIsActive ()
|
||
, "CHttpClientT::ClearParam: It is not allowed to call this method if the POST context is active.") ;
|
||
return m_mapParam.Clear () ;
|
||
}
|
||
|
||
/*!
|
||
* This method erases a HTTP parameter at the given index specified by nIdx.
|
||
* It is not allowed to call this method if the BeginPost or BeginUpload method is not finished.
|
||
*
|
||
* \param nIdx [in] A zero-based parameter index to remove.
|
||
* \return TRUE if the parameter is found and removed, otherwise FALSE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::RemoveParam (DWORD nIdx)
|
||
throw (Exception &)
|
||
{
|
||
// It is not allowed to call this method if the POST context is active.
|
||
HTTPCLIENT_ASSERT (!_PostContextIsActive ()
|
||
, "CHttpClientT::RemoveParam: It is not allowed to call this method if the POST context is active.") ;
|
||
return m_mapParam.Remove (nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method erases a HTTP parameter of which name is szName.
|
||
* If the parameter has multiple values, you can specify a zero-based index for a specific value.
|
||
* It is not allowed to call this method if the BeginPost or BeginUpload method is not finished.
|
||
*
|
||
* \param szName [in] A case-insensitive parameter name to remove. NULL is not allowed.
|
||
* \param nIdx [in] A zero-based value index if the parameter has multiple values. The default is zero.
|
||
* \return TRUE if the parameter is found and removed, otherwise FALSE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::RemoveParam (PCSZ szName, DWORD nIdx)
|
||
throw (Exception &)
|
||
{
|
||
// It is not allowed to call this method if the POST context is active.
|
||
HTTPCLIENT_ASSERT (!_PostContextIsActive ()
|
||
, "CHttpClientT::RemoveParam: It is not allowed to call this method if the POST context is active.") ;
|
||
return m_mapParam.Remove (szName, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method erases all HTTP parameters of which name is szName.
|
||
* It is not allowed to call this method if the BeginPost or BeginUpload method is not finished.
|
||
*
|
||
* \param szName [in] A case-insensitive parameter name to remove. NULL is not allowed.
|
||
* \return TRUE if the parameter is found and removed, otherwise FALSE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::RemoveAllParam (PCSZ szName)
|
||
throw (Exception &)
|
||
{
|
||
// It is not allowed to call this method if the POST context is active.
|
||
HTTPCLIENT_ASSERT (!_PostContextIsActive ()
|
||
, "CHttpClientT::RemoveAllParam: It is not allowed to call this method if the POST context is active.") ;
|
||
return m_mapParam.RemoveAll (szName) ;
|
||
}
|
||
|
||
/*!
|
||
* This method adds a new HTTP parameter. The dwParamAttr specifies parameter attributes.
|
||
* For more information about parameter attributes, see the ParamAttr enumerator.
|
||
* It is not allowed to call this method if the BeginPost or BeginUpload method is not finished.
|
||
*
|
||
* \param szName [in] A case-insensitive parameter name. NULL is not allowed.
|
||
* \param szValue [in] A parameter value. The default is NULL.
|
||
* \param dwParamAttr [in] A parameter attribute.
|
||
* This is a bitwise Ored value of the ParamAttr enumerator.
|
||
* The default is ParamNormal.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ParamAttr
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::AddParam (PCSZ szName, PCSZ szValue, DWORD dwParamAttr)
|
||
throw (Exception &)
|
||
{
|
||
// It is not allowed to call this method if the POST context is active.
|
||
/*HTTPCLIENT_ASSERT (!_PostContextIsActive ()
|
||
, "CHttpClientT::AddParam: It is not allowed to call this method if the POST context is active.") ;*/
|
||
if( _PostContextIsActive () ) {
|
||
OutputDebugString(L"CHttpClientT::AddParam: It is not allowed to call this method if the POST context is active.\n");
|
||
}
|
||
m_mapParam.Add (szName, szValue, dwParamAttr) ;
|
||
}
|
||
|
||
/*!
|
||
* This method modifies the HTTP parameter value of which name is szName.
|
||
* If the parameter has multiple values, you can specify a zero-based index for a specific value.
|
||
* If the parameter is not found and the nIdx is zero, it will add a new parameter.
|
||
* The dwParamAttr specifies parameter attributes.
|
||
* For more information about parameter attributes, see the ParamAttr enumerator.
|
||
* It is not allowed to call this method if the BeginPost or BeginUpload method is not finished.
|
||
*
|
||
* \param szName [in] A case-insensitive parameter name. NULL is not allowed.
|
||
* \param szValue [in] A parameter value. The default is NULL.
|
||
* \param dwParamAttr [in] A parameter attribute.
|
||
* This is a bitwise Ored value of the ParamAttr enumerator.
|
||
* The default is ParamNormal.
|
||
* \param nIdx [in] A zero-based value index if the parameter has multiple values.
|
||
* The default is zero.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ParamAttr
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::SetParam (PCSZ szName, PCSZ szValue, DWORD dwParamAttr, DWORD nIdx)
|
||
throw (Exception &)
|
||
{
|
||
// It is not allowed to call this method if the POST context is active.
|
||
HTTPCLIENT_ASSERT (!_PostContextIsActive ()
|
||
, "CHttpClientT::SetParam: It is not allowed to call this method if the POST context is active.") ;
|
||
m_mapParam.Set (szName, szValue, dwParamAttr, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a HTTP parameter name at the given index specified by nIdx.
|
||
* If the index is out of range, it will return NULL. Otherwise it always returns a null-terminated string.
|
||
* The returned string is owned by the CHttpClient. So you can not free it.
|
||
*
|
||
* \param nIdx [in] A zero-based parameter index.
|
||
* \return A parameter name.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetParamName (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapParam.GetKey (nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a HTTP parameter at the given index specified by nIdx.
|
||
* If the index is out of range, it will return NULL. Otherwise it always returns a null-terminated string.
|
||
* The returned string is owned by the CHttpClient. So you can not free it.
|
||
*
|
||
* \param nIdx [in] A zero-based parameter index.
|
||
* \return A parameter.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetParam (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapParam.GetValue (nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a HTTP parameter of which name is szName.
|
||
* If the parameter has multiple values, you can specify a zero-based index for a specific value.
|
||
* If the parameter is not found, it will return NULL. Otherwise it always returns a null-terminated string.
|
||
* The returned string is owned by the CHttpClient. So you can not free it.
|
||
*
|
||
* \param szName [in] A case-insensitive parameter name to find. NULL is not allowed.
|
||
* \param nIdx [in] A zero-based value index if the parameter has multiple values.
|
||
* The default is zero.
|
||
* \return A parameter.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetParam (PCSZ szName, DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapParam.GetValue (szName, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a HTTP parameter attribute at the given index specified by nIdx.
|
||
* If the index is out of range or the attribute is 0, it will return 0.
|
||
*
|
||
* \param nIdx [in] A zero-based parameter index.
|
||
* \return A parameter attribute.
|
||
*
|
||
* \sa ParamAttr
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::GetParamAttr (DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapParam.GetFlag (nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns an attribute of the HTTP parameter of which name is szName.
|
||
* If the parameter has multiple values, you can specify a zero-based index for a specific value.
|
||
* If the parameter is not found or the attribute is 0, it will return 0.
|
||
*
|
||
* \param szName [in] A case-insensitive parameter name to find. NULL is not allowed.
|
||
* \param nIdx [in] A zero-based value index if the parameter has multiple values.
|
||
* The default is zero.
|
||
* \return A parameter attribute.
|
||
*
|
||
* \sa ParamAttr
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::GetParamAttr (PCSZ szName, DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapParam.GetFlag (szName, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns whether the HTTP parameter of which name is szName exists.
|
||
* If the parameter has multiple values, you can specify a zero-based index for a specific value.
|
||
*
|
||
* \param szName [in] A case-insensitive parameter name to find. NULL is not allowed.
|
||
* \param nIdx [in] A zero-based value index if the parameter has multiple values.
|
||
* The default is zero.
|
||
* \return TRUE if the parameter is found, otherwise FALSE.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::ParamExists (PCSZ szName, DWORD nIdx)
|
||
throw ()
|
||
{
|
||
return m_mapParam.Exists (szName, nIdx) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the number of HTTP parameters of which name is szName.
|
||
* If the szName is NULL, it will return the number of all parameters.
|
||
*
|
||
* \param szName [in] A case-insensitive parameter name to find.
|
||
* The default is NULL.
|
||
* \return The number of parameters.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::GetParamCount (PCSZ szName)
|
||
throw ()
|
||
{
|
||
return m_mapParam.Count (szName) ;
|
||
}
|
||
|
||
|
||
|
||
/*!
|
||
* This method sets parameters for the ::InternetOpen function which is called internally before sending a request.
|
||
* All parameters passed to this method is forwarded to the ::InternetOpen function.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* The following code snippet demonstrates the usage of this method.
|
||
* \code
|
||
...
|
||
CHttpClient objHttpReq ;
|
||
|
||
try {
|
||
// Changes the HTTP user agent.
|
||
objHttpReq.SetInternet (_T ("My Custom User Agent")) ;
|
||
...
|
||
|
||
} catch (httpclientexception & e) {
|
||
... // Place error handling codes here.
|
||
}
|
||
* \endcode
|
||
*
|
||
* \param szUserAgent [in] A User Agent which corresponds to the lpszAgent parameter of the ::InternetOpen function.
|
||
* \param dwAccessType [in] A type of access which corresponds to the dwAccessType parameter of the ::InternetOpen function.
|
||
* \param szProxyName [in] A name of a proxy server which corresponds to the lpszProxyName parameter of the ::InternetOpen function.
|
||
* \param szProxyBypass [in] A proxy bypass list which corresponds to the lpszProxyBypass parameter of the ::InternetOpen function.
|
||
* \param dwFlags [in] Options which corresponds to the dwFlags parameter of the ::InternetOpen function.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ::InternetOpen
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::SetInternet (PCSZ szUserAgent, DWORD dwAccessType
|
||
, PCSZ szProxyName, PCSZ szProxyBypass
|
||
, DWORD dwFlags)
|
||
throw (Exception &)
|
||
{
|
||
PSZ szNewUserAgent = NULL ;
|
||
PSZ szNewProxyName = NULL ;
|
||
PSZ szNewProxyBypass = NULL ;
|
||
|
||
try {
|
||
szNewUserAgent = _AllocNCopyIfNewString (szUserAgent, m_szInternetUserAgent) ;
|
||
szNewProxyName = _AllocNCopyIfNewString (szProxyName, m_szInternetProxyName) ;
|
||
szNewProxyBypass = _AllocNCopyIfNewString (szProxyBypass, m_szInternetProxyBypass) ;
|
||
} catch (Exception &) {
|
||
if ( m_szInternetUserAgent != szNewUserAgent ) SAFEFREE (szNewUserAgent) ;
|
||
if ( m_szInternetProxyName != szNewProxyName ) SAFEFREE (szNewProxyName) ;
|
||
if ( m_szInternetProxyBypass != szNewProxyBypass ) SAFEFREE (szNewProxyBypass) ;
|
||
throw httpclientexceptionA();
|
||
}
|
||
|
||
if ( m_szInternetUserAgent != szNewUserAgent ) {
|
||
SAFEFREE (m_szInternetUserAgent) ;
|
||
m_szInternetUserAgent = szNewUserAgent ;
|
||
}
|
||
|
||
if ( m_szInternetProxyName != szNewProxyName ) {
|
||
SAFEFREE (m_szInternetProxyName) ;
|
||
m_szInternetProxyName = szNewProxyName ;
|
||
}
|
||
|
||
if ( m_szInternetProxyBypass != szNewProxyBypass ) {
|
||
SAFEFREE (m_szInternetProxyBypass) ;
|
||
m_szInternetProxyBypass = szNewProxyBypass ;
|
||
}
|
||
|
||
m_dwInternetAccessType = dwAccessType ;
|
||
m_dwInternetFlags = dwFlags ;
|
||
}
|
||
|
||
/*!
|
||
* This method sets the lpszAgent parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* The parameter passed to this method is forwarded to the ::InternetOpen function.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \param szUserAgent [in] A User Agent which corresponds to the lpszAgent parameter of the ::InternetOpen function.
|
||
* If this is NULL, The default is used.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::SetInternetUserAgent (PCSZ szUserAgent)
|
||
throw (Exception &)
|
||
{
|
||
PSZ szNewUserAgent = NULL ;
|
||
|
||
try {
|
||
szNewUserAgent = _AllocNCopyIfNewString (szUserAgent, m_szInternetUserAgent) ;
|
||
} catch (Exception &) {
|
||
if ( m_szInternetUserAgent != szNewUserAgent ) SAFEFREE (szNewUserAgent) ;
|
||
throw ;
|
||
}
|
||
|
||
if ( m_szInternetUserAgent != szNewUserAgent ) {
|
||
SAFEFREE (m_szInternetUserAgent) ;
|
||
m_szInternetUserAgent = szNewUserAgent ;
|
||
}
|
||
}
|
||
|
||
/*!
|
||
* This method returns the lpszAgent parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \return A User Agent which corresponds to the lpszAgent parameter of the ::InternetOpen function.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetInternetUserAgent (void)
|
||
throw ()
|
||
{
|
||
return m_szInternetUserAgent ? m_szInternetUserAgent : HttpTool::szDefUsrAgent ;
|
||
}
|
||
|
||
|
||
/*!
|
||
* This method sets the dwAccessType parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* The parameter passed to this method is forwarded to the ::InternetOpen function.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \param dwAccessType [in] A type of access which corresponds to the dwAccessType parameter of the ::InternetOpen function.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::SetInternetAccessType (DWORD dwAccessType)
|
||
throw ()
|
||
{
|
||
m_dwInternetAccessType = dwAccessType ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the dwAccessType parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \return A type of access which corresponds to the dwAccessType parameter of the ::InternetOpen function.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::GetInternetAccessType (void)
|
||
throw ()
|
||
{
|
||
return m_dwInternetAccessType ;
|
||
}
|
||
|
||
/*!
|
||
* This method sets the lpszProxyName parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* The parameter passed to this method is forwarded to the ::InternetOpen function.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \param szProxyName [in] A proxy server name which corresponds to the lpszProxyName parameter of the ::InternetOpen function.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::SetInternetProxyName (PCSZ szProxyName)
|
||
throw (Exception &)
|
||
{
|
||
PSZ szNewProxyName = NULL ;
|
||
|
||
try {
|
||
szNewProxyName = _AllocNCopyIfNewString (szProxyName, m_szInternetProxyName) ;
|
||
} catch (Exception &) {
|
||
if ( m_szInternetProxyName != szNewProxyName ) SAFEFREE (szNewProxyName) ;
|
||
throw ;
|
||
}
|
||
|
||
if ( m_szInternetProxyName != szNewProxyName ) {
|
||
SAFEFREE (m_szInternetProxyName) ;
|
||
m_szInternetProxyName = szNewProxyName ;
|
||
}
|
||
}
|
||
|
||
/*!
|
||
* This method returns the lpszProxyName parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \return A proxy server name which corresponds to the lpszProxyName parameter of the ::InternetOpen function.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetInternetProxyName (void)
|
||
throw ()
|
||
{
|
||
return m_szInternetProxyName ;
|
||
}
|
||
|
||
|
||
/*!
|
||
* This method sets the lpszProxyBypass parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* The parameter passed to this method is forwarded to the ::InternetOpen function.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \param szProxyBypass [in] A proxy bypass list which corresponds to the lpszProxyBypass parameter of the ::InternetOpen function.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::SetInternetProxyBypass (PCSZ szProxyBypass)
|
||
throw (Exception &)
|
||
{
|
||
PSZ szNewProxyBypass = NULL ;
|
||
|
||
try {
|
||
szNewProxyBypass = _AllocNCopyIfNewString (szProxyBypass, m_szInternetProxyBypass) ;
|
||
} catch (Exception &) {
|
||
if ( m_szInternetProxyBypass != szNewProxyBypass ) SAFEFREE (szNewProxyBypass) ;
|
||
throw ;
|
||
}
|
||
|
||
if ( m_szInternetProxyBypass != szNewProxyBypass ) {
|
||
SAFEFREE (m_szInternetProxyBypass) ;
|
||
m_szInternetProxyBypass = szNewProxyBypass ;
|
||
}
|
||
}
|
||
|
||
/*!
|
||
* This method returns the lpszProxyBypass parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \return A proxy bypass list which corresponds to the lpszProxyBypass parameter of the ::InternetOpen function.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetInternetProxyBypass (void)
|
||
throw ()
|
||
{
|
||
return m_szInternetProxyBypass ;
|
||
}
|
||
|
||
/*!
|
||
* This method sets the dwFlags parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* The parameter passed to this method is forwarded to the ::InternetOpen function.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \param dwFlags [in] Options which corresponds to the dwFlags parameter of the ::InternetOpen function.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::SetInternetFlags (DWORD dwFlags)
|
||
throw ()
|
||
{
|
||
m_dwInternetFlags = dwFlags ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the dwFlags parameter for the ::InternetOpen function which is called internally before sending a request.
|
||
* For more infomation about the ::InternetOpen function, see the MSDN documentation.
|
||
*
|
||
* \return Options which corresponds to the dwFlags parameter of the ::InternetOpen function.
|
||
*
|
||
* \sa ::InternetOpen, SetInternet
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::GetInternetFlags (void)
|
||
throw ()
|
||
{
|
||
return m_dwInternetFlags ;
|
||
}
|
||
|
||
|
||
/*!
|
||
* This method returns the number of characters required to make a URL for a HTTP
|
||
* GET request. If you want to pass some parameters to a web server using HTTP GET,
|
||
* you have to append parameters to the requested URL. This method calculates
|
||
* the length of the URL for that situation. If the CHttpClient does not contain any
|
||
* HTTP parameters, it returns the length of the szUrl. Otherwise it returns
|
||
* the calculated length. It does not check whether the szUrl is valid.
|
||
* If the szUrl is NULL, it returns the length of the appended parameters.
|
||
* (Not including the beginning '?' character)
|
||
* The returned value does not include the terminating NULL character.
|
||
*
|
||
* \param szUrl [in] An URL which is used to calculate the length of the GET URL.
|
||
* \return The number of characters required. (Not including the terminating NULL character)
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
DWORD CHttpClientT<HttpTool, HttpEncoder>::MakeGetUrlLen (PCSZ szUrl)
|
||
throw (Exception &)
|
||
{
|
||
// Calculates the number of required characters
|
||
::SafeInt<DWORD> cchUrlForGet = 0 ;
|
||
|
||
try {
|
||
cchUrlForGet = szUrl ? HttpTool::StringLen (szUrl) : 0 ;
|
||
|
||
if ( m_mapParam.Empty () )
|
||
return cchUrlForGet.Value () ;
|
||
|
||
for (ConstMapIter iter = m_mapParam.Begin (); iter != m_mapParam.End (); ++iter) {
|
||
// If the parameter's name is a URL-encoded string
|
||
if ( (iter->second).dwFlag & ParamEncodedName )
|
||
cchUrlForGet += (iter->first ? HttpTool::StringLen (iter->first) : 0) ;
|
||
else
|
||
cchUrlForGet += _UrlEncodeLen (iter->first) ;
|
||
|
||
// If the parameter's value is a URL-encoded string
|
||
if ( (iter->second).dwFlag & ParamEncodedValue )
|
||
cchUrlForGet += ((iter->second).szValue ? HttpTool::StringLen ((iter->second).szValue) : 0) ;
|
||
else
|
||
cchUrlForGet += _UrlEncodeLen ((iter->second).szValue) ;
|
||
|
||
cchUrlForGet += 2 ; // for ('?' or '&') and '='
|
||
}
|
||
|
||
// If the szUrl is NULL, it does not insert '?' or '&' character
|
||
// which divides the GET URL into the szUrl and HTTP parameters.
|
||
if ( szUrl == NULL && m_mapParam.Count () >= 0 )
|
||
cchUrlForGet-- ;
|
||
|
||
// If the URL does not contain the path (ex. 'http://www.kw.ac.kr')
|
||
// we have to append '/' to the URL.
|
||
// It does not care whether the server address exists.
|
||
// (It does not check the URL)
|
||
if ( szUrl ) {
|
||
CHttpUrlAnalyzer objAnalyzer (szUrl, m_nAnsiCodePage) ;
|
||
|
||
if ( objAnalyzer.PathLen () == 0 )
|
||
cchUrlForGet++ ;
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
return cchUrlForGet.Value () ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a URL for a HTTP GET request.
|
||
* If you want to pass some parameters to a web server using HTTP GET,
|
||
* you have to append parameters to the requested URL. This method creates a URL for that situation.
|
||
* If the CHttpClient does not contain any HTTP parameters, it returns the szUrl.
|
||
* It does not check whether the szUrl is valid.
|
||
* If the szUrl is NULL, it copies only the appended parameters.
|
||
* (Not including the beginning '?' character)
|
||
*
|
||
* \param szBuff [out] A buffer to save the GET URL. The buffer can not be NULL.
|
||
* \param szUrl [in] An URL which is used to make a URL for a HTTP GET request.
|
||
* \return A generated URL.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::MakeGetUrl (PSZ szBuff, PCSZ szUrl)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (szBuff != NULL, "CHttpClientT::MakeGetUrl: szBuff can not be NULL.") ;
|
||
|
||
if ( m_mapParam.Empty () ) {
|
||
if ( szUrl == NULL ) {
|
||
szBuff[0] = '\0' ;
|
||
return szBuff ;
|
||
}
|
||
|
||
HttpTool::StringCopy (szBuff, szUrl) ;
|
||
return szBuff ;
|
||
}
|
||
|
||
PSZ pchBuff = szBuff ;
|
||
DWORD i ;
|
||
CHttpUrlAnalyzer objAnalyzer (szUrl, m_nAnsiCodePage) ;
|
||
|
||
if ( szUrl ) {
|
||
for (i = 0; i < objAnalyzer.PathIdx (); *(pchBuff++) = szUrl[i], i++) ;
|
||
|
||
// If the path does not exist, it is needed to append '/' to the server address.
|
||
if ( objAnalyzer.PathLen () == 0 )
|
||
*(pchBuff++) = '/' ;
|
||
|
||
// Appends the path and the search string.
|
||
for (i = objAnalyzer.PathIdx (); i < objAnalyzer.BookmarkIdx (); *(pchBuff++) = szUrl[i], i++) ;
|
||
|
||
// Copies '?' or '&'
|
||
*(pchBuff++) = objAnalyzer.SearchLen () == 0 ? '?' : '&' ;
|
||
}
|
||
|
||
// Copies the HTTP parameters
|
||
for (ConstMapIter iter = m_mapParam.Begin (); iter != m_mapParam.End (); ++iter) {
|
||
if ( iter != m_mapParam.Begin () )
|
||
*(pchBuff++) = '&' ;
|
||
|
||
// If the parameter's name is a URL-encoded string
|
||
if ( (iter->second).dwFlag & ParamEncodedName )
|
||
HttpTool::StringCopy (pchBuff
|
||
, iter->first ? iter->first : HttpTool::szEmptyString) ;
|
||
else
|
||
_UrlEncode (pchBuff, iter->first) ;
|
||
|
||
for (; *pchBuff != '\0'; pchBuff++) ;
|
||
|
||
*(pchBuff++) = '=' ;
|
||
|
||
// If the parameter's value is a URL-encoded string
|
||
if ( (iter->second).dwFlag & ParamEncodedValue )
|
||
HttpTool::StringCopy (pchBuff
|
||
, (iter->second).szValue ? (iter->second).szValue : HttpTool::szEmptyString) ;
|
||
else
|
||
_UrlEncode (pchBuff, (iter->second).szValue) ;
|
||
|
||
for (; *pchBuff != '\0'; pchBuff++) ;
|
||
}
|
||
|
||
// Appends the bookmark
|
||
for (i = objAnalyzer.BookmarkIdx (); i < objAnalyzer.BookmarkIdx () + objAnalyzer.BookmarkLen (); *(pchBuff++) = szUrl[i], i++) ;
|
||
*pchBuff = '\0' ;
|
||
|
||
return szBuff ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a new HINTERNET handle which is returned by ::InternetOpen
|
||
* using the settings saved in the CHttpClient.
|
||
* The caller is responsible for closing the returned handle when it has finished with it.
|
||
*
|
||
* \return A new HINTERNET handle.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ::InternetOpen
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
HINTERNET CHttpClientT<HttpTool, HttpEncoder>::OpenInternet (void)
|
||
throw (Exception &)
|
||
{
|
||
return HttpTool::OpenInternet (
|
||
GetInternetUserAgent (), GetInternetAccessType (), GetInternetProxyName (),
|
||
GetInternetProxyBypass (), GetInternetFlags ()) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a new HINTERNET handle which is returned by ::InternetConnect.
|
||
* It only checks the protocol, server address and server port of the URL.
|
||
* So you can use the following URLs.
|
||
* <UL>
|
||
* <LI>http://www.k-net.or.kr:80/member.html?type=5 -> A full HTTP URL (or a full HTTPS URL)</LI>
|
||
* <LI>http://club.hooriza.com:80 -> A HTTP URL without path (or a HTTPS URL without path)</LI>
|
||
* <LI>wedding.makeself.net:80 -> Only a server location (http is assumed)</LI>
|
||
* <LI>www.kw.ac.kr/index.html -> A URL without protocol (http is assumed)</LI>
|
||
* <LI>ftp://knews.k-net.or.kr -> An URL with another protocol (http is assumed)</LI>
|
||
* </UL>
|
||
*
|
||
* The caller is responsible for closing the returned handle when it has finished with it.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen.
|
||
* \param szUrl [in] An URL which is used to return a new handle.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A new HINTERNET handle.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ::InternetConnect
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
HINTERNET CHttpClientT<HttpTool, HttpEncoder>::OpenConnection (HINTERNET hInternet, PCSZ szUrl, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (hInternet != NULL, "CHttpClientT::OpenConnection: hInternet can not be NULL.") ;
|
||
|
||
INTERNET_PORT nPort = INTERNET_DEFAULT_HTTP_PORT ;
|
||
CHttpUrlAnalyzer objAnalyzer (szUrl, m_nAnsiCodePage) ;
|
||
|
||
// If the protocol is HTTPS, the default port is INTERNET_DEFAULT_HTTPS_PORT.
|
||
if ( (objAnalyzer.ProtocolLen () == 5 /* ::strlen ("HTTPS") */)
|
||
&& (0 == HttpTool::StringNICmp (
|
||
szUrl + objAnalyzer.ProtocolIdx (), HttpTool::szHTTPS, objAnalyzer.ProtocolLen ())) )
|
||
nPort = INTERNET_DEFAULT_HTTPS_PORT ;
|
||
|
||
// Get the server port
|
||
if ( objAnalyzer.PortLen () > 0 ) {
|
||
// The port number can not be greater than 65535
|
||
if ( objAnalyzer.PortLen () > 5 )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_INTERNET_PORT_NOT_VALID) ;
|
||
|
||
CharType szPort[6] ;
|
||
HttpTool::StringNCopy (szPort, szUrl + objAnalyzer.PortIdx (), objAnalyzer.PortLen ()) ;
|
||
szPort[objAnalyzer.PortLen ()] = '\0' ;
|
||
|
||
unsigned long ulPort ;
|
||
PSZ pEndPtr ;
|
||
ulPort = HttpTool::StringToUL (szPort, &pEndPtr, 10) ;
|
||
if ( *pEndPtr != NULL || ulPort > 65535 )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_INTERNET_PORT_NOT_VALID) ;
|
||
nPort = static_cast<INTERNET_PORT> (ulPort) ;
|
||
}
|
||
|
||
// Get the server address
|
||
if ( objAnalyzer.AddressLen () == 0 )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_INVALID_URL) ;
|
||
|
||
::SafeInt<size_t> cbAddress = 0 ;
|
||
try {
|
||
cbAddress = objAnalyzer.AddressLen () ;
|
||
cbAddress += 1 ;
|
||
cbAddress *= sizeof (CharType) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
PSZ szServerAddr = (PSZ) ::malloc (cbAddress.Value ()) ;
|
||
if ( szServerAddr == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
HttpTool::StringNCopy (szServerAddr, szUrl + objAnalyzer.AddressIdx (), objAnalyzer.AddressLen ()) ;
|
||
szServerAddr[objAnalyzer.AddressLen ()] = '\0' ;
|
||
|
||
HINTERNET hConnection = NULL ;
|
||
try {
|
||
hConnection = HttpTool::OpenConnection (hInternet, szServerAddr, nPort, szUsrName, szUsrPwd) ;
|
||
// Applys proxy server account
|
||
ApplyProxyAccount (hConnection) ;
|
||
} catch (Exception &) {
|
||
SAFEFREE (szServerAddr) ;
|
||
HttpTool::CloseConnection (hConnection) ;
|
||
throw ;
|
||
}
|
||
|
||
SAFEFREE (szServerAddr) ;
|
||
return hConnection ;
|
||
}
|
||
|
||
/*!
|
||
* This method sets a user name and a password which are used to access HTTP proxy server.
|
||
* If the szUserName parameter is NULL, the proxy account saved in CHttpClient will be removed.
|
||
* You can handle proxy authorization using this method, but there are some restrictions.
|
||
* First, The HTTP POST is not safe if you are not an authorized user.
|
||
* (It is possible that the proxy server closes the connection before the request is finished).
|
||
* Second, Only the HTTP GET can be used to request proxy authorization.
|
||
* (This restriction is caused by the WinInet API).
|
||
*
|
||
* The following code snippet demonstrates the usage of this method.
|
||
* \code
|
||
...
|
||
CHttpClient objHttpReq ;
|
||
CHttpResponse * pobjHttpRes = NULL ;
|
||
|
||
try {
|
||
... // Initialize the CHttpClient object
|
||
|
||
// It is safe to use HTTP GET method.
|
||
pobjHttpRes = objHttpReq.RequestGet (...) ;
|
||
|
||
// If the server requests proxy authorization..
|
||
if ( pobjHttpRes->GetStatus () == HTTP_STATUS_PROXY_AUTH_REQ ) {
|
||
delete pobjHttpRes ;
|
||
pobjHttpRes = NULL ;
|
||
|
||
LPTSTR szUserName = NULL ;
|
||
LPTSTR szPassword = NULL ;
|
||
|
||
... // Get a proxy user name and password
|
||
|
||
// Set the proxy user name and password
|
||
objHttpReq.SetProxyAccount (szUserName, szPassword) ;
|
||
|
||
// Only a HTTP GET method can be used to request proxy authorization.
|
||
pobjHttpRes = objHttpReq.RequestGet (...) ;
|
||
|
||
if ( pobjHttpRes->GetStatus () == HTTP_STATUS_PROXY_AUTH_REQ ) {
|
||
... // If the authorization fails, try again or stop
|
||
}
|
||
}
|
||
|
||
... // Continue to execute
|
||
|
||
} catch (httpclientexception & e) {
|
||
... // Place error handling codes here.
|
||
}
|
||
* \endcode
|
||
*
|
||
* \param szUserName [in] A proxy user name. Empty string is not allowed.
|
||
* If it is NULL, account information saved in CHttpClient will be removed.
|
||
* \param szPassword [in] A proxy password. NULL and empty string are not allowed.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ApplyProxyAccount, ::InternetSetOption, <a href="http://support.microsoft.com/?kbid=195650" target="_blank">How To Handle Proxy Authorization with WinInet</a>
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::SetProxyAccount (PCSZ szUserName, PCSZ szPassword)
|
||
throw (Exception &)
|
||
{
|
||
if ( szUserName == NULL ) {
|
||
SAFEFREE (m_szProxyUserName) ;
|
||
SAFEFREE (m_szProxyPassword) ;
|
||
return ;
|
||
}
|
||
|
||
HTTPCLIENT_ASSERT (szUserName != NULL, "CHttpClientT::SetProxyAccount: szUserName can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (HttpTool::StringLen (szUserName) > 0, "CHttpClientT::SetProxyAccount: szUserName can not be an empty string.") ;
|
||
HTTPCLIENT_ASSERT (szPassword != NULL, "CHttpClientT::SetProxyAccount: szPassword can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (HttpTool::StringLen (szPassword) > 0, "CHttpClientT::SetProxyAccount: szPassword can not be an empty string.") ;
|
||
|
||
PSZ szNewUserName = NULL ;
|
||
PSZ szNewPassword = NULL ;
|
||
|
||
try {
|
||
szNewUserName = _AllocNCopyIfNewString (szUserName, m_szProxyUserName) ;
|
||
szNewPassword = _AllocNCopyIfNewString (szPassword, m_szProxyPassword) ;
|
||
} catch (Exception &) {
|
||
if ( m_szProxyUserName != szNewUserName ) SAFEFREE (szNewUserName) ;
|
||
if ( m_szProxyPassword != szNewPassword ) SAFEFREE (szNewPassword) ;
|
||
throw ;
|
||
}
|
||
|
||
if ( m_szProxyUserName != szNewUserName ) {
|
||
SAFEFREE (m_szProxyUserName) ;
|
||
m_szProxyUserName = szNewUserName ;
|
||
}
|
||
|
||
if ( m_szProxyPassword != szNewPassword ) {
|
||
SAFEFREE (m_szProxyPassword) ;
|
||
m_szProxyPassword = szNewPassword ;
|
||
}
|
||
}
|
||
|
||
/*!
|
||
* This method returns a proxy user name which is used to access HTTP proxy server.
|
||
* It always returns a null-terminated string. The returned string is owned by
|
||
* the CHttpClientT. So you can not free it.
|
||
*
|
||
* \return A proxy user name.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetProxyUserName (void) const
|
||
throw ()
|
||
{
|
||
return m_szProxyUserName ? m_szProxyUserName : HttpTool::szEmptyString ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns the current proxy password.
|
||
* It always returns a null-terminated string. The returned string is owned by
|
||
* the CHttpClientT. So you can not free it.
|
||
*
|
||
* \return The current proxy password.
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::GetProxyPassword (void) const
|
||
throw ()
|
||
{
|
||
return m_szProxyPassword ? m_szProxyPassword : HttpTool::szEmptyString ;
|
||
}
|
||
|
||
/*!
|
||
* This method sets a proxy user name and password on the hConnection handle
|
||
* using the settings saved in CHttpClient.
|
||
* You can handle proxy authorization using this handle, but there are some restrictions.
|
||
* First, The HTTP POST method is not safe if you are not authorized
|
||
* (It is possible that the proxy server closes the connection before the request is finished).
|
||
* Second, Only a HTTP GET method can be used to request proxy authorization
|
||
* (This restriction is caused by the WinInet API).
|
||
* If an exception occurs, it is possible that the proxy user name is only applied.
|
||
*
|
||
* The following code snippet demonstrates the usage of this method.
|
||
* \code
|
||
...
|
||
CHttpClient objHttpReq ;
|
||
CHttpResponse * pobjHttpRes = NULL ;
|
||
HINTERNET hInternet = NULL ;
|
||
HINTERNET hConnection = NULL ;
|
||
|
||
try {
|
||
... // Initialize the CHttpClient object
|
||
|
||
// Get a new internet handle
|
||
hInternet = objHttpReq.OpenInternet () ;
|
||
|
||
// Get a new connection handle
|
||
hConnection = objHttpReq.OpenConnection (hInternet, _T ("http://www.k-net.or.kr")) ;
|
||
|
||
// It is safe to use HTTP GET method.
|
||
pobjHttpRes = objHttpReq.RequestGet (hInternet, hConnection, ...) ;
|
||
|
||
// If the server requests proxy authorization..
|
||
if ( pobjHttpRes->GetStatus () == HTTP_STATUS_PROXY_AUTH_REQ ) {
|
||
delete pobjHttpRes ;
|
||
pobjHttpRes = NULL ;
|
||
|
||
LPTSTR szUserName = NULL ;
|
||
LPTSTR szPassword = NULL ;
|
||
|
||
... // Get a proxy user name and password
|
||
|
||
// Set the proxy user name and password
|
||
objHttpReq.SetProxyAccount (szUserName, szPassword) ;
|
||
objHttpReq.ApplyProxyAccount (hConnection) ;
|
||
|
||
// Only a HTTP GET method can be used to request proxy authorization.
|
||
pobjHttpRes = objHttpReq.RequestGet (hInternet, hConnection, ...) ;
|
||
|
||
if ( pobjHttpRes->GetStatus () == HTTP_STATUS_PROXY_AUTH_REQ ) {
|
||
... // If the authorization fails, try again or stop
|
||
}
|
||
}
|
||
|
||
... // Continue to execute
|
||
|
||
} catch (httpclientexception & e) {
|
||
... // Place error handling codes here.
|
||
}
|
||
* \endcode
|
||
*
|
||
* \param hConnection [in] A HINTERNET handle returned by ::InternetConnect function.
|
||
* NULL is not allowed.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa SetProxyAccount, ::InternetSetOption, <a href="http://support.microsoft.com/?kbid=195650" target="_blank">How To Handle Proxy Authorization with WinInet</a>
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::ApplyProxyAccount (HINTERNET hConnection)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (hConnection != NULL, "CHttpClientT::ApplyProxyAccount: hConnection can not be NULL.") ;
|
||
|
||
if ( m_szProxyUserName == NULL || m_szProxyPassword == NULL )
|
||
return ;
|
||
|
||
::SafeInt<DWORD> cchProxyUserName ;
|
||
::SafeInt<DWORD> cchProxyPassword ;
|
||
|
||
try {
|
||
cchProxyUserName = HttpTool::StringLen (m_szProxyUserName) ;
|
||
cchProxyPassword = HttpTool::StringLen (m_szProxyPassword) ;
|
||
} catch (::SafeIntException & e) {
|
||
throw (e) ;
|
||
}
|
||
|
||
if ( cchProxyUserName == 0 || cchProxyPassword == 0 )
|
||
return ;
|
||
|
||
// Set a user name for Proxy
|
||
HttpTool::InternetSetOption (
|
||
hConnection
|
||
, INTERNET_OPTION_PROXY_USERNAME
|
||
, (LPVOID) m_szProxyUserName
|
||
, cchProxyUserName.Value ()
|
||
) ;
|
||
|
||
// Set a password for Proxy
|
||
HttpTool::InternetSetOption (
|
||
hConnection
|
||
, INTERNET_OPTION_PROXY_PASSWORD
|
||
, (LPVOID) m_szProxyPassword
|
||
, cchProxyPassword.Value ()
|
||
) ;
|
||
}
|
||
|
||
/*!
|
||
* This method returns a new HINTERNET handle which is returned by ::HttpOpenRequest
|
||
* using the settings saved in the CHttpClient.
|
||
* It only checks the protocol and the path of the URL.
|
||
* So you can use the following URLs.
|
||
* <UL>
|
||
* <LI>http://drama.kbs.co.kr/winter/people/cast_02.shtml -> A full HTTP URL (or a full HTTPS URL)</LI>
|
||
* <LI>http:///winter/people/cast_02.shtml -> A HTTP URL without server location (or a HTTPS URL without server location)</LI>
|
||
* <LI>www.eggfilm.com/classic/intro.htm -> A HTTP URL without protocol (http is assumed)</LI>
|
||
* <LI>/classic/intro.htm -> Only A path (http is assumed)</LI>
|
||
* <LI>http://www.k-net.or.kr -> An HTTP URL without path (uses "/" as the path)</LI>
|
||
* <LI>www.k-net.or.kr -> Only A server location (http is assumed, uses "/" as the path)</LI>
|
||
* <LI> -> A NULL or an empty string (http is assumed, uses "/" as the path)</LI>
|
||
* <LI>ftp://www.k-net.or.kr/member.html -> An URL with another protocol (http is assumed)</LI>
|
||
* </UL>
|
||
*
|
||
* The caller is responsible for closing the returned handle when it has finished with it.
|
||
*
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect.
|
||
* \param szVerb [in] A HTTP verb which corresponds to the lpszVerb parameter of the ::HttpOpenRequest function.
|
||
* \param szUrl [in] An URL which is used to return a new handle.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \return A new HINTERNET handle.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
HINTERNET CHttpClientT<HttpTool, HttpEncoder>::OpenRequest (HINTERNET hConnection
|
||
, PCSZ szVerb, PCSZ szUrl
|
||
, DWORD dwFlags, PCSZ szReferer)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (hConnection != NULL, "CHttpClientT::OpenRequest: hConnection can not be NULL.") ;
|
||
|
||
CHttpUrlAnalyzer objAnalyzer (szUrl, m_nAnsiCodePage) ;
|
||
|
||
// If the protocol is HTTPS, adds the SSL flag.
|
||
if ( (objAnalyzer.ProtocolLen () == 5 /* ::strlen ("HTTPS") */)
|
||
&& (0 == HttpTool::StringNICmp (
|
||
szUrl + objAnalyzer.ProtocolIdx (), HttpTool::szHTTPS, objAnalyzer.ProtocolLen ())) )
|
||
dwFlags |= INTERNET_FLAG_SECURE ;
|
||
|
||
PCSZ szUrlPath ;
|
||
BOOL bNeedToFreeUrlPath = FALSE ;
|
||
|
||
// If the path does not exist, use "/" as the path
|
||
if ( objAnalyzer.PathLen () == 0 ) {
|
||
size_t cchAfterPath = szUrl ? HttpTool::StringLen (szUrl + objAnalyzer.PathIdx ()) : 0 ;
|
||
|
||
if ( cchAfterPath == 0 )
|
||
szUrlPath = HttpTool::szSlash ;
|
||
else {
|
||
|
||
::SafeInt<size_t> cbAfterPath = 0 ;
|
||
try {
|
||
cbAfterPath = cchAfterPath ;
|
||
cbAfterPath += 2 ; // for '/' & '\0'
|
||
cbAfterPath *= sizeof (CharType) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
szUrlPath = (PCSZ) ::malloc (cbAfterPath.Value ()) ;
|
||
if ( szUrlPath == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
bNeedToFreeUrlPath = TRUE ;
|
||
|
||
HttpTool::StringCopy (const_cast<PSZ> (szUrlPath), HttpTool::szSlash) ;
|
||
HttpTool::StringCat (const_cast<PSZ> (szUrlPath), szUrl + objAnalyzer.PathIdx ()) ;
|
||
}
|
||
} else
|
||
szUrlPath = szUrl + objAnalyzer.PathIdx () ;
|
||
|
||
HINTERNET hRequest = NULL ;
|
||
|
||
try {
|
||
hRequest = HttpTool::OpenRequest (hConnection, szVerb, szUrlPath, dwFlags, szReferer, m_nAnsiCodePage) ;
|
||
|
||
// Adds the cache-control header if it is needed
|
||
if ( dwFlags & INTERNET_FLAG_PRAGMA_NOCACHE )
|
||
HttpTool::AddHeader (hRequest, HttpTool::szCacheControl, HttpTool::szNoCache, m_nAnsiCodePage) ;
|
||
|
||
} catch (Exception &) {
|
||
HttpTool::CloseRequest (hRequest) ;
|
||
if ( bNeedToFreeUrlPath )
|
||
SAFEFREE (szUrlPath) ;
|
||
throw ;
|
||
}
|
||
|
||
if ( bNeedToFreeUrlPath )
|
||
SAFEFREE (szUrlPath) ;
|
||
|
||
return hRequest ;
|
||
}
|
||
|
||
/*!
|
||
* This method adds the HTTP headers to the handle which is returned by ::HttpOpenRequest
|
||
* using the settings saved in the CHttpClient.
|
||
* It uses the headers which is saved in the CHttpClient.
|
||
* If an exception occurs, it is possible that the headers are added partially.
|
||
*
|
||
* \param hRequest [in] A valid handle which is returned by ::HttpOpenRequest.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa ::HttpAddRequestHeaders
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::AddRequestHeader (HINTERNET hRequest)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (hRequest != NULL, "CHttpClientT::AddRequestHeader: hRequest can not be NULL.") ;
|
||
|
||
// Adds user's headers.
|
||
for (ConstMapIter iter = m_mapHeader.Begin (); iter != m_mapHeader.End (); ++iter)
|
||
HttpTool::AddHeader (hRequest, iter->first, (iter->second).szValue, m_nAnsiCodePage) ;
|
||
}
|
||
|
||
/*!
|
||
* \internal
|
||
* This method retrieves the resource specified by the szUrl using HTTP GET request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::_RequestGetEx (HINTERNET hInternet, HINTERNET hConnection
|
||
, PCSZ szUrl, DWORD dwFlags, PCSZ szReferer
|
||
, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
// Releases any existing Post Context
|
||
_EndPostContext () ;
|
||
|
||
PCSZ szGetUrl = NULL ;
|
||
BOOL bNeedToFreeGetUrl = FALSE ;
|
||
|
||
BOOL bBorrowedInternet = TRUE ;
|
||
BOOL bBorrowedConnection = TRUE ;
|
||
HINTERNET hRequest = NULL ;
|
||
|
||
CHttpResponse * pobjRes = NULL ;
|
||
|
||
try {
|
||
|
||
// Get WinInet API handles
|
||
if ( hInternet == NULL ) {
|
||
hInternet = OpenInternet () ;
|
||
bBorrowedInternet = FALSE ;
|
||
}
|
||
|
||
if ( hConnection == NULL ) {
|
||
hConnection = OpenConnection (hInternet, szUrl, szUsrName, szUsrPwd) ;
|
||
bBorrowedConnection = FALSE ;
|
||
}
|
||
|
||
szGetUrl = szUrl ;
|
||
|
||
// Appends the GET parameters to the URL
|
||
if ( !m_mapParam.Empty () ) {
|
||
::SafeInt<DWORD> cbGetUrl ;
|
||
|
||
try {
|
||
cbGetUrl = MakeGetUrlLen (szUrl) ;
|
||
cbGetUrl += 1 ;
|
||
cbGetUrl *= sizeof (CharType) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
if ( NULL == (szGetUrl = (PCSZ) ::malloc (cbGetUrl.Value ())) )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
bNeedToFreeGetUrl = TRUE ;
|
||
MakeGetUrl (const_cast<PSZ> (szGetUrl), szUrl) ;
|
||
}
|
||
|
||
hRequest = OpenRequest (hConnection, HttpTool::szGET, szGetUrl, dwFlags, szReferer) ;
|
||
AddRequestHeader (hRequest) ; // Adds user's custom header
|
||
|
||
if ( bNeedToFreeGetUrl ) {
|
||
SAFEFREE (szGetUrl) ;
|
||
bNeedToFreeGetUrl = FALSE ;
|
||
}
|
||
|
||
// Connect to the HTTP server
|
||
HttpTool::SendRequest (hRequest, NULL, m_nAnsiCodePage) ;
|
||
|
||
if ( NULL == (pobjRes = new CHttpResponse (
|
||
bBorrowedInternet ? NULL : hInternet
|
||
, bBorrowedConnection ? NULL : hConnection
|
||
, hRequest)) )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
} catch (Exception &) {
|
||
if ( bNeedToFreeGetUrl ) SAFEFREE (szGetUrl) ;
|
||
HttpTool::CloseRequest (hRequest) ;
|
||
if ( !bBorrowedConnection ) HttpTool::CloseRequest (hConnection) ;
|
||
if ( !bBorrowedInternet ) HttpTool::CloseRequest (hInternet) ;
|
||
throw ;
|
||
} catch (...) { // for the exception thrown by the new operator
|
||
if ( bNeedToFreeGetUrl ) SAFEFREE (szGetUrl) ;
|
||
HttpTool::CloseRequest (hRequest) ;
|
||
if ( !bBorrowedConnection ) HttpTool::CloseRequest (hConnection) ;
|
||
if ( !bBorrowedInternet ) HttpTool::CloseRequest (hInternet) ;
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_UNEXPECTED_ERROR) ;
|
||
}
|
||
|
||
return pobjRes ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP GET request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestGet (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
return RequestGetEx (hInternet, hConnection, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP GET request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, ::InternetOpen
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestGet (HINTERNET hInternet, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
return RequestGetEx (hInternet, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP GET request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestGet (PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
return RequestGetEx (szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP GET request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestGetEx (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl, DWORD dwFlags
|
||
, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
return _RequestGetEx (hInternet, hConnection, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP GET request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestGetEx (HINTERNET hInternet, PCSZ szUrl, DWORD dwFlags
|
||
, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
return _RequestGetEx (hInternet, NULL, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP GET request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestGetEx (PCSZ szUrl, DWORD dwFlags, PCSZ szReferer
|
||
, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
return _RequestGetEx (NULL, NULL, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP POST request. If you call this method, you can retrieve progress
|
||
* information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginPost (HINTERNET hInternet, HINTERNET hConnection
|
||
, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
BeginPostEx (hInternet, hConnection, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP POST request. If you call this method, you can retrieve progress
|
||
* information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa OpenInternet, ::InternetOpen
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginPost (HINTERNET hInternet, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
BeginPostEx (hInternet, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP POST request. If you call this method, you can retrieve progress
|
||
* information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginPost (PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
BeginPostEx (szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP POST request. If you call this method, you can retrieve progress
|
||
* information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginPostEx (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl, DWORD dwFlags
|
||
, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
_StartPostContext (hInternet, hConnection, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ; // Starts a new POST context
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP POST request. If you call this method, you can retrieve progress
|
||
* information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed, OpenInternet, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginPostEx (HINTERNET hInternet, PCSZ szUrl, DWORD dwFlags, PCSZ szReferer
|
||
, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
_StartPostContext (hInternet, NULL, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ; // Starts a new POST context
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP POST request. If you call this method, you can retrieve progress
|
||
* information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginPostEx (PCSZ szUrl, DWORD dwFlags, PCSZ szReferer
|
||
, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
_StartPostContext (NULL, NULL, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ; // Starts a new POST context
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP UPLOAD request which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If you call this method, you can retrieve progress information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginUpload (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
BeginUploadEx (hInternet, hConnection, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP UPLOAD request which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If you call this method, you can retrieve progress information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed, OpenInternet, ::InternetOpen
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginUpload (HINTERNET hInternet, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
BeginUploadEx (hInternet, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP UPLOAD request which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If you call this method, you can retrieve progress information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginUpload (PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
BeginUploadEx (szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP UPLOAD request which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If you call this method, you can retrieve progress information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginUploadEx (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl
|
||
, DWORD dwFlags, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
_StartUploadContext (hInternet, hConnection, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ; // Starts a new UPLOAD context
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP UPLOAD request which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If you call this method, you can retrieve progress information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed, OpenInternet, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginUploadEx (HINTERNET hInternet, PCSZ szUrl, DWORD dwFlags, PCSZ szReferer
|
||
, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
_StartUploadContext (hInternet, NULL, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ; // Starts a new UPLOAD context
|
||
}
|
||
|
||
/*!
|
||
* This method starts a new HTTP UPLOAD request which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If you call this method, you can retrieve progress information of the POST request by using the Query method.
|
||
* To finish the request, you have to call the Proceed method.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa Query, Proceed, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::BeginUploadEx (PCSZ szUrl, DWORD dwFlags, PCSZ szReferer
|
||
, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
// Starts a new UPLOAD context
|
||
_StartUploadContext (NULL, NULL, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
}
|
||
|
||
/*!
|
||
* This method queries progress information of the current POST context.
|
||
* If you call the BeginPost or the BeginUpload method which starts a new POST context,
|
||
* you can retrieve progress information by using this method.
|
||
* If an exception occurs, the current POST context is automatically canceled.
|
||
*
|
||
* \param objPostStat [in] A CHttpPostStatT object.
|
||
*
|
||
* \sa CHttpPostStatT, BeginPost, BeginPostEx, BeginUpload, BeginUploadEx, Cancel, Proceed
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::Query (CHttpPostStat & objPostStat)
|
||
throw ()
|
||
{
|
||
if ( _PostContextIsPost () )
|
||
_QueryPostStat (objPostStat) ;
|
||
else
|
||
_QueryUploadStat (objPostStat) ;
|
||
}
|
||
|
||
/*!
|
||
* This method cancels the current POST context which is started by
|
||
* the BeginPost or the BeginUpload method.
|
||
*
|
||
* \return Whether the operation canceled.
|
||
*
|
||
* \sa BeginPost, BeginPostEx, BeginUpload, BeginUploadEx, Query, Proceed
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::Cancel (void)
|
||
throw ()
|
||
{
|
||
if ( _PostContextIsPost () )
|
||
return _CancelPostContext () ;
|
||
|
||
return _CancelUploadContext () ;
|
||
}
|
||
|
||
/*!
|
||
* This method proceeds with the current POST context which is started by
|
||
* the BeginPost or the BeginUpload method.
|
||
* It transmits data of the current POST context to the web server.
|
||
* If all bytes are transmitted, a pointer to a CHttpResponseT object is returned.
|
||
* The returned pointer is allocated by the new operator.
|
||
* So you have to delete the returned pointer.
|
||
* If an exception occurs, the current POST context is automatically canceled.
|
||
*
|
||
* \param cbDesired [in] The number of bytes to be transmitted.
|
||
* \return A pointer to a CHttpResponseT object if all bytes are transmitted,
|
||
* otherwise NULL.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, BeginPost, BeginPostEx, BeginUpload, BeginUploadEx, Query, Cancel
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::Proceed (DWORD cbDesired)
|
||
throw (Exception &)
|
||
{
|
||
if ( _PostContextIsPost () )
|
||
return _ProceedPostContext (cbDesired) ;
|
||
|
||
return _ProceedUploadContext (cbDesired) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP POST request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestPost (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
return RequestPostEx (hInternet, hConnection, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP POST request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, ::InternetOpen
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestPost (HINTERNET hInternet, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
return RequestPostEx (hInternet, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP POST request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestPost (PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
return RequestPostEx (szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP POST request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestPostEx (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl
|
||
, DWORD dwFlags, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
BeginPostEx (hInternet, hConnection, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
|
||
CHttpResponse * pResponse = NULL ;
|
||
while ( !(pResponse = Proceed (::SafeInt<DWORD>::MaxInt ())) ) ;
|
||
return pResponse ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP POST request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestPostEx (HINTERNET hInternet, PCSZ szUrl, DWORD dwFlags
|
||
, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
BeginPostEx (hInternet, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
|
||
CHttpResponse * pResponse = NULL ;
|
||
while ( !(pResponse = Proceed (::SafeInt<DWORD>::MaxInt ())) ) ;
|
||
return pResponse ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP POST request.
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestPostEx (PCSZ szUrl, DWORD dwFlags, PCSZ szReferer
|
||
, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
BeginPostEx (szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
|
||
CHttpResponse * pResponse = NULL ;
|
||
while ( !(pResponse = Proceed (::SafeInt<DWORD>::MaxInt ())) ) ;
|
||
return pResponse ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP UPLOAD request
|
||
* which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestUpload (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
return RequestUploadEx (hInternet, hConnection, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP UPLOAD request
|
||
* which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, ::InternetOpen
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestUpload (HINTERNET hInternet, PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
return RequestUploadEx (hInternet, szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP UPLOAD request
|
||
* which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param bUseCache [in] Specifies whether to use cache.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestUpload (PCSZ szUrl, BOOL bUseCache)
|
||
throw (Exception &)
|
||
{
|
||
return RequestUploadEx (szUrl
|
||
, bUseCache ? HTTPCLIENT_DEF_REQUEST_FLAGS : HTTPCLIENT_DEF_REQUEST_FLAGS_NOCACHE) ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP UPLOAD request
|
||
* which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* If the caller passes the hConnection parameter which is returned by ::InternetConnect,
|
||
* the CHttpClient also uses the passed handle instead of creating a new one.
|
||
* In this case, the caller has to pass the hInternet parameter which is used to get the hConnection parameter.
|
||
* The caller is responsible for closing the hConnection handle when it has finished with it.
|
||
* If the hConnection is not NULL, the CHttpClient does not use the server location part in the szUrl.
|
||
* You can omit the server location part of the szUrl.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param hConnection [in] A valid handle returned by ::InternetConnect. NULL is allowed.
|
||
* If this parameter is not NULL, the caller has to pass the hInternet parameter
|
||
* which is used to get the hConnection parameter.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, OpenConnection, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestUploadEx (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl, DWORD dwFlags, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
BeginUploadEx (hInternet, hConnection, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
|
||
CHttpResponse * pResponse = NULL ;
|
||
while ( !(pResponse = Proceed (::SafeInt<DWORD>::MaxInt ())) ) ;
|
||
return pResponse ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP UPLOAD request
|
||
* which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* If the caller passes the hInternet parameter which is returned by ::InternetOpen,
|
||
* the CHttpClient uses the passed handle instead of creating a new one.
|
||
* The caller is responsible for closing the hInternet handle when it has finished with it.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param hInternet [in] A valid handle returned by ::InternetOpen. NULL is allowed.
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, OpenInternet, ::InternetOpen, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestUploadEx (HINTERNET hInternet, PCSZ szUrl, DWORD dwFlags, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
BeginUploadEx (hInternet, szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
|
||
CHttpResponse * pResponse = NULL ;
|
||
while ( !(pResponse = Proceed (::SafeInt<DWORD>::MaxInt ())) ) ;
|
||
return pResponse ;
|
||
}
|
||
|
||
/*!
|
||
* This method retrieves the resource specified by the szUrl using HTTP UPLOAD request
|
||
* which is a HTTP POST request with another content-type (multipart/form-data).
|
||
* If the szUrl does not start with "https://", "http" is used as the protocol.
|
||
* The returned CHttpResponseT object is allocated by the new operator.
|
||
* So you have to delete the returned CHttpResponseT object.
|
||
*
|
||
* \param szUrl [in] A HTTP URL.
|
||
* \param dwFlags [in] A flags which corresponds to the dwFlags parameter of the ::HttpOpenRequest function.
|
||
* \param szReferer [in] A referer which corresponds to the lpszReferer parameter of the ::HttpOpenRequest function.
|
||
* \param szUsrName [in] An user name which corresponds to the lpszUsername parameter of the ::InternetConnect function.
|
||
* \param szUsrPwd [in] An user password which corresponds to the lpszPassword parameter of the ::InternetConnect function.
|
||
* \return A pointer to a CHttpResponseT object.
|
||
* \throw Throws a httpclientexception if an error occurs.
|
||
*
|
||
* \sa CHttpResponseT, ::InternetConnect, ::HttpOpenRequest
|
||
*/
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::RequestUploadEx (PCSZ szUrl, DWORD dwFlags, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
BeginUploadEx (szUrl, dwFlags, szReferer, szUsrName, szUsrPwd) ;
|
||
|
||
CHttpResponse * pResponse = NULL ;
|
||
while ( !(pResponse = Proceed (::SafeInt<DWORD>::MaxInt ())) ) ;
|
||
return pResponse ;
|
||
}
|
||
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_InitPostContext (void)
|
||
throw ()
|
||
{
|
||
m_ahPostedFiles = NULL ;
|
||
m_aszMimeTypes = NULL ;
|
||
m_szPostedValue = NULL ;
|
||
m_bNeedToFreePostedValue = FALSE ;
|
||
m_hInternet = NULL ;
|
||
m_bBorrowedInternet = FALSE ;
|
||
m_hConnection = NULL ;
|
||
m_bBorrowedConnection = FALSE ;
|
||
m_hRequest = NULL ;
|
||
m_bIsPost = TRUE ;
|
||
m_pbyCntxBuff = NULL ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::_PostContextIsActive (void) const
|
||
throw ()
|
||
{
|
||
return m_objPostStat.IsActive () ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::_PostContextIsPost (void) const
|
||
throw ()
|
||
{
|
||
return m_bIsPost ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_SetPostedValue (LPCSTR szPostedValue, BOOL bNeedToFree)
|
||
throw ()
|
||
{
|
||
if ( m_bNeedToFreePostedValue )
|
||
SAFEFREE (m_szPostedValue) ;
|
||
|
||
m_szPostedValue = szPostedValue ;
|
||
m_bNeedToFreePostedValue = bNeedToFree ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_InitPostCntxBuff (void)
|
||
throw (Exception &)
|
||
{
|
||
// If the buffer is aleady allocated
|
||
if ( m_pbyCntxBuff )
|
||
return ;
|
||
|
||
if ( NULL == (m_pbyCntxBuff = (BYTE *) ::malloc (HTTPCLIENT_POSTCNTX_BUFF_SIZE)) )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_WritePost (BOOL bUseUtf8, PCSZ szValue, BOOL bIsValue)
|
||
throw (Exception &)
|
||
{
|
||
if ( szValue == NULL || szValue[0] == '\0' )
|
||
return ;
|
||
|
||
PCSTR szValueA = NULL ;
|
||
BOOL bNeedToFreeValueA = FALSE ;
|
||
|
||
try {
|
||
if ( bUseUtf8 ) {
|
||
szValueA = _Utf8Encode (szValue) ;
|
||
bNeedToFreeValueA = TRUE ;
|
||
} else
|
||
szValueA = _String2Ansi (szValue, bNeedToFreeValueA) ;
|
||
|
||
_WritePost (szValueA, bIsValue) ;
|
||
} catch (Exception &) {
|
||
if ( bNeedToFreeValueA )
|
||
SAFEFREE (szValueA) ;
|
||
throw ;
|
||
}
|
||
|
||
if ( bNeedToFreeValueA )
|
||
SAFEFREE (szValueA) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_WritePost (LPCSTR szValue, BOOL bIsValue)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_hRequest != NULL, "CHttpClientT::_WritePost: m_hRequest can not be NULL.") ;
|
||
|
||
if ( szValue == NULL )
|
||
return ;
|
||
|
||
::SafeInt<DWORD> cbValue ;
|
||
try {
|
||
cbValue = ::strlen (szValue) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
_WritePost (reinterpret_cast<const BYTE *> (szValue), cbValue.Value (), bIsValue) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_WritePost (const BYTE * pbyBuff, DWORD cbyBuff, BOOL bIsValue)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_hRequest != NULL, "CHttpClientT::_WritePost: m_hRequest can not be NULL.") ;
|
||
|
||
if ( pbyBuff == NULL || cbyBuff == 0 )
|
||
return ;
|
||
|
||
// Before increasing values. Checks overflow exception.
|
||
if ( bIsValue ) m_objPostStat._TestAddPostedBytes (cbyBuff) ;
|
||
else m_objPostStat._TestAddActualPostedBytes (cbyBuff) ;
|
||
|
||
HttpTool::InternetWriteFile (m_hRequest, pbyBuff, cbyBuff) ;
|
||
|
||
if ( bIsValue ) m_objPostStat._AddPostedBytes (cbyBuff) ;
|
||
else m_objPostStat._AddActualPostedBytes (cbyBuff) ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_StartPostContext (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl, DWORD dwFlags, PCSZ szReferer
|
||
, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
// Closes the POST context if it exists.
|
||
_EndPostContext () ;
|
||
|
||
BOOL bBorrowedInternet = TRUE ;
|
||
BOOL bBorrowedConnection = TRUE ;
|
||
HINTERNET hRequest = NULL ;
|
||
|
||
try {
|
||
// Calculates the total number of bytes to upload
|
||
::SafeInt<size_t> nTotalByte = 0 ;
|
||
::SafeInt<size_t> nValuesTotalByte = 0 ;
|
||
PCSZ szFirstParamName = NULL ;
|
||
size_t cbFirstParamValue = 0 ;
|
||
|
||
if ( !m_mapParam.Empty () ) {
|
||
ConstMapIter iter ;
|
||
|
||
size_t cbValue ;
|
||
for (iter = m_mapParam.Begin (); iter != m_mapParam.End (); ++iter) {
|
||
nTotalByte += 1 ; // '&'
|
||
|
||
if ( (iter->second).dwFlag & ParamEncodedName )
|
||
nTotalByte += _String2AnsiLen (iter->first) ;
|
||
else
|
||
nTotalByte += _UrlEncodeLenA (iter->first) ;
|
||
|
||
nTotalByte += 1 ; // '='
|
||
|
||
if ( (iter->second).dwFlag & ParamEncodedValue )
|
||
cbValue = _String2AnsiLen ((iter->second).szValue) ;
|
||
else
|
||
cbValue = _UrlEncodeLenA ((iter->second).szValue) ;
|
||
|
||
nTotalByte += cbValue ;
|
||
nValuesTotalByte += cbValue ;
|
||
|
||
// If the item is the first item
|
||
if ( iter == m_mapParam.Begin () ) {
|
||
szFirstParamName = iter->first ;
|
||
cbFirstParamValue = cbValue ;
|
||
}
|
||
}
|
||
|
||
if ( nTotalByte > 0 )
|
||
nTotalByte-- ; // for the first '&'
|
||
}
|
||
|
||
::SafeInt<DWORD> dwTotalByte = nTotalByte ;
|
||
|
||
// Get WinInet handles
|
||
if ( hInternet == NULL ) {
|
||
hInternet = OpenInternet () ;
|
||
bBorrowedInternet = FALSE ;
|
||
}
|
||
|
||
if ( hConnection == NULL ) {
|
||
hConnection = OpenConnection (hInternet, szUrl, szUsrName, szUsrPwd) ;
|
||
bBorrowedConnection = FALSE ;
|
||
}
|
||
|
||
hRequest = OpenRequest (hConnection, HttpTool::szPost, szUrl, dwFlags, szReferer) ;
|
||
AddRequestHeader (hRequest) ; // Adds user's custom header
|
||
|
||
// Adds the Content-Type header
|
||
HttpTool::AddHeader (hRequest, HttpTool::szContentType, HttpTool::szFormUrlEncoded, m_nAnsiCodePage) ;
|
||
|
||
// Connects to the HTTP server
|
||
HttpTool::SendRequestEx (hRequest, dwTotalByte.Value ()) ;
|
||
|
||
// Starts a new POST state
|
||
m_objPostStat._MakeActive (nTotalByte.Value (), nValuesTotalByte.Value (), m_mapParam.Count (), 0) ;
|
||
|
||
m_bBorrowedInternet = bBorrowedInternet ;
|
||
m_hInternet = hInternet ;
|
||
m_bBorrowedConnection = bBorrowedConnection ;
|
||
m_hConnection = hConnection ;
|
||
m_hRequest = hRequest ;
|
||
m_bIsPost = TRUE ;
|
||
|
||
// Initializes the initial POST state
|
||
if ( !m_mapParam.Empty () ) {
|
||
m_objInitialStat = m_objPostStat ;
|
||
// It always does not throw an overflow exception.
|
||
// So it's safe. (doesn't need to restore the internal states)
|
||
m_objInitialStat._StartNewEntry (szFirstParamName, cbFirstParamValue) ;
|
||
}
|
||
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::CloseRequest (hRequest) ;
|
||
if ( !bBorrowedConnection ) HttpTool::CloseRequest (hConnection) ;
|
||
if ( !bBorrowedInternet ) HttpTool::CloseRequest (hInternet) ;
|
||
HttpTool::ThrowException (e) ;
|
||
} catch (Exception &) {
|
||
HttpTool::CloseRequest (hRequest) ;
|
||
if ( !bBorrowedConnection ) HttpTool::CloseRequest (hConnection) ;
|
||
if ( !bBorrowedInternet ) HttpTool::CloseRequest (hInternet) ;
|
||
throw ;
|
||
}
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_QueryPostStat (CHttpPostStat & objPostStat)
|
||
throw ()
|
||
{
|
||
// If the _ProceedPOSTContext method is not called yet,
|
||
if ( (m_objPostStat.IsActive ()) && (m_objPostStat.TotalCount () > 0)
|
||
&& (m_objPostStat.PostedCount () == 0) )
|
||
objPostStat = m_objInitialStat ;
|
||
else
|
||
objPostStat = m_objPostStat ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::_CancelPostContext (void)
|
||
throw ()
|
||
{
|
||
if ( !m_objPostStat.IsActive () )
|
||
return FALSE ;
|
||
|
||
// Cancels the POST context
|
||
_EndPostContext () ;
|
||
return TRUE ;
|
||
}
|
||
|
||
// If all parameters are sent, returns a pointer to the CHttpResponseT.
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::_ProceedPostContext (DWORD nDesired)
|
||
throw (Exception &)
|
||
{
|
||
// If the Post context is not started
|
||
if ( !m_objPostStat.IsActive () )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_POST_NOT_STARTED) ;
|
||
|
||
HTTPCLIENT_ASSERT (m_hInternet != NULL, "CHttpClientT::_ProceedPostContext: m_hInternet can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (m_hConnection != NULL, "CHttpClientT::_ProceedPostContext: m_hConnection can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (m_hRequest != NULL, "CHttpClientT::_ProceedPostContext: m_hRequest can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (nDesired != 0, "CHttpClientT::_ProceedPostContext: nDesired can not be zero.") ;
|
||
|
||
try {
|
||
// If the current parameter is completed,
|
||
if ( m_objPostStat.CurrParamIsComplete () ) {
|
||
|
||
// If all parameters are sent
|
||
if ( m_objPostStat.TotalCount () == m_objPostStat.PostedCount () ) {
|
||
HttpTool::EndRequest (m_hRequest) ;
|
||
|
||
// Releases the POST context
|
||
return _ReleasePostResponse () ;
|
||
}
|
||
|
||
DWORD nNextIdx = m_objPostStat.PostedCount () ;
|
||
|
||
ConstMapIter iter = m_mapParam.Begin () ;
|
||
for (DWORD i = 0; i < nNextIdx; i++, ++iter) ;
|
||
|
||
if ( nNextIdx != 0 )
|
||
_WritePost ("&") ;
|
||
|
||
// Writes the parameter name
|
||
{
|
||
PSTR szNameA = NULL ;
|
||
BOOL bNeedToFreeNameA = FALSE ;
|
||
|
||
try {
|
||
if ( (iter->second).dwFlag & ParamEncodedName ) {
|
||
szNameA = const_cast<PSTR> (_String2Ansi (iter->first, bNeedToFreeNameA)) ;
|
||
_WritePost (szNameA) ;
|
||
} else {
|
||
::SafeInt<size_t> cbRequired = _UrlEncodeLenA (iter->first) ;
|
||
|
||
if ( cbRequired > 0 ) {
|
||
cbRequired += 1 ;
|
||
cbRequired *= sizeof (CHAR) ;
|
||
|
||
if ( NULL == (szNameA = (PSTR) ::malloc (cbRequired.Value ())) )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
bNeedToFreeNameA = TRUE ;
|
||
_UrlEncodeA (szNameA, iter->first) ;
|
||
_WritePost (szNameA) ;
|
||
}
|
||
}
|
||
} catch (::SafeIntException & e) {
|
||
if ( bNeedToFreeNameA )
|
||
SAFEFREE (szNameA) ;
|
||
HttpTool::ThrowException (e) ;
|
||
} catch (Exception &) {
|
||
if ( bNeedToFreeNameA )
|
||
SAFEFREE (szNameA) ;
|
||
throw ;
|
||
}
|
||
|
||
if ( bNeedToFreeNameA ) {
|
||
SAFEFREE (szNameA) ;
|
||
bNeedToFreeNameA = FALSE ;
|
||
}
|
||
}
|
||
|
||
_WritePost ("=") ;
|
||
|
||
size_t cbValue = 0 ;
|
||
|
||
// Sets the value
|
||
if ( (iter->second).szValue ) {
|
||
PSTR szValueA = NULL ;
|
||
BOOL bNeedToFreeValueA = FALSE ;
|
||
|
||
if ( (iter->second).dwFlag & ParamEncodedValue ) {
|
||
szValueA = const_cast<PSTR> (_String2Ansi ((iter->second).szValue, bNeedToFreeValueA)) ;
|
||
cbValue = szValueA ? CHttpToolA::StringLen (szValueA) : 0 ;
|
||
} else {
|
||
cbValue = _UrlEncodeLenA ((iter->second).szValue) ;
|
||
|
||
if ( cbValue > 0 ) {
|
||
::SafeInt<size_t> cbRequired = cbValue ;
|
||
|
||
try {
|
||
cbRequired += 1 ;
|
||
cbRequired *= sizeof (CHAR) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
if ( NULL == (szValueA = static_cast<PSTR> (::malloc (cbRequired.Value ()))) )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
bNeedToFreeValueA = TRUE ;
|
||
|
||
try {
|
||
_UrlEncodeA (szValueA, (iter->second).szValue) ;
|
||
} catch (Exception &) {
|
||
if ( bNeedToFreeValueA )
|
||
SAFEFREE (szValueA) ;
|
||
throw ;
|
||
}
|
||
}
|
||
}
|
||
|
||
_SetPostedValue (szValueA, bNeedToFreeValueA) ;
|
||
}
|
||
|
||
// Starts a new parameter
|
||
m_objPostStat._StartNewEntry (iter->first, cbValue) ;
|
||
|
||
return NULL ;
|
||
}
|
||
|
||
DWORD cbToWrite = nDesired ;
|
||
|
||
if ( cbToWrite > m_objPostStat.CurrParamRemainByte () )
|
||
cbToWrite = static_cast<DWORD> (m_objPostStat.CurrParamRemainByte ()) ;
|
||
|
||
_WritePost (
|
||
reinterpret_cast<const BYTE *> (m_szPostedValue + m_objPostStat.CurrParamPostedByte ())
|
||
, cbToWrite, TRUE) ;
|
||
|
||
} catch (Exception &) {
|
||
_EndPostContext () ; // Aborts the Post Context
|
||
throw ;
|
||
}
|
||
|
||
return NULL ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::_GetUploadBoundary (void)
|
||
throw ()
|
||
{
|
||
return m_szBoundary ? m_szBoundary : HttpTool::szDefBoundary ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
LPCSTR CHttpClientT<HttpTool, HttpEncoder>::_GetUploadBoundaryA (void)
|
||
throw ()
|
||
{
|
||
return m_szBoundaryA ? m_szBoundaryA : CHttpToolA::szDefBoundary ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::PCSZ
|
||
CHttpClientT<HttpTool, HttpEncoder>::_GetUploadContType (void)
|
||
throw ()
|
||
{
|
||
return m_szUploadContType ? m_szUploadContType : HttpTool::szDefUploadContType ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_StartUploadContext (HINTERNET hInternet, HINTERNET hConnection, PCSZ szUrl
|
||
, DWORD dwFlags, PCSZ szReferer, PCSZ szUsrName, PCSZ szUsrPwd)
|
||
throw (Exception &)
|
||
{
|
||
// Closes any existing Post Context
|
||
_EndPostContext () ;
|
||
|
||
BOOL bBorrowedInternet = TRUE ;
|
||
BOOL bBorrowedConnection = TRUE ;
|
||
HINTERNET hRequest = NULL ;
|
||
|
||
HANDLE * ahFileHandles = NULL ;
|
||
LPSTR * aszMimeTypes = NULL ;
|
||
::SafeInt<DWORD> nPostedFileCount = 0 ;
|
||
|
||
try {
|
||
// Calculates the nubmer of bytes to upload
|
||
::SafeInt<size_t> nTotalByte = 0 ;
|
||
::SafeInt<size_t> nValuesTotalByte = 0 ;
|
||
size_t cchBoundary = HttpTool::StringLen (_GetUploadBoundary ()) ;
|
||
|
||
PCSZ szFirstParamName = NULL ;
|
||
PCSZ szFirstParamFileName = NULL ;
|
||
size_t cbFirstParamValue = 0 ;
|
||
BOOL bFirstParamIsFile = FALSE ;
|
||
|
||
if ( !m_mapParam.Empty () ) {
|
||
try {
|
||
ConstMapIter iter ;
|
||
|
||
// Get the number of files
|
||
for (iter = m_mapParam.Begin (); iter != m_mapParam.End (); ++iter) {
|
||
if ( (iter->second).dwFlag & ParamFile )
|
||
nPostedFileCount++ ;
|
||
}
|
||
|
||
if ( nPostedFileCount.Value () ) {
|
||
// Allocates memory for handles and MimeTypes of the uploaded files
|
||
ahFileHandles = (HANDLE *) ::calloc (nPostedFileCount.Value (), sizeof (HANDLE)) ;
|
||
if ( ahFileHandles == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
|
||
// Initializes the file handles
|
||
for (DWORD i = 0; i < nPostedFileCount; i++)
|
||
ahFileHandles[i] = INVALID_HANDLE_VALUE ;
|
||
|
||
aszMimeTypes = (LPSTR *) ::calloc (nPostedFileCount.Value (), sizeof (LPSTR)) ;
|
||
if ( aszMimeTypes == NULL )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
}
|
||
|
||
/*
|
||
Calculates the total upload size
|
||
|
||
<1> The number of bytes to upload If the parameter is not a file
|
||
= strlen ("--") + strlen (Boundary) + strlen ("\r\n")
|
||
+ strlen ("Content-Disposition: form-data; name=\"\"\r\n\r\n")
|
||
+ strlen (The name of the parameter) + strlen (The value of the parameter) + strlen ("\r\n") ;
|
||
|
||
<2> The number of bytes to upload If the parameter is a file
|
||
= strlen ("--") + strlen (Boundary) + strlen ("\r\n")
|
||
+ strlen ("Content-Disposition: form-data; name=\"\"; filename=\"\"\r\n")
|
||
+ strlen (The name of the parameter) + strlen (The value of the parameter)
|
||
+ strlen ("Content-Type: \r\n\r\n") + strlen (The Mime Type of the file)
|
||
+ The length of the file + strlen ("\r\n")
|
||
|
||
The last boundary
|
||
= strlen ("--") + strlen (Boundary) + strlen ("--\r\n")
|
||
|
||
The total upload size
|
||
= ( <1> * The number of normal parameters)
|
||
+ ( <2> * The number of file parameters)
|
||
+ The last boundary
|
||
*/
|
||
|
||
::SafeInt<size_t> cbValue ;
|
||
DWORD nFileIdx = 0 ;
|
||
|
||
nTotalByte = 0 ;
|
||
nValuesTotalByte = 0 ;
|
||
for (iter = m_mapParam.Begin (); iter != m_mapParam.End (); ++iter) {
|
||
if ( !((iter->second).dwFlag & ParamFile) ) {
|
||
// If the parameter is not a file
|
||
// = strlen ("--") + strlen (Boundary) + strlen ("\r\n")
|
||
// + strlen ("Content-Disposition: form-data; name=\"\"\r\n\r\n")
|
||
// + strlen (The name of the parameter) + strlen (The value of the parameter) + strlen ("\r\n") ;
|
||
nTotalByte += (cchBoundary + 4) ;
|
||
nTotalByte += 43 ;
|
||
|
||
if ( m_bUseUtf8 ) {
|
||
nTotalByte += _Utf8EncodeLen (iter->first) ;
|
||
cbValue = _Utf8EncodeLen ((iter->second).szValue) ;
|
||
} else {
|
||
nTotalByte += _String2AnsiLen (iter->first) ;
|
||
cbValue = _String2AnsiLen ((iter->second).szValue) ;
|
||
}
|
||
|
||
nTotalByte += cbValue ;
|
||
nValuesTotalByte += cbValue ;
|
||
|
||
nTotalByte += 2 ;
|
||
|
||
// Saves the state of the first parameter
|
||
if ( iter == m_mapParam.Begin () ) {
|
||
szFirstParamName = iter->first ;
|
||
cbFirstParamValue = cbValue.Value () ;
|
||
bFirstParamIsFile = FALSE ;
|
||
szFirstParamFileName = NULL ;
|
||
}
|
||
} else {
|
||
// If the parameter is a file
|
||
// = strlen ("--") + strlen (Boundary) + strlen ("\r\n")
|
||
// + strlen ("Content-Disposition: form-data; name=\"\"; filename=\"\"\r\n")
|
||
// + strlen (The name of the parameter) + strlen (The value of the parameter)
|
||
// + strlen ("Content-Type: \r\n\r\n") + strlen (The Mime Type of the file)
|
||
// + The length of the file + strlen ("\r\n")
|
||
nTotalByte += (cchBoundary + 4) ;
|
||
nTotalByte += 54 ;
|
||
|
||
if ( m_bUseUtf8 ) {
|
||
nTotalByte += _Utf8EncodeLen (iter->first) ;
|
||
nTotalByte += _Utf8EncodeLen ((iter->second).szValue) ;
|
||
} else {
|
||
nTotalByte += _String2AnsiLen (iter->first) ;
|
||
nTotalByte += _String2AnsiLen ((iter->second).szValue) ;
|
||
}
|
||
|
||
nTotalByte += 18 ;
|
||
|
||
// Get the file size and MimeType
|
||
cbValue = 0 ;
|
||
if ( (iter->second).szValue ) {
|
||
// Open the file
|
||
ahFileHandles[nFileIdx] = HttpTool::OpenFile ((iter->second).szValue) ;
|
||
|
||
// Get the file size
|
||
if ( ahFileHandles[nFileIdx] != INVALID_HANDLE_VALUE )
|
||
cbValue = HttpTool::GetFileSize (ahFileHandles[nFileIdx], (iter->second).szValue) ;
|
||
}
|
||
|
||
// Throws an exception
|
||
if ( m_bStrictFileCheck && (ahFileHandles[nFileIdx] == INVALID_HANDLE_VALUE) )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OPENFILE_FAILED, ::GetLastError (), (iter->second).szValue) ;
|
||
|
||
// Get the MimeType of the file
|
||
aszMimeTypes[nFileIdx] = HttpTool::GetMimeType (ahFileHandles[nFileIdx], m_nAnsiCodePage) ;
|
||
nTotalByte += CHttpToolA::StringLen (aszMimeTypes[nFileIdx]) ;
|
||
nTotalByte += cbValue ;
|
||
nValuesTotalByte += cbValue ;
|
||
nTotalByte += 2 ;
|
||
nFileIdx++ ;
|
||
|
||
// Saves the state of the first parameter
|
||
if ( iter == m_mapParam.Begin () ) {
|
||
szFirstParamName = iter->first ;
|
||
cbFirstParamValue = cbValue.Value () ;
|
||
bFirstParamIsFile = TRUE ;
|
||
szFirstParamFileName = (iter->second).szValue ;
|
||
}
|
||
}
|
||
}
|
||
|
||
// The last boundary
|
||
// = strlen ("--") + strlen (Boundary) + strlen ("--\r\n")
|
||
nTotalByte += (cchBoundary + 6) ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
} else {
|
||
// The total upload size
|
||
// = (strlen ("\r\n") + strlen ("--") + strlen (Boundary) + strlen ("--\r\n")
|
||
nTotalByte = cchBoundary + 8 ;
|
||
nValuesTotalByte = 0 ;
|
||
}
|
||
|
||
::SafeInt<DWORD> dwTotalByte ;
|
||
try {
|
||
dwTotalByte = nTotalByte ;
|
||
} catch (::SafeIntException & e) {
|
||
HttpTool::ThrowException (e) ;
|
||
}
|
||
|
||
// Get WinInet handles
|
||
if ( hInternet == NULL ) {
|
||
hInternet = OpenInternet () ;
|
||
bBorrowedInternet = FALSE ;
|
||
}
|
||
|
||
if ( hConnection == NULL ) {
|
||
hConnection = OpenConnection (hInternet, szUrl, szUsrName, szUsrPwd) ;
|
||
bBorrowedConnection = FALSE ;
|
||
}
|
||
|
||
hRequest = OpenRequest (hConnection, HttpTool::szPost, szUrl, dwFlags, szReferer) ;
|
||
AddRequestHeader (hRequest) ; // Adds user's custom header
|
||
|
||
// Adds the Content-Type header
|
||
HttpTool::AddHeader (hRequest, HttpTool::szContentType, _GetUploadContType (), m_nAnsiCodePage) ;
|
||
|
||
// Make a connection to the server
|
||
HttpTool::SendRequestEx (hRequest, dwTotalByte.Value ()) ;
|
||
|
||
// Activates the Post Context
|
||
m_objPostStat._MakeActive (nTotalByte.Value (), nValuesTotalByte.Value (), m_mapParam.Count (), nPostedFileCount.Value ()) ;
|
||
m_bBorrowedInternet = bBorrowedInternet ;
|
||
m_hInternet = hInternet ;
|
||
m_bBorrowedConnection = bBorrowedConnection ;
|
||
m_hConnection = hConnection ;
|
||
m_hRequest = hRequest ;
|
||
m_ahPostedFiles = ahFileHandles ;
|
||
ahFileHandles = NULL ;
|
||
m_aszMimeTypes = aszMimeTypes ;
|
||
aszMimeTypes = NULL ;
|
||
m_bIsPost = FALSE ;
|
||
|
||
// Saves the initial Post context
|
||
if ( !m_mapParam.Empty () ) {
|
||
m_objInitialStat = m_objPostStat ;
|
||
// It always does not throw an overflow exception.
|
||
// So it's safe. (doesn't need to restore the internal states)
|
||
m_objInitialStat._StartNewEntry (szFirstParamName, cbFirstParamValue
|
||
, bFirstParamIsFile, szFirstParamFileName) ;
|
||
}
|
||
|
||
} catch (Exception &) {
|
||
HttpTool::CloseRequest (hRequest) ;
|
||
if ( !bBorrowedConnection ) HttpTool::CloseRequest (hConnection) ;
|
||
if ( !bBorrowedInternet ) HttpTool::CloseRequest (hInternet) ;
|
||
|
||
for (DWORD i = 0; i < nPostedFileCount; i++) {
|
||
if ( ahFileHandles ) {
|
||
if ( ahFileHandles[i] != INVALID_HANDLE_VALUE ) {
|
||
::CloseHandle (ahFileHandles[i]) ;
|
||
ahFileHandles[i] = INVALID_HANDLE_VALUE ;
|
||
}
|
||
}
|
||
|
||
if ( aszMimeTypes )
|
||
SAFEFREE ( (aszMimeTypes[i]) ) ;
|
||
}
|
||
SAFEFREE (ahFileHandles) ;
|
||
SAFEFREE (aszMimeTypes) ;
|
||
throw httpclientexceptionA();
|
||
}
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_QueryUploadStat (CHttpPostStat & objPostStat)
|
||
throw ()
|
||
{
|
||
// If the _ProceedUploadContext method is not called yet,
|
||
if ( (m_objPostStat.IsActive ()) && (m_objPostStat.TotalCount () > 0)
|
||
&& (m_objPostStat.PostedCount () == 0) )
|
||
objPostStat = m_objInitialStat ;
|
||
else
|
||
objPostStat = m_objPostStat ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
BOOL CHttpClientT<HttpTool, HttpEncoder>::_CancelUploadContext (void)
|
||
throw ()
|
||
{
|
||
if ( !m_objPostStat.IsActive () )
|
||
return FALSE ;
|
||
|
||
// Cancels the Post Context
|
||
_EndPostContext () ;
|
||
return TRUE ;
|
||
}
|
||
|
||
// If all parameters are sent, returns a pointer to the CHttpResponseT.
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::_ProceedUploadContext (DWORD nDesired)
|
||
throw (Exception &)
|
||
{
|
||
// If the Post context is not started
|
||
if ( !m_objPostStat.IsActive () )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_POST_NOT_STARTED) ;
|
||
|
||
HTTPCLIENT_ASSERT (m_hInternet != NULL, "CHttpClientT::_ProceedUploadContext: m_hInternet can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (m_hConnection != NULL, "CHttpClientT::_ProceedUploadContext: m_hConnection can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (m_hRequest != NULL, "CHttpClientT::_ProceedUploadContext: m_hRequest can not be NULL.") ;
|
||
HTTPCLIENT_ASSERT (nDesired != 0, "CHttpClientT::_ProceedUploadContext: nDesired can not be zero.") ;
|
||
|
||
try {
|
||
// If all parameters are posted
|
||
// releases the Post context
|
||
if ( m_objPostStat._IsComplete () ) {
|
||
HttpTool::EndRequest (m_hRequest) ;
|
||
return _ReleasePostResponse () ;
|
||
}
|
||
|
||
LPCSTR szBoundary = _GetUploadBoundaryA () ;
|
||
|
||
// If there is no parameter to upload
|
||
if ( m_objPostStat.TotalCount () == 0 ) {
|
||
// Writes the last boundary
|
||
_WritePost ("\r\n--") ;
|
||
_WritePost (szBoundary) ;
|
||
_WritePost ("--\r\n") ;
|
||
return NULL ;
|
||
}
|
||
|
||
// If the current parameter is completed
|
||
if ( m_objPostStat.CurrParamIsComplete () ) {
|
||
|
||
// If all parameters are sent
|
||
if ( m_objPostStat.TotalCount () == m_objPostStat.PostedCount () ) {
|
||
// Writes the last boundary
|
||
_WritePost ("--") ;
|
||
_WritePost (szBoundary) ;
|
||
_WritePost ("--\r\n") ;
|
||
return NULL ;
|
||
}
|
||
|
||
DWORD nNextIdx = m_objPostStat.PostedCount () ;
|
||
DWORD nNextFileIdx = m_objPostStat.PostedFileCount () ;
|
||
PCSZ szEntryFile = NULL ;
|
||
::SafeInt<size_t> nEntryValueTotalByte = 0 ;
|
||
|
||
ConstMapIter iter = m_mapParam.Begin () ;
|
||
for (size_t i = 0; i < nNextIdx; i++, ++iter) ;
|
||
|
||
if ( (iter->second).dwFlag & ParamFile ) {
|
||
// If the parameter is a file parameter
|
||
|
||
szEntryFile = (iter->second).szValue ;
|
||
if ( m_ahPostedFiles[nNextFileIdx] != INVALID_HANDLE_VALUE )
|
||
nEntryValueTotalByte = HttpTool::GetFileSize (m_ahPostedFiles[nNextFileIdx], szEntryFile) ;
|
||
|
||
// Writes the boundary and headers
|
||
_WritePost ("--") ;
|
||
_WritePost (szBoundary) ;
|
||
_WritePost ("\r\n") ;
|
||
_WritePost ("Content-Disposition: form-data; name=\"") ;
|
||
_WritePost (m_bUseUtf8, iter->first) ; // Writes form name
|
||
_WritePost ("\"; filename=\"") ;
|
||
_WritePost (m_bUseUtf8, szEntryFile) ; // Writes file path
|
||
_WritePost ("\"\r\nContent-Type: ") ;
|
||
_WritePost (m_aszMimeTypes[nNextFileIdx]) ;
|
||
_WritePost ("\r\n\r\n") ;
|
||
|
||
} else {
|
||
// If the parameter is not a file parameter
|
||
|
||
if ( (iter->second).szValue && (iter->second).szValue[0] != '\0' ) {
|
||
LPCSTR szPostedValue ;
|
||
BOOL bNeedToFree ;
|
||
|
||
if ( m_bUseUtf8 ) {
|
||
szPostedValue = _Utf8Encode ((iter->second).szValue) ;
|
||
bNeedToFree = TRUE ;
|
||
} else
|
||
// Converts into a Ansi string
|
||
szPostedValue = _String2Ansi ((iter->second).szValue, bNeedToFree) ;
|
||
|
||
nEntryValueTotalByte = CHttpToolA::StringLen (szPostedValue) ;
|
||
_SetPostedValue (szPostedValue, bNeedToFree) ;
|
||
} else {
|
||
_SetPostedValue (NULL, FALSE) ;
|
||
nEntryValueTotalByte = 0 ;
|
||
}
|
||
|
||
// Writes the boundary and headers
|
||
_WritePost ("--") ;
|
||
_WritePost (szBoundary) ;
|
||
_WritePost ("\r\n") ;
|
||
_WritePost ("Content-Disposition: form-data; name=\"") ;
|
||
_WritePost (m_bUseUtf8, iter->first) ; // Write form name
|
||
_WritePost ("\"\r\n\r\n") ;
|
||
}
|
||
|
||
// Starts a new parameter
|
||
m_objPostStat._StartNewEntry (iter->first, nEntryValueTotalByte.Value ()
|
||
, static_cast<BOOL> ((iter->second).dwFlag & ParamFile), szEntryFile) ;
|
||
|
||
if ( nEntryValueTotalByte == 0 )
|
||
_WritePost ("\r\n") ;
|
||
return NULL ;
|
||
}
|
||
|
||
// Writes the requested number of bytes
|
||
DWORD cbToWrite = nDesired ;
|
||
if ( cbToWrite > m_objPostStat.CurrParamRemainByte () )
|
||
cbToWrite = static_cast<DWORD> (m_objPostStat.CurrParamRemainByte ()) ;
|
||
|
||
DWORD cbWritten = 0 ;
|
||
|
||
if ( m_objPostStat.CurrParamIsFile () ) {
|
||
_InitPostCntxBuff () ;
|
||
|
||
DWORD cbBuff ; // The number of bytes to read
|
||
DWORD cbRead ; // The number of bytes read from the file
|
||
DWORD nFileIdx = m_objPostStat.PostedFileCount () - 1 ;
|
||
|
||
while ( cbWritten < cbToWrite ) {
|
||
cbBuff = cbToWrite - cbWritten >
|
||
HTTPCLIENT_POSTCNTX_BUFF_SIZE ? HTTPCLIENT_POSTCNTX_BUFF_SIZE : cbToWrite - cbWritten ;
|
||
|
||
// Read from file
|
||
if ( !::ReadFile (m_ahPostedFiles[nFileIdx]
|
||
, m_pbyCntxBuff
|
||
, cbBuff
|
||
, &cbRead
|
||
, NULL)
|
||
)
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_READFILE_FAILED, ::GetLastError ()) ;
|
||
|
||
// cbBuff and cbRead must be the same
|
||
if ( cbBuff != cbRead )
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_READ_UNEXPECTED_SIZE) ;
|
||
|
||
_WritePost (m_pbyCntxBuff, cbBuff, TRUE) ;
|
||
cbWritten += cbBuff ;
|
||
}
|
||
} else {
|
||
_WritePost (
|
||
reinterpret_cast<const BYTE *> (m_szPostedValue + m_objPostStat.CurrParamPostedByte ())
|
||
, cbToWrite, TRUE) ;
|
||
cbWritten = cbToWrite ;
|
||
}
|
||
|
||
// If all bytes are written, writes the last new line character
|
||
if ( m_objPostStat.CurrParamRemainByte () == 0 )
|
||
_WritePost ("\r\n") ;
|
||
|
||
} catch (::SafeIntException & e) {
|
||
_EndPostContext () ; // Aborts the POST context if an error occurs
|
||
HttpTool::ThrowException (e) ;
|
||
} catch (Exception &) {
|
||
_EndPostContext () ; // Aborts the POST context if an error occurs
|
||
throw ;
|
||
}
|
||
return NULL ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
typename CHttpClientT<HttpTool, HttpEncoder>::CHttpResponse *
|
||
CHttpClientT<HttpTool, HttpEncoder>::_ReleasePostResponse ()
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_objPostStat.IsActive (), "CHttpClientT::_ReleasePostResponse: The post context is not active.") ;
|
||
|
||
HINTERNET hReleasedInternet = NULL ;
|
||
HINTERNET hReleasedConnection = NULL ;
|
||
HINTERNET hReleasedRequest = NULL ;
|
||
|
||
_ReleasePostContext (hReleasedInternet, hReleasedConnection, hReleasedRequest) ;
|
||
CHttpResponse * pobjRes = NULL ;
|
||
|
||
try {
|
||
if ( NULL == (pobjRes = new CHttpResponse (hReleasedInternet, hReleasedConnection, hReleasedRequest)) )
|
||
throw "Out of memory" ;
|
||
|
||
} catch (...) {
|
||
HttpTool::CloseRequest (hReleasedRequest) ;
|
||
HttpTool::CloseConnection (hReleasedConnection) ;
|
||
HttpTool::CloseInternet (hReleasedInternet) ;
|
||
HttpTool::ThrowException (HTTPCLIENT_ERR_OUT_OF_MEMORY) ;
|
||
}
|
||
|
||
return pobjRes ;
|
||
}
|
||
|
||
// Releases the POST context when the upload task has been completed
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_ReleasePostContext (HINTERNET & hInternet, HINTERNET & hConnection, HINTERNET & hRequest)
|
||
throw (Exception &)
|
||
{
|
||
HTTPCLIENT_ASSERT (m_objPostStat.IsActive (), "CHttpClientT::_ReleasePostResponse: The post context is not active.") ;
|
||
|
||
hInternet = m_bBorrowedInternet ? NULL : m_hInternet ;
|
||
hConnection = m_bBorrowedConnection ? NULL : m_hConnection ;
|
||
hRequest = m_hRequest ;
|
||
|
||
m_hInternet = NULL ;
|
||
m_bBorrowedInternet = FALSE ;
|
||
m_hConnection = NULL ;
|
||
m_bBorrowedConnection = FALSE ;
|
||
m_hRequest = NULL ;
|
||
|
||
// Closes all file handles and frees the MimeType
|
||
if ( m_ahPostedFiles ) {
|
||
for (DWORD i = 0; i < m_objPostStat.FileCount (); i++) {
|
||
if ( m_ahPostedFiles[i] != INVALID_HANDLE_VALUE ) {
|
||
::CloseHandle (m_ahPostedFiles[i]) ;
|
||
m_ahPostedFiles[i] = INVALID_HANDLE_VALUE ;
|
||
}
|
||
|
||
if ( m_aszMimeTypes[i] )
|
||
SAFEFREE ( (m_aszMimeTypes[i]) ) ;
|
||
}
|
||
|
||
SAFEFREE (m_ahPostedFiles) ;
|
||
SAFEFREE (m_aszMimeTypes) ;
|
||
}
|
||
|
||
// Removes the posted value
|
||
_SetPostedValue (NULL, FALSE) ;
|
||
|
||
// Frees the buffer
|
||
SAFEFREE (m_pbyCntxBuff) ;
|
||
|
||
// Unactivate the Post context
|
||
m_objPostStat._MakeUnActive () ;
|
||
}
|
||
|
||
template <typename HttpTool, typename HttpEncoder>
|
||
void CHttpClientT<HttpTool, HttpEncoder>::_EndPostContext (void)
|
||
throw (Exception &)
|
||
{
|
||
if ( !m_objPostStat.IsActive () )
|
||
return ;
|
||
|
||
HINTERNET hInternet, hConnection, hRequest ;
|
||
_ReleasePostContext (hInternet, hConnection, hRequest) ;
|
||
|
||
// Closes internet handles
|
||
HttpTool::CloseRequest (hRequest) ;
|
||
HttpTool::CloseConnection (hConnection) ;
|
||
HttpTool::CloseInternet (hInternet) ;
|
||
}
|
||
///////////////////////////////////////// CHttpClientT /////////////////////////////////////////
|
||
|
||
}
|
||
|