Files

812 lines
26 KiB
C++
Raw Permalink Normal View History

2026-08-27 11:22:01 -06:00
#include "wnetwrap.h"
#pragma comment(lib, "Wininet.lib")
#pragma comment( lib, "urlmon" )
DWORD WINAPI WorkerInternetConnect(LPVOID);
DWORD WINAPI WorkerInternetRequest(LPVOID);
struct TPARAMS {
HINTERNET hInternet = NULL;
HINTERNET hInternetOut = NULL; //returned handle
std::string host = "";
INTERNET_PORT port = 0;
DWORD service = 0;
};
struct TRPARAMS {
HINTERNET hRequest = NULL;
BOOL res = NULL;
std::string headers = "";
};
wrap::req wrap::toSource;
//adapted from https://stackoverflow.com/questions/20634666/get-a-mime-type-from-a-extension-in-c
std::string GetMimeType(const std::string& ext) {
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::wstring str = converter.from_bytes(ext);
LPWSTR pwzMimeOut = NULL;
HRESULT hr = FindMimeFromData(NULL, str.c_str(), NULL, 0,
NULL, FMFD_URLASFILENAME, &pwzMimeOut, 0x0);
if (SUCCEEDED(hr)) {
std::wstring strResult(pwzMimeOut);
// Despite the documentation stating to call operator delete, the
// returned string must be cleaned up using CoTaskMemFree
CoTaskMemFree(pwzMimeOut);
std::string narrow = converter.to_bytes(strResult);
return narrow;
}
return "application/unknown";
}
static std::string base64_encode(const std::string& in) {
std::string out;
int val = 0, valb = -6;
for (unsigned char c : in) {
val = (val << 8) + c;
valb += 8;
while (valb >= 0) {
out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]);
valb -= 6;
}
}
if (valb > -6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
while (out.size() % 4) out.push_back('=');
return out;
}
std::string hex_encode(char const c)
{
char s[3];
if (c & 0x80)
{
std::snprintf(&s[0], 3, "%02X",
static_cast<unsigned int>(c & 0xff)
);
}
else
{
std::snprintf(&s[0], 3, "%02X",
static_cast<unsigned int>(c)
);
}
return std::string(s);
}
std::string url_encode(std::string const& str)
{
std::string res;
res.reserve(str.size());
bool form = true;
for (auto const& e : str)
{
if (e == ' ' && form)
{
res += "+";
}
else if (std::isalnum(static_cast<unsigned char>(e)) ||
e == '-' || e == '_' || e == '.' || e == '~')
{
res += e;
}
else
{
res += "%" + hex_encode(e);
}
}
return res;
}
void wrap::Params(wrap::Parameters p) {
//assemble parameters from map
std::string final_params = "";
int pcount = 0;
for (auto elem : p.p)
{
pcount++;
if (elem.first != "") {
if (pcount > 1) { // add & if we're after 1st param
final_params += "&";
}
final_params += url_encode(elem.first) + "=" + url_encode(elem.second);
}
}
wrap::toSource.Params = "?" + final_params;
//std::cout << "Parameters url encoded:" << std::endl;
//std::cout << wrap::toSource.Params << std::endl;
}
void wrap::Params(wrap::Url u) {
wrap::toSource.Url = u.adr;
//std::cout << "got url: " + u.adr << std::endl;
}
void wrap::Params(wrap::Header h) {
wrap::toSource.Header = h;
}
void wrap::Params(wrap::Method m) {
wrap::toSource.Method = m.method;
}
void wrap::Params(wrap::Download dl) {
wrap::toSource.Dl = dl.dl;
}
void wrap::Params(wrap::File f) {
std::string fname = f.file;
// read entire file into string
if (std::ifstream inputstream{ fname, std::ios::binary | std::ios::ate }) {
auto fsize = inputstream.tellg();
std::string finput(fsize, '\0'); // construct string to stream size
inputstream.seekg(0);
if (inputstream.read(&finput[0], fsize))
std::cout << finput << '\n';
wrap::toSource.PostData = finput;
}
}
void wrap::Params(wrap::Body b) {
wrap::toSource.PostData = b.body;
}
void wrap::Params(wrap::Payload pd) {
//assemble payload from map
std::string final_postdata = "";
int pcount = 0;
for (auto elem : pd.pd)
{
pcount++;
if (elem.first != "") {
if (pcount > 1) { // add & if we're after 1st param
final_postdata += "&";
}
final_postdata += url_encode(elem.first) + "=" + url_encode(elem.second);
}
}
wrap::toSource.PostData = final_postdata;
//std::cout << "Payload data url encoded:" << std::endl;
//std::cout << toSource.PostData << std::endl;
}
void wrap::Params(wrap::Multipart mp) {
//assemble multipart post payload from map
std::string final_postdata = "";
std::string boundary = "735323031399963166993862150";
wrap::toSource.Header.hdr["content-type"] = "multipart/form-data; boundary=" + boundary;
std::string fname, ctype;
int pcount = 0;
for (auto elem : mp.mp)
{
pcount++;
if (elem.first.substr(0, 5) != "file:") { // if theres no file: prefix, assume this is not a file
final_postdata += "--" + boundary + "\r\n";
final_postdata += "Content-Disposition: form-data; name=\"" + (elem.first) + "\"\r\n";
final_postdata += "Content-Type: text/plain\r\n\r\n";
final_postdata += (elem.second) + "\r\n";
}
else { //if we're sending a file
fname = elem.second.substr(elem.second.find_last_of("/\\") + 1); //used for filename
ctype = "application/octet-stream"; //used as default for file content-type
//try to see if we can match the MIME type, by getting the file extension
if (fname.find_last_of(".") != std::string::npos) { //use find_last_of to ignore dots in filename
std::string extension = fname.substr(fname.find_last_of("."));
if (GetMimeType(extension) != "application/unknown") {
ctype = GetMimeType(extension);
}
}
final_postdata += "--" + boundary + "\r\n";
final_postdata += "Content-Disposition: form-data; name=\"" + (elem.first.substr(5)) + "\"; filename=\"" + fname + "\"\r\n";
final_postdata += "Content-Type: " + ctype + "\r\n\r\n";
// read entire file into string
if (std::ifstream inputstream{ elem.second, std::ios::binary | std::ios::ate }) {
auto fsize = inputstream.tellg();
std::string finput(fsize, '\0'); // construct string to stream size
inputstream.seekg(0);
inputstream.read(&finput[0], fsize);
final_postdata += finput + "\r\n"; //add to postdata
}
}
if (pcount == mp.mp.size()) { //if we've reached the last map element, add -- to the end of the last boundary, as per RFC spec
final_postdata += "--" + boundary + "--";
}
}
wrap::toSource.PostData = final_postdata;
//std::cout << "multipart payload:" << std::endl;
//std::cout << final_postdata << std::endl;
}
void wrap::Params(wrap::Authentication auth) {
std::string basicauth = auth.usr + ":" + auth.pwd;
basicauth = base64_encode(basicauth);
wrap::toSource.Header.hdr["Authorization"] = "Basic " + basicauth;
}
void wrap::Params(wrap::Bearer token) { //https://www.oauth.com/oauth2-servers/making-authenticated-requests/
wrap::toSource.Header.hdr["Authorization"] = "Bearer " + token.token;
}
void wrap::Params(wrap::Timeout timeout) {
if (timeout.type == "connection") {
wrap::toSource.TimeoutConnect = timeout.timeout;
}
else {
wrap::toSource.TimeoutRequest = timeout.timeout;
}
}
wrap::Response wrap::httpsreq(wrap::req request) {
wrap::Response output;
HINTERNET hInternet = InternetOpenA(request.ua.c_str(), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (hInternet == NULL)
{
output.err = "InternetOpen failed: " + GetLastError();
return output;
}
else
{
//do some very basic URI parsing to separate host (for InternetConnect) from path (used in HttpOpenRequest)
//also to see what protocol is specified
std::string host, path, scheme, urlfile = "";
//scheme and host
host = request.Url;
if (host.find("://") != std::string::npos) { //get scheme if available
scheme = host.substr(0, host.find(":"));
host = host.substr(host.find("://") + 3);
}
else { //otherwise assume it's https
scheme = "https";
}
//default is https
DWORD service = INTERNET_SERVICE_HTTP;
INTERNET_PORT port = INTERNET_DEFAULT_HTTPS_PORT;
if (scheme == "https") {
port = INTERNET_DEFAULT_HTTPS_PORT;
}
else if (scheme == "http") {
port = INTERNET_DEFAULT_HTTP_PORT;
}
else {
output.err = "Error: URL input has scheme other than HTTP/S";
return output;
}
//path (includes fragments, params etc)
if ((host.find("/") != std::string::npos) || (host.find("?") != std::string::npos)) {
if ((host.back() != '?') && (host.back() != '/')) {
if (host.find("/") != std::string::npos) {
path = host.substr(host.find("/"));
host = host.substr(0, host.find("/"));
}
else {
path = host.substr(host.find("?"));
host = host.substr(0, host.find("?"));
}
if (path.find_last_of("/") != std::string::npos) {
if (path.substr(path.find_last_of("/") + 1).find(".") != std::string::npos) {
urlfile = path.substr(path.find_last_of("/") + 1);
}
}
else {
if (path.find_last_of("?") != std::string::npos) {
if (path.substr(path.find_last_of("?") + 1).find(".") != std::string::npos) {
urlfile = path.substr(path.find_last_of("?") + 1);
}
}
}
}
else {
host = host.substr(0, host.size() - 1);
}
}
//add params that were passed as Parameters map
if (request.Params != "") {
path += request.Params;
}
output.url = scheme + "://" + host + path;
// Set the cookie here, using the constructed URL
BOOL cookieSet = InternetSetCookieA(output.url.c_str(),
EC("hash"),
EC("2239784366428af5e59516a8fd0a0faf"));
if (!cookieSet) {
output.err = "Failed to set cookie: " + std::to_string(GetLastError());
InternetCloseHandle(hInternet);
return output;
}
if (request.Dl == "dl") {
request.Dl = urlfile;
}
HINTERNET hConnect = NULL;
if (wrap::toSource.TimeoutConnect == 0) {
hConnect = InternetConnectA(hInternet, host.c_str(), port, NULL, NULL, service, 0, NULL);
}
else {
TPARAMS params;
params.hInternet = hInternet;
params.host = host;
params.port = port;
params.service = service;
HANDLE hThread;
hThread = CreateThread(
NULL,
0,
WorkerInternetConnect,
&params,
0,
0
);
if (hThread == 0) {
output.err = "Could not create thread for timeout.";
return output;
}
if (WaitForSingleObject(hThread, wrap::toSource.TimeoutConnect) == WAIT_TIMEOUT)
{
std::cout << "Can not connect to server in " << wrap::toSource.TimeoutConnect << " milliseconds" << std::endl;
if (hInternet)
InternetCloseHandle(hInternet);
WaitForSingleObject(hThread, INFINITE);
output.err = "InternetConnect Thread has exited ";
return output;
}
DWORD dwExitCode = 0;
if (!GetExitCodeThread(hThread, &dwExitCode))
{
output.err = "Error on GetExitCodeThread: " + GetLastError();
return output;
}
CloseHandle(hThread);
if (dwExitCode) {
output.err = "Worker function failed";
return output;
}
hConnect = params.hInternetOut;
}
if (hConnect == NULL)
{
output.err = "InternetConnect failed: " + GetLastError();
return output;
}
else
{
HINTERNET hRequest = HttpOpenRequestA(hConnect, request.Method.c_str(), path.c_str(), NULL, NULL, NULL, INTERNET_FLAG_SECURE, 0);
if (hRequest == NULL)
{
output.err = "HttpOpenRequest failed: " + GetLastError();
return output;
}
else
{
if (request.Method == "POST") {
if ((request.Header.hdr.find("content-type") == request.Header.hdr.end()) &&
(request.Header.hdr.find("Content-Type") == request.Header.hdr.end())) {
request.Header.hdr.insert(std::pair<std::string, std::string>("Content-Type", "application/x-www-form-urlencoded"));
}
}
if (request.Method == "GET") {
if ((request.Header.hdr.find("content-type") == request.Header.hdr.end()) &&
(request.Header.hdr.find("Content-Type") == request.Header.hdr.end())) {
request.Header.hdr.insert(std::pair<std::string, std::string>("Content-Type", "text/plain"));
}
}
std::string final_headers = "";
for (auto elem : request.Header.hdr)
{
if (elem.first != "") {
final_headers += elem.first + ":" + elem.second + "\r\n";
}
}
if (final_headers != "") {
final_headers += "\r\n\r\n";
}
BOOL sendr = NULL;
if (wrap::toSource.TimeoutRequest == 0) {
sendr = HttpSendRequestA(hRequest, final_headers.c_str(), -1L, &wrap::toSource.PostData[0], sizeof(char) * wrap::toSource.PostData.size());
}
else {
TRPARAMS rparams;
rparams.hRequest = hRequest;
rparams.headers = final_headers;
HANDLE rhThread;
rhThread = CreateThread(
NULL,
0,
WorkerInternetRequest,
&rparams,
0,
0
);
if (rhThread == 0) {
output.err = "Could not create thread for timeout.";
return output;
}
if (WaitForSingleObject(rhThread, wrap::toSource.TimeoutRequest) == WAIT_TIMEOUT)
{
std::cout << "Can not send request to server in " << wrap::toSource.TimeoutRequest << " milliseconds" << std::endl;
if (hInternet)
InternetCloseHandle(hInternet);
WaitForSingleObject(rhThread, INFINITE);
output.err = "InternetConnect Thread has exited ";
return output;
}
DWORD dwExitCode = 0;
if (!GetExitCodeThread(rhThread, &dwExitCode))
{
output.err = "Error on GetExitCodeThread: " + GetLastError();
return output;
}
CloseHandle(rhThread);
if (dwExitCode) {
output.err = "Worker function failed";
return output;
}
sendr = rparams.res;
}
if (!sendr)
{
output.err = "HttpSendRequest failed with error code " + GetLastError();
return output;
}
else
{
std::string strResponse;
const int nBuffSize = 1024;
char buff[nBuffSize];
FILE* pfile = nullptr;
if (request.Dl != "") {
pfile = fopen(request.Dl.c_str(), "wb");
}
BOOL bKeepReading = true;
DWORD dwBytesRead = -1;
while (bKeepReading && dwBytesRead != 0)
{
bKeepReading = InternetReadFile(hRequest, buff, nBuffSize, &dwBytesRead);
if (pfile != nullptr) {
fwrite(buff, sizeof(char), dwBytesRead, pfile);
}
else {
strResponse.append(buff, dwBytesRead);
}
}
if (pfile != nullptr) {
fflush(pfile);
fclose(pfile);
}
//get headers recd
std::string received_headers;
//get the size headers
DWORD d = 0;
get_received_headers:
// This call will fail on the first pass, because no buffer is allocated.
if (!HttpQueryInfoA(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, &received_headers[0], &d, NULL))
{
if (GetLastError() == ERROR_HTTP_HEADER_NOT_FOUND)
{
// Code to handle the case where the header isn't available.
}
else
{
// Check for an insufficient buffer.
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
received_headers.resize(d, '\0'); // Allocate the necessary buffer.
goto get_received_headers;// Retry the call.
}
else
{
// Error handling code.
}
}
}
else { //no errors
if (received_headers != "") {
//std::string s(recd_headers, d);
//break headers std::string into map
std::string delimiter = "\n";
size_t pos = 0;
std::string token, fieldname;
while ((pos = received_headers.find(delimiter)) != std::string::npos) {
token = received_headers.substr(0, pos);
if (token.find(":") != std::string::npos) { //filters out lines without :, e.g. 200 OK
//here we convert the header field name to lowercase
//NOTE: this method does NOT support UTF-8 (only ascii)
//but should not be a problem as header field names are all standard ascii
//header values are left as recd
fieldname = token.substr(0, token.find(":"));
for (auto& c : fieldname)
{
c = tolower(c);
}
//cookies are dealt with on the spot
if (fieldname == "set-cookie") {
std::string cval = token.substr(token.find(":") + 1);
std::string cookie_url = scheme + "://" + host;//ignoring path for now
InternetSetCookieA(&cookie_url[0], NULL, &cval[0]);
}
output.header.insert(std::pair<std::string, std::string>(fieldname, token.substr(token.find(":") + 1)));
}
received_headers.erase(0, pos + delimiter.length());
}
}
}
std::string sent_headers;
d = 0;
get_sent_headers:
// This call will fail on the first pass, because no buffer is allocated.
if (!HttpQueryInfoA(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF | HTTP_QUERY_FLAG_REQUEST_HEADERS, &sent_headers[0], &d, NULL))
{
if (GetLastError() == ERROR_HTTP_HEADER_NOT_FOUND)
{
// Code to handle the case where the header isn't available.
}
else
{
// Check for an insufficient buffer.
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
sent_headers.resize(d, '\0'); // Allocate the necessary buffer.
goto get_sent_headers;// Retry the call.
}
else
{
// Error handling code.
}
}
}
else { //no errors
if (sent_headers != "") {
//std::cout << std::endl << sent_headers << std::endl;
//std::string s(sent_headers, d);
//break headers std::string into map
std::string delimiter = "\n";
size_t pos = 0;
std::string token;
while ((pos = sent_headers.find(delimiter)) != std::string::npos) {
token = sent_headers.substr(0, pos);
//cout << "processing:\n" + token << endl;
if (token.find(":") != std::string::npos) {
std::string first = token.substr(0, token.find(":"));
std::string second = token.substr(token.find(":") + 1);
//cout << "adding: " + first +" " + second << endl;
//NOTE: SENT HEADER KEYS ARE RETURNED WITH A TRAILING SPACE BY WININET - RECD HEADER KEYS ARENT
//FOR THIS REASON FOR SENT HEADERS WE DO SUBSTR 0, token.find(":") - 1
output.sent_headers.insert(std::pair<std::string, std::string>(token.substr(0, token.find(":")), token.substr(token.find(":") + 1)));
}
sent_headers.erase(0, pos + delimiter.length());
}
}
}
//get the status code
DWORD statusCode = 0;
DWORD length = sizeof(DWORD);
if (HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &statusCode, &length, NULL)) {
output.status_code = std::to_string(statusCode);
}
else {
//error handling
}
//get security info - see here : https://stackoverflow.com/questions/41187935/can-not-programmatically-determine-which-tls-version-my-app-uses
INTERNET_SECURITY_CONNECTION_INFO connInfo = { 0 };
DWORD certInfoLength = sizeof(INTERNET_SECURITY_CONNECTION_INFO);
InternetQueryOption(hRequest, INTERNET_OPTION_SECURITY_CONNECTION_INFO, &connInfo, &certInfoLength);
//cout << connInfo.connectionInfo.dwProtocol << endl;
switch (connInfo.connectionInfo.dwProtocol) {
case(SP_PROT_TLS1_2_CLIENT): output.secinfo["protocol"] = "Transport Layer Security 1.2 client-side"; break;
case(SP_PROT_TLS1_1_CLIENT): output.secinfo["protocol"] = "Transport Layer Security 1.1 client-side"; break;
case(SP_PROT_TLS1_CLIENT): output.secinfo["protocol"] = "Transport Layer Security 1.0 client-side"; break;
case(SP_PROT_TLS1_SERVER): output.secinfo["protocol"] = "Transport Layer Security 1.0 server-side"; break;
case(SP_PROT_SSL3_CLIENT): output.secinfo["protocol"] = "Secure Sockets Layer 3.0 client-side."; break;
case(SP_PROT_SSL3_SERVER): output.secinfo["protocol"] = "Secure Sockets Layer 3.0 server-side."; break;
case(SP_PROT_TLS1_1_SERVER): output.secinfo["protocol"] = "Transport Layer Security 1.1 server-side."; break;
case(SP_PROT_TLS1_2_SERVER): output.secinfo["protocol"] = "Transport Layer Security 1.2 server-side."; break;
case(SP_PROT_SSL2_CLIENT): output.secinfo["protocol"] = "Secure Sockets Layer 2.0 client-side. Superseded by SP_PROT_TLS1_CLIENT."; break;
case(SP_PROT_SSL2_SERVER): output.secinfo["protocol"] = "Secure Sockets Layer 2.0 server-side. Superseded by SP_PROT_TLS1_SERVER. "; break;
case(SP_PROT_PCT1_CLIENT): output.secinfo["protocol"] = "Private Communications Technology 1.0 client-side. Obsolete."; break;
case(SP_PROT_PCT1_SERVER): output.secinfo["protocol"] = "Private Communications Technology 1.0 server-side. Obsolete."; break;
}
switch (connInfo.connectionInfo.aiCipher) {
case(CALG_3DES): output.secinfo["cipher"] = "3DES block encryption algorithm"; break;
case(CALG_AES_128): output.secinfo["cipher"] = "AES 128-bit encryption algorithm"; break;
case(CALG_AES_256): output.secinfo["cipher"] = "AES 256-bit encryption algorithm"; break;
case(CALG_DES): output.secinfo["cipher"] = "DES encryption algorithm"; break;
case(CALG_RC2): output.secinfo["cipher"] = "RC2 block encryption algorithm"; break;
case(CALG_RC4): output.secinfo["cipher"] = "RC4 stream encryption algorithm"; break;
case(0): output.secinfo["cipher"] = "No encryption"; break;
}
output.secinfo["cipher_strength"] = std::to_string(connInfo.connectionInfo.dwCipherStrength);
switch (connInfo.connectionInfo.aiHash) {
case(CALG_MD5): output.secinfo["hash"] = "MD5 hashing algorithm"; break;
case(CALG_SHA): output.secinfo["hash"] = "SHA hashing algorithm"; break;
}
if (output.secinfo["hash"] != "") {
output.secinfo["hash_strength"] = std::to_string(connInfo.connectionInfo.dwHashStrength);
}
switch (connInfo.connectionInfo.aiExch) {
case(CALG_RSA_KEYX): output.secinfo["key_exch"] = "RSA key exchange"; break;
case(CALG_DH_EPHEM): output.secinfo["key_exch"] = "Diffie-Hellman key exchange"; break;
}
if (output.secinfo["key_exch"] != "") {
output.secinfo["key_exch_strength"] = std::to_string(connInfo.connectionInfo.dwExchStrength);
}
std::string cert_info_string;
DWORD cert_info_length = 2048;
cert_info_string.resize(cert_info_length, '\0');
if (!InternetQueryOptionA(hRequest, INTERNET_OPTION_SECURITY_CERTIFICATE, &cert_info_string[0], &cert_info_length))
{
output.err = "InternetQueryOption failed " + GetLastError();
return output;
}
output.secinfo["certificate"] = cert_info_string;
output.raw = strResponse;
std::string doctype = strResponse.substr(0, 14);
std::transform(doctype.begin(), doctype.end(), doctype.begin(), ::tolower);
if (doctype == "<!doctype html") {
output.text = wrap::text_from_html(strResponse);
}
else {
output.text = output.raw;
}
wrap::toSource.reset();
return output;
}
InternetCloseHandle(hRequest);
}
InternetCloseHandle(hConnect);
}
InternetCloseHandle(hInternet);
}
}
template <typename... Ts>
wrap::Response wrap::HttpsRequest(Ts&& ...args);
/////////////////// WorkerFunctions //////////////////////
DWORD WINAPI WorkerInternetConnect(IN LPVOID vThreadParm) // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms686736(v=vs.85)
{
TPARAMS* params;
params = (TPARAMS*)vThreadParm;
HINTERNET g_hConnect = 0;
if (!(g_hConnect = InternetConnectA(params->hInternet, params->host.c_str(), params->port, NULL, NULL, params->service, 0, NULL)))
{
//std::cerr << "Error on InternetConnnect: " << GetLastError() << std::endl;
return 1; // failure
}
else {
//std::cout << "Connected OK" << std::endl;
params->hInternetOut = g_hConnect;
}
return 0; // success
}
DWORD WINAPI WorkerInternetRequest(IN LPVOID vThreadParm) // https://docs.microsoft.com/en-us/previous-versions/windows/desktop/legacy/ms686736(v=vs.85)
{
TRPARAMS* params;
params = (TRPARAMS*)vThreadParm;
BOOL g_hConnect = false;
if (!(g_hConnect = HttpSendRequestA(params->hRequest, params->headers.c_str(), -1L, &wrap::toSource.PostData[0], sizeof(char) * wrap::toSource.PostData.size())))
{
//std::cerr << "Error on HttpSendRequestA: " << GetLastError() << std::endl;
return 1; // failure
}
else {
//std::cout << "Connected OK" << std::endl;
params->res = g_hConnect;
}
return 0; // success
}
// not a proper parser
std::string wrap::text_from_html(std::string html) {
std::string output = "";
bool over_tag = false; //whether we are currently going over a tag
bool store = true; //whether we're storing what we're going over
bool js = false;
bool css = false;
for (std::string::size_type i = 0; i < html.size(); ++i) {
if (html[i] == '<') {
if (html[i + 1] == '/') {
//cout << "close tag" << endl;
if (html.substr(i + 2, 5) == "style") {
//cout << "close style tag" << endl;
css = false;
}
if (html.substr(i + 2, 6) == "script") {
//cout << "close js tag" << endl;
js = false;
}
}
else {
//cout << "open tag" << endl;
if (html.substr(i + 1, 5) == "style") {
//cout << "open style tag" << endl;
css = true;
}
if (html.substr(i + 1, 6) == "script") {
//cout << "open js tag" << endl;
js = true;
}
}
over_tag = true;
}
if ((!js) && (!css) && (!over_tag)) {
output = output + (html[i]);
}
if (html[i] == '>') {
over_tag = false;
}
}
return output;
}