DownloadHttp.cpp
上传用户:oadesign
上传日期:2013-12-25
资源大小:265k
文件大小:11k
源码类别:

进程与线程

开发平台:

Visual C++

  1. // DownloadHttp.cpp: implementation of the CDownloadHttp class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "NetDownMTR.h"
  6. #include "DownloadHttp.h"
  7. #ifdef _DEBUG
  8. #undef THIS_FILE
  9. static char THIS_FILE[]=__FILE__;
  10. #define new DEBUG_NEW
  11. #endif
  12. void DownloadNotify ( int nIndex, UINT nNotityType, LPVOID lpNotifyData, LPVOID pDownloadMTR );
  13. //////////////////////////////////////////////////////////////////////
  14. // Construction/Destruction
  15. //////////////////////////////////////////////////////////////////////
  16. CDownloadHttp::CDownloadHttp()
  17. {
  18. }
  19. CDownloadHttp::~CDownloadHttp()
  20. {
  21. }
  22. BOOL CDownloadHttp::DownloadOnce()
  23. {
  24. // 不需要下载了
  25. int nWillDownloadSize = Get_WillDownloadSize(); // 本次应该下载的字节数
  26. int nDownloadedSize = Get_DownloadedSize (); // 已下载字节数
  27. if ( nWillDownloadSize > 0 && nDownloadedSize >= nWillDownloadSize )
  28. return DownloadEnd(TRUE);
  29. if ( !CDownloadPub::DownloadOnce () )
  30. return DownloadEnd(FALSE);
  31. char szTailData[NET_BUFFER_SIZE] = {0};
  32. int nTailSize = sizeof(szTailData);
  33. if ( !RequestHttpData ( TRUE, szTailData, &nTailSize ) )
  34. return DownloadEnd(FALSE);
  35. // 从HTTP服务器中读取数据,并保存到文件中
  36. return DownloadEnd ( RecvDataAndSaveToFile(m_SocketClient,szTailData, nTailSize) );
  37. }
  38. BOOL CDownloadHttp::RequestHttpData(BOOL bGet, char *szTailData/*=NULL*/, int *pnTailSize/*=NULL*/ )
  39. {
  40. int nTailSizeTemp = 0;
  41. BOOL bRedirect = TRUE;
  42. while ( bRedirect )
  43. {
  44. CString csReq = GetRequestStr ( bGet );
  45. CString csResponse;
  46. nTailSizeTemp = pnTailSize?(*pnTailSize):0;
  47. if ( !SendRequest ( csReq, csResponse, szTailData, &nTailSizeTemp ) )
  48. return FALSE;
  49. if ( !ParseResponseString ( csResponse, bRedirect ) )
  50. return FALSE;
  51. }
  52. if ( pnTailSize )
  53. *pnTailSize = nTailSizeTemp;
  54. return TRUE;
  55. }
  56. //
  57. // 获取远程站点信息,如:是否支持断点续传、要下载的文件大小和创建时间等
  58. //
  59. BOOL CDownloadHttp::GetRemoteSiteInfo()
  60. {
  61. if ( !CDownloadPub::GetRemoteSiteInfo() )
  62. return FALSE;
  63. if ( !RequestHttpData ( TRUE ) )
  64. return FALSE;
  65. m_SocketClient.Disconnect ();
  66. return TRUE;
  67. }
  68. CString CDownloadHttp::GetRequestStr(BOOL bGet)
  69. {
  70. CString strVerb;
  71. if( bGet )
  72. strVerb = _T("GET ");
  73. else
  74. strVerb = _T("HEAD ");
  75. CString csReq, strAuth, strRange;
  76. csReq  = strVerb  + m_csObject + " HTTP/1.1rn";
  77. if ( !m_csUsername.IsEmpty () )
  78. {
  79. strAuth = _T("");
  80. Base64Encode ( m_csUsername + ":" + m_csPassword, strAuth );
  81. csReq += "Authorization: Basic " + strAuth + "rn";
  82. }
  83. csReq += "Host: " + m_csServer + "rn";
  84. csReq += "Accept: */*rn";
  85. csReq += "Pragma: no-cachern"; 
  86. csReq += "Cache-Control: no-cachern";
  87. csReq += "User-Agent: "+m_csUserAgent+"rn";
  88. if( !m_csReferer.IsEmpty() )
  89. csReq += "Referer: "+m_csReferer+"rn";
  90. csReq += "Connection: closern";
  91. // 指定要下载的文件范围
  92. CString csEndPos;
  93. int nWillDownloadStartPos = Get_WillDownloadStartPos (); // 开始位置
  94. int nWillDownloadSize = Get_WillDownloadSize(); // 本次应该下载的字节数
  95. int nDownloadedSize = Get_DownloadedSize (); // 已下载字节数
  96. if ( nWillDownloadSize >= 0 )
  97. csEndPos.Format ( "%d", nWillDownloadStartPos+nWillDownloadSize-1 );
  98. ASSERT ( nWillDownloadSize < 0 || nDownloadedSize < nWillDownloadSize );
  99. strRange.Format ( _T("Range: bytes=%d-%srn"), nWillDownloadStartPos+nDownloadedSize, csEndPos );
  100. csReq += strRange;
  101. csReq += "rn";
  102. return csReq;
  103. }
  104. //
  105. // 向服务器提交请求,并得到返回字符串
  106. //
  107. BOOL CDownloadHttp::SendRequest(LPCTSTR lpszReq, CString &csResponse, char *szTailData/*=NULL*/, int *pnTailSize/*=NULL*/ )
  108. {
  109. m_SocketClient.Disconnect ();
  110. if ( !Connect () ) return FALSE;
  111. if ( !m_SocketClient.SendString ( lpszReq ) )
  112. {
  113. return FALSE;
  114. }
  115. for ( int i=0; ; i++ )
  116. {
  117. char szRecvBuf[NET_BUFFER_SIZE] = {0};
  118. int nReadSize = m_SocketClient.Receive ( szRecvBuf, sizeof(szRecvBuf) );
  119. if ( nReadSize <= 0 )
  120. {
  121. Log ( L_WARNING, "Receive response data failed" );
  122. return FALSE;
  123. }
  124. csResponse += szRecvBuf;
  125. char *p = strstr ( szRecvBuf, "rnrn" );
  126. if ( p )
  127. {
  128. if ( szTailData && pnTailSize && *pnTailSize > 0 )
  129. {
  130. p += 4;
  131. int nOtioseSize = nReadSize - int( p - szRecvBuf );
  132. *pnTailSize = MIN ( nOtioseSize, *pnTailSize );
  133. memcpy ( szTailData, p, *pnTailSize );
  134. }
  135. #ifdef _DEBUG
  136. int nPos = csResponse.Find ( "rnrn", 0 );
  137. CString csDump;
  138. if ( nPos >= 0 ) csDump = csResponse.Left ( nPos );
  139. else csDump = csResponse;
  140. // TRACE ( "n收到回应 <<<---------------------nn%sn", csDump );
  141. #endif
  142. break;
  143. }
  144. }
  145. return TRUE;
  146. }
  147. DWORD CDownloadHttp::GetResponseCode(CString csLineText)
  148. {
  149. csLineText.MakeLower ();
  150. ASSERT ( csLineText.Find ( "http/", 0 ) >= 0 );
  151. int nPos = csLineText.Find ( " ", 0 );
  152. if ( nPos < 0 ) return 0;
  153. CString csCode = csLineText.Mid ( nPos + 1 );
  154. csCode.TrimLeft(); csCode.TrimRight();
  155. nPos = csCode.Find ( " ", 0 );
  156. if ( nPos < 0 ) nPos = csCode.GetLength() - 1;
  157. csCode = csCode.Left ( nPos );
  158. return (DWORD)atoi(csCode);
  159. }
  160. BOOL CDownloadHttp::ParseResponseString ( CString csResponseString, OUT BOOL &bRedirect )
  161. {
  162. bRedirect = FALSE;
  163. // 获取返回代码
  164. CString csOneLine = GetOneLine ( csResponseString );
  165. DWORD dwResponseCode = GetResponseCode ( csOneLine );
  166. if ( dwResponseCode < 1 )
  167. {
  168. Log ( L_WARNING, "Received error response code : %s", csOneLine );
  169. return FALSE;
  170. }
  171. int nPos = 0;
  172. // 请求文件被重定向
  173. if( dwResponseCode >= 300 && dwResponseCode < 400 )
  174. {
  175. bRedirect = TRUE;
  176. // 得到请求文件新的URL
  177. CString csRedirectFileName = FindAfterFlagString ( "location:", csResponseString );
  178. // 设置 Referer
  179. m_csReferer = m_csDownloadUrl;
  180. // 重定向到其他的服务器
  181. nPos = csRedirectFileName.Find("://");
  182. if ( nPos >= 0 )
  183. {
  184. m_csDownloadUrl = csRedirectFileName;
  185. // 检验要下载的URL是否有效
  186. if ( !ParseURL ( m_csDownloadUrl, m_csServer, m_csObject, m_nPort, m_csProtocolType ) )
  187. {
  188. Log ( L_WARNING, "Redirect media path [%s] invalid", m_csDownloadUrl );
  189. return FALSE;
  190. }
  191. return TRUE;
  192. }
  193. // 重定向到本服务器的其他地方
  194. csRedirectFileName.Replace ( "\", "/" );
  195. // 重定向于根目录
  196. if( csRedirectFileName[0] == '/' )
  197. {
  198. m_csObject = csRedirectFileName;
  199. DownloadNotify ( -1, NOTIFY_TYPE_GOT_REMOTE_FILENAME, (LPVOID)(LPCTSTR)(GetDownloadObjectFileName()), m_pDownloadMTR );
  200. return TRUE;
  201. }
  202. // 定向于相对当前目录
  203. int nParentDirCount = 0;
  204. nPos = csRedirectFileName.Find ( "../" );
  205. while ( nPos >= 0 )
  206. {
  207. csRedirectFileName = csRedirectFileName.Mid(nPos+3);
  208. nParentDirCount++;
  209. nPos = csRedirectFileName.Find("../");
  210. }
  211. for (int i=0; i<=nParentDirCount; i++)
  212. {
  213. nPos = m_csDownloadUrl.ReverseFind('/');
  214. if (nPos != -1)
  215. m_csDownloadUrl = m_csDownloadUrl.Left(nPos);
  216. }
  217. if ( csRedirectFileName.Find ( "./", 0 ) == 0 )
  218. csRedirectFileName.Delete ( 0, 2 );
  219. m_csDownloadUrl = m_csDownloadUrl+"/"+csRedirectFileName;
  220. return ParseURL ( m_csDownloadUrl, m_csServer, m_csObject, m_nPort, m_csProtocolType );
  221. }
  222. // 请求被成功接收、理解和接受
  223. else if( dwResponseCode >= 200 && dwResponseCode < 300 )
  224. {
  225. if ( m_nIndex == -1 ) // 主线程才需要获取文件大小的信息
  226. {
  227. // 获取 Content-Length
  228. CString csDownFileLen = FindAfterFlagString ( "content-length:", csResponseString );
  229. m_nFileTotalSize = (int) _ttoi( (LPCTSTR)csDownFileLen );
  230. DownloadNotify ( -1, NOTIFY_TYPE_GOT_REMOTE_FILESIZE, (LPVOID)m_nFileTotalSize, m_pDownloadMTR );
  231. int nWillDownloadStartPos = Get_WillDownloadStartPos (); // 开始位置
  232. int nWillDownloadSize = Get_WillDownloadSize(); // 本次应该下载的字节数
  233. int nDownloadedSize = Get_DownloadedSize (); // 已下载字节数
  234. if ( m_nFileTotalSize > 0 && nWillDownloadSize-nDownloadedSize > m_nFileTotalSize )
  235. Set_WillDownloadSize ( m_nFileTotalSize-nDownloadedSize );
  236. }
  237. // 获取服务器文件的最后修改时间
  238. CString csModifiedTime = FindAfterFlagString ( "last-modified:", csResponseString );
  239. if ( !csModifiedTime.IsEmpty() )
  240. {
  241. m_TimeLastModified = ConvertHttpTimeString(csModifiedTime);
  242. }
  243. if ( dwResponseCode == 206 ) // 支持断点续传
  244. {
  245. m_bSupportResume = TRUE;
  246. }
  247. else // 不支持断点续传
  248. {
  249. m_bSupportResume = FALSE;
  250. }
  251. return TRUE;
  252. }
  253. // Log ( L_WARNING, "Index.%d receive invalid code : %d", m_nIndex, dwResponseCode );
  254. return FALSE;
  255. }
  256. CString CDownloadHttp::FindAfterFlagString(LPCTSTR lpszFoundStr, CString csOrg)
  257. {
  258. ASSERT ( lpszFoundStr && strlen(lpszFoundStr) > 0 );
  259. CString csReturing, csFoundStr = GET_SAFE_STRING(lpszFoundStr);
  260. csFoundStr.MakeLower ();
  261. CString csOrgLower = csOrg;
  262. csOrgLower.MakeLower ();
  263. int nPos = csOrgLower.Find ( csFoundStr );
  264. if ( nPos < 0 ) return "";
  265. csReturing = csOrg.Mid ( nPos + csFoundStr.GetLength() );
  266. nPos = csReturing.Find("rn");
  267. if ( nPos < 0 ) return "";
  268. csReturing = csReturing.Left(nPos);
  269. csReturing.TrimLeft();
  270. csReturing.TrimRight();
  271. return csReturing;
  272. }
  273. //
  274. // 将 HTTP 服务器表示的时间转换为 CTime 格式,如:Wed, 16 May 2007 14:29:53 GMT
  275. //
  276. CTime CDownloadHttp::ConvertHttpTimeString(CString csTimeGMT)
  277. {
  278. CString csYear, csMonth, csDay, csTime;
  279. CTime tReturning = -1;
  280. int nPos = csTimeGMT.Find ( ",", 0 );
  281. if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
  282. return tReturning;
  283. csTimeGMT = csTimeGMT.Mid ( nPos + 1 );
  284. csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();
  285. // 日
  286. nPos = csTimeGMT.Find ( " ", 0 );
  287. if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
  288. return tReturning;
  289. csDay = csTimeGMT.Left ( nPos );
  290. csTimeGMT = csTimeGMT.Mid ( nPos + 1 );
  291. csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();
  292. // 月
  293. nPos = csTimeGMT.Find ( " ", 0 );
  294. if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
  295. return tReturning;
  296. csMonth = csTimeGMT.Left ( nPos );
  297. int nMonth = GetMouthByShortStr ( csMonth );
  298. ASSERT ( nMonth >= 1 && nMonth <= 12 );
  299. csMonth.Format ( "%02d", nMonth );
  300. csTimeGMT = csTimeGMT.Mid ( nPos + 1 );
  301. csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();
  302. // 年
  303. nPos = csTimeGMT.Find ( " ", 0 );
  304. if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
  305. return tReturning;
  306. csYear = csTimeGMT.Left ( nPos );
  307. csTimeGMT = csTimeGMT.Mid ( nPos + 1 );
  308. csTimeGMT.TrimLeft(); csTimeGMT.TrimRight ();
  309. // 时间
  310. nPos = csTimeGMT.Find ( " ", 0 );
  311. if ( nPos < 0 || nPos >= csTimeGMT.GetLength()-1 )
  312. return tReturning;
  313. csTime = csTimeGMT.Left ( nPos );
  314. csTimeGMT = csTimeGMT.Mid ( nPos + 1 );
  315. CString csFileTimeInfo;
  316. csFileTimeInfo.Format ( "%s-%s-%s %s", csYear, csMonth, csDay, csTime );
  317. ConvertStrToCTime ( csFileTimeInfo.GetBuffer(0), tReturning );
  318. return tReturning;
  319. }