Недавно я портировал полностью действующую программу WinInet на WinHTTP. Вот функция, я написал, чтобы обернуть запрос целиком попасть в одной строке кода:WinHTTP загружает нулевые байты или я неправильно копирую буфер результатов?
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;
}
Код работает в том, что он загружает требуемый URL. Проблема возникает, когда сервер не возвращает заголовок Content-Length (который самый того времени). Код все равно будет загружать все данные, но при преобразовании в строку будут введены нулевые байты.
Код выше, называется так:
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 является ЬурейеЕ станд :: basic_string <TCHAR> и STDOUT макрос, который использует COUT или wcout в зависимости от того, если UNICODE определен.
Из-за встроенных нулей на консоли отображается не весь ответ. Вывод отображается, когда я запускаю код с отладкой can be viewed here (обратите внимание, что разрывы строк просто там, где текст завернут в мою консоль). Первый нуль отображается сразу после «__in» в самом конце и происходит прямо там, где отображается «Нажмите любую клавишу, чтобы продолжить ...». Вот экран крышка выхода:
Вот текст визуализатор экран защитный колпачок из значения HTML переменной показывая, где именно появляются нули по отношению к тому, что для просмотра:
Я делаю плохое копирование где-то или есть какой-то нюанс WinHTTP, о котором я не знаю?
Можете ли вы привести пример, который воспроизводит поведение? Я скопировал ваш код и попробовал эту страницу msdn, и не было встроенных нулей. – Luke
Отредактировано для включения следующих ссылок: http://pastebin.com/aEH9GzDE http://i.imgur.com/vRmNL.png http://i.imgur.com/eu8rH.png – jvstech