Files
2022-10-26 12:25:11 +08:00

336 lines
10 KiB
C++

#include "http_client.h"
#include "system.h"
#include "md5.h"
#include "converter.h"
#include <fstream>
#include <algorithm>
extern std::ofstream frostLogFile;
extern bool frostLogging;
namespace http_client {
std::wstring client::get_server(const std::wstring& url)
{
if(frostLogging) {
frostLogFile << "get_server(" << utils::utf16_to_ascii(url.c_str()) << ")" << std::endl;
}
if((url.size() > 7) &&
(0 == _wcsicmp(url.substr(0, 7).c_str(), L"http://"))) {
size_t i = 7;
while(((i+1) < url.size()) && (L'/' != url[i])) ++i;
if(frostLogging) {
frostLogFile << "get_server() ok" << std::endl;
}
return url.substr(7, i - 7);
}
if(frostLogging) {
frostLogFile << "get_server() fail" << std::endl;
}
return L"";
}
std::wstring client::get_path(const std::wstring& url)
{
if(frostLogging) {
frostLogFile << "get_path(" << utils::utf16_to_ascii(url.c_str()) << ")" << std::endl;
}
if((url.size() > 7) &&
(0 == _wcsicmp(url.substr(0, 7).c_str(), L"http://"))) {
size_t i = 7;
while(((i+1) < url.size()) && (L'/' != url[i])) ++i;
while((i < url.size()) && (L'/' == url[i])) ++i;
if(frostLogging) {
frostLogFile << "get_path() ok" << std::endl;
}
return url.substr(i);
}
if(frostLogging) {
frostLogFile << "get_path() fail" << std::endl;
}
return L"";
}
struct download_info
{
download_info(const std::wstring& src,
const std::wstring& dest,
const std::wstring& crc,
unsigned __int64 size):
m_src(src),
m_dest(L""),
m_crc(crc),
m_size(size)
{
if(frostLogging) {
frostLogFile << "download_info::download_info("
<< utils::utf16_to_ascii(src.c_str()) << ", "
<< utils::utf16_to_ascii(dest.c_str()) << ", "
<< utils::utf16_to_ascii(crc.c_str()) << ", "
<< size << ")" << std::endl;
}
bool isSep = false;
for(size_t i=0; i<dest.size(); ++i) {
wchar_t w = dest[i];
if(w == L'\\' || w == L'/') {
if(!isSep) {
m_dest += L'\\';
isSep = true;
}
} else {
m_dest += w;
isSep = false;
}
}
if(frostLogging) {
frostLogFile << "download_info::download_info() end" << std::endl;
}
}
std::wstring get_info_file() const
{
if(frostLogging) {
frostLogFile << "download_info::get_info_file()" << std::endl;
}
return m_dest + client::m_downloadInfoExt;
}
bool load(std::wstring& crc,
unsigned __int64& size) const
{
if(frostLogging) {
frostLogFile << "download_info::load()" << std::endl;
}
FILE* in = _wfopen((m_dest + client::m_downloadInfoExt).c_str(), L"rb");
if(!in) {
if(frostLogging) {
frostLogFile << "download_info::load() end1" << std::endl;
}
return false;
}
char header[29] = {0};
fread(header, 1, 28, in);
if(m_infoHeader != std::string(header)) {
fclose(in);
if(frostLogging) {
frostLogFile << "download_info::load() end2" << std::endl;
}
return false;
}
size_t len = 0;
len = fread(&size, 1, sizeof(size), in);
if(len != sizeof(m_size)) {
fclose(in);
if(frostLogging) {
frostLogFile << "download_info::load() end3" << std::endl;
}
return false;
}
wchar_t crcBuff[33] = {0};
fread(crcBuff, sizeof(wchar_t), 32, in);
fclose(in);
crc.assign(crcBuff);
if(frostLogging) {
frostLogFile << "download_info::load() end4" << std::endl;
}
return true;
}
bool save() const
{
if(frostLogging) {
frostLogFile << "download_info::save()" << std::endl;
}
const std::wstring destFile = m_dest + client::m_downloadInfoExt;
utils::create_parent_directories(destFile);
SetFileAttributesW(destFile.c_str(), FILE_ATTRIBUTE_NORMAL);
FILE* out = _wfopen(destFile.c_str(), L"wb");
if(!out) {
if(frostLogging) {
frostLogFile << "download_info::save() end1" << std::endl;
}
return false;
}
char header[29] = {0};
memcpy(header, m_infoHeader.c_str(), m_infoHeader.size());
fwrite(header, 1, 28, out);
fwrite(&m_size, 1, sizeof(m_size), out);
std::wstring crc = m_crc;
if(crc.find(L"?hash=") == 0) {
crc = crc.substr(6);
}
fwrite(crc.c_str(), sizeof(wchar_t), crc.size(), out);
fclose(out);
SetFileAttributesW(destFile.c_str(), FILE_ATTRIBUTE_HIDDEN);
if(frostLogging) {
frostLogFile << "download_info::save() end2" << std::endl;
}
return true;
}
unsigned __int64 get_downloaded_size() const
{
if(frostLogging) {
frostLogFile << "download_info::get_downloaded_size()" << std::endl;
}
std::wstring crc;
unsigned __int64 size = 0;
if(load(crc, size) &&
(m_size == size) &&
(m_crc.find(crc) != std::string::npos)) {
size = utils::get_file_size(m_dest);
if(frostLogging) {
frostLogFile << "download_info::get_downloaded_size() = " << size << std::endl;
}
return size;
}
if(frostLogging) {
frostLogFile << "download_info::get_downloaded_size() = " << 0 << std::endl;
}
return 0;
}
std::string get_url() const
{
if(frostLogging) {
frostLogFile << "download_info::get_url()" << std::endl;
}
std::string url, crc;
url = utils::utf16_to_ascii(m_src.c_str());
std::replace(url.begin(), url.end(), '\\', '/');
std::string::size_type i = url.find("//");
while(i != std::string::npos) {
url = url.substr(0, i) + url.substr(i+1);
i = url.find("//");
}
if(!m_crc.empty()) {
utils::utf16_to_ascii(m_crc.c_str(), crc);
} else {
utils::utf16_to_ascii(utils::md5Hash::get_random_crc().c_str(), crc);
crc = "?hash=" + crc;
}
url += crc;
if(frostLogging) {
frostLogFile << "download_info::get_url() = " << url << std::endl;
}
return url;
}
std::wstring m_src;
std::wstring m_dest;
std::wstring m_crc;
unsigned __int64 m_size;
static const std::string m_infoHeader;
};
const std::wstring client::m_downloadInfoExt = L".downloading";
const std::string download_info::m_infoHeader = "innDownloaderInfo";
client::client(const std::wstring& ipport):
m_socket(ipport, 1, 1000),
m_error(0),
m_currentFile()
{
if(frostLogging) {
frostLogFile << "client::client()" << std::endl;
}
}
client::~client()
{
if(frostLogging) {
frostLogFile << "client::~client()" << std::endl;
}
}
int client::download(const std::wstring& src,
const std::wstring& dest,
const std::wstring& crc,
unsigned __int64 size,
unsigned __int64* actualSize,
std::string& errors,
bool firstTime)
{
if(frostLogging) {
frostLogFile << "client::download("
<< utils::utf16_to_ascii(src.c_str()) << ", "
<< utils::utf16_to_ascii(dest.c_str()) << ", "
<< utils::utf16_to_ascii(crc.c_str()) << ", "
<< size << ", "
<< (actualSize ? "actualSize" : "null") << ", "
<< errors << ", "
<< firstTime << ") " << std::endl;
}
utils::create_parent_directories(dest);
m_currentFile = dest;
download_info di(src, dest, crc, size);
unsigned __int64 oldSize = di.get_downloaded_size();
if(size && (oldSize == size)) {
return 0;
} else if(oldSize > size) {
oldSize = 0;
}
if(0 == oldSize) {
utils::delete_file(dest);
}
if(oldSize && firstTime) {
unsigned __int64 allSize = 0;
while(allSize < oldSize) {
unsigned delta = (oldSize < (allSize + 10000000)) ? (oldSize - allSize) : 10000000;
allSize += delta;
}
}
unsigned triesCount = 0;
m_error = 0;
if(actualSize) *actualSize = 0;
if(!m_socket.connect()) {
while (true) {
std::string range;
if(size) {
if(oldSize == size) {
break;
}
range += "Range: bytes=";
range += utils::int2str(oldSize);
range += "-";
range += utils::int2str(size);
range += "\r\n";
}
m_error = m_socket.send(di.get_url(), range);
unsigned __int64 newSize = 0;
if(!m_error) {
di.save();
m_error = m_socket.recv(size - oldSize, dest, actualSize);
if(!m_error) {
newSize = di.get_downloaded_size();
}
}
if(!errors.empty()) {
errors += "; ";
}
errors += m_socket.get_errors();
if(((newSize < size) || m_error) && (triesCount < 10)) {
++triesCount;
oldSize = di.get_downloaded_size();
if(!size) {
size = m_socket.get_conntent_size();
}
Sleep(500);
} else {
utils::delete_file(di.get_info_file());
break;
}
}
} else {
m_error = m_socket.m_error;
errors += m_socket.get_errors();
}
m_currentFile = L"";
if(frostLogging) {
frostLogFile << "client::download() = " << m_error << std::endl;
}
return m_error;
}
}