Im not sure if this is lack of knowledge in msdn or not. i Have the following code:
#include "stdafx.h"
#include <iostream>
#include <string>
#include <windows.h>
#include <WinHttp.h>
#include "myHTTP.h"
int main(){
WinHTTP newHTTP("test", "test");
bool myResult;
newHTTP.httpConnect(L"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36",
L"https://pages.awscloud.com/awsomedayonlineconference-reg.html",
1,
L"GET");
newHTTP.httpAddHeader(L"Content-Type: application/x-www-form-urlencoded\r\n");
newHTTP.httpSend();
myResult = newHTTP.httpReceive();
newHTTP.closeHandles();
return 0;
}
I have a class for this and the following line is being executed: // open the request - not connected at this point
hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
if (!hRequest) {
printf("error2: %d", GetLastError());
}
SO basically when i run my software, it returns here because !hrequest is empty when calling winhttpopenrequest. I have added getlasterror to see why this is but the only output i get is:
error2: 6
I then read the msdn for winhttp and i can see the errors returned from the function here: https://msdn.microsoft.com/en-us/library/windows/desktop/aa384099(v=vs.85).aspx but this mysterious error 6 is making no sense to me.
Any help on seeing why the handle is invalid?
full class code:
#pragma once
// WinHTTP wrapper for web protocol -- windows 8.1+
class WinHTTP {
private:
std::string siteUsername, sitePassword;
std::wstring UA, URL;
bool bResult = false;
DWORD dwSize = sizeof(DWORD); // used to handle reading data in bytes
LPSTR pszOutBuffer; // used to Allocate space for the buffer.
DWORD dwDownloaded = 0; // set to null if using asynchronously and use in callback function only
HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;
public:
WinHTTP(std::string myuser = "", std::string mypass = "") {
siteUsername = myuser;
sitePassword = mypass;
}
// TODO: update to be able to add proxy details either here or before. do check if proxy has been detected in here and open/connect accordingly
void httpConnect(std::wstring userAgent, std::wstring myURL, int isHTTPS, std::wstring protocol) {
UA = userAgent;
URL = myURL;
std::wstring acceptTypes = L"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8";
int portToUse;
if (isHTTPS == 1) {
portToUse = 443;
}
else {
portToUse = 80;
}
//initialize http and return session handle -- use c_str to convert wstring to LPCWSTR
hSession = WinHttpOpen(UA.c_str(),
WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
//make the connection request
if (hSession) {
hConnect = WinHttpConnect(hSession, URL.c_str(), portToUse, 0);
}
else {
std::cout << "winhttpconnect error " << GetLastErrorAsString();
}
// open the request - not connected at this point
hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
if (!hRequest) {
std::cout << "winhttpopenrequest error " << GetLastErrorAsString();
}
}
std::string GetLastErrorAsString()
{
//Get the error message, if any.
DWORD errorMessageID = ::GetLastError();
if (errorMessageID == 0)
return std::string(); //No error message has been recorded
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&messageBuffer, 0, NULL);
std::string message(messageBuffer, size);
//Free the buffer.
LocalFree(messageBuffer);
return message;
}
void httpAddHeader(std::wstring myheader) {
if (hRequest) {
bResult = WinHttpAddRequestHeaders(hRequest, myheader.c_str(), (ULONG)-1L, WINHTTP_ADDREQ_FLAG_ADD);
}
}
bool httpSend() {
if (hRequest) {
bResult = WinHttpSendRequest(hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
}
if (!bResult) {
std::cout << "winhttpsendrequest error " << GetLastErrorAsString();
return false;
}
else {
return true;
}
}
bool httpReceive() {
if (bResult) {
bResult = WinHttpReceiveResponse(hRequest, NULL);
}
if (bResult) {
do
{
// Check for available data.
dwSize = 0; //query data available looks for data in bytes
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
{
std::cout << "WinHttpQueryDataAvailable error " << GetLastErrorAsString();
break;
}
// No more available data.
if (!dwSize)
return false;
// Allocate space for the buffer. as dwSize now holds the size of the request
pszOutBuffer = new char[dwSize + 1]; // just a way of freeing up memory
if (!pszOutBuffer)
{
printf("Out of memory\n"); // couldnt allocate enough
return false;
}
ZeroMemory(pszOutBuffer, dwSize + 1); // fills a block of memory with 0s
// we know the expect size and have the pszoutbffer to write to - read the Data.
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
{
std::cout << "WinHttpReadData error " << GetLastErrorAsString();
return false;
}
else
{
printf("%s", pszOutBuffer);
}
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
return true;
// This condition should never be reached since WinHttpQueryDataAvailable
// reported that there are bits to read.
if (!dwDownloaded)
return false;
} while (dwSize > 0);
}
return false;
}
void closeHandles() {
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
}
};
Why you get error code 6
Error code 6 is the System Error Code ERROR_INVALID_HANDLE
.
It tells you that the hConnect
you pass into WinHttpOpenRequest
is invalid.
You only check hSession
after your call to WinHttpOpen
, and hRequest
after your call to WinHttpOpenRequest
. But you never check if hConnect
is valid.
You need to check the hConnect
returned by WinHttpConnect
as well, and if it's invalid check GetLastError()
before calling another WINAPI method:
hSession = WinHttpOpen(UA.c_str(), WINHTTP_ACCESS_TYPE_NO_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession) {
hConnect = WinHttpConnect(hSession, URL.c_str(), portToUse, 0);
if (hConnect) {
hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
if (!hRequest) {
std::cout << "WinHttpOpenRequest error " << GetLastErrorAsString();
}
}
else {
std::cout << "WinHttpConnect error " << GetLastErrorAsString();
}
}
else {
std::cout << "WinHttpOpen error " << GetLastErrorAsString();
}
Why your call to WinHttpConnect
fails
The docs tell us that WinHttpConnect
expects a server name, not a URL:
pswzServerName [in]
Pointer to a null-terminated string that contains the host name of an HTTP server. Alternately, the string can contain the IP address of the site in ASCII, for example, 10.0.1.45.
However the string you provide contains a URL, which is not valid. You need to change "https://pages.awscloud.com/awsomedayonlineconference-reg.html"
to "pages.awscloud.com"
, and then provide the path to the page as parameter in WinHttpOpenRequest
:
hRequest = WinHttpOpenRequest(hConnect, protocol.c_str(), path.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, 0);
where path
is a string containing "/awsomedayonlineconference-reg.html"
.
You could split your URL into parts for this, or change your httpConnect
method to get servername and path as separate parameters.