1
0
Fork 0

Updated downslib

- Added support for GZIP decompression
- Increased chunk_size for the buffer to 8kb
- Changed how header information is queried using HttpQueryInfoA using
HTTP_QUERY_FLAG_NUMBER rather than copying it into the char buffer
This commit is contained in:
pitticus 2023-07-30 16:41:04 +10:00
parent 4d725925d0
commit 8f06703061
1 changed files with 52 additions and 31 deletions

View File

@ -27,6 +27,10 @@ downslib_error downslib_download(const char* url,
HINTERNET hInternet = nullptr;
HINTERNET hUrl = nullptr;
HANDLE hFile = nullptr;
DWORD dwBufferSize = 0;
const char* headers = nullptr;
DWORD dwHeaderslen = 0;
const DWORD chunk_size = 8192;
Cleanup cleanup([&]()
{
@ -51,6 +55,7 @@ downslib_error downslib_download(const char* url,
SetLastError(dwLastError);
});
// Create the PDB file that will be written to
hFile = CreateFileW(filename, GENERIC_WRITE | FILE_READ_ATTRIBUTES, 0, NULL, CREATE_ALWAYS, 0, NULL);
if(hFile == INVALID_HANDLE_VALUE)
return downslib_error::createfile;
@ -64,57 +69,65 @@ downslib_error downslib_download(const char* url,
if(!hInternet)
return downslib_error::inetopen;
// Set a time-out value in milliseconds
InternetSetOptionA(hInternet,
INTERNET_OPTION_RECEIVE_TIMEOUT,
&timeout,
sizeof(timeout));
// Attempt to enable content decoding if the option is supported
DWORD gzipDecoding = true;
if (InternetSetOptionA(hInternet,
INTERNET_OPTION_HTTP_DECODING,
&gzipDecoding,
sizeof(gzipDecoding))) {
// Add the required request headers
headers = "Accept-Encoding: gzip\r\n";
dwHeaderslen = static_cast<DWORD>(strlen(headers));
}
DWORD dwFlags = INTERNET_FLAG_RELOAD;
if(strncmp(url, "https://", 8) == 0)
dwFlags |= INTERNET_FLAG_SECURE;
hUrl = InternetOpenUrlA(hInternet, url, NULL, 0, dwFlags, 0);
// Make the HTTP request
hUrl = InternetOpenUrlA(hInternet, url, headers, dwHeaderslen, dwFlags, 0);
if(!hUrl)
return downslib_error::openurl;
// Get HTTP status code
DWORD dwStatusCode;
dwBufferSize = sizeof(dwStatusCode);
if (HttpQueryInfoA(hUrl, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &dwStatusCode, &dwBufferSize, 0))
{
if (dwStatusCode != 200)
{
SetLastError(dwStatusCode);
return downslib_error::statuscode;
}
}
// Get HTTP content length
unsigned long long contentLength = 0;
dwBufferSize = sizeof(contentLength);
HttpQueryInfoA(hUrl, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER, &contentLength, &dwBufferSize, 0);
// Get HTTP content length
char buffer[2048];
memset(buffer, 0, sizeof(buffer));
DWORD dwLen = sizeof(buffer);
unsigned long long total_bytes = 0;
if(HttpQueryInfoA(hUrl, HTTP_QUERY_CONTENT_LENGTH, buffer, &dwLen, 0))
{
if(sscanf_s(buffer, "%llu", &total_bytes) != 1)
total_bytes = 0;
}
// Get HTTP status code
dwLen = sizeof(buffer);
if(HttpQueryInfoA(hUrl, HTTP_QUERY_STATUS_CODE, buffer, &dwLen, 0))
{
int status_code = 0;
if(sscanf_s(buffer, "%d", &status_code) != 1)
status_code = 500;
if(status_code != 200)
{
SetLastError(status_code);
return downslib_error::statuscode;
}
}
// Receive the data from the HINTERNET handle
char buffer[chunk_size];
DWORD dwRead = 0;
DWORD dwWritten = 0;
unsigned long long read_bytes = 0;
unsigned long long readBytes = 0;
unsigned long long totalBytes = contentLength;
while(InternetReadFile(hUrl, buffer, sizeof(buffer), &dwRead))
{
read_bytes += dwRead;
readBytes += dwRead;
// We are done if nothing more to read, so now we can report total size in our final cb call
if(dwRead == 0)
total_bytes = read_bytes;
totalBytes = readBytes;
// Call the callback to report progress and cancellation
if(cb && !cb(userdata, read_bytes, total_bytes))
if (cb && !cb(userdata, readBytes, totalBytes))
{
SetLastError(ERROR_OPERATION_ABORTED);
return downslib_error::cancel;
@ -124,10 +137,18 @@ downslib_error downslib_download(const char* url,
if(dwRead == 0)
break;
// Write buffer to PDB file
WriteFile(hFile, buffer, dwRead, &dwWritten, nullptr);
// Check WriteFile successfully wrote the entire buffer
if (dwWritten != dwRead) {
SetLastError(ERROR_IO_INCOMPLETE);
return downslib_error::incomplete;
}
}
if(total_bytes > 0 && read_bytes != total_bytes)
if (totalBytes > 0 && readBytes != totalBytes)
{
SetLastError(ERROR_IO_INCOMPLETE);
return downslib_error::incomplete;