www.pudn.com > download.rar > HTTPSDownload.cpp


// HTTPSDownload.cpp: implementation of the CHTTPSDownload class. 
// 
////////////////////////////////////////////////////////////////////// 
 
#include "stdafx.h" 
#include "download.h" 
#include "HTTPSDownload.h" 
 
#ifdef _DEBUG 
#undef THIS_FILE 
static char THIS_FILE[]=__FILE__; 
#define new DEBUG_NEW 
#endif 
 DWORD WINAPI HSDownloadThread(LPVOID); 
 DWORD WINAPI HSNotify(LPVOID);  
 
////////////////////////////////////////////////////////////////////// 
// Construction/Destruction 
////////////////////////////////////////////////////////////////////// 
 
 
 //包含HTTPS下载函数,利用OpenSSL库进行加密的数据传输,其具体下载实现与http基本相同 
 CHTTPSDownload::CHTTPSDownload() 
{ 
   for(int  i=0; i<10; i++) 
   { 
	  m_hThread[i] = NULL; 
	  m_bTerminate[i] = FALSE; 
	  ss[i]=0; 
	  m_sum[i]=0; 
   } 
   m_SupportResume = FALSE; 
   m_bResume = FALSE; 
} 
 
CHTTPSDownload::~CHTTPSDownload() 
{ 
 
} 
 
void  CHTTPSDownload::Begin(CString Allurl, CString Saveas, int nParts) 
{ 
    for(int i=0;i<10;i++){ 
			m_state.wcsize[i] = 0; 
			m_sum[i] = 0; 
			ss[i]=0; 
			m_dwFileSize=0; 
	} 
	 
	 
	if(!(AnalyseURL(Allurl))) 
	{ 
	  AfxMessageBox("URL错误,请确认地址正确"); 
	  return; 
    } 
   
    m_strSavePath = Saveas; 
    m_nParts = nParts; 
    m_strSavePath.TrimLeft(); 
    m_strSavePath.TrimRight(); 
 
    if(SendRequest() != HS_LINK_OK) { AfxMessageBox("下载出现错误"); return; } 
 	 
    m_strTempSavePath = m_strSavePath; 
	m_strTempSavePath += ".down"; 
	 
	FILE* fp = NULL; 
	if((fp = fopen(m_strTempSavePath, "r")) == NULL){ 
		m_state.range[0] = -1; 
		m_bResume = FALSE; 
	} 
	else{ 
		m_bResume = TRUE; 
		fread(m_state.range, sizeof(LONG), 2*nParts, fp); 
		fread(m_state.threadsize, sizeof(LONG), nParts, fp); 
		fread(m_state.wcsize, sizeof(LONG), nParts, fp); 
		fclose(fp); 
		DeleteFile(m_strTempSavePath);  
	} 
 
    if(m_state.range[0] == -1){ 
	 
 
    for(int i = 0; i < m_nParts; i++){ 
			m_state.range[i * 2] = i * (m_dwFileSize /m_nParts); 
			m_state.range[i * 2 + 1] = (i + 1) * (m_dwFileSize / m_nParts) - 1; 
			m_state.threadsize[i] = m_state.range[i * 2 + 1] - m_state.range[i * 2]; 
		} 
		m_state.range[2*m_nParts-1] = m_dwFileSize; 
		m_state.threadsize[m_nParts-1] = m_state.range[2*m_nParts-1] - m_state.range[2*m_nParts-2]; 
	} 
	CreateThread();   
	 
	return ; 
} 
 
