您的位置:首页 > 理论基础 > 计算机网络

vc++实现http下载的通用类

2014-07-30 10:36 549 查看
// DownloadHttp.cpp: implementation of the CDownloadHttp class.

//

//////////////////////////////////////////////////////////////////////

#include "stdafx.h"

#include "downtest.h"

#include "DownloadHttp.h"

#ifdef _DEBUG

#undef THIS_FILE

static char THIS_FILE[]=__FILE__;

#define new DEBUG_NEW

#endif

void DownloadNotify ( int nIndex, UINT nNotityType, LPVOID lpNotifyData, LPVOID pDownloadMTR );

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////

CDownloadHttp::CDownloadHttp()

{

}

CDownloadHttp::~CDownloadHttp()

{

}

BOOL CDownloadHttp::DownloadOnce()

{

// 不需要下载了

int nWillDownloadSize = Get_WillDownloadSize(); // 本次应该下载的字节数

int nDownloadedSize = Get_DownloadedSize (); // 已下载字节数

if ( nWillDownloadSize > 0 && nDownloadedSize >= nWillDownloadSize )

return DownloadEnd(TRUE);

if ( !CDownloadPub::DownloadOnce () )

return DownloadEnd(FALSE);

char szTailData[NET_BUFFER_SIZE] = {0};

int nTailSize = sizeof(szTailData);

if ( !RequestHttpData ( TRUE, szTailData, &nTailSize ) )

return DownloadEnd(FALSE);

// 从HTTP服务器中读取数据,并保存到文件中

return DownloadEnd ( RecvDataAndSaveToFile(m_SocketClient,szTailData, nTailSize) );

}

BOOL CDownloadHttp::RequestHttpData(BOOL bGet, char *szTailData/*=NULL*/, int *pnTailSize/*=NULL*/ )

{

int nTailSizeTemp = 0;

BOOL bRetryRequest = TRUE;

while ( bRetryRequest )

{

CString csReq = GetRequestStr ( bGet );

CString csResponse;

nTailSizeTemp = pnTailSize?(*pnTailSize):0;

if ( !SendRequest ( csReq, csResponse, szTailData, &nTailSizeTemp ) )

return FALSE;

CString csReferer_Old = m_csReferer;

CString csDownloadUrl_Old = m_csDownloadUrl;

CString csServer_Old = m_csServer;

CString csObject_Old = m_csObject;

USHORT nPort_Old = m_nPort;

CString csProtocolType_Old = m_csProtocolType;

if ( !ParseResponseString ( csResponse, bRetryRequest ) )

{

if ( !m_csCookieFlag.IsEmpty () )

{

m_csCookieFlag.Empty();

return FALSE;

}

m_csReferer = csReferer_Old;

m_csDownloadUrl = csDownloadUrl_Old;

m_csServer = csServer_Old;

m_csObject = csObject_Old;

m_nPort = nPort_Old;

m_csProtocolType = csProtocolType_Old;

m_csCookieFlag = "Flag=UUIISPoweredByUUSoft";

bRetryRequest = TRUE;

}

}

if ( pnTailSize )

*pnTailSize = nTailSizeTemp;

return TRUE;

}

//

// 获取远程站点信息,如:是否支持断点续传、要下载的文件大小和创建时间等

//

BOOL CDownloadHttp::GetRemoteSiteInfo_Pro()

{

BOOL bRet = FALSE;

if ( !CDownloadPub::GetRemoteSiteInfo_Pro() )

goto finished;

if ( !RequestHttpData ( TRUE ) )

goto finished;

bRet = TRUE;

finished:

return bRet;

}

CString CDownloadHttp::GetRequestStr(BOOL bGet)

{

CString strVerb;

if( bGet )

strVerb = _T("GET ");

else

strVerb = _T("HEAD ");

CString csReq, strAuth, strRange;

csReq = strVerb + m_csObject + " HTTP/1.1/r/n";

if ( !m_csUsername.IsEmpty () )

{

strAuth = _T("");

Base64Encode ( m_csUsername + ":" + m_csPassword, strAuth );

csReq += "Authorization: Basic " + strAuth + "/r/n";

}

CString csPort;

if ( m_nPort != DEFAULT_HTTP_PORT )

csPort.Format ( ":%d", m_nPort );

csReq += "Host: " + m_csServer + csPort + "/r/n";

csReq += "Accept: */*/r/n";

csReq += "Pragma: no-cache/r/n";

csReq += "Cache-Control: no-cache/r/n";

csReq += "User-Agent: "+m_csUserAgent+"/r/n";

if( m_csReferer.IsEmpty() )

{

m_csReferer = GetRefererFromURL ();

}

csReq += "Referer: "+m_csReferer+"/r/n";

csReq += "Connection: close/r/n";

if ( !m_csCookieFlag.IsEmpty() )

{

csReq += "Cookie: " + m_csCookieFlag + "/r/n";

}

// 指定要下载的文件范围

CString csEndPos;

int nWillDownloadStartPos = Get_WillDownloadStartPos (); // 开始位置

int nWillDownloadSize = Get_WillDownloadSize(); // 本次应该下载的字节数

int nDownloadedSize = Get_DownloadedSize (); // 已下载字节数

if ( nWillDownloadSize > 0 )

csEndPos.Format ( "%d", nWillDownloadStartPos+nWillDownloadSize-1 );

ASSERT ( nWillDownloadSize < 0 || nDownloadedSize < nWillDownloadSize );

strRange.Format ( _T("Range: bytes=%d-%s/r/n"), nWillDownloadStartPos+nDownloadedSize, csEndPos );

csReq += strRange;

csReq += "/r/n";

return csReq;

}

