#include "stdafx.h"
#include "SocketHttp.h"
#pragma comment (lib, "ws2_32")
#include
#include "define.h"
#include "httpHeader.h"
CHttpSocket::CHttpSocket()
: m_socket(INVALID_SOCKET)
, m_nResponseCode(0)
{
memset(&m_paramsData, 0, sizeof(HttpParamsData));
}
CHttpSocket::~CHttpSocket()
{
if (INVALID_SOCKET != m_socket)
closesocket(m_socket);
}
bool CHttpSocket::InitSocket(const string& strHostName, const WORD sPort)
{
bool bResult = false;
try
{
//æ¥è¯¢åå对åºçIPå°å
HOSTENT* pHostent = gethostbyname(strHostName.c_str());
if (NULL == pHostent)
throw HttpErrorQueryIP;
char szIP[16] = { 0 };
sprintf_s(szIP, "%d.%d.%d.%d",
pHostent->h_addr_list[0][0] & 0x00ff,
pHostent->h_addr_list[0][1] & 0x00ff,
pHostent->h_addr_list[0][2] & 0x00ff,
pHostent->h_addr_list[0][3] & 0x00ff);
m_strIpAddr = A2U(szIP);
if (INVALID_SOCKET != m_socket)
closesocket(m_socket);
//è¿æ¥HTTPæå¡å¨
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (INVALID_SOCKET == m_socket)
throw HttpErrorSocket;
int nSec = 1000 * 10;//10ç§å
æ²¡ææ°æ®å说æç½ç»æå¼
setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&nSec, sizeof(int));
sockaddr_in addrServer;
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(sPort);
addrServer.sin_addr.S_un.S_addr = inet_addr(szIP);
if (SOCKET_ERROR == connect(m_socket, (SOCKADDR*)&addrServer, sizeof(addrServer)))
throw HttpErrorConnect;
bResult = true;
}
catch (HttpInterfaceError error)
{
m_paramsData.errcode = error;
}
catch (...)
{
}
return bResult;
}
bool CHttpSocket::DownloadFile(LPCWSTR lpUrl, LPCWSTR lpFilePath)
{
bool bResult = false;
FILE* fp = NULL;
BYTE* pBuffer = NULL;
try
{
wstring strHostName, strPage;
u_short uPort = 80;
MyParseUrlW(lpUrl, strHostName, strPage, uPort);
if (uPort == 443) {
//æ±æï¼socketæ¹å¼ææ¶ä¸æ¯æHTTPSåè®®
return false;
}
string host = U2A(strHostName);
if (!InitSocket(host, uPort))
throw L"";
m_header.setHost(host);
//è¿éå¯è½ä¼éå®å忥
__request:
m_header.setRequestPath(U2A(strPage));
std::string strSend = m_header.toString(HttpGet);
int nRet = send(m_socket, strSend.c_str(), strSend.size(), 0);
if (SOCKET_ERROR == nRet)
throw HttpErrorSend;
int nRecvSize = 0, nWriteSize = 0;
double nFileSize = 0, nLoadSize = 0;
bool bFilter = false;//HTTPè¿å头æ¯å¦å·²ç»è¢«è¿æ»¤æ
if (FileExistW(lpFilePath))
DeleteFile(lpFilePath);
_wfopen_s(&fp, lpFilePath, L"wb+");
if (NULL == fp)
throw HttpErrorCreateFile;
pBuffer = (BYTE*)malloc(READ_BUFFER_SIZE + 1);
do
{
if (m_paramsData.callback && m_paramsData.callback->IsNeedStop())
throw HttpErrorUserCancel;
nRecvSize = recv(m_socket, (char*)pBuffer, READ_BUFFER_SIZE, 0);
if (SOCKET_ERROR == nRecvSize)
throw HttpErrorSocket;
if (nRecvSize>0)
{
pBuffer[nRecvSize] = '\0';
if (!bFilter)
{
std::string str((char*)pBuffer);
int nPos = str.find("\r\n\r\n");
if (-1 == nPos)
continue;
std::string strHeader;
strHeader.append((char*)pBuffer, nPos);
CHttpHeader header(strHeader);
m_nResponseCode = header.GetHttpCode();
if (m_nResponseCode == 400) {
throw HttpError404;
}
if (m_nResponseCode >300 && m_nResponseCode <400)//éå®å
{
wstring strReLoadUrl = A2U(header.GetValue(HEADER_LOCATION));
if (strReLoadUrl.find(L"http://") != 0)
{
strPage = strReLoadUrl;
goto __request;
}
if (INVALID_SOCKET != m_socket)
{
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
//éå®ååï¼æ¸
çææ¬å½æ°å建çèµæº
free(pBuffer);
pBuffer = NULL;
fclose(fp);
fp = NULL;
return DownloadFile(strReLoadUrl.c_str(), lpFilePath);
}
nFileSize = atof(header.GetValue(HEADER_CONTENT_LENGTH).c_str());
nWriteSize = nRecvSize - nPos - 4;
if (nWriteSize>0)
{
fwrite(pBuffer + nPos + 4, nWriteSize, 1, fp);
nLoadSize += nRecvSize;
if (m_paramsData.callback)
m_paramsData.callback->OnDownloadCallback(m_paramsData.lpparam, HttpLoading, nFileSize, nLoadSize);
}
if (nFileSize == nLoadSize)
{
if (m_paramsData.callback)
m_paramsData.callback->OnDownloadCallback(m_paramsData.lpparam, HttpFinished, nFileSize, nLoadSize);
bResult = true;
break;
}
bFilter = true;
continue;
}
fwrite(pBuffer, nRecvSize, 1, fp);
nLoadSize += nRecvSize;
if (m_paramsData.callback)
m_paramsData.callback->OnDownloadCallback(m_paramsData.lpparam, HttpLoading, nFileSize, nLoadSize);
if (nLoadSize >= nFileSize)
{
bResult = true;
if (m_paramsData.callback)
m_paramsData.callback->OnDownloadCallback(m_paramsData.lpparam, HttpFinished, nFileSize, nLoadSize);
break;
}
}
} while (nRecvSize>0);
}
catch (HttpInterfaceError error)
{
m_paramsData.errcode = error;
if (m_paramsData.callback)
m_paramsData.callback->OnDownloadCallback(m_paramsData.lpparam, HttpFialed, 0, 0);
}
catch (...)
{
}
if (pBuffer)
{
free(pBuffer);
pBuffer = NULL;
}
if (fp)
{
fclose(fp);
fp = NULL;
}
if (!bResult)//ä¸è½½ä¸æåï¼å é¤ä¸å®æ´çæä»¶
DeleteFile(lpFilePath);
return bResult;
}
void CHttpSocket::SetDownloadCallback(IHttpCallback* pCallback, void* pParam)
{
m_paramsData.callback = pCallback;
m_paramsData.lpparam = pParam;
}
bool CHttpSocket::DownloadToMem(LPCWSTR lpUrl, OUT void** ppBuffer, OUT int* nSize)
{
bool bResult = false;
BYTE *pBuffer = NULL;
try
{
wstring strHostName, strPage;
u_short uPort = 80;
MyParseUrlW(lpUrl, strHostName, strPage, uPort);
if (uPort == 443) {
//æ±æï¼socketæ¹å¼ææ¶ä¸æ¯æHTTPSåè®®
return false;
}
string host = U2A(strHostName);
if (!InitSocket(host, uPort))
throw HttpErrorInit;
m_header.setHost(host);
//è¿éå¯è½ä¼éå®å忥
__request:
m_header.setRequestPath(U2A(strPage));
std::string strSend = m_header.toString(HttpGet);
int nRet = send(m_socket, strSend.c_str(), strSend.size(), 0);
if (SOCKET_ERROR == nRet)
throw HttpErrorSend;
int nRecvSize = 0, nWriteSize = 0;
int nFileSize = 0, nLoadSize = 0;
bool bFilter = false;//HTTPè¿å头æ¯å¦å·²ç»è¢«è¿æ»¤æ
const int nBufferSzie = 1024 * 4;
char szHeader[nBufferSzie + 1];
while (true)
{
nRecvSize = recv(m_socket, szHeader, nBufferSzie, 0);
if (SOCKET_ERROR == nRecvSize)
throw HttpErrorSocket;
if (nRecvSize == 0)
break;
if (!bFilter)
{
std::string str(szHeader, nRecvSize);
int nPos = str.find("\r\n\r\n");
if (-1 == nPos)
throw HttpErrorHeader;
std::string strHeader(szHeader, nPos);
CHttpHeader header(strHeader);
m_nResponseCode = header.GetHttpCode();
if (m_nResponseCode == 400) {
throw HttpError404;
}
if (m_nResponseCode >300 && m_nResponseCode <400)//éå®å
{
wstring reloadUrl = A2U(header.GetValue(HEADER_LOCATION));
if (reloadUrl.find(L"http://") != 0 && reloadUrl.find(L"https://") != 0)
{
strPage = reloadUrl;
goto __request;
}
if (INVALID_SOCKET != m_socket)
{
closesocket(m_socket);
m_socket = INVALID_SOCKET;
}
return DownloadToMem(reloadUrl.c_str(), ppBuffer, nSize);
}
nFileSize = atoi(header.GetValue(HEADER_CONTENT_LENGTH).c_str());
*nSize = nFileSize;
if (nFileSize>DOWNLOAD_BUFFER_SIZE || nFileSize <= 0)
throw HttpErrorBuffer;
pBuffer = (BYTE*)malloc(nFileSize);
nWriteSize = nRecvSize - nPos - 4;
if (nWriteSize>0)
{
memcpy(pBuffer + nLoadSize, szHeader + nPos + 4, nWriteSize);
nLoadSize += nWriteSize;
}
if (nFileSize == nLoadSize)
{
bResult = true;
break;
}
bFilter = true;
continue;
}
memcpy(pBuffer + nLoadSize, szHeader, nRecvSize);
nLoadSize += nRecvSize;
if (nLoadSize >= nFileSize)
{
bResult = true;
break;
}
}
}
catch (HttpInterfaceError error)
{
m_paramsData.errcode = error;
if (pBuffer)
{
free(pBuffer);
pBuffer = NULL;
}
*ppBuffer = NULL;
*nSize = 0;
}
if (bResult)
{
*ppBuffer = pBuffer;
}
return bResult;
}
void CHttpSocket::AddHeader(LPCSTR key, LPCSTR value)
{
if (isEmptyString(key) || isEmptyString(value)) {
return;
}
m_header.addHeader(std::string(key), std::string(value));
}