651 lines
17 KiB
C++
651 lines
17 KiB
C++
#include "sgu_stdafx.h"
|
|
#include "sgu_download_ant.h"
|
|
#include "sgu_utils.h"
|
|
|
|
#include "libEncrypt_MD5.h"
|
|
|
|
#define debugLog(...) __noop
|
|
|
|
bool parseURL(const wchar_t* pstrURL, INTERNET_SCHEME& schemeType, wchar_t* strServer, wchar_t* strObject, INTERNET_PORT& nPort);
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
CDownloadAnt::CDownloadAnt()
|
|
{
|
|
m_hThread = 0;
|
|
|
|
m_theStateCategory = IDLE;
|
|
m_theState = IDLE_NOTINIT;
|
|
|
|
m_wszURLToDownload[0] = 0;
|
|
m_wszFileToDownloadInto[0] = 0;
|
|
|
|
m_pOwner = NULL;
|
|
|
|
m_schemeType = INTERNET_SCHEME_UNKNOWN;
|
|
m_wszServer[0] = 0;
|
|
m_wszObject[0] = 0;
|
|
m_nPort = 80;
|
|
|
|
m_hInternetSession = NULL;
|
|
m_hHttpConnection = NULL;
|
|
m_hHttpFile = NULL;
|
|
|
|
m_dwUserCmd = MANAGER_CMD_CONTINUE;
|
|
m_nOverTime = INFINITE;
|
|
|
|
m_bGotFileSize = FALSE;
|
|
m_dwFileSizeTotal = 0;
|
|
m_dwFileSizeRead = 0;
|
|
m_fpFileToWrite = NULL;
|
|
|
|
UserCallBack = NULL;
|
|
|
|
m_wszStatusInfor[0] = 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
CDownloadAnt::~CDownloadAnt()
|
|
{
|
|
//关闭
|
|
UserCallBack = NULL;
|
|
if (m_hHttpFile)
|
|
{
|
|
::InternetCloseHandle(m_hHttpFile);
|
|
m_hHttpFile = NULL;
|
|
}
|
|
if (m_hHttpConnection)
|
|
{
|
|
::InternetCloseHandle(m_hHttpConnection);
|
|
m_hHttpConnection = NULL;
|
|
}
|
|
if (m_hInternetSession)
|
|
{
|
|
::InternetCloseHandle(m_hInternetSession);
|
|
m_hInternetSession = NULL;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
bool CDownloadAnt::init(const wchar_t* wszURLToDownload, const wchar_t* wszFileToDownloadInto,
|
|
DOWNANT_STATUS_CALLBACK funcUserCallBack, void* pOwner, unsigned int nOverTime)
|
|
{
|
|
assert(m_theStateCategory != BUSY);
|
|
assert(wszURLToDownload && wszFileToDownloadInto);
|
|
|
|
StringCchCopyW(m_wszURLToDownload, INTERNET_MAX_URL_LENGTH, wszURLToDownload);
|
|
StringCchCopyW(m_wszFileToDownloadInto, MAX_PATH, wszFileToDownloadInto);
|
|
|
|
debugLog(L"build ant download \"%s\" to \"%s\"", m_wszURLToDownload, m_wszFileToDownloadInto);
|
|
|
|
m_pOwner = pOwner;
|
|
UserCallBack = funcUserCallBack;
|
|
|
|
if (wcslen(m_wszURLToDownload) > 0 && wcslen(m_wszFileToDownloadInto) > 0)
|
|
{
|
|
if (!parseURL(m_wszURLToDownload, m_schemeType, m_wszServer, m_wszObject, m_nPort) ||
|
|
m_schemeType == INTERNET_SCHEME_UNKNOWN)
|
|
{
|
|
const wchar_t* wsz = L"Parser URL Error: %s";
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"Parser URL Error: %s", m_wszURLToDownload);
|
|
setStatus(IDLE_INIT_FAILED);
|
|
return FALSE;
|
|
}
|
|
setStatus(IDLE_INIT_SUCCESS);
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"url and local file address can't be empty!");
|
|
setStatus(IDLE_INIT_FAILED);
|
|
return FALSE;
|
|
}
|
|
|
|
m_nOverTime = nOverTime;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
void CDownloadAnt::begin(bool bBlock)
|
|
{
|
|
assert(m_theState == IDLE_INIT_SUCCESS);
|
|
|
|
UINT nThreadID;
|
|
m_hThread = (HANDLE)::_beginthreadex(NULL, 0, _downloadThread, this, CREATE_SUSPENDED, &nThreadID);
|
|
|
|
if (m_hThread == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
setStatus(BUSY_BEGIN_THREAD);
|
|
m_beginTime = ::GetTickCount64();
|
|
ResumeThread(m_hThread);
|
|
|
|
if (bBlock)
|
|
{
|
|
::WaitForSingleObject(m_hThread, INFINITE);
|
|
//关闭句柄
|
|
CloseHandle(m_hThread); m_hThread = 0;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
UINT CDownloadAnt::_downloadThread(void* pParam)
|
|
{
|
|
CDownloadAnt* pAnt = (CDownloadAnt*)pParam;
|
|
assert(pAnt);
|
|
|
|
try
|
|
{
|
|
pAnt->downloadThread();
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
void CDownloadAnt::downloadThread(void)
|
|
{
|
|
assert(m_theState == BUSY_BEGIN_THREAD);
|
|
assert(m_hInternetSession == NULL);
|
|
assert(m_fpFileToWrite == NULL);
|
|
assert(m_hHttpConnection == NULL);
|
|
assert(m_hHttpFile == NULL);
|
|
|
|
_wfopen_s(&m_fpFileToWrite, m_wszFileToDownloadInto, L"wb");
|
|
if (m_fpFileToWrite == NULL)
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"Create local file error: %s, Error:%d", m_wszFileToDownloadInto, ::GetLastError());
|
|
setStatus(FINISH_ERROR_TRY_OPEN_LOCALFILE);
|
|
return;
|
|
}
|
|
|
|
//打开Internet句柄
|
|
m_hInternetSession = InternetOpenW(NULL, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
|
|
if (m_hInternetSession == NULL)
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"(::InternetOpen) Error:%d\n", ::GetLastError());
|
|
setStatus(FINISH_ERROR_INTERNET_OPEN);
|
|
return;
|
|
}
|
|
if (_checkAbort()) return;
|
|
|
|
DWORD dwTemp = 0, dwSize = sizeof(DWORD);
|
|
BOOL bRet = InternetQueryOptionW(m_hInternetSession, INTERNET_OPTION_MAX_CONNS_PER_SERVER, &dwTemp, &dwSize);
|
|
DWORD dwErr = GetLastError();
|
|
|
|
//设置状态回调函数
|
|
if (::InternetSetStatusCallbackW(m_hInternetSession, _onWininetStatusCallBack) == INTERNET_INVALID_STATUS_CALLBACK)
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"(::InternetSetStatusCallback), Error:%d\n", ::GetLastError());
|
|
setStatus(FINISH_ERROR_SETSTATUSCALLBACK);
|
|
return;
|
|
}
|
|
if (_checkAbort()) return;
|
|
|
|
DWORD serviceType = 0;
|
|
if(m_schemeType == INTERNET_SCHEME_HTTP||m_schemeType== INTERNET_SCHEME_HTTPS)
|
|
{
|
|
serviceType = INTERNET_SERVICE_HTTP;
|
|
}
|
|
else if (m_schemeType == INTERNET_SCHEME_FTP)
|
|
{
|
|
serviceType = INTERNET_SERVICE_FTP;
|
|
}
|
|
else
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"Unsupported scheme type: %d", m_schemeType);
|
|
setStatus(FINISH_ERROR_UNSUPPORTED_SCHEME);
|
|
return;
|
|
}
|
|
|
|
//打开Internet连接
|
|
m_hHttpConnection = InternetConnectW(m_hInternetSession, m_wszServer, m_nPort, NULL,
|
|
NULL, serviceType, 0, (DWORD_PTR)this);
|
|
|
|
if (m_hHttpConnection == NULL)
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"(::InternetConnect), Error:%d\n", ::GetLastError());
|
|
setStatus(FINISH_ERROR_INTERNETCONNECT);
|
|
return;
|
|
}
|
|
if (_checkAbort()) return;
|
|
|
|
//生成Request
|
|
const wchar_t* ppszAcceptTypes[2];
|
|
ppszAcceptTypes[0] = L"*/*";
|
|
ppszAcceptTypes[1] = NULL;
|
|
|
|
DWORD dwFlags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_NO_COOKIES;
|
|
if(serviceType==INTERNET_SERVICE_HTTP && m_schemeType == INTERNET_SCHEME_HTTPS)
|
|
{
|
|
dwFlags |= INTERNET_FLAG_SECURE;
|
|
}
|
|
|
|
m_hHttpFile = HttpOpenRequestW(m_hHttpConnection,
|
|
L"GET", m_wszObject, NULL, NULL, ppszAcceptTypes,
|
|
dwFlags,
|
|
(DWORD_PTR)this);
|
|
if (m_hHttpFile == NULL)
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"(::HttpOpenRequest), Error:%d\n", ::GetLastError());
|
|
setStatus(FINISH_ERROR_OPENREQUEST);
|
|
return;
|
|
}
|
|
if (_checkAbort()) return;
|
|
setStatus(BUSY_OPEN_REQUEST);
|
|
|
|
//发送Request
|
|
BOOL bSend = HttpSendRequestW(m_hHttpFile, NULL, 0, NULL, 0);
|
|
if (!bSend)
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"(::HttpSendRequest), Error:%d\n", ::GetLastError());
|
|
setStatus(FINISH_ERROR_SENDREQUEST);
|
|
return;
|
|
}
|
|
if (_checkAbort()) return;
|
|
|
|
//查询状态
|
|
DWORD dwInfoSize = 64;
|
|
CHAR szStatusCode[64] = { 0 };
|
|
if (!::HttpQueryInfoW(m_hHttpFile, HTTP_QUERY_STATUS_CODE, szStatusCode, &dwInfoSize, NULL))
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"Failed in call to HttpQueryInfo for HTTP query status code, Error:%d\n", ::GetLastError());
|
|
setStatus(FINISH_ERROR_QUERYINFO);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
long nStatusCode = atoi(szStatusCode);
|
|
|
|
if (nStatusCode != HTTP_STATUS_OK)
|
|
{
|
|
m_theState = FINISH_ERROR_INVALID_HTTP_RESPONSE;
|
|
|
|
if (nStatusCode == HTTP_STATUS_PROXY_AUTH_REQ)
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"Authentication errors, Status Code:%d\n", nStatusCode);
|
|
setStatus(FINISH_ERROR_NEED_PROXY_AUTH_REQ);
|
|
return;
|
|
}
|
|
else if (nStatusCode == HTTP_STATUS_DENIED)
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"Authentication errors, Status Code:%d\n", nStatusCode);
|
|
setStatus(FINISH_ERROR_DENIED);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (_checkAbort()) return;
|
|
|
|
// 取得文件大小
|
|
dwInfoSize = 64;
|
|
wchar_t wszContentLength[64] = { 0 };
|
|
if (HttpQueryInfoW(m_hHttpFile, HTTP_QUERY_CONTENT_LENGTH, wszContentLength, &dwInfoSize, NULL))
|
|
{
|
|
m_bGotFileSize = TRUE;
|
|
m_dwFileSizeTotal = _wtoi64(wszContentLength);
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"FileSize: %I64d", m_dwFileSizeTotal);
|
|
}
|
|
|
|
debugLog(L"Get file size %I64d, begin download...", m_dwFileSizeTotal);
|
|
//得到文件大小,让Manager处理位置
|
|
setStatus(BUSY_GET_FILE_INFORMATION);
|
|
if (_checkAbort()) return;
|
|
|
|
//开始下载
|
|
ULONGLONG startTicks = ::GetTickCount64();
|
|
DWORD dwBytesRead = 0;
|
|
char szReadBuf[DOWNANT_MINSIZE] = { 0 };
|
|
DWORD dwBytesToRead = DOWNANT_MINSIZE;
|
|
m_dwFileSizeRead = 0;
|
|
|
|
MD5Context md5Ctx;
|
|
md5Init(&md5Ctx);
|
|
|
|
setStatus(BUSY_BEGIN_DOWNFILE);
|
|
do
|
|
{
|
|
if (!InternetReadFile(m_hHttpFile, szReadBuf, dwBytesToRead, &dwBytesRead))
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"(::InternetReadFile), Error:%d\n", ::GetLastError());
|
|
setStatus(FINISH_ERROR_READFILE);
|
|
return;
|
|
}
|
|
else if (dwBytesRead && m_dwUserCmd == MANAGER_CMD_CONTINUE)
|
|
{
|
|
try
|
|
{
|
|
if (dwBytesRead != ::fwrite(szReadBuf, 1, dwBytesRead, m_fpFileToWrite))
|
|
{
|
|
throw FINISH_ERROR_EXCEPTION;
|
|
}
|
|
|
|
md5Update(&md5Ctx, (unsigned char*)szReadBuf, dwBytesRead);
|
|
}
|
|
catch (...)
|
|
{
|
|
StringCchPrintfW(m_wszStatusInfor, MAX_PATH, L"write local file error!, Error:%d", ::GetLastError());
|
|
setStatus(FINISH_ERROR_EXCEPTION);
|
|
return;
|
|
}
|
|
|
|
m_dwFileSizeRead += dwBytesRead;
|
|
onStatusCallback();
|
|
}
|
|
|
|
if (_checkAbort())
|
|
{
|
|
if (m_fpFileToWrite)::fclose(m_fpFileToWrite);
|
|
m_fpFileToWrite = NULL;
|
|
return;
|
|
}
|
|
} while (dwBytesRead && m_dwUserCmd == MANAGER_CMD_CONTINUE);
|
|
|
|
//生成MD5
|
|
m_fileMD5 = md5Finalize(&md5Ctx);
|
|
|
|
if (m_fpFileToWrite)::fclose(m_fpFileToWrite);
|
|
m_fpFileToWrite = NULL;
|
|
|
|
debugLog(L"Download success over!");
|
|
|
|
setStatus(FINISH_SUCCESS_OVER);
|
|
return;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
bool CDownloadAnt::checkMD5(const char* md5_string) const
|
|
{
|
|
MD5Digest md5;
|
|
if (!string2MD5(md5_string, md5)) return false;
|
|
|
|
return (0 == memcmp(&md5, &m_fileMD5, md5.size()));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
void CALLBACK CDownloadAnt::_onWininetStatusCallBack(HINTERNET hInternet, DWORD_PTR dwContext, DWORD dwInternetStatus,
|
|
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)
|
|
{
|
|
CDownloadAnt* pDownMan = (CDownloadAnt*)dwContext;
|
|
assert(pDownMan);
|
|
|
|
pDownMan->onWininetStatusCallBack(hInternet, dwInternetStatus, lpvStatusInformation, dwStatusInformationLength);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
void CDownloadAnt::onWininetStatusCallBack(HINTERNET /*hInternet*/, DWORD dwInternetStatus,
|
|
LPVOID lpvStatusInformation, DWORD /*dwStatusInformationLength*/)
|
|
{
|
|
switch (dwInternetStatus)
|
|
{
|
|
case INTERNET_STATUS_RESOLVING_NAME:
|
|
{
|
|
StringCchCopyW(m_wszStatusInfor, MAX_PATH, (LPCWSTR)lpvStatusInformation);
|
|
setStatus(BUSY_RESOLVING_NAME);
|
|
break;
|
|
}
|
|
case INTERNET_STATUS_NAME_RESOLVED:
|
|
{
|
|
StringCchCopyW(m_wszStatusInfor, MAX_PATH, (LPCWSTR)lpvStatusInformation);
|
|
setStatus(BUSY_RESOLVED_NAME);
|
|
break;
|
|
}
|
|
case INTERNET_STATUS_CONNECTING_TO_SERVER:
|
|
{
|
|
StringCchCopyW(m_wszStatusInfor, MAX_PATH, (LPCWSTR)lpvStatusInformation);
|
|
setStatus(BUSY_CONNECTING);
|
|
break;
|
|
}
|
|
case INTERNET_STATUS_CONNECTED_TO_SERVER:
|
|
{
|
|
StringCchCopyW(m_wszStatusInfor, MAX_PATH, (LPCWSTR)lpvStatusInformation);
|
|
setStatus(BUSY_CONNECTED);
|
|
break;
|
|
}
|
|
case INTERNET_STATUS_REDIRECT:
|
|
{
|
|
StringCchCopyW(m_wszStatusInfor, MAX_PATH, (LPCWSTR)lpvStatusInformation);
|
|
setStatus(BUSY_REDIRECTING);
|
|
break;
|
|
}
|
|
|
|
default: break;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
void CDownloadAnt::setStatus(CDownloadAnt::DOWN_STATE newState)
|
|
{
|
|
m_theState = newState;
|
|
onStatusCallback();
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
void CDownloadAnt::onStatusCallback(void)
|
|
{
|
|
switch (m_theState)
|
|
{
|
|
case IDLE_NOTINIT:
|
|
case IDLE_INIT_SUCCESS:
|
|
case IDLE_INIT_FAILED:
|
|
{
|
|
m_theStateCategory = IDLE;
|
|
}
|
|
break;
|
|
|
|
case BUSY_BEGIN_THREAD:
|
|
case BUSY_OPEN_REQUEST:
|
|
case BUSY_RESOLVING_NAME:
|
|
case BUSY_RESOLVED_NAME:
|
|
case BUSY_CONNECTING:
|
|
case BUSY_CONNECTED:
|
|
case BUSY_REDIRECTING:
|
|
case BUSY_GET_FILE_INFORMATION:
|
|
case BUSY_BEGIN_DOWNFILE:
|
|
{
|
|
m_theStateCategory = BUSY;
|
|
}
|
|
break;
|
|
|
|
case FINISH_SUCCESS_OVER:
|
|
case FINISH_SUCCESS_STOPHERE:
|
|
{
|
|
m_theStateCategory = FINISH_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
case FINISH_FORCEABORT:
|
|
case FINISH_ERROR_TIMEOUT:
|
|
case FINISH_ERROR_TRY_OPEN_LOCALFILE:
|
|
case FINISH_ERROR_INTERNET_OPEN:
|
|
case FINISH_ERROR_SETSTATUSCALLBACK:
|
|
case FINISH_ERROR_INTERNETCONNECT:
|
|
case FINISH_ERROR_OPENREQUEST:
|
|
case FINISH_ERROR_SENDREQUEST:
|
|
case FINISH_ERROR_QUERYINFO:
|
|
case FINISH_ERROR_NEED_PROXY_AUTH_REQ:
|
|
case FINISH_ERROR_DENIED:
|
|
case FINISH_ERROR_INVALID_HTTP_RESPONSE:
|
|
case FINISH_ERROR_READFILE:
|
|
case FINISH_ERROR_EXCEPTION:
|
|
{
|
|
m_theStateCategory = FINISH_NOT_SUCCESS;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
if (m_theStateCategory == FINISH_SUCCESS || m_theStateCategory == FINISH_NOT_SUCCESS)
|
|
{
|
|
if (m_fpFileToWrite)
|
|
{
|
|
::fclose(m_fpFileToWrite);
|
|
m_fpFileToWrite = NULL;
|
|
}
|
|
|
|
if (m_hHttpFile)
|
|
{
|
|
::InternetCloseHandle(m_hHttpFile);
|
|
m_hHttpFile = NULL;
|
|
}
|
|
if (m_hHttpConnection)
|
|
{
|
|
::InternetCloseHandle(m_hHttpConnection);
|
|
m_hHttpConnection = NULL;
|
|
}
|
|
if (m_hInternetSession)
|
|
{
|
|
::InternetCloseHandle(m_hInternetSession);
|
|
m_hInternetSession = NULL;
|
|
}
|
|
}
|
|
|
|
if (UserCallBack)
|
|
{
|
|
m_dwUserCmd = UserCallBack(m_pOwner, this);
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------------
|
|
BOOL CDownloadAnt::_checkAbort(void)
|
|
{
|
|
HANDLE hCloseMutex = OpenMutexW(SYNCHRONIZE, FALSE, L"Global\\8e931dcb-868e-4ba6-aff4-d1a22bc9d476");
|
|
if (hCloseMutex != 0)
|
|
{
|
|
CloseHandle(hCloseMutex);
|
|
debugLog(L"[ANT]Receive autoclose signal, quit!");
|
|
return TRUE;
|
|
}
|
|
|
|
if (MANAGER_CMD_FORCEABORT == m_dwUserCmd)
|
|
{
|
|
setStatus(FINISH_FORCEABORT);
|
|
return TRUE;
|
|
}
|
|
if (MANAGER_CMD_STOPHERE == m_dwUserCmd)
|
|
{
|
|
setStatus(FINISH_SUCCESS_STOPHERE);
|
|
return TRUE;
|
|
}
|
|
|
|
if (m_nOverTime != INFINITE && m_theStateCategory == BUSY)
|
|
{
|
|
ULONGLONG timeNow = ::GetTickCount64();
|
|
ULONGLONG timeRun;
|
|
if (timeNow >= m_beginTime) timeRun = timeNow - m_beginTime;
|
|
else timeRun = timeNow + (0XFFFFFFFFFFFFFFFFULL - m_beginTime);
|
|
|
|
if (timeRun > m_nOverTime * 1000ULL)
|
|
{
|
|
setStatus(FINISH_ERROR_TIMEOUT);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
BOOL MyAfxIsValidAddress(const void* lp, UINT nBytes, BOOL bReadWrite /* = TRUE */)
|
|
{
|
|
// simple version using Win-32 APIs for pointer validation.
|
|
return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
|
|
(!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
|
|
}
|
|
|
|
bool _AfxParseURLWorker(const wchar_t* pstrURL, LPURL_COMPONENTSW lpComponents,
|
|
INTERNET_SCHEME& schemeType, INTERNET_PORT& nPort, DWORD dwFlags)
|
|
{
|
|
// this function will return bogus stuff if lpComponents
|
|
// isn't set up to copy the components
|
|
|
|
assert(lpComponents != NULL && pstrURL != NULL);
|
|
if (lpComponents == NULL || pstrURL == NULL)
|
|
return FALSE;
|
|
assert(lpComponents->dwHostNameLength == 0 ||
|
|
lpComponents->lpszHostName != NULL);
|
|
assert(lpComponents->dwUrlPathLength == 0 ||
|
|
lpComponents->lpszUrlPath != NULL);
|
|
assert(lpComponents->dwUserNameLength == 0 ||
|
|
lpComponents->lpszUserName != NULL);
|
|
assert(lpComponents->dwPasswordLength == 0 ||
|
|
lpComponents->lpszPassword != NULL);
|
|
|
|
assert(MyAfxIsValidAddress(lpComponents, sizeof(URL_COMPONENTS), TRUE));
|
|
|
|
wchar_t* pstrCanonicalizedURL;
|
|
wchar_t szCanonicalizedURL[INTERNET_MAX_URL_LENGTH];
|
|
DWORD dwNeededLength = INTERNET_MAX_URL_LENGTH;
|
|
BOOL bRetVal;
|
|
BOOL bMustFree = FALSE;
|
|
DWORD dwCanonicalizeFlags = dwFlags &
|
|
(ICU_NO_ENCODE | ICU_DECODE | ICU_NO_META |
|
|
ICU_ENCODE_SPACES_ONLY | ICU_BROWSER_MODE);
|
|
DWORD dwCrackFlags = dwFlags & (ICU_ESCAPE | ICU_USERNAME);
|
|
|
|
bRetVal = InternetCanonicalizeUrlW(pstrURL, szCanonicalizedURL,
|
|
&dwNeededLength, dwCanonicalizeFlags);
|
|
|
|
if (!bRetVal)
|
|
{
|
|
if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
|
return FALSE;
|
|
|
|
pstrCanonicalizedURL = new wchar_t[dwNeededLength];
|
|
bMustFree = TRUE;
|
|
bRetVal = InternetCanonicalizeUrlW(pstrURL, pstrCanonicalizedURL,
|
|
&dwNeededLength, dwCanonicalizeFlags);
|
|
if (!bRetVal)
|
|
{
|
|
delete[] pstrCanonicalizedURL;
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
pstrCanonicalizedURL = szCanonicalizedURL;
|
|
|
|
// now that it's safely canonicalized, crack it
|
|
bRetVal = InternetCrackUrlW(pstrCanonicalizedURL, 0, dwCrackFlags, lpComponents);
|
|
if (bMustFree)
|
|
delete[] pstrCanonicalizedURL;
|
|
|
|
if (bRetVal)
|
|
{
|
|
nPort = lpComponents->nPort;
|
|
schemeType = lpComponents->nScheme;
|
|
}
|
|
else
|
|
{
|
|
schemeType = INTERNET_SCHEME_UNKNOWN;
|
|
}
|
|
|
|
return bRetVal == TRUE;
|
|
}
|
|
|
|
bool parseURL(const wchar_t* pstrURL, INTERNET_SCHEME& schemeType, wchar_t* strServer, wchar_t* strObject, INTERNET_PORT& nPort)
|
|
{
|
|
schemeType = INTERNET_SCHEME_UNKNOWN;
|
|
|
|
assert(pstrURL != NULL);
|
|
if (pstrURL == NULL)
|
|
return FALSE;
|
|
|
|
URL_COMPONENTSW urlComponents;
|
|
memset(&urlComponents, 0, sizeof(URL_COMPONENTS));
|
|
urlComponents.dwStructSize = sizeof(URL_COMPONENTS);
|
|
|
|
urlComponents.dwHostNameLength = MAX_PATH;
|
|
urlComponents.lpszHostName = strServer;
|
|
urlComponents.dwUrlPathLength = INTERNET_MAX_URL_LENGTH;
|
|
urlComponents.lpszUrlPath = strObject;
|
|
|
|
return _AfxParseURLWorker(pstrURL, &urlComponents, schemeType, nPort, ICU_BROWSER_MODE);
|
|
}
|
|
|