📄 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 <m_nParts; i++){
name.Empty();
name.Format(".down%d", i);
name = m_strSavePath + name;
f[i].Open(name, CFile::modeRead);
DWORD len = f[i].GetLength();
if(lpData){
delete [] lpData;
lpData = NULL;
}
if(lpData == NULL){
lpData = new char[len];
}
f[i].Read(lpData, len);
file.Write(lpData, len);
f[i].Close();
DeleteFile(name);
}
if(lpData){
delete [] lpData;
lpData = NULL;
}
file.Close();
name.Empty();
name = m_strSavePath + ".down";
DeleteFile(name);
AfxMessageBox("下载完成");
}
}
else{
HRESULT ret = WaitForSingleObject(m_hThread[0], INFINITE);
if(m_bTerminate[0]){
return ;
}
if(ret == 0){
CFile file, f;
CString name;
file.Open(m_strSavePath, CFile::modeCreate | CFile::modeWrite);
name = m_strSavePath + ".down0";
f.Open(name, CFile::modeRead);
DWORD len = f.GetLength();
if(lpData){
delete [] lpData;
lpData = NULL;
}
if(lpData == NULL){
lpData = new char[len];
}
f.Read(lpData, len);
file.Write(lpData, len);
f.Close();
DeleteFile(name);
if(lpData){
delete [] lpData;
lpData = NULL;
}
file.Close();
AfxMessageBox("下载完成");
}
}
if(lpData){
delete [] lpData;
lpData = NULL;
}
return ;
}
void CHTTPSDownload::OnCancel()
{
for(int i = 0; i < m_nParts; i++)
m_bTerminate[i] = TRUE;
HRESULT ret = WaitForSingleObject(m_hNotify, INFINITE);
if(ret != WAIT_OBJECT_0) return;
FILE* fp = NULL;
CString name;
name = m_strSavePath + ".down";
fp = fopen(name, "w+") ;
fwrite(m_state.range, sizeof(LONG), 2*m_nParts, fp);
fwrite(m_state.threadsize, sizeof(LONG), m_nParts, fp);
fwrite(m_state.wcsize, sizeof(LONG), m_nParts, fp);
fclose(fp);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -