Проблема в том, что ваш параметр host
должен быть только именем хоста, а не полным URL, а ресурс должен быть только частью ресурса на хосте.
Например:
std::string data = GetUrlData("/", "example.com");
Заметка: вы приобретаете до трех ресурсов, которые необходимо высвободить вручную, и стараетесь их высвобождать, используя InternetCloseHandle()
, но вскоре он становится многословным, и вы рискуете в конце концов забыть о нем. Как это случается, если ваш GetUrlData()
вызов завершается успешно, вы не освобождаете каких-либо ресурсов.
Рассмотрите возможность оборачивания каждого ресурса в std::unique_ptr
для его автоматического освобождения. Это не только делает его более безопасным, но и облегчает чтение и обслуживание кода.
Пример:
#include <Windows.h>
#include <wininet.h>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
#include <type_traits>
// custom deleter for the resource
struct internet_deleter {
void operator()(HINTERNET hi) { InternetCloseHandle(hi); }
};
// the resource's wrapper type
using ihandle = std::unique_ptr<std::remove_pointer_t<HINTERNET>, internet_deleter>;
// functions for acquiring resources
auto RAII_InternetOpen() {
ihandle rv(InternetOpenA("token", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0));
if (rv) return rv;
throw std::runtime_error("InternetOpenA: " + std::to_string(GetLastError()));
}
auto RAII_InternetConnect(const ihandle& hIntSession, const std::string& host) {
ihandle rv(
InternetConnectA(hIntSession.get(), host.c_str(), 80, 0, 0,
INTERNET_SERVICE_HTTP, 0, NULL));
if (rv) return rv;
throw std::runtime_error("InternetConnectA: " + std::to_string(GetLastError()));
}
auto RAII_HttpOpenRequest(const ihandle& hHttpSession, const std::string& resource) {
ihandle rv(
HttpOpenRequestA(hHttpSession.get(), "GET", resource.c_str(), 0, 0, 0,
INTERNET_FLAG_RELOAD, 0));
if (rv) return rv;
throw std::runtime_error("HttpOpenRequestA: " + std::to_string(GetLastError()));
}
С тремя вышеупомянутыми функциями GetUrlData()
функция становится проще и не будет пропускать ресурсы:
std::string GetUrlData(const std::string& resource, const std::string& host)
{
std::string output;
auto hIntSession = RAII_InternetOpen();
auto hHttpSession = RAII_InternetConnect(hIntSession, host);
auto hHttpRequest = RAII_HttpOpenRequest(hHttpSession, resource);
if (!HttpSendRequestA(hHttpRequest.get(), NULL, 0, NULL, 0))
throw std::runtime_error("HttpSendRequestA: " +
std::to_string(GetLastError()));
char szBuffer[1024];
DWORD dwRead = 0;
do {
if (!InternetReadFile(hHttpRequest.get(), szBuffer, sizeof(szBuffer), &dwRead))
throw std::runtime_error("InternetReadFile: " +
std::to_string(GetLastError()));
if (dwRead == 0)
break;
output.append(szBuffer, dwRead);
} while (true);
return output;
}
int main() {
try {
std::cout << GetUrlData("/", "www.google.com");
}
catch (const std::exception& ex) {
std::cerr << "Exception: " << ex.what() << '\n';
}
}