【问题标题】:Is WinHTTP downloading null bytes or am I copying the results buffer incorrectly?WinHTTP 是在下载空字节还是我错误地复制了结果缓冲区?
【发布时间】:2012-02-17 18:26:48
【问题描述】:

我最近将一个完整的 WinInet 程序移植到 WinHTTP。这是我编写的一个函数,用于将整个 GET 请求包装到一行代码中:

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 是 typedef std::basic_string 并且 StdOut 是一个宏,它根据是否定义了 UNICODE 来使用 cout 或 wcout。

由于嵌入了空值,并非所有响应都显示在控制台上。当我在调试关闭can be viewed here 的情况下运行代码时显示的输出(请注意,换行符只是文本在我的控制台中包装的位置)。第一个空值出现在最后的“__in”之后,并且出现在“按任意键继续......”输出显示的地方。这是输出的屏幕截图:

这是 html 变量值的文本可视化器屏幕截图,准确显示了空值相对于可见内容的显示位置:

我是否在某处进行了糟糕的复制,还是我不知道 WinHTTP 的一些细微差别?

【问题讨论】:

标签: c++ winapi http winhttp winhttprequest


【解决方案1】:

在进一步检查输出后,这些是 not 空值。它们是控制台无法显示的 unicode 字符,因为它们存储不正确(因此转换不正确)。我能够通过更改解决 Get 方法(和调用代码)中的问题

std::vector<char>

std::vector<unsigned char>

现在一切都很好。

【讨论】:

    猜你喜欢
    • 2010-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-19
    相关资源
    最近更新 更多