//

// 向服务器提交请求,并得到返回字符串

//

BOOL CDownloadHttp::SendRequest(LPCTSTR lpszReq, CString &csResponse, char *szTailData/*=NULL*/, int *pnTailSize/*=NULL*/ )

{

m_SocketClient.Disconnect ();

if ( !Connect () ) return FALSE;

if ( !m_SocketClient.SendString ( lpszReq ) )

{

return FALSE;

}

for ( int i=0; ; i++ )

{

char szRecvBuf[NET_BUFFER_SIZE] = {0};

int nReadSize = m_SocketClient.Receive ( szRecvBuf, sizeof(szRecvBuf) );

if ( nReadSize <= 0 )

{

Log ( L_WARNING, "(%d) Receive response data failed", m_nIndex );

return FALSE;

}

csResponse += szRecvBuf;

char *p = strstr ( szRecvBuf, "/r/n/r/n" );

if ( p )

{

if ( szTailData && pnTailSize && *pnTailSize > 0 )

{

p += 4;

int nOtioseSize = nReadSize - int( p - szRecvBuf );

*pnTailSize = MIN ( nOtioseSize, *pnTailSize );

memcpy ( szTailData, p, *pnTailSize );

}

#ifdef _DEBUG

int nPos = csResponse.Find ( "/r/n/r/n", 0 );

CString csDump;

if ( nPos >= 0 ) csDump = csResponse.Left ( nPos );

else csDump = csResponse;

Log ( L_NORMAL, "(%d) HTTP server response : /r/n<<<++++++++++++++++++++++++/r/n%s/r/n<<<++++++++++++++++++++++++",

m_nIndex, csDump );

#endif

break;

}

}

return TRUE;

}

DWORD CDownloadHttp::GetResponseCode(CString csLineText)

{

csLineText.MakeLower ();

ASSERT ( csLineText.Find ( "http/", 0 ) >= 0 );

int nPos = csLineText.Find ( " ", 0 );

if ( nPos < 0 ) return 0;

CString csCode = csLineText.Mid ( nPos + 1 );

csCode.TrimLeft(); csCode.TrimRight();

nPos = csCode.Find ( " ", 0 );

if ( nPos < 0 ) nPos = csCode.GetLength() - 1;

csCode = csCode.Left ( nPos );

return (DWORD)atoi(csCode);

}

BOOL CDownloadHttp::ParseResponseString ( CString csResponseString, OUT BOOL &bRetryRequest )