BOOL CHTTPSDownload::AnalyseURL(CString Allurl) 
{ 
 
	m_strServer = _T(""); 
	m_strObject = _T(""); 
	m_Port	  = 0; 
 
	Allurl.TrimLeft(); 
	Allurl.TrimRight(); 
	CString strTemp; 
	int n=Allurl.Find("://"); 
	if(n == -1)  return FALSE;  
	strTemp = Allurl.Mid(n+3); 
	 
    n=strTemp.Find('/'); 
	if(n == -1)  return FALSE; 
	m_strServer = strTemp.Left(n); 
	m_strObject = strTemp.Mid(n); 
     
	n = m_strServer.Find(':'); 
	if(n != -1) 
	{ 
        CString temp = m_strServer.Mid(n+1); 
        m_Port = (USHORT)_ttoi((LPCTSTR)temp); 
		m_strServer = m_strServer.Left(n); 
	} 
	else 
	{ 
		m_Port = 443; 
	} 
    return TRUE; 
} 
 
 
UINT CHTTPSDownload::SendRequest() 
{ 
	CString	 strSend,strHeader; 
	CString  m_P; 
	m_P.Empty();  m_P.Format("%d",m_Port); 
	strHost = m_strServer+":"+m_P; 
	int      ret; 
    SSL_CTX *ssl_ctx=NULL; 
    SSL *ssl; 
    BIO *bio; 
	char	 ReadBuf[1025]; 
	DWORD	 Length,Code; 
 
    while(TRUE) 
	{ 
		//应用OpenSSL的加密连接进行与服务器的连接 
	    if (ssl_ctx != NULL) SSL_CTX_free(ssl_ctx); 
        SSL_load_error_strings(); 
        OpenSSL_add_ssl_algorithms(); 
        ssl_ctx=SSL_CTX_new(SSLv23_client_method()); 
         
		bio = BIO_new_ssl_connect(ssl_ctx); 
        BIO_get_ssl(bio, & ssl); 
         
		BIO_set_conn_hostname(bio, strHost.GetBuffer(0)); 
 
 
		 
		strSend  = "GET " + m_strObject + " HTTP/1.1\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 += "Connection: close\r\n"; 
		strSend += "Range: bytes=100-\r\n"; 
		strSend += "\r\n"; 
 
		ret = BIO_write(bio,strSend.GetBuffer(0), strSend.GetLength()); 
		strSend.ReleaseBuffer(); 
		 
		strHeader.Empty(); 
        ZeroMemory(ReadBuf,1025); 
		ret = BIO_read(bio, ReadBuf, 1025); 
		strHeader += ReadBuf; 
		strHeader += "\r\n"; 
 
		BOOL sign=AnalyseReceive(strHeader,Length, Code); 
		 
		if(sign) 
		{ 
			if(linkcode==1) 
			{ 
				if (Code == 206 )	 
				{ 
					m_SupportResume = TRUE; 
					m_dwFileSize = Length + 100; 
				} 
				  else						 
				{ 
					m_SupportResume = FALSE; 
					m_dwFileSize = Length + 100; 
				} 
 
				return HS_LINK_OK; 
			} 
 
			if(linkcode==2)  continue; 
		} 
		else 
		{ 
			if(linkcode==-1) { AfxMessageBox("服务器返回信息错误"); return HS_LINK_ERROR;} 
			if(linkcode==-2) { AfxMessageBox("服务器连接错误"); return HS_LINK_ERROR;} 
		} 
	} 
	BIO_free_all(bio); 
	if (ssl_ctx != NULL) SSL_CTX_free(ssl_ctx); 
 
} 
 
 
BOOL CHTTPSDownload::AnalyseReceive(CString ReadBuf, DWORD &Length, DWORD &Code) 
{ 
	Length = 0; 
	Code	= 0; 
 
    CString strHeader =ReadBuf; 
	strHeader.MakeLower(); 
	 
    int n = strHeader.Find("\r\n"); 
	if (n == -1)   { linkcode =-1; return false; } 
	CString strFirstLine = strHeader.Left(n); 
 
 
	strFirstLine.TrimLeft(); 
	strFirstLine.TrimRight(); 
	n = strFirstLine.Find(' '); 
    if (n == -1)   { linkcode =-1; return false; } 
	strFirstLine = strFirstLine.Mid(n+1); 
	n = strFirstLine.Find(' '); 
	if (n == -1)   { linkcode =-1; return false; } 
	strFirstLine = strFirstLine.Left(n); 
	Code = (DWORD)_ttoi((LPCTSTR)strFirstLine); 
	 
 
	if( Code >= 300 && Code < 400 )  
	{ 
		n = strHeader.Find("location:"); 
		if (n == -1)   { linkcode =-1; return false; } 
 
		CString strRedirectURL = strHeader.Mid(n + strlen("location:")); 
		n = strRedirectURL.Find("\r\n"); 
		if (n == -1)   { linkcode =-1; return false; } 
 
		strRedirectURL = strRedirectURL.Left(n); 
		strRedirectURL.TrimLeft(); 
		strRedirectURL.TrimRight(); 
	     
		n = strRedirectURL.ReverseFind('/'); 
		CString temp = strRedirectURL.Mid(n+1); 
	 
	    n = temp.Find('?'); 
	    if(n != -1) 
		{ 
          temp=temp.Left(n); 
		} 
 
		n = m_strSavePath.ReverseFind('\\'); 
        m_strSavePath = m_strSavePath.Left(n+1); 
		m_strSavePath+= temp; 
 
        if(!(AnalyseURL(strRedirectURL))) 
		{ 
	      linkcode =-1; return false; 
		} 
		linkcode=2;	return true; 
	} 
 
    if( Code >=400  )  { linkcode =-2; return false; } 
 
 
	n = strHeader.Find("content-length:"); 
	if (n == -1)   {linkcode =-1;  return false; } 
 
	CString strDownFileLen = strHeader.Mid(n + strlen("content-length:"));	 
	n = strDownFileLen.Find("\r\n"); 
	if (n == -1)   {linkcode =-1;  return false; } 
 
	strDownFileLen = strDownFileLen.Left(n);	 
	strDownFileLen.TrimLeft(); 
	strDownFileLen.TrimRight(); 
	 
	Length = (DWORD) _ttoi( (LPCTSTR)strDownFileLen ); 
 
    linkcode=1; return true; 
} 
 
 
void CHTTPSDownload::CreateThread() 
{ 
	if(m_SupportResume){ 
		DWORD dwThread; 
		m_index = 0; 
		for(int i = 0; i < m_nParts; i++) 
		{ 
			m_bTerminate[i] = FALSE; 
			m_hThread[i] = ::CreateThread(NULL, 0, HSDownloadThread, (LPVOID)this, 0, &dwThread); 
 
		} 
	} 
	else{ 
		 
		DWORD dwThread; 
		m_index = 0; 
		m_bTerminate[0] = FALSE; 
		m_hThread[0] = ::CreateThread(NULL, 0, HSDownloadThread, (LPVOID)this, 0, &dwThread); 
 
	} 
	DWORD dwNotify; 
	m_hNotify = ::CreateThread(NULL, 0, HSNotify, (LPVOID)this, 0, &dwNotify); 
 
} 
 
 
DWORD WINAPI HSDownloadThread(LPVOID lpParam) 
{ 
	CHTTPSDownload* pThis = (CHTTPSDownload*)lpParam; 
	int index; 
	index = pThis->m_index; 
	InterlockedIncrement(&pThis->m_index); 
    pThis->ThreadFunc(index); 
	return 0L; 
} 
 
