CppUtils/Utils/HttpHelper.cpp
2025-06-05 10:06:43 +08:00

601 lines
16 KiB
C++

#include "HttpHelper.h"
#include "Utils.h"
#include <Winhttp.h>
#pragma comment(lib, "winhttp.lib")
std::string HttpHelper::UrlEncode(const std::string str)
{
auto input = Convert::AnsiToUtf8(str);
std::ostringstream encoded;
for (uint8_t c : input) {
if (
(c >= ' ' && c <= '~')
) {
encoded << c;
}
else {
encoded << '%' << std::uppercase << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(c);
}
}
return encoded.str();
}
std::string HttpHelper::CheckUrl(std::string input)
{
auto replace = [](std::string str, const char* old_str, const char* new_str) {
size_t len_old = strlen(old_str);
size_t len_new = strlen(new_str);
size_t pos = str.find(old_str);
while (pos != std::string::npos) {
str.replace(pos, len_old, new_str);
pos = str.find(old_str, pos + len_new);
}
};
replace(input, " ", "%20");
replace(input, "\"", "%22");
replace(input, "#", "%23");
replace(input, "%", "%25");
replace(input, "&", "%26");
replace(input, "(", "%28");
replace(input, ")", "%29");
replace(input, "+", "%2B");
replace(input, ",", "%2C");
replace(input, "/", "%2F");
replace(input, ":", "%3A");
replace(input, ";", "%3B");
replace(input, "<", "%3C");
replace(input, "=", "%3D");
replace(input, ">", "%3E");
replace(input, "?", "%3F");
replace(input, "@", "%40");
replace(input, "\\", "%5C");
replace(input, "|", "%7C");
return UrlEncode(input);
}
std::string HttpHelper::GetHostNameFromURL(std::string url) {
if (url._Starts_with("https://"))
{
url;
}
else if (!url._Starts_with("http://"))
{
url = "http://" + url;
}
std::string hostName;
size_t pos = url.find("//");
if (pos != std::string::npos) {
pos += 2;
size_t endPos = url.find('/', pos);
if (endPos != std::string::npos) {
hostName = url.substr(pos, endPos - pos);
}
else {
hostName = url.substr(pos);
}
}
return hostName;
}
std::string HttpHelper::Get(std::string url, std::string headers, std::string cookies)
{
HINTERNET hSession = nullptr, hConnect = nullptr, hRequest = nullptr;
std::string response;
url = UrlEncode(url);
// Parse URL components
URL_COMPONENTS urlComp;
ZeroMemory(&urlComp, sizeof(urlComp));
urlComp.dwStructSize = sizeof(urlComp);
wchar_t hostName[256];
wchar_t urlPath[256];
urlComp.lpszHostName = hostName;
urlComp.dwHostNameLength = _countof(hostName);
urlComp.lpszUrlPath = urlPath;
urlComp.dwUrlPathLength = _countof(urlPath);
std::wstring wUrl(url.begin(), url.end());
if (!WinHttpCrackUrl(wUrl.c_str(), static_cast<DWORD>(wUrl.length()), 0, &urlComp)) {
std::cerr << "Error: Unable to crack URL." << std::endl;
return "";
}
// Initialize WinHTTP session
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) {
std::cerr << "Error: WinHttpOpen failed." << std::endl;
return "";
}
// Connect to server
hConnect = WinHttpConnect(hSession, urlComp.lpszHostName, urlComp.nPort, 0);
if (!hConnect) {
std::cerr << "Error: WinHttpConnect failed." << std::endl;
WinHttpCloseHandle(hSession);
return "";
}
// Prepare the GET request
hRequest = WinHttpOpenRequest(hConnect, L"GET", urlComp.lpszUrlPath,
nullptr, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0);
if (!hRequest) {
std::cerr << "Error: WinHttpOpenRequest failed." << std::endl;
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Set headers
std::wstring wHeaders(headers.begin(), headers.end());
if (!headers.empty()) {
WinHttpAddRequestHeaders(hRequest, wHeaders.c_str(), static_cast<DWORD>(-1L), WINHTTP_ADDREQ_FLAG_ADD);
}
// Set cookies
if (!cookies.empty()) {
std::wstring wCookies(cookies.begin(), cookies.end());
WinHttpAddRequestHeaders(hRequest, wCookies.c_str(), static_cast<DWORD>(-1L), WINHTTP_ADDREQ_FLAG_ADD);
}
// Send the request
BOOL bResult = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
if (!bResult) {
std::cerr << "Error: WinHttpSendRequest failed." << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Receive the response
bResult = WinHttpReceiveResponse(hRequest, nullptr);
if (!bResult) {
std::cerr << "Error: WinHttpReceiveResponse failed." << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Read the response data
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
do {
// Check for available data
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
std::cerr << "Error: WinHttpQueryDataAvailable failed." << std::endl;
break;
}
// Allocate space for the buffer
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer) {
std::cerr << "Error: Out of memory." << std::endl;
dwSize = 0;
break;
}
// Read the data
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) {
std::cerr << "Error: WinHttpReadData failed." << std::endl;
}
else {
response.append(pszOutBuffer, dwDownloaded);
}
// Free the memory
delete[] pszOutBuffer;
} while (dwSize > 0);
// Cleanup
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return response;
}
std::string HttpHelper::GetStream(std::string url, std::string headers, std::string cookies, HTTP_STREAM_CALLBACK callback)
{
HINTERNET hSession = nullptr, hConnect = nullptr, hRequest = nullptr;
std::string response;
url = UrlEncode(url);
// Parse URL components
URL_COMPONENTS urlComp;
ZeroMemory(&urlComp, sizeof(urlComp));
urlComp.dwStructSize = sizeof(urlComp);
wchar_t hostName[256];
wchar_t urlPath[256];
urlComp.lpszHostName = hostName;
urlComp.dwHostNameLength = _countof(hostName);
urlComp.lpszUrlPath = urlPath;
urlComp.dwUrlPathLength = _countof(urlPath);
std::wstring wUrl(url.begin(), url.end());
if (!WinHttpCrackUrl(wUrl.c_str(), static_cast<DWORD>(wUrl.length()), 0, &urlComp)) {
std::cerr << "Error: Unable to crack URL." << std::endl;
return "";
}
// Initialize WinHTTP session
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) {
std::cerr << "Error: WinHttpOpen failed." << std::endl;
return "";
}
// Connect to server
hConnect = WinHttpConnect(hSession, urlComp.lpszHostName, urlComp.nPort, 0);
if (!hConnect) {
std::cerr << "Error: WinHttpConnect failed." << std::endl;
WinHttpCloseHandle(hSession);
return "";
}
// Prepare the GET request
hRequest = WinHttpOpenRequest(hConnect, L"GET", urlComp.lpszUrlPath,
nullptr, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0);
if (!hRequest) {
std::cerr << "Error: WinHttpOpenRequest failed." << std::endl;
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Set headers
std::wstring wHeaders(headers.begin(), headers.end());
if (!headers.empty()) {
WinHttpAddRequestHeaders(hRequest, wHeaders.c_str(), static_cast<DWORD>(-1L), WINHTTP_ADDREQ_FLAG_ADD);
}
// Set cookies
if (!cookies.empty()) {
std::wstring wCookies(cookies.begin(), cookies.end());
WinHttpAddRequestHeaders(hRequest, wCookies.c_str(), static_cast<DWORD>(-1L), WINHTTP_ADDREQ_FLAG_ADD);
}
// Send the request
BOOL bResult = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
if (!bResult) {
std::cerr << "Error: WinHttpSendRequest failed." << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Receive the response
bResult = WinHttpReceiveResponse(hRequest, nullptr);
if (!bResult) {
std::cerr << "Error: WinHttpReceiveResponse failed." << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Read the response data
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
do {
// Check for available data
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
std::cerr << "Error: WinHttpQueryDataAvailable failed." << std::endl;
break;
}
// Allocate space for the buffer
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer) {
std::cerr << "Error: Out of memory." << std::endl;
dwSize = 0;
break;
}
// Read the data
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) {
std::cerr << "Error: WinHttpReadData failed." << std::endl;
}
else {
response.append(pszOutBuffer, dwDownloaded);
if (callback)
callback(pszOutBuffer);
}
// Free the memory
delete[] pszOutBuffer;
} while (dwSize > 0);
// Cleanup
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return response;
}
std::vector<uint8_t> HttpHelper::HttpGetBytes(std::string url) {
auto bytes = Get(url);
return std::vector<uint8_t>((uint8_t*)bytes.data(), (uint8_t*)bytes.data() + bytes.size());
}
std::string HttpHelper::Post(std::string url, std::string body, std::string headers, std::string cookies)
{
HINTERNET hSession = nullptr, hConnect = nullptr, hRequest = nullptr;
std::string response;
url = UrlEncode(url);
// Parse URL components
URL_COMPONENTS urlComp;
ZeroMemory(&urlComp, sizeof(urlComp));
urlComp.dwStructSize = sizeof(urlComp);
wchar_t hostName[256];
wchar_t urlPath[256];
urlComp.lpszHostName = hostName;
urlComp.dwHostNameLength = _countof(hostName);
urlComp.lpszUrlPath = urlPath;
urlComp.dwUrlPathLength = _countof(urlPath);
std::wstring wUrl(url.begin(), url.end());
if (!WinHttpCrackUrl(wUrl.c_str(), static_cast<DWORD>(wUrl.length()), 0, &urlComp)) {
std::cerr << "Error: Unable to crack URL." << std::endl;
return "";
}
// Initialize WinHTTP session
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) {
std::cerr << "Error: WinHttpOpen failed." << std::endl;
return "";
}
// Connect to server
hConnect = WinHttpConnect(hSession, urlComp.lpszHostName, urlComp.nPort, 0);
if (!hConnect) {
std::cerr << "Error: WinHttpConnect failed." << std::endl;
WinHttpCloseHandle(hSession);
return "";
}
// Prepare the POST request
hRequest = WinHttpOpenRequest(hConnect, L"POST", urlComp.lpszUrlPath,
nullptr, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0);
if (!hRequest) {
std::cerr << "Error: WinHttpOpenRequest failed." << std::endl;
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Set headers
std::wstring wHeaders(headers.begin(), headers.end());
if (!headers.empty()) {
WinHttpAddRequestHeaders(hRequest, wHeaders.c_str(), static_cast<DWORD>(-1L), WINHTTP_ADDREQ_FLAG_ADD);
}
// Set cookies
if (!cookies.empty()) {
std::wstring wCookies(cookies.begin(), cookies.end());
WinHttpAddRequestHeaders(hRequest, wCookies.c_str(), static_cast<DWORD>(-1L), WINHTTP_ADDREQ_FLAG_ADD);
}
// Send the request
BOOL bResult = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
(LPVOID)body.c_str(), static_cast<DWORD>(body.length()),
static_cast<DWORD>(body.length()), 0);
if (!bResult) {
std::cerr << "Error: WinHttpSendRequest failed." << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Receive the response
bResult = WinHttpReceiveResponse(hRequest, nullptr);
if (!bResult) {
std::cerr << "Error: WinHttpReceiveResponse failed." << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Read the response data
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
do {
// Check for available data
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
std::cerr << "Error: WinHttpQueryDataAvailable failed." << std::endl;
break;
}
// Allocate space for the buffer
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer) {
std::cerr << "Error: Out of memory." << std::endl;
dwSize = 0;
break;
}
// Read the data
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) {
std::cerr << "Error: WinHttpReadData failed." << std::endl;
}
else {
printf(pszOutBuffer);
response.append(pszOutBuffer, dwDownloaded);
}
// Free the memory
delete[] pszOutBuffer;
} while (dwSize > 0);
// Cleanup
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return response;
}
std::string HttpHelper::PostStream(std::string url, std::string body, std::string headers, std::string cookies, HTTP_STREAM_CALLBACK callback)
{
HINTERNET hSession = nullptr, hConnect = nullptr, hRequest = nullptr;
std::string response;
url = UrlEncode(url);
// Parse URL components
URL_COMPONENTS urlComp;
ZeroMemory(&urlComp, sizeof(urlComp));
urlComp.dwStructSize = sizeof(urlComp);
wchar_t hostName[256];
wchar_t urlPath[256];
urlComp.lpszHostName = hostName;
urlComp.dwHostNameLength = _countof(hostName);
urlComp.lpszUrlPath = urlPath;
urlComp.dwUrlPathLength = _countof(urlPath);
std::wstring wUrl(url.begin(), url.end());
if (!WinHttpCrackUrl(wUrl.c_str(), static_cast<DWORD>(wUrl.length()), 0, &urlComp)) {
std::cerr << "Error: Unable to crack URL." << std::endl;
return "";
}
// Initialize WinHTTP session
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (!hSession) {
std::cerr << "Error: WinHttpOpen failed." << std::endl;
return "";
}
// Connect to server
hConnect = WinHttpConnect(hSession, urlComp.lpszHostName, urlComp.nPort, 0);
if (!hConnect) {
std::cerr << "Error: WinHttpConnect failed." << std::endl;
WinHttpCloseHandle(hSession);
return "";
}
// Prepare the POST request
hRequest = WinHttpOpenRequest(hConnect, L"POST", urlComp.lpszUrlPath,
nullptr, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
(urlComp.nScheme == INTERNET_SCHEME_HTTPS) ? WINHTTP_FLAG_SECURE : 0);
if (!hRequest) {
std::cerr << "Error: WinHttpOpenRequest failed." << std::endl;
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Set headers
std::wstring wHeaders(headers.begin(), headers.end());
if (!headers.empty()) {
WinHttpAddRequestHeaders(hRequest, wHeaders.c_str(), static_cast<DWORD>(-1L), WINHTTP_ADDREQ_FLAG_ADD);
}
// Set cookies
if (!cookies.empty()) {
std::wstring wCookies(cookies.begin(), cookies.end());
WinHttpAddRequestHeaders(hRequest, wCookies.c_str(), static_cast<DWORD>(-1L), WINHTTP_ADDREQ_FLAG_ADD);
}
// Send the request
BOOL bResult = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
(LPVOID)body.c_str(), static_cast<DWORD>(body.length()),
static_cast<DWORD>(body.length()), 0);
if (!bResult) {
std::cerr << "Error: WinHttpSendRequest failed." << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Receive the response
bResult = WinHttpReceiveResponse(hRequest, nullptr);
if (!bResult) {
std::cerr << "Error: WinHttpReceiveResponse failed." << std::endl;
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return "";
}
// Read the response data
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
do {
// Check for available data
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize)) {
std::cerr << "Error: WinHttpQueryDataAvailable failed." << std::endl;
break;
}
// Allocate space for the buffer
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer) {
std::cerr << "Error: Out of memory." << std::endl;
dwSize = 0;
break;
}
// Read the data
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) {
std::cerr << "Error: WinHttpReadData failed." << std::endl;
}
else {
callback(pszOutBuffer);
response.append(pszOutBuffer, dwDownloaded);
}
// Free the memory
delete[] pszOutBuffer;
} while (dwSize > 0);
// Cleanup
WinHttpCloseHandle(hRequest);
WinHttpCloseHandle(hConnect);
WinHttpCloseHandle(hSession);
return response;
}