{

bRetryRequest = FALSE;

// 获取返回代码

CString csOneLine = GetOneLine ( csResponseString );

DWORD dwResponseCode = GetResponseCode ( csOneLine );

if ( dwResponseCode < 1 )

{

Log ( L_WARNING, "(%d) Received error response code : %s", m_nIndex, csOneLine );

return FALSE;

}

int nPos = 0;

// 请求文件被重定向

if( dwResponseCode >= 300 && dwResponseCode < 400 )

{

bRetryRequest = TRUE;

// 得到请求文件新的URL

CString csRedirectFileName = FindAfterFlagString ( "location:", csResponseString );

// 设置 Referer

m_csReferer = GetRefererFromURL ();

// 重定向到其他的服务器

nPos = csRedirectFileName.Find("://");

if ( nPos >= 0 )

{

m_csDownloadUrl = csRedirectFileName;

// 检验要下载的URL是否有效

if ( !ParseURL ( m_csDownloadUrl, m_csServer, m_csObject, m_nPort, m_csProtocolType ) )

{

Log ( L_WARNING, "(%d) Redirect media path [%s] invalid", m_nIndex, m_csDownloadUrl );

return FALSE;

}

return TRUE;

}

// 重定向到本服务器的其他地方

csRedirectFileName.Replace ( "//", "/" );

// 重定向于根目录

if( csRedirectFileName[0] == '/' )

{

m_csObject = csRedirectFileName;

DownloadNotify ( -1, NOTIFY_TYPE_GOT_REMOTE_FILENAME, (LPVOID)(LPCTSTR)(GetDownloadObjectFileName()), m_pDownloadMTR );

return TRUE;

}

// 定向于相对当前目录

int nParentDirCount = 0;

nPos = csRedirectFileName.Find ( "../" );

while ( nPos >= 0 )

{

csRedirectFileName = csRedirectFileName.Mid(nPos+3);

nParentDirCount++;

nPos = csRedirectFileName.Find("../");

}

for (int i=0; i<=nParentDirCount; i++)

{

nPos = m_csDownloadUrl.ReverseFind('/');

if (nPos != -1)

m_csDownloadUrl = m_csDownloadUrl.Left(nPos);

}

if ( csRedirectFileName.Find ( "./", 0 ) == 0 )

csRedirectFileName.Delete ( 0, 2 );

m_csDownloadUrl = m_csDownloadUrl+"/"+csRedirectFileName;

return ParseURL ( m_csDownloadUrl, m_csServer, m_csObject, m_nPort, m_csProtocolType );

}

// 请求被成功接收、理解和接受

else if( dwResponseCode >= 200 && dwResponseCode < 300 )

{

if ( m_nIndex == -1 ) // 主线程才需要获取文件大小的信息

{

// 获取 Content-Length

CString csDownFileLen = FindAfterFlagString ( "content-length:", csResponseString );

m_nFileTotalSize = (int) _ttoi( (LPCTSTR)csDownFileLen );

DownloadNotify ( -1, NOTIFY_TYPE_GOT_REMOTE_FILESIZE, (LPVOID)m_nFileTotalSize, m_pDownloadMTR );

int nWillDownloadStartPos = Get_WillDownloadStartPos (); // 开始位置

int nWillDownloadSize = Get_WillDownloadSize(); // 本次应该下载的字节数

int nDownloadedSize = Get_DownloadedSize (); // 已下载字节数

if ( m_nFileTotalSize > 0 && nWillDownloadSize-nDownloadedSize > m_nFileTotalSize )

Set_WillDownloadSize ( m_nFileTotalSize-nDownloadedSize );

}

// 获取服务器文件的最后修改时间

CString csModifiedTime = FindAfterFlagString ( "last-modified:", csResponseString );

if ( !csModifiedTime.IsEmpty() )

{

m_TimeLastModified = ConvertHttpTimeString(csModifiedTime);

}

if ( dwResponseCode == 206 ) // 支持断点续传

{

m_bSupportResume = TRUE;

}

else // 不支持断点续传

{

m_bSupportResume = FALSE;

}

return TRUE;

}

// Log ( L_WARNING, "(%d) Receive invalid code : %d", m_nIndex, dwResponseCode );

return FALSE;

}

CString CDownloadHttp::FindAfterFlagString(LPCTSTR lpszFoundStr, CString csOrg)

{

ASSERT ( lpszFoundStr && strlen(lpszFoundStr) > 0 );

CString csReturing, csFoundStr = GET_SAFE_STRING(lpszFoundStr);

csFoundStr.MakeLower ();

CString csOrgLower = csOrg;

csOrgLower.MakeLower ();

int nPos = csOrgLower.Find ( csFoundStr );

if ( nPos < 0 ) return "";

csReturing = csOrg.Mid ( nPos + csFoundStr.GetLength() );

nPos = csReturing.Find("/r/n");

if ( nPos < 0 ) return "";

csReturing = csReturing.Left(nPos);

csReturing.TrimLeft();

csReturing.TrimRight();

return csReturing;

}

//

// 将 HTTP 服务器表示的时间转换为 CTime 格式,如:Wed, 16 May 2007 14:29:53 GMT

//

CTime CDownloadHttp::ConvertHttpTimeString(CString csTimeGMT)

{

CString csYear, csMonth, csDay, csTime;

CTime tReturning = -1;

int nPos = csTimeGMT.Find ( ",", 0 );

if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )

return tReturning;

csTimeGMT = csTimeGMT.Mid ( nPos + 1 );

csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();

// 日

nPos = csTimeGMT.Find ( " ", 0 );

if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )

return tReturning;

csDay = csTimeGMT.Left ( nPos );

csTimeGMT = csTimeGMT.Mid ( nPos + 1 );

csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();

// 月

nPos = csTimeGMT.Find ( " ", 0 );

if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )

return tReturning;

csMonth = csTimeGMT.Left ( nPos );

int nMonth = GetMouthByShortStr ( csMonth );

ASSERT ( nMonth >= 1 && nMonth <= 12 );

csMonth.Format ( "%02d", nMonth );

csTimeGMT = csTimeGMT.Mid ( nPos + 1 );

csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();

// 年

nPos = csTimeGMT.Find ( " ", 0 );

if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )

return tReturning;

csYear = csTimeGMT.Left ( nPos );

csTimeGMT = csTimeGMT.Mid ( nPos + 1 );

csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();

// 时间

nPos = csTimeGMT.Find ( " ", 0 );

if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )

return tReturning;

csTime = csTimeGMT.Left ( nPos );

csTimeGMT = csTimeGMT.Mid ( nPos + 1 );

CString csFileTimeInfo;

csFileTimeInfo.Format ( "%s-%s-%s %s", csYear, csMonth, csDay, csTime );

ConvertStrToCTime ( csFileTimeInfo.GetBuffer(0), tReturning );

return tReturning;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: