I use CInternetSession to get and post request. But when a connexion time out occurs, I lost the connexion and I always get invalid server request error, I don't understand why. Moreover, there is also a memory leak.
#include "stdafx.h"
#include "httpConnexion.h"
#include "TSException.h"
ChttpConnexion::ChttpConnexion()
: CInternetSession(AfxGetAppName(), INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, NULL, INTERNET_FLAG_DONT_CACHE)
, m_lastRequest()
{
SetOption(INTERNET_OPTION_CONNECT_TIMEOUT, 10000);
SetOption(INTERNET_OPTION_RECEIVE_TIMEOUT, 10000);
m_bAttente = true;
}
ChttpConnexion::~ChttpConnexion()
{
}
std::string ChttpConnexion::sendRequest(const std::string& strUrl)
{
DWORD dwServiceType;
CString strServerName;
CString strObject;
INTERNET_PORT nPort;
AfxParseURL(strUrl.c_str(), dwServiceType, strServerName, strObject, nPort);
CString strHeaders = _T("User-Agent: User-Agent=Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7\r\nConnection: keep-alive\r\nContent-Type: application/x-www-form-urlencoded");
CString strTmp = "", strResult = "";
CHttpConnection* pHttpConnexion = NULL;
CHttpFile* pHttpFile = NULL;
try
{
//Creation de la connexion Http
pHttpConnexion = GetHttpConnection(strServerName, INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, nPort, NULL, NULL);
//Creation de la requete GET
pHttpFile = pHttpConnexion->OpenRequest(CHttpConnection::HTTP_VERB_GET, strObject, NULL, 1, NULL, NULL, INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE);
//Envoi de la requéte
BOOL bRequestSend = pHttpFile->SendRequest(strHeaders);
CString headers;headers.Empty();
DWORD dwRet;
pHttpFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF,headers);
pHttpFile->QueryInfoStatusCode(dwRet);
//Lecture du résultat
while ( pHttpFile->ReadString(strTmp))
{
strResult += strTmp;
}
//Fermeture de la requéte
pHttpFile->Close();
//Fermeture de la connexion
pHttpConnexion->Close();
//Suppression des objets
if (pHttpFile != NULL)
delete pHttpFile;
if (pHttpConnexion != NULL)
delete pHttpConnexion;
}
catch(CInternetException* exp)
{
exp->Delete();
//Fermeture de la requéte
if (pHttpFile != NULL)
{
pHttpFile->Close();
delete pHttpFile;
}
//Fermeture de la connexion
if (pHttpConnexion != NULL)
{
pHttpConnexion->Close();
delete pHttpConnexion;
}
throw CTSException("sendRequest");
}
return strResult.GetString();
}
std::string ChttpConnexion::postRequest(const std::string& strUrl, const std::string& postData)
{
DWORD dwServiceType;
CString strServerName;
CString strObject;
INTERNET_PORT nPort;
AfxParseURL(strUrl.c_str(), dwServiceType, strServerName, strObject, nPort);
CString strHeaders = _T("User-Agent: User-Agent=Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7\r\nConnection: keep-alive\r\nContent-Type: application/x-www-form-urlencoded");
CString strTmp = "", strResult = "";
CHttpConnection* pHttpConnexion = NULL;
CHttpFile* pHttpFile = NULL;
try
{
//Creation de la connexion Http
pHttpConnexion = GetHttpConnection(strServerName, INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE, nPort, NULL, NULL);
//Creation de la requete GET
pHttpFile = pHttpConnexion->OpenRequest(CHttpConnection::HTTP_VERB_POST, strObject, NULL, 1, NULL, NULL, INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE);
//Envoi de la requéte
BOOL bRequestSend = pHttpFile->SendRequest(strHeaders, (LPVOID) (LPCTSTR) postData.c_str(), postData.length());
CString headers;headers.Empty();
DWORD dwRet;
pHttpFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF,headers);
pHttpFile->QueryInfoStatusCode(dwRet);
CString data;
GetCookie(strServerName, "sess_id", data);
//Lecture du résultat
while ( pHttpFile->ReadString(strTmp))
{
strResult += strTmp;
}
//Fermeture de la requéte
pHttpFile->Close();
//Fermeture de la connexion
pHttpConnexion->Close();
//Suppression des objets
if (pHttpFile != NULL)
delete pHttpFile;
if (pHttpConnexion != NULL)
delete pHttpConnexion;
}
catch(CInternetException* exp)
{
exp->Delete();
//Fermeture de la requéte
if (pHttpFile != NULL)
{
pHttpFile->Close();
delete pHttpFile;
}
//Fermeture de la connexion
if (pHttpConnexion != NULL)
{
pHttpConnexion->Close();
delete pHttpConnexion;
}
throw CTSException("postRequest");
}
return strResult.GetString();
}
Thanks for helping!
when you construct your object and you call CInternetSession constructor, why the 3rd param is NULL? It should be something like PRE_CONFIG_INTERNET_ACCESS. You may need to use the proxy settings if you are behind a proxy.
check the content of strServerName, it may be invalid and GetHttpConnection fails because of that.
in your try, you GetHttpConnection and OpenRequest, but you don't check if the results aren't NULL. You only check later (too late) if they aren't NULL to delete them. You should check them after GetHttpConnection and OpenRequest, before using them. (But I guess the exception occurs during GetHttpConnection)
if the timeout occurs after 10sec, maybe it's because your timeout is too low (in your constructor).
there were some old reports that https may be a problem. But you didn't mentioned what was your request and what you were requesting.
in your request header, you are requesting different file formats (xml, html, png, etc...), but you are using a GetString and appending it to a string. If you are getting a binary data, it may not work. You should use a char[] buffer. Check this example.
after using your object ChttpConnexion, did you call .Close() on it?
In the end, I would recommend attaching a debugger and put a breakpoint in the catch to see where exactly the error occurs, or add some debug logs. This may help.
Related
I am trying to send an http post request through a proxy that has headers and optionally, json content, using WinHTTP. I have tried solutions outlined in the questions here:
WinHttpSendRequest failed with error code 87
WinHttpSendRequest returns ERROR_INVALID_PARAMETER
However, it just does not seem to change anything. I have the post request functions pasted below. Perhaps there is something that I missed. Please let me know if there is anything I can do to fix this.
The problematic area is around WinHttpSendRequest
std::string PostRequest(std::wstring token, std::string json, std::string proxy, std::wstring url, std::wstring domain) {
std::cout<<"PostRequest function started"<<std::endl;
std::cout<<"json is being processed"<<std::endl;
LPSTR data = (LPSTR)json.c_str();
DWORD data_len;
if(data!=0) data_len = strlen(data); else data_len = 0;
std::cout<<"json done"<<std::endl<<GetLastError()<<std::endl;
std::string response;
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
BOOL bResults = FALSE;
HINTERNET hConnect = NULL, hRequest = NULL;
std::wstring stemp = std::wstring(proxy.begin(), proxy.end());
const wchar_t* sw = stemp.c_str();
std::cout<<"initializing WinHttpOpen"<<std::endl<<GetLastError()<<std::endl;
HINTERNET hSession=WinHttpOpen(L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, L"http://"+*sw, WINHTTP_NO_PROXY_BYPASS, 0);
std::cout<<"initializing WinHttpConnect"<<std::endl<<GetLastError()<<std::endl;
if(hSession) hConnect = WinHttpConnect(hSession, domain.c_str(), INTERNET_DEFAULT_HTTPS_PORT, 0 );
std::cout<<"initializing WinHttpOpenRequest"<<std::endl<<GetLastError()<<std::endl;
if(hConnect) hRequest = WinHttpOpenRequest(hConnect, L"POST", url.c_str(), NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
const wchar_t *additionalHeaders =
L"Content-Type: application/json\r\n"
L"User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11\r\n"
L"Authorization: "+*token.c_str()+*L"\r\n";
DWORD headersLength = -1;
std::cout<<"initializing WinHttpSendRequest"<<std::endl<<GetLastError()<<std::endl;
std::cout<<"bResults: "<<bResults<<std::endl;
LPVOID rqdata;
if(data==0)rqdata = WINHTTP_NO_REQUEST_DATA;
else rqdata=(LPVOID)data;
if (hRequest) bResults = WinHttpSendRequest(hRequest, additionalHeaders, headersLength, rqdata, data_len, data_len, 0);
else std::cout<<"else 1"<<std::endl;
std::cout<<"bResults: "<<bResults<<std::endl;
std::cout<<"initializing WinHttpReceiveResponse"<<std::endl<<GetLastError()<<std::endl;
if (bResults) bResults = WinHttpReceiveResponse(hRequest, NULL);
else std::cout<<"else 2"<<std::endl;
std::cout<<"bResults: "<<bResults<<std::endl;
if (bResults)
{
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
std::cout<<"Error in WinHttpQueryDataAvailable.\n"<<GetLastError();
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer)
{
printf("Out of memory\n");
dwSize = 0;
}
else
{
// Read the data.
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
std::cout<<"Error in WinHttpReadData.\n"<<GetLastError();
else
response = response + std::string(pszOutBuffer);
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
}
} while (dwSize > 0);
}
if (!bResults)
std::cout<<"Error has occurred.\n"<<GetLastError()<<std::endl;
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
return response;
}
all of the cout's are for debugging which will be removed by me later.
The output looks like this: (sorry if it is kind of messy)
PostRequest function started
json is being processed
json done
0
initializing WinHttpOpen
0
initializing WinHttpConnect
0
initializing WinHttpOpenRequest
0
initializing WinHttpSendRequest
0
bResults: 0
bResults: 0
initializing WinHttpReceiveResponse
87
else 2
bResults: 0
Error has occurred.
87
This question already has answers here:
My attempt at value initialization is interpreted as a function declaration, and why doesn't A a(()); solve it?
(5 answers)
Closed 4 years ago.
I am really confused at the error 'expression must have class type' on newHTTP on line 13
#include "stdafx.h"
#include <iostream>
#include <string>
#include <windows.h>
#include <WinHttp.h>
#include "myHTTP.h"
int main()
{
WinHTTP newHTTP();
// error is here
HINTERNET myResponse = 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"http://api",
0,
L"GET");
//
int x;
std::cin >> x;
return 0;
}
I just dont understand what im missing, i have specified HINTERNET on myresponse and made sure the method httpConnect returns a value. Can someone assist?
My class code (trimmed of course):
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
HINTERNET 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 {
printf("error: %d",GetLastError());
}
// 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) {
return hRequest;
}
else {
printf("error: %d", GetLastError());
return hRequest;
}
}
};
Please add default constructor if you invoking one . I see only parametrized one .
I need to send WININET request to rest server and get json response. Code works only while fiddler is working. I've tried everything what I've found but every time I get 0 into bytesRead. There aren't any errors and HttpSendRequestand and InternetReadFile both return true but buffer is still empty.
Server works fine and answers in a right way. When fiddler is running I get my 76 bytes, which I need. I tried to figure out using that blog Help! Running Fiddler Fixes My App???, no luck.
HINTERNET session = nullptr;
HINTERNET request = nullptr;
HINTERNET connect = nullptr;
BOOST_SCOPE_EXIT((&session)(&request)(&connect)) {
if (request != nullptr)
::InternetCloseHandle(request);
if (session != nullptr)
::InternetCloseHandle(session);
if (connect != nullptr)
::InternetCloseHandle(connect);
} BOOST_SCOPE_EXIT_END;
try
{
//std::wstring agent(L"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1");
std::wstring agent{ L"Mozilla/5.0 (compatible)" };
session = ::InternetOpen(agent.c_str(), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!session)
return;
InternetSetStatusCallback(
session,
(INTERNET_STATUS_CALLBACK)IStatusCallback);
connect = InternetConnect(
session
, serverName.c_str()
, INTERNET_DEFAULT_HTTP_PORT
, NULL
, NULL
, INTERNET_SERVICE_HTTP
, 0
, 1);
if (!connect)
return;
//const wchar_t* parrAcceptTypes[] = { L"text/*", NULL };
const wchar_t* parrAcceptTypes[] = { L"application/json", L"text/*", NULL };
request = HttpOpenRequest(
connect
, L"GET"
, virtualFolder.c_str()
, L"HTTP/1.1"
, NULL
, parrAcceptTypes
, /*INTERNET_FLAG_KEEP_CONNECTION*/INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_PRAGMA_NOCACHE
, 1);
std::string data;
if (request)
{
BOOL isRequestComplete = HttpSendRequest(request, NULL, 0, NULL, 0);
if (isRequestComplete)
{
const int dataSize = 1024;
BYTE buff[dataSize];
DWORD bytesRead = (DWORD)-1;
BOOL bKeepReading = true;
while (bKeepReading && bytesRead != 0)
{
bKeepReading = InternetReadFile(request, buff, sizeof(buff) - 1, &bytesRead);
data.append((char*)buff, bytesRead);
}
}
else
{
DWORD dwErr = GetLastError();
InternetErrorDlg(parent_, request, dwErr, 0, NULL);
LERR_ << "Request was failed. Error code: " << dwErr;
}
}
I want to read multiple DWORDS and concatenate them into an array of type TCHAR. How can I do that?
At the end, array should look like a list sepparated through endline characters.
TCHAR array[MAX_PATH];
while(reading dwords)
{
lstrcat(array, dword to be concatenated);
lstrcat(array, L"\n");}
Added my code after people asking me to. I am trying to get the ID's in the same manner I get the names.
void getProcessList()
{//snapshot la toate procesele din sistem
HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
PROCESSENTRY32 proc32;
TCHAR names[MAX_PATH]; //wchar_t pentru ca folosim Unicode
char* pids=new char[200];
if(hSnap == INVALID_HANDLE_VALUE)
{
cout<<"invalid handle value error!\n";
return;
}
//setez dimensiunea structurii
proc32.dwSize = sizeof(PROCESSENTRY32);
//get info despre primul proces(se va afisa in do...while)
if(!Process32First(hSnap, &proc32))
{
cout<<"Tread32First() error!\n";
CloseHandle(hSnap);
return ;
}
wcscpy(names, L"");
//cauta in restul proceselor
//daca nr. threaduri<3, introdu in fisierul mapat
do
{
if(proc32.cntThreads < 3)
{
//cout<<"Current process id(adica programul A): "<<GetCurrentProcessId()<<"\n";
wcout<<L"Process Name: "<<proc32.szExeFile<<"\n";
cout<<"Process ID: " <<proc32.th32ProcessID<<"\n";
cout<<"Thread Count: "<<proc32.cntThreads<<"\n"<<endl;
//exclud procesul curent, nu vreau sa-l termin
//includ celelalte procese in string, separate de newline
if(GetCurrentProcessId()!=proc32.th32ProcessID)
{ // sprintf(pids,"%d",proc32.th32ProcessID);
lstrcat(names, proc32.szExeFile);
lstrcat(names, L"\n");
}
}
}while(Process32Next(hSnap, &proc32));
//afisez
wcout<<names;
//printf("asd: %d",pids);
//scriu in fisierul mapat
writeToFileMap(names);
//inchid handle la snapshot
CloseHandle(hSnap);
}
If you want to do it all with win32, use StringCchPrintf:
HRESULT hr = StringCchPrintf(names, ARRAYSIZE(names), L"%ld", proc32.th32ProcessID);
if (FAILED(hr)) {
// Handle error...
}
I'm writing an application that captures some Outlook events, I want to capture ItemAdd event on sentMail folder for each account, for Outlook 2007 (where there is only one sent mail folder for all accounts) I'm using the following code. What changes I have to perform to make it work with Outlook 2010 (subscribe to the event for all accounts)? Any help is appreciated.
const IID IID_ItemsEvents = {0x00063077, 0x0000, 0x0000, {0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46}};
CComPtr<Outlook::_Application> spApplication;
hr = spApplication.CoCreateInstance(__uuidof(Outlook::Application), 0, CLSCTX_LOCAL_SERVER );
if(SUCCEEDED(hr) && spApplication)
{
CComPtr<Outlook::_NameSpace> spSession;
hr = spApplication->get_Session(reinterpret_cast<Outlook::_NameSpace **>(&spSession));
if (SUCCEEDED(hr) && spSession)
{
CComPtr<Outlook::MAPIFolder> spSentMailsFolder;
hr = spSession->GetDefaultFolder(Outlook::olFolderSentMail, &spSentMailsFolder);
CComPtr<Outlook::_Items> spItems;
spSentMailsFolder->get_Items(&spItems);
if (SUCCEEDED(hr) && spItems)
{
CComPtr<Outlook::ItemsEvents > spItem;
CComPtr<IConnectionPointContainer> spContainer;
HRESULT hr = spItems->QueryInterface(__uuidof(IConnectionPointContainer),reinterpret_cast<void **>(&spContainer));
if (SUCCEEDED(hr))
{
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
CComPtr<CItemsEventListener> spSink = new CItemsEventListener(hEvent);
CComPtr<IConnectionPoint> spConnectionPoint;
hr = spContainer->FindConnectionPoint(IID_ItemsEvents, &spConnectionPoint);
if (SUCCEEDED(hr) && spConnectionPoint)
{
DWORD dwCookie = 0;
hr = spConnectionPoint->Advise(spSink, &dwCookie);
if (SUCCEEDED(hr))
{
while(true)
{
MSG Message;
while(PeekMessage(&Message, NULL, WM_NULL, WM_NULL, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
DWORD dwStatus = WaitForSingleObject(hEvent, 0);
Sleep(1);
}
spConnectionPoint->Unadvise(dwCookie);
}
}
}
}
else
{
//m_LogTrace->WriteLine("\tERROR\tEchec de l'appel de la méthode get_Items");
}
}
else
{
//m_LogTrace->WriteLine("\tERROR\tEchec de l'appel de la méthode get_Session");
}
spApplication.Release();
}
Yu will need to keep each Items object in a list/array and run the code above for each Items object.