DWORD WINAPI HSNotify(LPVOID lpParam) 
{ 
    CHTTPSDownload* pThis = (CHTTPSDownload*)lpParam; 
    pThis->Finish(); 
	return 0L; 
} 
 
 
void CHTTPSDownload::ThreadFunc(int index) 
{ 
	 
	if(m_state.range[2*index] ==-99) { ss[index]=1000; m_sum[index]=m_state.threadsize[index]; return; } 
	 
	m_sum[index] =0; 
 
    SSL_CTX *ssl_ctx=NULL; 
    SSL *ssl; 
    BIO *bio; 
 
    SSL_load_error_strings(); 
    OpenSSL_add_ssl_algorithms(); 
    ssl_ctx=SSL_CTX_new(SSLv23_client_method()); 
    bio = BIO_new_ssl_connect(ssl_ctx); 
 
    BIO_get_ssl(bio, & ssl); 
 
    BIO_set_conn_hostname(bio, strHost.GetBuffer(0)); 
     
    CString strSend, strRange; 
	char szReadBuf[1025]; 
 
	strSend  = "GET " + m_strObject + " HTTP/1.1\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 += "Connection: close\r\n"; 
	strRange.Format("Range: bytes=%d-%d\r\n", m_state.range[2 * index], m_state.range[2 * index + 1]); 
    if(m_SupportResume) 
		strSend += strRange; 
	strSend += "\r\n"; 
 
	int ret = BIO_write(bio,strSend.GetBuffer(0), strSend.GetLength()); 
	strSend.ReleaseBuffer(); 
 
	ZeroMemory(szReadBuf,1025); 
	ret = BIO_read(bio, szReadBuf, 1025); 
		 
	int n = GetHeadLength(szReadBuf);		 
	 
	CFile file; 
	CString name; 
	name.Format("%d", index); 
	name = m_strTempSavePath + name; 
	 
	if(!m_bResume) 
	  file.Open(name, CFile::modeCreate | CFile::modeWrite); 
	else 
	  file.Open(name, CFile::modeWrite); 
 
 
	file.SeekToEnd(); 
 
	file.Write(szReadBuf + n, ret - n); 
	int sum = ret - n, num = 0; 
 
	if(!m_SupportResume) m_state.threadsize[0]=m_dwFileSize; 
 
	while(1){ 
		if(m_bTerminate[index]){ 
			m_state.range[2 * index] = m_state.range[2 * index] + sum; 
            m_state.wcsize[index] = m_sum[index]; 
            return; 
		} 
		ZeroMemory(szReadBuf,1025); 
		 
		num = BIO_read(bio,szReadBuf, 1025); 
		if(num<=0) break; 
			 
		file.Write(szReadBuf, num); 
		sum += num;  
		m_sum[index]=sum+m_state.wcsize[index]; 
			 
		ss[index]=long((1.0*m_sum[index])*1000/m_state.threadsize[index]); 
	} 
	 
	file.Close(); 
	BIO_free_all(bio); 
	SSL_CTX_free(ssl_ctx); 
 
    m_state.range[2*index]= -99; 
	return ; 
} 
 
 
int CHTTPSDownload::GetHeadLength(char *lpData) 
{ 
	int nhead = 0,nstr;  
	while(1){ 
		nstr=0; 
		BOOL bLine = FALSE; 
	    while ( bLine == FALSE && nhead < 1025 ) 
		{ 
		  char ch = (char)(lpData[nhead]); 
		  if(ch=='\n')  bLine = TRUE; 
		  if(ch!='\n'&&ch!='\r') nstr++; 
		  nhead++; 
		 } 
		 
		if(nstr==0)  break; 
	} 
	return (nhead); 
} 
 
 
 
void CHTTPSDownload::Finish() 
{ 
	char* lpData = NULL; 
	if(m_SupportResume){ 
		HRESULT ret = WaitForMultipleObjects(m_nParts, m_hThread, TRUE, INFINITE); 
		if(m_bTerminate[0]){ 
			return; 
		} 
		if(ret == 0){ 
		 
			 
			CFile file, f[10]; 
			CString name; 
			 
			file.Open(m_strSavePath, CFile::modeCreate | CFile::modeWrite); 
			for(int i = 0; i