1、HttpUtil.h
#ifndef __HTTP_UTIL_H__
#define __HTTP_UTIL_H__
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <atlbase.h>
#include <map>
#include <string>
#include <vector>
#include <sstream>
#include <fstream>
#include <Winsock2.h>
#include <Windows.h>
using namespace std;
#pragma comment(lib, "ws2_32.lib")
//
//
// error codes for socket
//
//
#define ERR_SOCK_SUCCEED 0
#define ERR_SOCK_BASECODE (30000)
#define ERR_SOCK_FAIL ERR_SOCK_BASECODE
#define ERR_SOCK_CREATE_FAIL (ERR_SOCK_BASECODE + 1)
#define ERR_SOCK_BIND_FAIL (ERR_SOCK_BASECODE + 2)
#define ERR_SOCK_LISTEN_FAIL (ERR_SOCK_BASECODE + 3)
#define ERR_SOCK_CONNECT_FAIL (ERR_SOCK_BASECODE + 4)
#define ERR_SOCK_SEND_FAIL (ERR_SOCK_BASECODE + 5)
#define ERR_SOCK_RECV_FAIL (ERR_SOCK_BASECODE + 6)
#define ERR_HTTP_SUCCESS 0
#define ERR_HTTP_BASECODE (10000)
#define ERR_HTTP_FAIL (ERR_HTTP_BASECODE+1)
#define ERR_HTTP_RES_BODY_INVALID (ERR_HTTP_BASECODE+2)
#define ERR_HTTP_GEN_REQDATA_FAIL (ERR_HTTP_BASECODE+3)
#define ERR_HTTP_IP_ADDR_INVALID (ERR_HTTP_BASECODE+4)
#define ERR_HTTP_STATUS_NOT_200 (ERR_HTTP_BASECODE+5)
//
//
// stl types replacement
//
//
typedef std::map<const std::string, const std::string> MAP_STRING_STRING;
typedef std::pair<const std::string, const std::string> PAIR_STRING_STRING;
typedef std::map<const char *, const char *> MAP_PCHAR_PCHAR;
//
//
// CIHttpUtil: abstract class
//
//
class CIHttpUtil
{
public:
//set fields
virtual void SetReqAction(const char *pcAction) = 0;
virtual void SetReqUri(const char *pcReqUri) = 0;
virtual void SetReqHttpVer(const char *pcHttpVer) = 0;
virtual void SetReqHost(const char *pcHost) = 0;
virtual void SetReqField(const char *pcFieldName, const char *pcValue) = 0;
virtual void SetReqBody(const char *pcReqBody) = 0;
//get field value
virtual string GetReqAction() const = 0;
virtual string GetReqUri() const = 0;
virtual string GetReqHttpVer() const = 0;
virtual string GetReqHost() const = 0;
virtual string GetReqFieldValue(const char *pcFieldName) const = 0;
virtual string GetReqBody() const = 0;
public:
// actions
virtual int GenerateReqData() = 0;
virtual int SendReqData(const char *pcIP, unsigned int nPort) = 0;
//reponse
public:
virtual const MAP_STRING_STRING &GetResHeaderMap() const = 0;
virtual string GetResBody() const = 0;
virtual int HandleResData() = 0;
};
//
//
// CHttpUtil derived from CIHttpUtil
//
//
class CHttpUtil:public CIHttpUtil
{
public:
//construct
CHttpUtil();
//destruct
virtual ~CHttpUtil();
public:
/*************************************************
*FUNCTION : set request action
*[INPUT] :
* pcAction - action method, e.g. POST/GET
*[OUTPUT] :
* N/A
*RETURN :
* N/A
*************************************************/
void SetReqAction(const char *pcAction);
/*************************************************
*FUNCTION : set uri
*[INPUT] :
* pcReqUri - uri
*[OUTPUT] :
* N/A
*RETURN :
* N/A
*************************************************/
void SetReqUri(const char *pcReqUri);
/*************************************************
*FUNCTION : set http version
*[INPUT] :
* pcHttpVer - http version, e.g. HTTP/1.1
*[OUTPUT] :
* N/A
*RETURN :
* N/A
*************************************************/
void SetReqHttpVer(const char *pcHttpVer);
/*************************************************
*FUNCTION : set host
*[INPUT] :
* pcHost - host
*[OUTPUT] :
* N/A
*RETURN :
* N/A
*************************************************/
void SetReqHost(const char *pcHost);
/*************************************************
*FUNCTION : set request message type
*[INPUT] :
* pcMsgType - message type
*[OUTPUT] :
* N/A
*RETURN :
* N/A
*************************************************/
void SetReqMsgType(const char *pcMsgType);
/*************************************************
*FUNCTION : set request token
*[INPUT] :
* pcToken - token
*[OUTPUT] :
* N/A
*RETURN :
* N/A
*************************************************/
void SetReqToken(const char *pcToken);
/*************************************************
*FUNCTION : set field name and value
*[INPUT] :
* pcFieldName - field name
* pcValue - value
*[OUTPUT] :
* N/A
*RETURN :
* N/A
*************************************************/
void SetReqField(const char *pcFieldName, const char *pcValue);
/*************************************************
*FUNCTION : set request body
*[INPUT] :
* pcReqBody - request body
*[OUTPUT] :
* N/A
*RETURN :
* N/A
*************************************************/
void SetReqBody(const char *pcReqBody);
/*************************************************
*FUNCTION : get request action
*[INPUT] :
* sockCon - connecting socket
*[OUTPUT] :
* N/A
*RETURN :
* valid string - succeed
* NULL - empty
*************************************************/
string GetReqAction() const;
/*************************************************
*FUNCTION : get request uri
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* valid string - succeed
* NULL - empty
*************************************************/
string GetReqUri() const;
/*************************************************
*FUNCTION : get http version
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* valid string - succeed
* NULL - empty
*************************************************/
string GetReqHttpVer() const;
/*************************************************
*FUNCTION : get host
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* valid string - succeed
* NULL - empty
*************************************************/
string GetReqHost() const;
/*************************************************
*FUNCTION : get value by field name
*[INPUT] :
* pcFieldName - field name
*[OUTPUT] :
* N/A
*RETURN :
* valid string - succeed
* NULL - empty
*************************************************/
string GetReqFieldValue(const char *pcFieldName) const;
/*************************************************
*FUNCTION : get request message type
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* valid string - succeed
* NULL - empty
*************************************************/
string GetReqMsgType() const;
/*************************************************
*FUNCTION : get request token
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* valid string - succeed
* NULL - empty
*************************************************/
string GetReqToken() const;
/*************************************************
*FUNCTION : get request body
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* valid string - succeed
* NULL - empty
*************************************************/
string GetReqBody() const;
/*************************************************
*FUNCTION : get request data including header and body
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* valid string - succeed
* NULL - empty
*************************************************/
string GetReqData() const;
/*************************************************
*FUNCTION : generate request data
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* 0 - succeed
* others - fail
*************************************************/
int GenerateReqData() ;
/*************************************************
*FUNCTION : send request data to server
*[INPUT] :
* pcIP - server ip
* nPort - server port
*[OUTPUT] :
* N/A
*RETURN :
* >0 - succeed
* others - fail
*************************************************/
int SendReqData(const char *pcIP, unsigned int nPort);
/*************************************************
*FUNCTION : get response header map
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* map - succeed
* others - fail
*************************************************/
const MAP_STRING_STRING &GetResHeaderMap() const ;
/*************************************************
*FUNCTION : close socket
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* string value - succeed
* NULL - empty
*************************************************/
string GetResBody() const ;
/*************************************************
*FUNCTION : handle response data
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* 0 - succeed
* others - fail
*************************************************/
int HandleResData() ;
public:
/*************************************************
*FUNCTION : start up socket
*[INPUT] :
* N/A
*[OUTPUT] :
* N/A
*RETURN :
* >0 - succeed
* <0 - fail
*************************************************/
SOCKET SOCK_Create();
/*************************************************
*FUNCTION : connect with server via socket
*[INPUT] :
* sockCon - socket to connect with server
* pcSrvIP - server ip
* uiPort - server port
*[OUTPUT] :
* N/A
*RETURN :
* 0 - succeed
* others - fail
*************************************************/
int SOCK_Connect(SOCKET &sockCon, const char *pcSrvIP, unsigned int uiPort);
/*************************************************
*FUNCTION : send data via socket
*[INPUT] :
* sockCon - connecting socket
* pcSendBuf - buffer of data to send
* nSendLen - the length of data to send
*[OUTPUT] :
* N/A
*RETURN :
* nSendLen - succeed
* other - fail
*************************************************/
int SOCK_Send(SOCKET sockCon, const char *pcSendBuf, int nSendLen );
/*************************************************
*FUNCTION : recv data via socket
*[INPUT] :
* sockCon - connecting socket
*[OUTPUT] :
* pcRecvBuf - buffer of data to recv
* pnRecvLen - the length of data to recv
*RETURN :
* >0 - succeed
* <0 - fail
*************************************************/
int SOCK_Recv(SOCKET sockCon, char *pcRecvBuf, int *pnRecvLen);
/*************************************************
*FUNCTION : download data and store in file
*[INPUT] :
* sockCon - connecting socket
* lpwstrSaveFilePath - file path to save download data
*[OUTPUT] :
* N/A
*RETURN :
* 0 - succeed
* others - fail
*************************************************/
int SOCK_Download(SOCKET sockCon, LPCWSTR lpwstrSaveFilePath);
int SOCK_DownloadEx(SOCKET sockCon, LPCWSTR lpwstrSaveFilePath);
/*************************************************
*FUNCTION : close socket
*[INPUT] :
* sockCon - connecting socket
*[OUTPUT] :
* N/A
*RETURN :
* 0 - succeed
* others - fail
*************************************************/
int SOCK_Close(SOCKET sockCon);
private:
//req header - common fields
string m_strReqAction;
string m_strReqUri;
string m_strReqHttpVer;
string m_strReqHost;
//msg-type, tokn
string m_strReqMsgType;
string m_strReqToken;
MAP_STRING_STRING m_mapReqHeader;
string m_strReqHeader;
string m_strReqBody;
string m_strReqData;
//res header - common fields
string m_strResData;
//vector<char> m_vectResDataBuf;
string m_strResTopHeader;
MAP_STRING_STRING m_mapResHeader;
string m_strResHeader;
string m_strResBody;
//xml parse
string m_strXMLValue;
};
#endif
2、HttpUtil.cpp
#include "stdafx.h"
#include "HttpUtil.h"
CHttpUtil::CHttpUtil()
{
}
CHttpUtil::~CHttpUtil()
{
}
// req header operations
void CHttpUtil::SetReqAction(const char *pcAction)
{
if (strlen(pcAction) > 0)
{
m_strReqAction = pcAction;
}
}
void CHttpUtil::SetReqUri(const char * pcReqUri)
{
if (strlen(pcReqUri) > 0)
{
m_strReqUri = pcReqUri;
}
}
void CHttpUtil::SetReqHttpVer(const char *pcHttpVer)
{
if (strlen(pcHttpVer) > 0)
{
m_strReqHttpVer = pcHttpVer;
}
}
void CHttpUtil::SetReqHost(const char* pcHost)
{
if (strlen(pcHost) >0)
{
m_strReqHost = pcHost;
}
}
void CHttpUtil::SetReqMsgType(const char* pcMsgType)
{
if (strlen(pcMsgType) > 0)
{
m_strReqMsgType = pcMsgType;
}
}
void CHttpUtil::SetReqToken(const char* pcToken)
{
if (strlen(pcToken) > 0 )
{
m_strReqToken = pcToken;
}
}
void CHttpUtil::SetReqField(const char *pcFieldName, const char *pcValue)
{
if (strlen(pcFieldName) <= 0 || strlen(pcValue) <= 0)
{
return ;
}
bool fExist = false;
for (MAP_STRING_STRING::iterator iter = m_mapReqHeader.begin(); iter != m_mapReqHeader.end(); ++iter)
{
if (iter->first == pcFieldName)
{
fExist = true;
break;
}
}
if (!fExist)
{
m_mapReqHeader.insert(PAIR_STRING_STRING(pcFieldName, pcValue));
}
}
void CHttpUtil::SetReqBody(const char *pcReqBody)
{
if (strlen(pcReqBody) > 0)
{
m_strReqBody = pcReqBody;
}
}
string CHttpUtil::GetReqAction() const
{
return m_strReqAction;
}
string CHttpUtil::GetReqUri() const
{
return m_strReqUri;
}
string CHttpUtil::GetReqHttpVer() const
{
return m_strReqHttpVer;
}
string CHttpUtil::GetReqHost() const
{
return m_strReqHost;
}
string CHttpUtil::GetReqFieldValue(const char *pcFieldName) const
{
if (pcFieldName != NULL || strlen(pcFieldName) <= 0)
{
return NULL;
}
for (MAP_STRING_STRING::const_iterator iter = m_mapReqHeader.begin(); iter != m_mapReqHeader.end(); iter++)
{
if (iter->first == pcFieldName)
{
return iter->second;
}
}
return NULL;
}
string CHttpUtil::GetReqBody() const
{
return m_strReqBody;
}
int CHttpUtil::GenerateReqData()
{
m_strReqData.append(m_strReqAction).append(" ").append(m_strReqUri).append(" ").append("HTTP/1.1").append("\r\n");
m_strReqData.append("Host:").append(m_strReqHost).append("\r\n");
m_strReqData.append("Accept:*/*\r\n");
//append message and Token
m_strReqData.append("message: ").append(m_strReqMsgType).append("\r\n");
m_strReqData.append("Token:").append(m_strReqToken).append("\r\n");
//add Content-Length
int nReqBodyLen = (int)strlen(m_strReqBody.c_str());
//if (nReqBodyLen > 0)
//{
char pcLenBuf[32] = {0};
sprintf(pcLenBuf, "%d", nReqBodyLen );
m_strReqData.append("Content-Length:").append(pcLenBuf).append("\r\n");
//}
//m_strReqData.append("Content-Type:application/xml").append("\r\n");
m_strReqData.append("Accept-language: zh-cn").append("\r\n");
m_strReqData.append("Accept-Encoding: gzip, deflate").append("\r\n");
m_strReqData.append("User-Agent: Mozilla/4.0 (compatible; MS IE 6.0; EIS iPanel 2.0;(ziva))").append("\r\n");
m_strReqData.append("Connection: Keep-Alive").append("\r\n");
m_strReqData.append("\r\n");
//append the req body
m_strReqData.append(m_strReqBody);
return 0;
}
string CHttpUtil::GetReqData() const
{
return m_strReqData;
}
//send req data
int CHttpUtil::SendReqData(const char *pcIPAddr, unsigned int uiPort)
{
if (NULL == pcIPAddr || strlen(pcIPAddr) <=0)
{
return ERR_HTTP_IP_ADDR_INVALID;
}
int nRet = GenerateReqData();
if (nRet != 0)
{
return ERR_HTTP_GEN_REQDATA_FAIL;
}
int nErrCode = ERR_HTTP_FAIL;
SOCKET sockCon = SOCK_Create();
char pcRecvBuf[2048*4] = {0};
int nRecvBuf = 2048*4;
if (INVALID_SOCKET != sockCon)
{
nRet = SOCK_Connect(sockCon, pcIPAddr, uiPort);
if (0 == nRet)
{
const char *pcReqData = m_strReqData.c_str() ;
int nByteSend = m_strReqData.size();
int nLen = SOCK_Send(sockCon, pcReqData, nByteSend);
if (nLen <= 0)
{
nErrCode = ERR_SOCK_SEND_FAIL;
}
nLen = SOCK_Recv(sockCon, pcRecvBuf, &nRecvBuf);
if (nLen <= 0)
{
nErrCode = ERR_SOCK_RECV_FAIL;
}
else
{
m_strResData = pcRecvBuf;
nErrCode = ERR_SOCK_SUCCEED;
}
}
}
return nErrCode;
}
const MAP_STRING_STRING &CHttpUtil::GetResHeaderMap() const
{
return m_mapResHeader;
}
string CHttpUtil::GetResBody() const
{
return m_strResBody;
}
int CHttpUtil::HandleResData()
{
string strTemp = m_strResData;
// res top header,e.g. HTTP/1.1 200 OK
size_t nResTopHeaderPos = strTemp.find("\r\n");
m_strResTopHeader = strTemp.substr(0, nResTopHeaderPos - 0);
if (m_strResTopHeader.find("200") == std::string::npos)
{
return ERR_HTTP_STATUS_NOT_200;
}
// get res header
size_t nResHeaderTailPos = strTemp.find("\r\n\r\n");
m_strResHeader = strTemp.substr(0, nResHeaderTailPos-0);
//get res body
m_strResBody = strTemp.substr(nResHeaderTailPos+strlen("\r\n\r\n"));
return ERR_HTTP_SUCCESS;
}
SOCKET CHttpUtil::SOCK_Create()
{
//connect to server
int nRet = ERR_SOCK_FAIL;
WSADATA wsaData;
nRet = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (nRet < 0)
{
return -1;
}
SOCKET sockCon = INVALID_SOCKET;
sockCon = socket(AF_INET, SOCK_STREAM, 0);
if (INVALID_SOCKET == sockCon)
{
return -2;
}
return sockCon;
}
int CHttpUtil::SOCK_Connect(SOCKET &sockCon, const char *pcSrvIP, unsigned int uiPort)
{
int nRet = ERR_SOCK_FAIL;
SOCKADDR_IN srvSockAddr;
memset(&srvSockAddr, 0, sizeof(SOCKADDR_IN));
srvSockAddr.sin_family = AF_INET;
srvSockAddr.sin_addr.s_addr = inet_addr(pcSrvIP);
srvSockAddr.sin_port = htons(uiPort);
nRet = connect(sockCon, (struct sockaddr*)& srvSockAddr, sizeof(srvSockAddr));
if (nRet < 0)
{
closesocket(sockCon);
return ERR_SOCK_CONNECT_FAIL;
}
return ERR_SOCK_SUCCEED;
}
//send data
int CHttpUtil::SOCK_Send(SOCKET sockCon, const char *pcSendBuf, int nSendLen)
{
int nRet = ERR_SOCK_FAIL;
int nSendTempLen = 0;
int nLeftLen = nSendLen;
int nSendBlockLen = 1024;
nRet = send(sockCon, pcSendBuf, nSendLen, 0);
return nRet;
/* while(nLeftLen >0)
{
nSendTempLen = send(sockCon, pcSendBuf, nSendBlockLen, 0);
if (nSendTempLen < 0)
{
DWORD dwErr = GetLastError();
if (WSAEWOULDBLOCK == dwErr)
{
continue;
}
return dwErr;
}
nLeftLen-=nSendTempLen;
pcSendBuf+=nSendTempLen;
}
return nSendLen - nLeftLen;*/
}
//recv data via select modal
int CHttpUtil::SOCK_Recv(SOCKET sockCon, char *pcRecvBuf, int *pnRecvLen)
{
//nRet = recv(sockfd, pcRecvBuffer, SOCK_RECV_BUFFER_LEN, 0);
struct timeval struTimeOut;
struTimeOut.tv_sec = 5;//wait for 8 seconds
struTimeOut.tv_usec = 0;
//use set
fd_set fdReadSet;
FD_ZERO(&fdReadSet);
FD_SET(sockCon, &fdReadSet);
int nRecvedLen = 0;
int nTotalLen = 0;
int nRet = 0;
nRet = select(NULL, &fdReadSet, NULL, NULL, &struTimeOut);
switch (nRet)
{
case SOCKET_ERROR:
//return ERR_SOCK_RECV_FAIL;
break;
case 0:
break;
default:
{
while(1)
{
nRecvedLen = recv(sockCon, pcRecvBuf, 2048, 0);
if ( SOCKET_ERROR == nRecvedLen)
{
return ERR_SOCK_RECV_FAIL;
}
else if (0 == nRecvedLen)
{
goto END;
}
pcRecvBuf+=nRecvedLen;
nTotalLen+=nRecvedLen;
break;
}
}
}
END:
//recv Async
if (nTotalLen <= 0)
{
return ERR_SOCK_RECV_FAIL;
}
*pnRecvLen = nTotalLen;
return nTotalLen;
}
//recv and save data to local file
int CHttpUtil::SOCK_Download(SOCKET sockCon, LPCWSTR lpwstrSaveFilePath)
{
char pcTmpRecvBuf[2048] = {0};
int nRet = ERR_SOCK_FAIL;
int nTempRecvLen = 0;
BOOL fIsFirstTime = TRUE;
int nRecvedLen = 0;
long nContentLen = 0;
int nHeaderLen = 0;
int nTempBodyLen = 0;
DWORD dwWriten = 0;
BOOL bRet = FALSE;
vector<char> vectRecvBuf;//to recv the data
char pcResHeaders[2048] = {0};
char pcResBody[2048] = {0};
HANDLE hSaveFile = CreateFile(lpwstrSaveFilePath,
GENERIC_WRITE|GENERIC_READ,
0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE ==hSaveFile)
{
return GetLastError();
}
while(1)
{
nTempRecvLen = recv(sockCon, pcTmpRecvBuf, 2048, 0);
if (SOCKET_ERROR == nTempRecvLen )
{
int nErr = WSAGetLastError();
if (WSAEWOULDBLOCK == nErr)
{
continue;
}
}
else if (0 == nTempRecvLen)
{
break;
}
//at first time, we will recv the header data
if (fIsFirstTime)
{
vectRecvBuf.resize(nTempRecvLen);
memcpy(&vectRecvBuf.front(), pcTmpRecvBuf, nTempRecvLen);
//divid the recved data to headers and body
string strRecvBuf = pcTmpRecvBuf;
size_t nPosStart = strRecvBuf.find("Content-Length: "); // Content-Length: 69
if (string::npos == nPosStart)
{
continue;
}
nPosStart+=strlen("Content-Length: ");
string strContentLenField = strRecvBuf.substr(nPosStart);
nContentLen = atoi(strContentLenField.c_str());
size_t nPosHeaderEnd = strRecvBuf.find("\r\n\r\n");
nHeaderLen = nPosHeaderEnd+strlen("\r\n\r\n");
nTempBodyLen= nTempRecvLen - nHeaderLen;
if (nContentLen > nTempBodyLen)
{
bRet = WriteFile(hSaveFile, pcTmpRecvBuf+nHeaderLen, nTempBodyLen, &dwWriten, NULL);
nRecvedLen += nTempBodyLen;
fIsFirstTime = FALSE;
}
else
{
bRet = WriteFile(hSaveFile, pcTmpRecvBuf+nHeaderLen, nTempBodyLen, &dwWriten, NULL);
}
}
else // continue to download the left data without headers
{
nRecvedLen+=nTempRecvLen;
if (nContentLen > nRecvedLen)
{
bRet = WriteFile(hSaveFile, pcTmpRecvBuf, nTempRecvLen, &dwWriten, NULL);
nRecvedLen+=nTempRecvLen;
}
else
{
bRet = WriteFile(hSaveFile, pcTmpRecvBuf, nTempRecvLen, &dwWriten, NULL);
}
}
SetEndOfFile(hSaveFile);
ZeroMemory(pcTmpRecvBuf, 2048);
}
CloseHandle(hSaveFile);
return nRecvedLen;
}
//close socket
int CHttpUtil::SOCK_Close(SOCKET sockCon)
{
if (sockCon)
{
closesocket(sockCon);
}
return ERR_SOCK_SUCCEED;
}
int CHttpUtil::SOCK_DownloadEx(SOCKET sockCon, LPCWSTR lpwstrSaveFilePath)
{
int nRet = ERR_SOCK_FAIL;
char pcTmpRecvBuf[2048] = {0};
int nTempRecvLen = 0;
BOOL boIsFirstTime = TRUE;
BOOL boRet = FALSE;
BOOL boContinue = FALSE;
int nTotalRecvLen = 0;//total recv length
int nContentLen = 0;//
int nHeadersLen = 0;
int nTempBodyLen = 0;
int nTotalBodyLen = 0;
DWORD dwWriten = 0;
vector<char> vectRecvBuf;//to recv the data
char pcResHeaders[2048] = {0};
char pcResBody[2048] = {0};
HANDLE hSaveFile = CreateFile(lpwstrSaveFilePath, GENERIC_WRITE|GENERIC_READ,
0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE == hSaveFile)
{
return GetLastError();
}
while(true)
{
nTempRecvLen = recv(sockCon, pcTmpRecvBuf, 2048, 0);
if (SOCKET_ERROR == nTempRecvLen )
{
int nErr = WSAGetLastError();
if (WSAEWOULDBLOCK == nErr)
{
continue;
}
}
else if (0 == nTempRecvLen)
{
break;
}
//at the first time, we will recv the headers
if (boIsFirstTime)
{
vectRecvBuf.resize(nTempRecvLen);
char *pRecvBufStart = &vectRecvBuf.front();
memcpy(pRecvBufStart, pcTmpRecvBuf, nTempRecvLen);
//divid the recved data to headers and body
char *pHeadersEnd = strstr(pRecvBufStart, "\r\n\r\n");
//get the headers
nHeadersLen = int (pHeadersEnd - pRecvBufStart) + (int)strlen("\r\n\r\n");
memcpy(pcResHeaders, pRecvBufStart, nHeadersLen);
//get the body legth
char *pContentLenField = strstr(pRecvBufStart, "Content-Length: ");
nContentLen = atoi(pContentLenField+strlen("Content-Length: "));
nTempBodyLen = nTempRecvLen - nHeadersLen;
boRet = WriteFile(hSaveFile, pHeadersEnd+strlen("\r\n\r\n"), nTempBodyLen, &dwWriten, NULL);
nTotalRecvLen+= nTempRecvLen;
nTotalBodyLen+= nTempBodyLen;
boIsFirstTime = FALSE;
if (nContentLen > nTempBodyLen)
{
boContinue = TRUE;
}
}
else // continue to download the left data without headers
{
boRet = WriteFile(hSaveFile, pcTmpRecvBuf, nTempRecvLen, &dwWriten, NULL);
nTotalRecvLen+=nTempRecvLen;
nTempBodyLen = nTempRecvLen;
nTotalBodyLen+=nTempBodyLen;
if (nContentLen > nTotalRecvLen)
{
boContinue = TRUE;
}
else
{
boContinue = FALSE;
}
}
SetEndOfFile(hSaveFile);
ZeroMemory(pcTmpRecvBuf, 2048);
}
CloseHandle(hSaveFile);
return nTotalRecvLen;
}