Winhttp sta scaricando null byte o sto copiando il buffer dei risultati in modo errato?
-
13-11-2019 - |
Domanda
Di recente ho portato un programma Wininet completamente funzionante a WinHttp. Ecco una funzione che ho scritto per avvolgere un'intera richiesta Get in una singola riga di codice:
bool Get(Url url, std::vector<char>& data, ProgressCallbackFunction progressCallback = nullptr) throw()
{
long cl = -1;
DWORD clSize = sizeof(cl);
DWORD readCount = 0;
DWORD totalReadCount = 0;
DWORD availableBytes = 0;
std::vector<char> buf;
if (_session != NULL)
throw std::exception("Concurrent sessions are not supported");
_session = ::WinHttpOpen(_userAgent.c_str(), WINHTTP_ACCESS_TYPE_NO_PROXY, NULL, NULL, NULL);
auto connection = ::WinHttpConnect(_session, url.HostName.c_str(), url.Port, 0);
auto request = ::WinHttpOpenRequest(connection, TEXT("GET"), url.GetPathAndQuery().c_str(), NULL, NULL, NULL, WINHTTP_FLAG_REFRESH);
if (request == NULL)
{
_lastError = ::GetLastError();
::WinHttpCloseHandle(_session);
_session = NULL;
return false;
}
auto sendRequest = ::WinHttpSendRequest(request, WINHTTP_NO_ADDITIONAL_HEADERS, NULL, WINHTTP_NO_REQUEST_DATA, NULL, NULL, NULL);
if (sendRequest == FALSE)
{
_lastError = ::GetLastError();
::WinHttpCloseHandle(request);
::WinHttpCloseHandle(_session);
_session = NULL;
return false;
}
if (::WinHttpReceiveResponse(request, NULL))
{
if (progressCallback != nullptr && progressCallback != NULL)
{
if (!::WinHttpQueryHeaders(request, WINHTTP_QUERY_CONTENT_LENGTH | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, reinterpret_cast<LPVOID>(&cl), &clSize, 0))
{
cl = -1;
}
}
while (::WinHttpQueryDataAvailable(request, &availableBytes))
{
if (availableBytes)
{
buf.resize(availableBytes + 1);
auto hasRead = ::WinHttpReadData(request, &buf[0], availableBytes, &readCount);
totalReadCount += readCount;
data.insert(data.end(), buf.begin(), buf.begin() + readCount);
buf.clear();
if (progressCallback != nullptr && progressCallback != NULL)
{
progressCallback(totalReadCount, cl, getProgress(totalReadCount, cl));
}
}
else
break;
}
}
else
{
_lastError = ::GetLastError();
::WinHttpCloseHandle(request);
::WinHttpCloseHandle(_session);
_session = NULL;
return false;
}
::WinHttpCloseHandle(request);
::WinHttpCloseHandle(_session);
_session = NULL;
return true;
}
Il codice lavori In quanto scarica l'URL richiesto. Il problema si presenta quando il server non restituisce l'intestazione della lunghezza del contenuto (che è più del tempo). Il codice scaricherà comunque tutti i dati, ma ci saranno byte nulla incorporati quando convertiti in una stringa.
Il codice sopra si chiama così:
Url url(TEXT("http://msdn.microsoft.com/en-us/site/aa384376"));
Client wc;
std::vector<char> results;
wc.Get(url, results);
StdString html(results.begin(), results.end());
StdOut << html << endl;
Stdstring è typedef std :: basic_stringu003CTCHAR> E STDOUT è una macro che utilizza Cout o WCOUT a seconda che Unicode è definito.
A causa dei null incorporati, non tutta la risposta viene visualizzata sulla console. L'output viene visualizzato quando eseguo il codice con il debug può essere visto qui (Si noti che le interruzioni della linea sono semplicemente dove il testo è avvolto nella mia console). Il primo null viene visto subito dopo "__in" alla fine e si verifica proprio dove viene visualizzato il tasto "Premi qualsiasi tasto per continuare ...". Ecco un tappo dello schermo dell'output:
Ecco un tappo di schermo del visualizzatore di testo del valore della variabile HTML che mostra esattamente dove compaiono i null in relazione a ciò che è visualizzabile:
Sto facendo un brutto copia da qualche parte o c'è qualche sfumatura di Winhttp di cui non sono a conoscenza?
Soluzione
Dopo un'ulteriore revisione dell'output, quelli lo sono non nulls. Sono caratteri Unicode che la console non può visualizzare perché vengono archiviati in modo errato (e quindi convertiti in modo errato). Sono stato in grado di risolvere il problema nel metodo Get (e nel codice chiamante) modificando
std::vector<char>
a
std::vector<unsigned char>
E ora va tutto bene.