Я загружаю .jar
файлы из libraries.minecraft.net
и repo1.maven.org
, используя WinHTTP (через HTTPS). Вот функция:
// Namespace alias, all stdfs mentions in the function refer to std::filesystem
namespace stdfs = std::filesystem;
bool downloadFile(DLElement element) {
HINTERNET session = WinHttpOpen(
// Identify as Firefox
L"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:10.0) Gecko/20100101 Firefox/10.0",
// Don't care about proxies
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (session == nullptr) return false;
HINTERNET connection;
connection = WinHttpConnect(session, element.hostname.c_str(),
element.https ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT, 0);
// Accept `.jar` files
const wchar_t** acceptTypes = new const wchar_t* [2];
acceptTypes[0] = L"application/java-archive";
acceptTypes[1] = nullptr;
HINTERNET request = WinHttpOpenRequest(connection, L"GET", element.object.c_str(),
nullptr, WINHTTP_NO_REFERER, acceptTypes, element.https ? WINHTTP_FLAG_SECURE : 0);
bool result = WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
if (!result) {
DWORD hr = GetLastError();
checkHresult(hr, window, false);
}
if (!result) {
failRet:
WinHttpCloseHandle(request);
WinHttpCloseHandle(connection);
WinHttpCloseHandle(session);
return false;
}
result = WinHttpReceiveResponse(request, nullptr);
DWORD size = 0;
DWORD downloaded = 0;
std::vector<uint8_t> file;
if (!result) goto failRet;
do {
if (!WinHttpQueryDataAvailable(request, &size)) {
goto failRet;
}
uint8_t* buffer;
alloc:
try {
buffer = new uint8_t[size];
}
catch (std::bad_alloc&) {
MessageBox(window, lstr(VCLS_OUT_OF_MEMORY_DESC), lstr(VCLS_OUT_OF_MEMORY_TITLE), MB_ICONERROR);
goto alloc;
}
// Dunno why, do I even need this memset?
memset(buffer, 0, size);
if (!WinHttpReadData(request, buffer, size, &downloaded)) {
delete[] buffer;
checkHresult(GetLastError(), window, false);
goto failRet;
}
size_t vectSize = file.size();
file.reserve(vectSize + size);
for (size_t i = vectSize; i < size; i++) {
// Might as well rewrite this and make this more efficient
file.push_back(buffer[i]);
}
delete[] buffer;
} while (size > 0);
WinHttpCloseHandle(request);
WinHttpCloseHandle(connection);
WinHttpCloseHandle(session);
element.path.make_preferred();
stdfs::path dir = stdfs::path(element.path).remove_filename();
std::wstring fdirStr = dir.wstring();
fdirStr.pop_back();
dir = fdirStr;
tryCreateDir:
try {
stdfs::create_directories(mcFolderPath/dir);
}
catch (const std::bad_alloc&) {
MessageBox(window, lstr(VCLS_OUT_OF_MEMORY_DESC), lstr(VCLS_OUT_OF_MEMORY_TITLE), MB_ICONERROR);
goto tryCreateDir;
}
catch (const stdfs::filesystem_error& e) {
// Error handling removed for brevity
return false;
}
std::basic_ofstream<uint8_t> ofs(mcFolderPath/element.path, std::ios::binary | std::ios::trunc);
ofs.write(file.data(), file.size());
ofs.close();
return true;
}
DLElement
определяется следующим образом:
struct DLElement {
std::wstring hostname; std::wstring object; stdfs::path path; std::string sha1hex;
bool hasSha = true; bool https = false;
};
Проблема в том, что по какой-то причине эта функция загружает только точно 8 КиБфактического файла, который оказывается размером буфера для WinHTTP. Этот код представляет собой модифицированный пример Microsoft WinHTTP , поэтому я предполагаю его правильность и возможность извлекать более 8 КиБ данных. Что я делаю не так и почему WinHttpQueryDataAvailable
возвращает 0 в size
, когда он достигает 8 КиБ?
ОС : Windows 10 Professional, обновление 1903
Архитектура : x86-64
CPU, x86-64
OS
CPU : Intel Core i5-2300 @ 2.8 GHz
RAM : 8 GiB
Файл подкачки : 16000 MB