📄 httprequest.cpp
字号:
void HttpRequest::MakeHeadMsg(BOOL post, LPTSTR buf)
{
LPTSTR start = buf;
if(post)
{
_tcscpy(start, _defaultContentType);
start += _tcslen(_defaultContentType);
}
if(h_File != NULL)
{
if(m_dwOffset != UINT_MAX)
{
_tcscpy(start, _T("\r\n"));
if(m_dwOffsetEnd != UINT_MAX)
_stprintf(start, _T("Range: bytes= %d-%d"), m_dwOffset, m_dwOffsetEnd);
else
_stprintf(start, _T("Range: bytes= %d-"), m_dwOffset);
}
}
}
BOOL HttpRequest::OpenRequest(LPCWSTR url, BOOL cache, LPCWSTR send)
{
#ifdef _UNICODE
LPCWSTR purl = url;
#else
char* purl = new char[2048];
WideCharToMultiByte(CP_ACP, 0, url, -1, purl, 2048, NULL, NULL);
#endif
size_t size = 0;
if(send != NULL)
size = wcslen(send) * sizeof(WCHAR);
LPVOID pdata = (LPVOID) send;
if(fWide == FALSE && send != NULL)
{
pdata = (LPVOID) new char[size];
WideCharToMultiByte(CP_ACP, 0, send, -1, (char*) pdata, size, NULL, NULL);
size = strlen((char*) pdata);
}
BOOL ret;
ret = OpenRequestEx(purl, cache, pdata, size);
#ifndef _UNICODE
delete[] purl;
#endif
if(fWide == FALSE && send != NULL)
delete[] pdata;
return ret;
}
BOOL HttpRequest::OpenRequest(LPCSTR url, BOOL cache, LPCSTR send)
{
#ifndef _UNICODE
LPCSTR purl = url;
#else
WCHAR* purl = new WCHAR[2048];
MultiByteToWideChar(CP_ACP, 0, url, -1, purl, 2048);
#endif
DWORD size = 0;
if(send != NULL)
size = strlen(send);
LPVOID pdata = (LPVOID) send;
if(fWide != FALSE && send != NULL)
{
pdata = (LPVOID) new WCHAR[size];
MultiByteToWideChar(CP_ACP, 0, send, -1, (WCHAR*) pdata, size);
size = wcslen((WCHAR*) pdata)*sizeof(WCHAR);
}
BOOL ret;
ret = OpenRequestEx(purl, cache, pdata, size);
#ifdef _UNICODE
delete[] purl;
#endif
if(fWide != FALSE && send != NULL)
delete[] pdata;
return ret;
}
BOOL HttpRequest::OpenRequestEx(LPCTSTR url, BOOL cache, const void* send, DWORD sendsize)
{
HANDLE hSemaphore = ::OpenSemaphore(SEMAPHORE_ALL_ACCESS | SEMAPHORE_MODIFY_STATE | SYNCHRONIZE
, NULL, HTTP_REQUEST_LIMIT_NAME);
BOOL funOK = FALSE;
HINTERNET HSO = NULL;
HINTERNET HIO = NULL;
HINTERNET HQO = NULL;
TCHAR* p_stN = new TCHAR[256];
TCHAR* p_flN = new TCHAR[2048];
TCHAR* p_bufstr = new TCHAR[1024];
BYTE* p_buf = new BYTE[1024];
DWORD port = 80;
__try{
if(!ParseURL(url, p_stN, p_flN, &port))
{
errorcode = ERROR_INTERNET_NAME_NOT_RESOLVED;
__leave;
}
if(hSemaphore)
{
DWORD ret = ::WaitForSingleObject(hSemaphore, Connect_timeout*2);
if(ret == WAIT_TIMEOUT)
{
errorcode = 12002;
__leave;
}
else if(ret == WAIT_ABANDONED)
{
errorcode = USER_STOP;
__leave;
}
}
DWORD type; LPCTSTR proxystr = NULL;
switch(b_useproxy)
{
case 0: type = INTERNET_OPEN_TYPE_DIRECT;break;
case 1: type = INTERNET_OPEN_TYPE_PRECONFIG;break;
case 2: type = INTERNET_OPEN_TYPE_PROXY;
proxystr = m_proxystr;
break;
default: type = INTERNET_OPEN_TYPE_PRECONFIG;break;
}
HSO = ::InternetOpen(INTERNET_CONNECT_ADAGENT, type, proxystr, NULL, INTERNET_FLAG_ASYNC);
if(HSO == NULL)
{
errorcode = GetLastError();
__leave;
}
if(::InternetSetStatusCallback(HSO, AsyncInternetCallback) == INTERNET_INVALID_STATUS_CALLBACK)
{
errorcode = GetLastError();
__leave;
}
HDResetEvent();
HIO = InternetConnect(HSO, p_stN, (WORD) port , NULL,NULL,
INTERNET_SERVICE_HTTP , 0, reinterpret_cast<DWORD>(this));
if(HIO == NULL)
{
if(WaitingEvent(Connect_timeout))
__leave;
HIO = m_hInternet;
}
// 3.初始化下载请求
const TCHAR AcceptType[] = _T("*/*");
LPCTSTR p_FA[] = {AcceptType, NULL};
TCHAR Verb[10];
if(send != NULL)
_tcscpy(Verb, _T("POST"));
else
_tcscpy(Verb, _T("GET"));
if(!cache)
type = INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_RELOAD;
else
type = 0;
HDResetEvent();
HQO = HttpOpenRequest(HIO,
Verb, // 从服务器获取数据
p_flN, // 想读取的文件的名称
_T("HTTP/1.1"), // 使用的协议
NULL,
p_FA,
type,
reinterpret_cast<DWORD>(this));
// 4.发送下载请求
*p_bufstr = 0;
MakeHeadMsg(send != NULL, p_bufstr);
BOOL ret;
if(*p_bufstr == 0)
ret = HttpSendRequest(HQO, NULL, 0, NULL, 0);
else if(send != NULL)
ret = HttpSendRequest(HQO, p_bufstr, _tcslen(p_bufstr), (LPVOID) send, sendsize);
else
ret = HttpSendRequest(HQO, p_bufstr, _tcslen(p_bufstr), NULL, 0);
if(!ret)
{
if(WaitingEvent(Connect_timeout))
__leave;
}
DWORD length, result;
result = 32774; //ERROR_HTML
length = sizeof(result);
if(!::HttpQueryInfo(HQO , HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER
, &result, &length, NULL))
{
errorcode = GetLastError();
__leave;
}
if(result != 200 && result != 206)
{
errorcode = result;
__leave;
}
result = UINT_MAX;
/* TCHAR* tbuf = new TCHAR[1024];
length = 1024;
::HttpQueryInfo(HQO , HTTP_QUERY_RAW_HEADERS_CRLF , tbuf, &length, NULL);*/
::HttpQueryInfo(HQO , HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &result, &length, NULL);
if(result == UINT_MAX)
result = 1024;
else
result += 1; //避免一次无效的扩展缓冲区
//downloading
InitWrite(result);
//**********the internetreadfileexW can't not be used for some reason *************//
INTERNET_BUFFERSA i_buf = {0};
i_buf.dwStructSize = sizeof(INTERNET_BUFFERSA);
i_buf.lpcszHeader = NULL;
i_buf.dwBufferLength = 1024;
i_buf.lpvBuffer = p_buf;
while(1)
{
HDResetEvent();
if (FALSE == ::InternetReadFileExA(HQO , &i_buf, IRF_ASYNC, reinterpret_cast<DWORD>(this)))
{
if(WaitingEvent(Request_timeout))
__leave;
}
else
{
//在网络传输速度快,步长较小的情况下,
//InternetReadFileEx 经常会直接返回成功,
//因此要判断是否发生了用户要求终止子线程事件。
if (WAIT_OBJECT_0 == ::WaitForSingleObject(m_hEvent[0], 0))
{
errorcode = USER_STOP;
__leave;
}
}
if(i_buf.dwBufferLength == 0)
break;
if(!WriteBuffer(p_buf, i_buf.dwBufferLength))
__leave;
i_buf.dwBufferLength = 1024;
i_buf.lpvBuffer = p_buf;
}
readstrpos = 0;
buflength = m_dwOffset;
funOK = TRUE;
}
__finally
{
InternetCloseHandleAsync(HQO);
InternetCloseHandleAsync(HSO);
if(hSemaphore)
::ReleaseSemaphore(hSemaphore, 1, NULL);
delete[] p_stN;
delete[] p_flN;
delete[] p_buf;
delete[] p_bufstr;
}
return funOK;
}
BOOL HttpRequest::ParseURL(LPCTSTR src, LPTSTR stN, LPTSTR flN, DWORD* port)
{
TCHAR* p_src = new TCHAR[4096];
_tcscpy(p_src, src);
TCHAR* tmp = _tcsstr(p_src, _T("http://"));
if(tmp == NULL || (p_src - tmp) != 0)
{
delete[] p_src;
return FALSE;
}
tmp = _tcschr(p_src + 7, _T('/'));
if(tmp == NULL)
{
flN[0] = 0;
_tcscpy(stN, p_src + 7);
}
else
{
*tmp = 0;
_tcscpy(stN, p_src + 7);
*tmp = _T('/');
_tcscpy(flN, tmp);
}
tmp = _tcschr(stN, _T(':'));
if(tmp == NULL)
*port = 80;
else
{
*tmp = 0;
*port = _ttoi(tmp + 1);
}
delete[] p_src;
return TRUE;
}
void CALLBACK HttpRequest::AsyncInternetCallback(
HINTERNET hInternet,
DWORD dwContext,
DWORD dwInternetStatus,
LPVOID lpvStatusInformation,
DWORD dwStatusInformationLength)
{
HttpRequest * pObj = reinterpret_cast<HttpRequest*>(dwContext);
switch(dwInternetStatus)
{
//句柄被创建
case INTERNET_STATUS_HANDLE_CREATED:
pObj->m_hInternet = (HINTERNET)(((LPINTERNET_ASYNC_RESULT)
(lpvStatusInformation))->dwResult);
break;
//句柄被关闭
case INTERNET_STATUS_HANDLE_CLOSING:
::SetEvent(pObj->m_hEvent[1]);
break;
//一个请求完成,比如一次句柄创建的请求,或者一次读数据的请求
case INTERNET_STATUS_REQUEST_COMPLETE:
//如果发生错误,则设置子线程退出事件
//这里也是一个陷阱,经常会忽视处理这个错误,
DWORD ret;
if (( ret = ((LPINTERNET_ASYNC_RESULT) (lpvStatusInformation))->dwError) != ERROR_SUCCESS)
pObj->errorcode = ret;
else
pObj->errorcode = 0;
::SetEvent(pObj->m_hEvent[1]);
break;
//连接中断
case INTERNET_STATUS_CONNECTION_CLOSED:
break;
//重定向连接
case INTERNET_STATUS_REDIRECT:
break;
//已连接
case INTERNET_STATUS_CONNECTED_TO_SERVER:
break;
//解析服务器
case INTERNET_STATUS_RESOLVING_NAME:
break;
case INTERNET_STATUS_REQUEST_SENT:
break;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -