⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 httpdownload.cpp

📁 基于Winsock2的支持断点续传和SOCKS代理的HTTP下载类 CHttpDownload
💻 CPP
📖 第 1 页 / 共 3 页
字号:
		strVerb = _T("HEAD ");
	else
		strVerb = _T("GET ");

	while (TRUE)
	{
		CString			strSend,strAuth,strAddr,strHeader;
		BYTE			bAuth,bAtyp;
		DWORD			dwIP;
		SOCKSREPPACKET	pack;
	
		int				iStatus,nRet;;
		char			szReadBuf[1025];
		DWORD			dwContentLength,dwStatusCode;


		m_dwFileDownloadedSize = 0;
		m_dwDownloadSize	   = 0;

		///////////////////////////////////////
		// 目前的版本中,此信息并没有用
		m_strHeader		= _T("");
		m_dwHeaderSize	= 0;
		//////////////////////////////////////
		if (!CreateSocket())
			return SENDREQUEST_FAIL;
	
		if (m_bStopDownload)
			return SENDREQUEST_STOP;

		switch( m_nProxyType )
		{
		case PROXY_NONE:
			if( TE_ConnectEx(m_hSocket,m_strServer,m_nPort,m_dwConnectTimeout,TRUE) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;
			break;
		case PROXY_HTTPGET:
			if( TE_ConnectEx(m_hSocket,m_strProxyServer,m_nProxyPort,m_dwConnectTimeout,TRUE) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;
			break;
		case PROXY_SOCKS4A:
			dwIP = TE_GetIP(m_strServer,TRUE);
			if( dwIP == INADDR_NONE )
			{
				if( TE_ConnectEx(m_hSocket,m_strProxyServer,m_nProxyPort,m_dwConnectTimeout,TRUE) == SOCKET_ERROR )
					return SENDREQUEST_ERROR;
				
				if( SOP_SendSocks4aReq(m_hSocket,CMD_CONNECT,m_nPort,m_strServer,m_strProxyUsername,m_dwSendTimeout) == SOCKET_ERROR )
					return SENDREQUEST_ERROR;

				ZeroMemory(&pack,sizeof(SOCKSREPPACKET));
				if( SOP_RecvPacket(m_pBSD,&pack,PACKET_SOCKS4AREP,m_dwReceiveTimeout) == SOCKET_ERROR )
					return SENDREQUEST_ERROR;

				if( !SOP_IsSocksOK(&pack,PACKET_SOCKS4AREP) )
					return SENDREQUEST_ERROR;

				break;// NOTICE:如果本地能够解析域名,可以使用SOCKS4 Proxy
			}
		case PROXY_SOCKS4:
			// 必须要得到Proxy Server的IP地址(不能为域名)
			dwIP = TE_GetIP(m_strServer,TRUE);
			if( dwIP == INADDR_NONE )
				return SENDREQUEST_ERROR;
			if( TE_ConnectEx(m_hSocket,m_strProxyServer,m_nProxyPort,m_dwConnectTimeout,TRUE) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;
			if( SOP_SendSocks4Req(m_hSocket,CMD_CONNECT,m_nPort,dwIP,m_strProxyUsername,m_dwSendTimeout) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;
		
			ZeroMemory(&pack,sizeof(SOCKSREPPACKET));
			if( SOP_RecvPacket(m_pBSD,&pack,PACKET_SOCKS4REP,m_dwReceiveTimeout) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;
			
			if( !SOP_IsSocksOK(&pack,PACKET_SOCKS4REP) )
				return SENDREQUEST_ERROR;
			break;
		case PROXY_SOCKS5:
			if( TE_ConnectEx(m_hSocket,m_strProxyServer,m_nProxyPort,m_dwConnectTimeout,TRUE) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;

			if( m_bProxyAuthorization )
			{
				strAuth =  _T("");
				char c	= (char)AUTH_NONE;
				strAuth += c;
				c 		= (char)AUTH_PASSWD;
				strAuth += c;
				
			}
			else
			{
				char c	= (char)AUTH_NONE;
				strAuth =  _T("");
				strAuth += c;
			}
			bAuth =(BYTE)strAuth.GetLength();
			
			if( SOP_SendSocks5AuthReq(m_hSocket,bAuth,(LPCTSTR)strAuth,m_dwSendTimeout) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;

			ZeroMemory(&pack,sizeof(SOCKSREPPACKET));
			if( SOP_RecvPacket(m_pBSD,&pack,PACKET_SOCKS5AUTHREP,m_dwReceiveTimeout) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;

			if( !SOP_IsSocksOK(&pack,PACKET_SOCKS5AUTHREP) )
				return SENDREQUEST_ERROR;

			switch( pack.socks5AuthRep.bAuth )
			{
			case AUTH_NONE:
				break;
			case AUTH_PASSWD:
				if( !m_bProxyAuthorization )
					return SENDREQUEST_FAIL;
				if( SOP_SendSocks5AuthPasswdReq(m_hSocket,m_strProxyUsername,m_strProxyPassword,m_dwSendTimeout) == SOCKET_ERROR )
					return SENDREQUEST_ERROR;

				ZeroMemory(&pack,sizeof(SOCKSREPPACKET));
				if( SOP_RecvPacket(m_pBSD,&pack,PACKET_SOCKS5AUTHPASSWDREP,m_dwReceiveTimeout) == SOCKET_ERROR )
					return SENDREQUEST_ERROR;

				if( !SOP_IsSocksOK(&pack,PACKET_SOCKS5AUTHPASSWDREP) )
					return SENDREQUEST_ERROR;
				break;
			case AUTH_GSSAPI:
			case AUTH_CHAP:
			case AUTH_UNKNOWN:
			default:
				return SENDREQUEST_FAIL;
				break;
			}

			dwIP = TE_GetIP(m_strServer,TRUE);
			if( dwIP != INADDR_NONE )
			{
				bAtyp = ATYP_IPV4ADDR;
				strAddr = _T("");
				// 转换字节序
				dwIP = htonl(dwIP);
				strAddr += (char)( (dwIP>>24) &0x000000ff); 
				strAddr += (char)( (dwIP>>16) &0x000000ff); 
				strAddr += (char)( (dwIP>>8 ) &0x000000ff); 
				strAddr += (char)( dwIP &0x000000ff); 

			}
			else
			{
				bAtyp = ATYP_HOSTNAME;
				char c = (char)m_strServer.GetLength();
				strAddr  = _T("");
				strAddr += c;
				strAddr += m_strServer;
			}
			if( SOP_SendSocks5Req(m_hSocket,CMD_CONNECT,bAtyp,(LPCTSTR)strAddr,m_nPort,m_dwSendTimeout) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;

			ZeroMemory(&pack,sizeof(SOCKSREPPACKET));
			if( SOP_RecvPacket(m_pBSD,&pack,PACKET_SOCKS5REP,m_dwReceiveTimeout) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;

			if( !SOP_IsSocksOK(&pack,PACKET_SOCKS5REP) )
				return SENDREQUEST_ERROR;

			break;
		case PROXY_HTTPCONNECT:
		default:
			return SENDREQUEST_FAIL;
			break;
		}

		if (m_bStopDownload)
			return SENDREQUEST_STOP;
	
		if( m_nProxyType == PROXY_HTTPGET )
		{
			strSend  = strVerb  + m_strDownloadUrl + " HTTP/1.1\r\n";
			if( m_bProxyAuthorization )
			{
				strAuth = _T("");
				Base64Encode(m_strProxyUsername+":"+m_strProxyPassword,strAuth);
				strSend += "Proxy-Authorization: Basic "+strAuth+"\r\n";
			}
		}
		else	// No Proxy or not a HTTP_GET Proxy
			strSend  = strVerb  + m_strObject + " HTTP/1.1\r\n";
		
		if( m_bAuthorization )
		{
			strAuth = _T("");
			Base64Encode(m_strUsername+":"+m_strPassword,strAuth);
			strSend += "Authorization: Basic "+strAuth+"\r\n";
		}

		strSend += "Host: " + m_strServer + "\r\n";
		strSend += "Accept: */*\r\n";
		strSend += "Pragma: no-cache\r\n"; 
		strSend += "Cache-Control: no-cache\r\n";
		strSend += "User-Agent: "+m_strUserAgent+"\r\n";
		if( !m_strReferer.IsEmpty() )
			strSend += "Referer: "+m_strReferer+"\r\n";
		strSend += "Connection: close\r\n";

		// 查看文件已经下载的长度
		CFileStatus fileDownStatus;
		CString		strRange;
		strRange.Empty();
		if (CFile::GetStatus(m_strTempSavePath,fileDownStatus) && !m_bForceDownload )
		{
			m_dwFileDownloadedSize = fileDownStatus.m_size;
			if (m_dwFileDownloadedSize > 0)
			{
				strRange.Format(_T("Range: bytes=%d-\r\n"),m_dwFileDownloadedSize );
			}
		}
		strSend += strRange;
		//必须要加一个空行,否则Http服务器将不会应答
		strSend += "\r\n";

		//发送请求
		nRet = TE_Send(m_hSocket,(LPCTSTR)strSend,strSend.GetLength(),m_dwSendTimeout);
		if( nRet < strSend.GetLength() )
		{
			if ( TE_GetLastError() == WSAETIMEDOUT)	// 超时
				continue;
			else	// 其他错误,可能是网络断了,等待一段时间后重试
				return SENDREQUEST_ERROR;
		}

		if (m_bStopDownload)
			return SENDREQUEST_STOP;

		strHeader.Empty();
		while( TRUE )
		{
			ZeroMemory(szReadBuf,1025);
			if( TE_BSocketGetStringEx(m_pBSD,szReadBuf,1024,&iStatus,m_dwReceiveTimeout) == SOCKET_ERROR )
				return SENDREQUEST_ERROR;
			
			if( szReadBuf[0] == '\0' ) // We have encountered "\r\n\r\n"
				break; 

			strHeader += szReadBuf;
			if( iStatus == 0)
				strHeader += "\r\n";
		}
		
		///////////////////////////////////////
		// 目前的版本中,此信息并没有用
		m_strHeader		= strHeader;
		m_dwHeaderSize	= m_strHeader.GetLength();
		//////////////////////////////////////
				
		nRet = GetInfo(strHeader,dwContentLength,dwStatusCode,m_TimeLastModified);
		switch ( nRet )
		{
		case HTTP_FAIL:
			return SENDREQUEST_FAIL;
			break;
		case HTTP_ERROR:
			return SENDREQUEST_ERROR;
			break;
		case HTTP_REDIRECT:
			continue;
			break;
		case HTTP_OK:
			m_dwDownloadSize = dwContentLength;
			// 应该判断一下服务器是否支持断点续传
			if( strRange.IsEmpty() )
				m_dwFileSize = dwContentLength; // 整个文件的长度
			else
			{
				if ( dwStatusCode == 206 )	//支持断点续传
				{
					m_dwFileSize = m_dwFileDownloadedSize +dwContentLength;
					m_bSupportResume = TRUE;
				}
				else						//不支持断点续传
				{
					m_bSupportResume = FALSE;
					m_dwFileDownloadedSize	= 0; //不支持断点续传,此值要设为0
					m_dwFileSize = dwContentLength;
				}
			}
			return SENDREQUEST_SUCCESS;
			break;
		default:
			return SENDREQUEST_FAIL;
			break;
		}

	}// WHILE LOOP

	return SENDREQUEST_SUCCESS;
}


// 设置代理及代理认证方式
void CHttpDownload::SetProxy(LPCTSTR lpszProxyServer, USHORT nProxyPort, BOOL bProxy, BOOL bProxyAuthorization, LPCTSTR lpszProxyUsername, LPCTSTR lpszProxyPassword,UINT nProxyType /*= PROXY_HTTPGET*/)
{
	if( bProxy && lpszProxyServer != NULL)
	{
		m_bProxy			= TRUE;
		m_strProxyServer	= lpszProxyServer;
		m_nProxyPort		= nProxyPort;
		m_nProxyType		= nProxyType;

		if( bProxyAuthorization && lpszProxyUsername != NULL)
		{
			m_bProxyAuthorization	= TRUE;
			m_strProxyUsername		= lpszProxyUsername;
			m_strProxyPassword		= lpszProxyPassword;
		}
		else
		{
			m_bProxyAuthorization	= FALSE;
			m_strProxyUsername		= _T("");
			m_strProxyPassword		= _T("");
		}
	}
	else
	{
		m_bProxy				= FALSE;
		m_bProxyAuthorization	= FALSE;
		m_nProxyPort			= 0;
		m_nProxyType			= PROXY_NONE;
		m_strProxyServer		= _T("");
		m_strProxyUsername		= _T("");
		m_strProxyPassword		= _T("");
	}
}


// 设置WWW认证信息
void CHttpDownload::SetAuthorization(LPCTSTR lpszUsername, LPCTSTR lpszPassword, BOOL bAuthorization)
{
	if( bAuthorization && lpszUsername != NULL )
	{
		m_bAuthorization = TRUE;
		m_strUsername	 = lpszUsername;
		m_strPassword	 = lpszPassword;
	}
	else
	{
		m_bAuthorization = FALSE;
		m_strUsername	 = _T("");
		m_strPassword	 = _T("");
	}
}

// 设置是否需要发送消息给调用窗口
void CHttpDownload::SetNotifyWnd(HWND hNotifyWnd, UINT nNotifyMsg, BOOL bNotify)
{
	if( bNotify && (hNotifyWnd != NULL) && ::IsWindow(hNotifyWnd) )
	{
		m_bNotify	 = TRUE;
		m_hNotifyWnd = hNotifyWnd;
		m_nNotifyMessage = nNotifyMsg;
	}
	else
	{
		m_bNotify	 = FALSE;
		m_hNotifyWnd = NULL;
		m_nNotifyMessage = 0;
	}
}

// 设置超时
void CHttpDownload::SetTimeout(DWORD dwSendTimeout, DWORD dwReceiveTimeout, DWORD dwConnectTimeout)
{
	if( dwSendTimeout > 0 )
		m_dwSendTimeout = dwSendTimeout;
	
	if( dwReceiveTimeout > 0 )
		m_dwReceiveTimeout = dwReceiveTimeout;

	if( dwConnectTimeout > 0 )
		m_dwConnectTimeout = dwConnectTimeout;


}

// 设置UserAgent
void CHttpDownload::SetUserAgent(LPCTSTR lpszUserAgent)
{
	m_strUserAgent = lpszUserAgent;	
	if( m_strUserAgent.IsEmpty())
		m_strUserAgent = _T("HttpDownload/2.0");
}

// 设置Referer
void CHttpDownload::SetReferer(LPCTSTR lpszReferer)
{
	if( lpszReferer != NULL )
		m_strReferer = lpszReferer;
	else
		m_strReferer = _T("");
}

// 设置重试的机制
// nRetryType = 0  不重试					RETRY_TYPE_NONE
// nRetryType = 1  重试一定次数				RETRY_TYPE_TIMES
// nRetryType = 2  永远重试(可能陷入死循环)	RETRY_TYPE_ALWAYS
void CHttpDownload::SetRetry(UINT nRetryType, UINT nRetryDelay, UINT nRetryMax)
{
	m_nRetryType  = nRetryType;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -