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

// 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;
}
posted on 2010-05-30 21:52  carekee  阅读(4016)  评论(0编辑  收藏  举报