277 lines
No EOL
6.8 KiB
C++
277 lines
No EOL
6.8 KiB
C++
#include "stdafx.h"
|
|
#include "CHttpDownload.h"
|
|
#include "MD5Checksum.h"
|
|
|
|
#include "mmsystem.h"
|
|
|
|
BOOL ClientDeleteFile( LPCTSTR FineName )
|
|
{
|
|
DWORD dwNowTime = timeGetTime();
|
|
|
|
if( ::GetFileAttributes( FineName ) != 0xFFFFFFFF )
|
|
{
|
|
while( 1 )
|
|
{
|
|
if( timeGetTime() > dwNowTime + 5000 )
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
DWORD dwAttr = ::GetFileAttributes( FineName );
|
|
if( dwAttr & FILE_ATTRIBUTE_READONLY )
|
|
{
|
|
dwAttr &= ~FILE_ATTRIBUTE_READONLY;
|
|
::SetFileAttributes( FineName , dwAttr );
|
|
}
|
|
if( DeleteFile( FineName ) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
CHttpDownload::CHttpDownload()
|
|
: m_hHttpConnection( NULL )
|
|
, m_dwTempFileLength( 0 )
|
|
, m_dwDownloadFileLength( 0 )
|
|
, m_dwTotalFileLength( 0 )
|
|
, m_dwTotalBytes( 0 )
|
|
, m_fRate( 0.0f )
|
|
, m_fPercent( 0.0f )
|
|
, m_bExit( FALSE )
|
|
{
|
|
}
|
|
|
|
CHttpDownload::~CHttpDownload()
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void CHttpDownload::Reset()
|
|
{
|
|
if( m_hHttpConnection )
|
|
InternetCloseHandle( m_hHttpConnection );
|
|
|
|
m_hHttpConnection = NULL;
|
|
m_dwTempFileLength = 0;
|
|
m_dwDownloadFileLength = 0;
|
|
m_dwTotalFileLength = 0;
|
|
m_dwTotalBytes = 0;
|
|
m_fRate = 0.0f;
|
|
m_fPercent = 0.0f;
|
|
m_bExit = FALSE;
|
|
}
|
|
|
|
int CHttpDownload::DownloadFile( HINTERNET hInternetSession, CString strHttpPath, CString strLocalPath )
|
|
{
|
|
if( hInternetSession == NULL || strHttpPath.GetLength() == 0 || strLocalPath.GetLength() == 0 )
|
|
return HTTPDOWNLOAD_ERROR; // argument error
|
|
|
|
m_strHttpPath = strHttpPath;
|
|
m_strLocalPath = strLocalPath + L".tmp";
|
|
|
|
// 다운 받을 파일 크기 구하기
|
|
DWORD dwDownloadFileSize = GetDownloadFileSize( hInternetSession, m_strHttpPath );
|
|
|
|
if( dwDownloadFileSize == 0 )
|
|
return HTTPDOWNLOAD_ERROR;
|
|
|
|
TRACE( L"Download File Size = %d\n", dwDownloadFileSize );
|
|
|
|
// 다운 완료된 파일이 있을 경우 유효성 검사
|
|
CFile file;
|
|
CFileException e;
|
|
|
|
if( file.Open( strLocalPath, CFile::modeRead, &e ) )
|
|
{
|
|
if( file.GetLength() == dwDownloadFileSize )
|
|
{
|
|
m_dwTotalFileLength = dwDownloadFileSize;
|
|
m_dwTotalBytes = dwDownloadFileSize;
|
|
m_fPercent = 100.0f;
|
|
return HTTPDOWNLOAD_ALREADY_DOWNLOAD; // 이미 다 받아진 파일이 있음
|
|
}
|
|
else
|
|
ClientDeleteFile( strLocalPath ); // 받았으나 서버의 파일 정보와 상이할 경우 삭제 후 다시 받음
|
|
}
|
|
|
|
// 기존 다운받던 tmp 파일 체크
|
|
FILE* fp;
|
|
fp = _wfopen( m_strLocalPath, _T("r") );
|
|
UINT uiFileModeFlag = CFile::modeCreate | CFile::modeWrite | CFile::shareDenyWrite;
|
|
|
|
if( fp != NULL ) // 다운받던 tmp파일이 있을 경우
|
|
{
|
|
fclose( fp );
|
|
uiFileModeFlag |= CFile::modeNoTruncate;
|
|
}
|
|
|
|
if( !file.Open( m_strLocalPath, uiFileModeFlag, &e ) )
|
|
return HTTPDOWNLOAD_ERROR; // file open error
|
|
|
|
file.SeekToEnd();
|
|
|
|
m_dwTempFileLength = static_cast<DWORD>( file.GetLength() );
|
|
|
|
if( m_dwTempFileLength < dwDownloadFileSize )
|
|
{
|
|
// Http 열기
|
|
CString strAddHeader;
|
|
strAddHeader.Format( L"Range:bytes=%d-\nCache-Control:no-cache\nPragma:no-cache", m_dwTempFileLength );
|
|
|
|
m_hHttpConnection = InternetOpenUrl( hInternetSession, m_strHttpPath, strAddHeader, strAddHeader.GetLength(),
|
|
INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0 );
|
|
|
|
if( m_hHttpConnection == NULL )
|
|
{
|
|
file.Close(); // http connection error
|
|
return HTTPDOWNLOAD_ERROR;
|
|
}
|
|
|
|
TCHAR szBuffer[MAX_PATH]={0,};
|
|
DWORD dwBufferSize = MAX_PATH;
|
|
DWORD dwIndex = 0;
|
|
|
|
// 다운받아야 할 파일 크기 구하기
|
|
if( HttpQueryInfo( m_hHttpConnection, HTTP_QUERY_CONTENT_LENGTH, (LPVOID)&szBuffer, &dwBufferSize, &dwIndex ) != FALSE )
|
|
{
|
|
m_dwDownloadFileLength = (DWORD)_wtoi( szBuffer );
|
|
m_dwTotalFileLength = m_dwTempFileLength + m_dwDownloadFileLength;
|
|
}
|
|
|
|
// 다운로드 시작 (이어받기)
|
|
if( m_dwDownloadFileLength > 0 )
|
|
{
|
|
DWORD dwRead, dwSize;
|
|
DWORD dwStartTick, dwCurrentTick;
|
|
m_dwTotalBytes = m_dwTempFileLength;
|
|
|
|
char szReadBuf[32768]; // 32KiB
|
|
|
|
dwStartTick = GetTickCount();
|
|
|
|
do
|
|
{
|
|
if( IsExit() )
|
|
{
|
|
file.Close();
|
|
InternetCloseHandle( m_hHttpConnection );
|
|
m_hHttpConnection = NULL;
|
|
return HTTPDOWNLOAD_TERMINATE;
|
|
}
|
|
|
|
if( !InternetQueryDataAvailable( m_hHttpConnection, &dwSize, 0, 0 ) )
|
|
{
|
|
// error "data not available!"
|
|
break;
|
|
}
|
|
|
|
if( !InternetReadFile( m_hHttpConnection, szReadBuf, dwSize, &dwRead ) )
|
|
{
|
|
// error "reading file fail!"
|
|
break;
|
|
}
|
|
|
|
if( dwRead )
|
|
{
|
|
dwCurrentTick = GetTickCount();
|
|
file.Write( szReadBuf, dwRead );
|
|
|
|
m_dwTotalBytes += dwRead;
|
|
m_fRate = (float)(m_dwTotalBytes / 1000) / (float)((dwCurrentTick - dwStartTick) / 1000);
|
|
m_fPercent = (float)m_dwTotalBytes / (float)m_dwTotalFileLength * 100.0f;
|
|
|
|
TRACE( L"Read : [%09d / %09d] --- [%4.2f KB/s] < %4.0f%% >\n", m_dwTotalBytes, m_dwTotalFileLength, m_fRate, m_fPercent );
|
|
}
|
|
|
|
} while( dwRead != 0 );
|
|
}
|
|
InternetCloseHandle( m_hHttpConnection );
|
|
}
|
|
file.Close();
|
|
|
|
TRACE( L"--- MD5 Check Start... ---\n" );
|
|
// 올바르게 다운로드 되었는지 MD5 Check
|
|
if( !GetMD5Checksum() )
|
|
{
|
|
ClientDeleteFile( m_strLocalPath );
|
|
return HTTPDOWNLOAD_ERROR; // md5 check error
|
|
}
|
|
TRACE( L"--- MD5 Check End! ---\n" );
|
|
|
|
// 정리 tmp -> 원래 파일명
|
|
CString strNewLocalPath = m_strLocalPath.Left( m_strLocalPath.GetLength() - 4 );
|
|
CFile::Rename( m_strLocalPath, strNewLocalPath );
|
|
|
|
TRACE( L"--- Download Complete! ---\n" );
|
|
|
|
return HTTPDOWNLOAD_SUCCESS;
|
|
}
|
|
|
|
DWORD CHttpDownload::GetDownloadFileSize( HINTERNET hInternetSession, CString strHttpPath )
|
|
{
|
|
if( hInternetSession == NULL )
|
|
return 0;
|
|
|
|
m_hHttpConnection = InternetOpenUrl( hInternetSession, strHttpPath, NULL, 0, INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, 0 );
|
|
|
|
if( m_hHttpConnection == NULL )
|
|
return 0;
|
|
|
|
TCHAR szBuffer[MAX_PATH]={0,};
|
|
DWORD dwBufferSize = MAX_PATH;
|
|
DWORD dwIndex = 0;
|
|
DWORD dwFileSize = 0;
|
|
|
|
// 다운받아야 할 파일 크기 구하기
|
|
if( HttpQueryInfo( m_hHttpConnection, HTTP_QUERY_CONTENT_LENGTH, (LPVOID)&szBuffer, &dwBufferSize, &dwIndex ) != FALSE )
|
|
dwFileSize = (DWORD)_wtoi( szBuffer );
|
|
|
|
InternetCloseHandle( m_hHttpConnection );
|
|
return dwFileSize;
|
|
}
|
|
|
|
BOOL CHttpDownload::GetMD5Checksum()
|
|
{
|
|
CString strHttpMD5 = m_strHttpPath + L".MD5";
|
|
CString strLocalMD5 = m_strLocalPath + L".MD5";
|
|
|
|
HRESULT hr = E_FAIL;
|
|
for( int i = 0 ; i < RETRY_MAX_COUNT ; i++ )
|
|
{
|
|
BOOL bResult = DeleteUrlCacheEntry( strHttpMD5 );
|
|
hr = ::URLDownloadToFile( NULL, strHttpMD5, strLocalMD5, 0, NULL );
|
|
if( hr == S_OK )
|
|
break;
|
|
}
|
|
|
|
if( FAILED( hr ) )
|
|
{
|
|
TRACE( L"MD5 Check File Download Failed!, Error : %ld", hr );
|
|
return FALSE;
|
|
}
|
|
|
|
CString strDownloadChecksum;
|
|
CFile fileMD5;
|
|
CFileException e;
|
|
|
|
if( !fileMD5.Open( strLocalMD5, CFile::modeRead, &e ) )
|
|
return FALSE;
|
|
|
|
char pBuf[100];
|
|
fileMD5.Read( pBuf, 100 );
|
|
fileMD5.Close();
|
|
ClientDeleteFile( strLocalMD5 );
|
|
|
|
strDownloadChecksum = pBuf;
|
|
int nIndex = strDownloadChecksum.Find('\n');
|
|
strDownloadChecksum = strDownloadChecksum.Left( nIndex - 1 );
|
|
|
|
CString strLocalChecksum = CMD5Checksum::GetMD5( m_strLocalPath );
|
|
// MD5 비교
|
|
return wcscmp( strLocalChecksum, strDownloadChecksum ) == 0 ? TRUE : FALSE;
|
|
} |