Last active
December 16, 2015 12:08
-
-
Save kyle-go/5432193 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "httpdownload.h" | |
#include <windows.h> | |
#include <wininet.h> | |
#include <shlwapi.h> | |
#include <tchar.h> | |
#include "scope.h" | |
#pragma comment(lib, "wininet") | |
#pragma comment(lib, "shlwapi") | |
int HttpDownLoad_real( | |
std::string& tmp_file, | |
const std::string& url, | |
const std::string& file, | |
std::function<void(double)> callback) | |
{ | |
HINTERNET hSession = InternetOpen(_T("HTTPDOWNLOAD"), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0); | |
scloud::ScopeGuard session([hSession]{InternetCloseHandle(hSession);}); | |
if (!hSession) { | |
session.cancel(); | |
return GetLastError(); | |
} | |
HINTERNET hInternet = InternetOpenUrl(hSession, url.c_str(), NULL, 0 , INTERNET_FLAG_RAW_DATA, 0 ); | |
scloud::ScopeGuard internet([hInternet]{InternetCloseHandle(hInternet);}); | |
if (!hInternet) { | |
internet.cancel(); | |
return GetLastError(); | |
} | |
//get http return code. | |
char szContent[32] = {0}; | |
DWORD dwInfoSize = 32; | |
HttpQueryInfoA(hInternet, HTTP_QUERY_STATUS_CODE, szContent, &dwInfoSize, NULL); | |
int ret = StrToIntA(szContent); | |
if (ret >= 400) | |
{ | |
return ret; | |
} | |
//get file size | |
ZeroMemory(szContent, 32); | |
dwInfoSize = 32; | |
HttpQueryInfoA(hInternet, HTTP_QUERY_CONTENT_LENGTH, szContent, &dwInfoSize, NULL); | |
__int64 size = 0; | |
StrToInt64ExA(szContent, 10, &size); | |
if (size <= 0) | |
{ | |
return ERROR_CONTENT_LENGTH_LESS_THAN_ZERO; | |
} | |
TCHAR szTmpFile[MAX_PATH] = {0}; | |
if (!tmp_file.empty()) | |
{ | |
lstrcpy(szTmpFile, tmp_file.c_str()); | |
} | |
else | |
{ | |
TCHAR szTmpPath[MAX_PATH] = {0}; | |
GetTempPath(MAX_PATH, szTmpPath); | |
if (0 == GetTempFileName(szTmpPath, _T("http"), 0, szTmpFile)) | |
{ | |
return GetLastError(); | |
} | |
} | |
tmp_file = szTmpFile; | |
HANDLE hFile = CreateFile(szTmpFile, | |
GENERIC_WRITE, | |
FILE_SHARE_READ, | |
NULL, | |
OPEN_ALWAYS, | |
FILE_ATTRIBUTE_NORMAL, | |
NULL); | |
scloud::ScopeGuard create_file([hFile]{CloseHandle(hFile);}); | |
if (INVALID_HANDLE_VALUE == hFile) | |
{ | |
create_file.cancel(); | |
return GetLastError(); | |
} | |
LARGE_INTEGER large_int = {0}; | |
GetFileSizeEx(hFile, &large_int); | |
if (large_int.QuadPart > size) | |
{ | |
return ERROR_TMP_FILE_TOO_BIG; | |
} | |
if (large_int.QuadPart > 0) | |
{ | |
if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_END)) | |
{ | |
return GetLastError(); | |
} | |
if (INVALID_SET_FILE_POINTER == InternetSetFilePointer( | |
hInternet, large_int.LowPart, NULL, FILE_BEGIN, 0)) | |
{ | |
return GetLastError(); | |
} | |
} | |
__int64 rsize = large_int.QuadPart; | |
for(;rsize < size;) | |
{ | |
char buf[512] = {0}; | |
DWORD dwRead = 0; | |
if (!InternetReadFile(hInternet, buf, 512, &dwRead)) | |
{ | |
return GetLastError(); | |
} | |
if (dwRead == 0) | |
{ | |
return ERROR_WTF_NO_DATA; | |
} | |
for(DWORD dwOnce=0; dwRead != dwOnce;) | |
{ | |
DWORD dwWritten = 0; | |
if (0 == WriteFile(hFile, buf+dwOnce, dwRead-dwOnce, &dwWritten, NULL)) | |
return GetLastError(); | |
dwOnce += dwWritten; | |
} | |
rsize += dwRead; | |
if (rsize == size) | |
break; | |
if (callback) | |
callback((double)rsize/size); | |
} | |
if (rsize == size) | |
{ | |
create_file.cancel(); | |
CloseHandle(hFile); | |
SetFileAttributes(file.c_str(), FILE_ATTRIBUTE_NORMAL); | |
DeleteFile(file.c_str()); | |
if (MoveFile(szTmpFile, file.c_str())) | |
{ | |
//succeed. | |
if (callback) | |
callback(1.0); | |
return 0; | |
} | |
} | |
return GetLastError(); | |
} | |
int HttpDownLoad( const std::string& url, | |
const std::string& file, | |
std::function<void(double)> callback, | |
int timeout /* = 30 */) | |
{ | |
int ret = 0; | |
std::string tmp_file; | |
int my_timeout = timeout >= 30? timeout:30; | |
for (;;) | |
{ | |
ret = HttpDownLoad_real(tmp_file, url, file, callback); | |
if (0 == ret) | |
{ | |
return 0; | |
} | |
else | |
{ | |
Sleep(3000); | |
my_timeout -= 3; | |
} | |
if(my_timeout <= 0) | |
break; | |
} | |
return ret; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef HTTP_DWONLOAD_H_ | |
#define HTTP_DWONLOAD_H_ | |
#include <string> | |
#include <functional> | |
enum { | |
ERROR_CONTENT_LENGTH_LESS_THAN_ZERO = 9527, | |
ERROR_WTF_NO_DATA, | |
ERROR_TMP_FILE_ERROR, | |
}; | |
/* | |
@brief | |
download a http file. | |
@param | |
url http address. | |
file local path save file. | |
callback process call back. | |
timeout timeout in second | |
@return | |
0 if succeed, else return GetLastError() or HTTP ERROR CODE or... | |
*/ | |
int HttpDownLoad( const std::string& url, | |
const std::string& file, | |
std::function<void(double)> callback, | |
int timeout = 30); | |
#endif //HTTP_DWONLOAD_H_ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef SCOPE_H_ | |
#define SCOPE_H_ | |
#include <functional> | |
namespace scloud{ | |
class ScopeGuard | |
{ | |
public: | |
explicit ScopeGuard(std::function<void(void)> onExitScope) | |
: doExit_(onExitScope), cancel_(false){} | |
~ScopeGuard() { | |
if(!cancel_) { | |
doExit_(); | |
} | |
} | |
void cancel() { | |
cancel_ = true; | |
} | |
private: | |
//disable copy | |
ScopeGuard(const ScopeGuard&); | |
void operator=(const ScopeGuard&); | |
std::function<void(void)> doExit_; | |
bool cancel_; | |
}; | |
}//end namespace | |
#define SCLOUD_CAT_STRING(name, line) name##line | |
#define SCLOUD_XSOCPEGUARD_LOCK_CAT(name, line) SCLOUD_CAT_STRING(name,line) | |
#define SCLOUD_SCOPE_EXIT scloud::ScopeGuard SCLOUD_XSOCPEGUARD_LOCK_CAT(ScopeGuard, __LINE__) | |
#endif //SCOPE_H_ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment