DownloadHttp.cpp
上传用户:oadesign
上传日期:2013-12-25
资源大小:265k
文件大小:11k
- // DownloadHttp.cpp: implementation of the CDownloadHttp class.
- //
- //////////////////////////////////////////////////////////////////////
- #include "stdafx.h"
- #include "NetDownMTR.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 bRedirect = TRUE;
- while ( bRedirect )
- {
- CString csReq = GetRequestStr ( bGet );
- CString csResponse;
- nTailSizeTemp = pnTailSize?(*pnTailSize):0;
- if ( !SendRequest ( csReq, csResponse, szTailData, &nTailSizeTemp ) )
- return FALSE;
- if ( !ParseResponseString ( csResponse, bRedirect ) )
- return FALSE;
- }
- if ( pnTailSize )
- *pnTailSize = nTailSizeTemp;
- return TRUE;
- }
- //
- // 获取远程站点信息,如:是否支持断点续传、要下载的文件大小和创建时间等
- //
- BOOL CDownloadHttp::GetRemoteSiteInfo()
- {
- if ( !CDownloadPub::GetRemoteSiteInfo() )
- return FALSE;
- if ( !RequestHttpData ( TRUE ) )
- return FALSE;
- m_SocketClient.Disconnect ();
- return TRUE;
- }
- 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.1rn";
- if ( !m_csUsername.IsEmpty () )
- {
- strAuth = _T("");
- Base64Encode ( m_csUsername + ":" + m_csPassword, strAuth );
- csReq += "Authorization: Basic " + strAuth + "rn";
- }
-
- csReq += "Host: " + m_csServer + "rn";
- csReq += "Accept: */*rn";
- csReq += "Pragma: no-cachern";
- csReq += "Cache-Control: no-cachern";
- csReq += "User-Agent: "+m_csUserAgent+"rn";
- if( !m_csReferer.IsEmpty() )
- csReq += "Referer: "+m_csReferer+"rn";
- csReq += "Connection: closern";
-
- // 指定要下载的文件范围
- 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-%srn"), nWillDownloadStartPos+nDownloadedSize, csEndPos );
- csReq += strRange;
- csReq += "rn";
-
- 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, "Receive response data failed" );
- return FALSE;
- }
- csResponse += szRecvBuf;
- char *p = strstr ( szRecvBuf, "rnrn" );
- 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 ( "rnrn", 0 );
- CString csDump;
- if ( nPos >= 0 ) csDump = csResponse.Left ( nPos );
- else csDump = csResponse;
- // TRACE ( "n收到回应 <<<---------------------nn%sn", 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 &bRedirect )
- {
- bRedirect = FALSE;
- // 获取返回代码
- CString csOneLine = GetOneLine ( csResponseString );
- DWORD dwResponseCode = GetResponseCode ( csOneLine );
- if ( dwResponseCode < 1 )
- {
- Log ( L_WARNING, "Received error response code : %s", csOneLine );
- return FALSE;
- }
-
- int nPos = 0;
- // 请求文件被重定向
- if( dwResponseCode >= 300 && dwResponseCode < 400 )
- {
- bRedirect = TRUE;
- // 得到请求文件新的URL
- CString csRedirectFileName = FindAfterFlagString ( "location:", csResponseString );
-
- // 设置 Referer
- m_csReferer = m_csDownloadUrl;
-
- // 重定向到其他的服务器
- 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, "Redirect media path [%s] invalid", 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, "Index.%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("rn");
- 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;
- }