我正在使用WinHTTP(通过HTTPS)从.jar
和libraries.minecraft.net
下载repo1.maven.org
文件。功能如下:
// 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,WINHTTP_NO_REQUEST_DATA,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,size);
if (!WinHttpReadData(request,buffer,size,&downloaded)) {
delete[] buffer;
checkHresult(GetLastError(),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,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 KiB,恰好是WinHTTP的缓冲区大小。这段代码是经过修改的Microsoft WinHTTP example,因此我假设它的正确性和能够读取8 KiB以上的数据的能力。我在做什么错了,为什么WinHttpQueryDataAvailable
一旦达到8 KiB就会返回0到size
?
操作系统:Windows 10专业版,更新1903
架构:x86-64
CPU,x86-64
操作系统
CPU :Intel Core i5-2300 @ 2.8 GHz
RAM :8 GiB
交换文件:16000 MB