Using InternetConnect with IP-address fails (error 12029) - c++

Here i have a snippet that doesn't work when i'am using IP address. But in MSDN it says that parameter could be dotted-decimal IP address, so it must work clearly. What is wrong? Thank you.
#include "stdafx.h"
#include <windows.h>
#include <wininet.h>
#include <tchar.h>
#include <iostream>
#pragma comment(lib,"wininet.lib")
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
char szServer[] = "127.0.0.1";
char szUrl[] = "/test/upload.php";
char Data[] = "text123";
char szHdrs[] = "Content-Type: multipart/form-data; boundary=AaB03x";
char szTead[] = "--AaB03x\r\n"
"Content-Disposition: form-data; name=\"file\"; filename=\"test.txt\"\r\n"
"Content-Type: application/octet-stream\r\n"
"\r\n";
char szTail[] = "\r\n"
"--AaB03x--\r\n";
char szUserAgent[] = "MyUA";
char *szTypes[] = {"*/*", NULL};
HINTERNET hIOpen = InternetOpenA(szUserAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if(!hIOpen)
{
printf("InternetOpenA Error\n");
}
HINTERNET hIConnect = InternetConnectA(hIOpen, szServer, INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
if(!hIConnect)
{
printf("InternetConnectA Error\n");
}
HINTERNET hHttpOpReq = HttpOpenRequestA(hIConnect, "POST", szUrl, NULL, NULL, (LPCSTR *)szTypes, 0, 1);
if(!hHttpOpReq)
{
printf("HttpOpenRequestA Error\n");
}
BOOL bHttpSendReq = HttpSendRequestA(hHttpOpReq, szHdrs, strlen(szHdrs), Data, strlen(Data));
if (!bHttpSendReq)
{ int Error = GetLastError();
printf("HttpSendRequest Error %d\n", Error);
}
system("pause");
return 0;
}
There is nothing more i can add, actually about this issue. I'am using Windows 7 x64 Ultimate and VS2008.
Now i checked this .exe on other XP and Seven machines. Looks like it works, but not on my machine. Maybe the problem is (out there) somewhere else.

Three hints:
Add following flags to your internetconnect:
INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE
Also add http to your reqest:
char szServer[] = "http://127.0.0.1";
You might also try with INTERNET_OPEN_TYPE_DIRECT instead of INTERNET_OPEN_TYPE_PRECONFIG
in my code base I have a work around for a 12029 error, but it happens only when connection is lost during file downloading - to fix it I must fully close all WinInet handles and retry download.

Related

Converting WinHttp to WinInet API POST request

I am trying to convert some HTTP request code from using the WinHttp COM interface to using lower-level WinInet calls from <wininet.h>. The COM version is working but I am having difficulty translating the calls into the WinInet API.
This code works fine and gets the correct error response (as the request data is empty) to the POST request:
#import <winhttpcom.dll>
#include <iostream>
#include <string>
int main()
{
HRESULT hr = CoInitialize(NULL);
using namespace WinHttp;
IWinHttpRequestPtr pReq = NULL;
hr = pReq.CreateInstance(__uuidof(WinHttpRequest));
const char* pszReq = "";
if (SUCCEEDED(hr))
{
_bstr_t bstrMethod("POST");
_bstr_t bstrUrl("https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ldb9.asmx");
hr = pReq->Open(bstrMethod, bstrUrl);
pReq->SetRequestHeader(_bstr_t("Content-Type"), _bstr_t("text/*"));
_variant_t vReq(pszReq);
hr = pReq->Send(vReq);
if (SUCCEEDED(hr))
{
_bstr_t bstrResp;
hr = pReq->get_ResponseText(&bstrResp.GetBSTR());
if (SUCCEEDED(hr))
{
std::cout << std::string(bstrResp) << "\n";
}
}
}
CoUninitialize();
}
Saving the output as html, gives this rendering of the response (which is what I expect, since I haven't provided any request data, which would usually include an access token).
This is the code (amended after comments below, and should be reproducible) that I am using to try and replicate this result using wininet.h and the low-level Win32 calls (I realize I haven't closed the handles).
#include <windows.h>
#include <WinInet.h>
#include <iostream>
int main()
{
const char* pszReq = "";
const char* pszUrl = "https://lite.realtime.nationalrail.co.uk/OpenLDBWS/ldb9.asmx";
char szHostName[256];
char szPath[256];
URL_COMPONENTSA comps = {};
comps.dwStructSize = sizeof(comps);
comps.lpszHostName = szHostName;
comps.dwHostNameLength = sizeof(szHostName);
comps.lpszUrlPath = szPath;
comps.dwUrlPathLength = sizeof(szPath);
if (!InternetCrackUrlA(pszUrl, strlen(pszUrl), 0, &comps)) return 1;
HINTERNET hOpen = InternetOpenA("XYZ",INTERNET_OPEN_TYPE_DIRECT,NULL,NULL,0);
if (!hOpen) return 1;
HINTERNET hConnect = InternetConnectA(hOpen,szHostName,comps.nPort,
NULL,NULL,INTERNET_SERVICE_HTTP,0,NULL);
if (!hConnect) return 1;
const char * rgpszAcceptTypes[] = { "text/*", NULL };
HINTERNET hOpenReq = HttpOpenRequestA(hConnect,"POST",szPath,NULL, NULL,
rgpszAcceptTypes, 0,NULL);
if (!hOpenReq) return 1;
const char* pszHeader = "Content-Type: text/xml;charset=UTF-8";
//*** This line returns FALSE ***
BOOL bRet = HttpSendRequestA(hOpenReq, pszHeader, strlen(pszHeader), (LPVOID)pszReq, strlen(pszReq));
//*** LastError is ERROR_HTTP_INVALID_SERVER_RESPONSE
DWORD dwErr = GetLastError();
return 0;
}
All the WinInet handles are non-zero, suggesting the calls are working, but the last HttpSendRequestA() is returning FALSE immediately, with LastError set to ERROR_HTTP_INVALID_SERVER_RESPONSE.
Clearly the COM route hides a lot of intermediate working, and presumably some constants are defaulted to specific values. It may also be adding other header information, I suppose.
Perhaps someone can suggest where I am going wrong?
There are some mistakes in your WinInet code:
the pszServerName value needs to be just the host name by itself, not a full URL. If you have a URL as input, you can parse it into its constituent pieces using InternetCrackUrlA().
the 3rd parameter of HttpOpenRequestA() is the requested resource relative to pszServerName. So, in your example, you need to use "/" to request the root resource.
the 1st parameter of HttpSendRequestA() needs to be hOpenReq, not hOpen. Also, you should not be including the null-terminators in your buffer sizes.
If you have not already done so, you should have a look at WinInet's documentation on HTTP Sessions.
With that said, try this:
#include <windows.h>
#include <WinInet.h>
#include <iostream>
const char * pszUrl = "https://someUrl";
const char * pszReq = "A string of request data";
const char* pszHeader = "Content-Type: text/xml;charset=UTF-8";
char szHostName[256];
char szPath[256];
URL_COMPONENTSA comps = {};
comps.dwStructSize = sizeof(comps);
comps.lpszHostName = szHostName;
comps.dwHostNameLength = sizeof(szHostName);
comps.lpszUrlPath = szPath;
comps.dwUrlPathLength = sizeof(szPath);
BOOL bRet = InternetCrackUrlA(pszUrl, strlen(pszUrl), 0, &comps);
if (!bRet) ...
HINTERNET hOpen = InternetOpenA("XYZ", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hOpen) ...
HINTERNET hConnect = InternetConnectA(hOpen, szHostName, comps.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, NULL);
if (!hConnect) ...
HINTERNET hOpenReq = HttpOpenRequestA(hConnect, "POST", szPath, NULL, NULL, NULL, comps.nScheme == INTERNET_SCHEME_HTTPS ? INTERNET_FLAG_SECURE : 0, NULL);
if (!hOpenReq) ...
bRet = HttpSendRequestA(hOpenReq, pszHeader, strlen(pszHeader), pszReq, strlen(pszReq));
if (!bRet) ...
...

How to make GET requests with WinInet for both HTTP and HTTPS? [duplicate]

I want to send HTTPS GET request using WinInet. As far as i know, i should do it just like sending HTTP request except i have to use INTERNET_DEFAULT_HTTPS_PORT and INTERNET_FLAG_SECURE flag.
So here is what i tried:
#include "stdafx.h"
#include <string>
#include <windows.h>
#include <WinInet.h>
#pragma comment (lib, "Wininet.lib")
using namespace std;
// convert string
wstring CharPToWstring(const char* _charP)
{
return wstring(_charP, _charP + strlen(_charP));
}
// send https request
wstring SendHTTPSRequest_GET(const wstring& _server,
const wstring& _page,
const wstring& _params = L"")
{
char szData[1024];
// initialize WinInet
HINTERNET hInternet = ::InternetOpen(TEXT("WinInet Test"), INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInternet != NULL)
{
// open HTTP session
HINTERNET hConnect = ::InternetConnect(hInternet, _server.c_str(), INTERNET_DEFAULT_HTTPS_PORT, NULL,NULL, INTERNET_SERVICE_HTTP, INTERNET_FLAG_SECURE, 1);
if (hConnect != NULL)
{
wstring request = _page +
(_params.empty() ? L"" : (L"?" + _params));
// open request
HINTERNET hRequest = ::HttpOpenRequest(hConnect, L"GET", (LPCWSTR)request.c_str() ,NULL, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION, 1);
if (hRequest != NULL)
{
// send request
BOOL isSend = ::HttpSendRequest(hRequest, NULL, 0, NULL, 0);
if (isSend)
{
for(;;)
{
// reading data
DWORD dwByteRead;
BOOL isRead = ::InternetReadFile(hRequest, szData, sizeof(szData) - 1, &dwByteRead);
// break cycle if error or end
if (isRead == FALSE || dwByteRead == 0)
break;
// saving result
szData[dwByteRead] = 0;
}
}
// close request
::InternetCloseHandle(hRequest);
}
// close session
::InternetCloseHandle(hConnect);
}
// close WinInet
::InternetCloseHandle(hInternet);
}
wstring answer = CharPToWstring(szData);
return answer;
}
int _tmain(int argc, _TCHAR* argv[])
{
wstring answer = SendHTTPSRequest_GET(L"www.site.com", L"page.php", L"param1=value1&param2=value2&param3=value3&param4=value4");
return 0;
}
And my function returned an answer:
<html>
<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<center>The plain HTTP request was sent to HTTPS port</center>
<hr><center>nginx/1.0.10</center>
</body>
</html>
What am i doing wrong?
INTERNET_FLAG_SECURE should be used in the flags for HttpOpenRequest, not InternetConnect.
This is explained in the MSDN documentation for WinINet API flags:
INTERNET_FLAG_SECURE
0x00800000
Uses secure transaction semantics. This translates to using Secure Sockets Layer/Private Communications Technology (SSL/PCT) and is only meaningful in HTTP requests. This flag is used by HttpOpenRequest and InternetOpenUrl, but this is redundant if https:// appears in the URL. The InternetConnect function uses this flag for HTTP connections; all the request handles created under this connection will inherit this flag.

C++ download file - if not available increasing RAM usage 1mb/s

my Code keeps filling the RAM, if it cant reach the file to download.(network disabled to test)
How can I stop downloading after timeout?
here is the main part for downloading:
int WINAPI WinMain(HINSTANCE instanceHandle, HINSTANCE, char*, int)
{
using namespace std;
std::wstring loadme = targetfolder;
loadme += L"\\filename.txt";
std::wstring url1(L"fileurl");
HRESULT hr1 = URLDownloadToFile(NULL, (url1.c_str()), (loadme.c_str()), 0, NULL); //Download-Start
}
You can use WinINet functions to check if internet is available, check if url link is available, and report progress. Needs "wininet.lib"
WinINet Reference
#include <windows.h>
#include <wininet.h>
#include <fstream>
void geturl(const wchar_t *url)
{
std::ofstream file("c:\\test\\test.htm");
HINTERNET hopen = InternetOpen(L"myAppName",INTERNET_OPEN_TYPE_PRECONFIG,NULL,NULL,0);
if (hopen)
{
HINTERNET hurl = InternetOpenUrl(hopen,url,NULL,0,INTERNET_FLAG_DONT_CACHE,0);
if (hurl)
{
DWORD received;
const int bufsize = 1024;
char buf[bufsize];
while (InternetReadFile(hurl, buf, bufsize, &received))
{
//progress...
if (!received) break;
file.write(buf, received);
}
InternetCloseHandle(hurl);
}
InternetCloseHandle(hopen);
}
}

How to use HTTP POST in C++ with Wininet

I am sending values of two variables using POST to the PHP server. The C++ application using Wininet connects to the server side script, but instead of sending the data correctly, it just shows empty fields in the parameters send using POST.
#include <windows.h> #include <wininet.h> #include <stdio.h> #include <fstream> #include <cstring>
#pragma comment (lib, "Wininet.lib")
#define SIZE 128
int main() {
HINTERNET Initialize, Connection, File;
DWORD dwBytes;
static const char *postData = "name=Jack+Din&age=38";
LPSTR accept1[2] = { "Accept: */*", NULL };
const char * const frmdata = "name=Arun+Pushkar&age=38";
static const char *hdrs[] = { "Content-Type: application/x-www-form-urlencoded" };
static const char *accept[] = { "*/*", NULL };
char ch;
Initialize = InternetOpen(L"HTTPGET", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!Initialize)
{
printf("Failed to open session\n");
exit(0);
}
Connection = InternetConnect(Initialize, L"192.168.1.10", INTERNET_DEFAULT_HTTP_PORT,
NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
File = HttpOpenRequest(
Connection,
L"POST",
L"/trydata.php",
L"HTTP/1.0",
NULL,
NULL,
INTERNET_FLAG_NO_CACHE_WRITE,
0);
unsigned long dataLen = strlen((char*)frmdata)+1;
bool res = HttpSendRequest(
File, // file to which reply will come
(LPCWSTR)hdrs,
0,
(char*)frmdata, // post variables to be send
dataLen); // length of data send
if (res)
{
std::ofstream webSource;
webSource.open("a.html");
while (InternetReadFile(File, &ch, 1, &dwBytes))
{
if (dwBytes != 1)break;
webSource << ch;
}
webSource.close();
}
InternetCloseHandle(File);
InternetCloseHandle(Connection);
InternetCloseHandle(Initialize);
return 0;
}
The server side script is
<?php
$yourname = isset($_POST['name']) ? $_POST['name'] : 'no name';
$yourage = isset($_POST['age']) ? $_POST['age'] : 'no age';
echo "Hello".htmlspecialchars($yourname). "!";
echo "Your Age".htmlspecialchars($yourage). "!";
?>
When I run this C++ code I get the following in my a.html:
Hello no Name!Your Age no Age!
I would use ATL Server classes to do the same. Here is the example:
CAtlHttpClient client;
AtlNavigateData navData;
LPCSTR lpData = "data=toto";
navData.SetMethod(ATL_HTTP_METHOD_POST);
navData.SetPostData((BYTE*)lpData, lstrlenA(lpData), _T("application/x-www-form-urlencoded"));
client.Navigate(_T("mysite.net"), _T("myscript.php"), &navData);
const char* pszBody = (const char*)client.GetBody();

POST form data using WinInet c++

I'm trying to make this program connect to a website and submit form data in order to login, but I don't know what I'm doing wrong. I have heard of others like curl and Winsock but I chose the WinINet library. So just for the testing of this program I've been using the website Pastebin to post to. So far, I haven't seen any results from this. If this program succeeds in posting the form data it will give me the header to the location of the post on their site.
Am I writing the form data char* correctly? I have seen on other stackoverflow posts where they had a large amount of dashes before some number then the put their form data.
Do I need to add something to it make it simulate clicking the submit button?
Do I need to write out values for each elements on the form?
I have tried HttpAddRequestHeaders and that didn't help me.
Also, I get the ERROR_INSUFFICIENT_BUFFER error on HttpOpenRequest but it still returns a valid HINTERNET.
#include <Windows.h>
#include <WinInet.h>
#include <iostream>
#pragma comment( lib,"Wininet.lib")
using namespace std;
char* getheaders(HINTERNET hRequest){
DWORD dwInfoLevel=HTTP_QUERY_RAW_HEADERS_CRLF;
DWORD dwInfoBufferLength=10;
char* pInfoBuffer=(char*)malloc(dwInfoBufferLength+1);
while(!HttpQueryInfo(hRequest,dwInfoLevel,pInfoBuffer,&dwInfoBufferLength,NULL)){
if (GetLastError()==ERROR_INSUFFICIENT_BUFFER){
free(pInfoBuffer);
pInfoBuffer=(char*)malloc(dwInfoBufferLength+1);
}else{
fprintf(stderr,"HttpQueryInfo failed, error = %d (0x%x)\n",GetLastError(),GetLastError());
break;
}
}
pInfoBuffer[dwInfoBufferLength] = '\0';
return pInfoBuffer;
}
void readfile(HINTERNET hRequest,char** buffs,int size){
DWORD dwBytesAvailable;
DWORD dwBytesRead;
for(int i=0;i<size;i++){
if(!InternetQueryDataAvailable(hRequest,&dwBytesAvailable,0,0)) break;
buffs[i]=(char*)malloc(dwBytesAvailable+1);
bool bResult=InternetReadFile(hRequest,buffs[i],dwBytesAvailable,&dwBytesRead);
if(!bResult | dwBytesRead==0) break;
}
}
int main(int argc,char** argv){
char* hdrs="Content-Type: application/x-www-form-urlencoded";
char* frmdata="paste_code=test";
LPCSTR accept[2]={"*/*", NULL};
HINTERNET hSession = InternetOpen("http generic",INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hSession, "www.pastebin.com",INTERNET_DEFAULT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = HttpOpenRequest(hConnect, "GET","/", NULL, NULL, accept, 0, 0);
//ERROR_INSUFFICIENT_BUFFER (122) with "accept".
bool send=HttpSendRequest(hRequest, hdrs, strlen(hdrs), NULL,NULL);
if(!send){
printf("HttpSendRequest failed, code=%d",GetLastError());
system("pause>nul");
return 0;
}
char* heads=getheaders(hRequest);
printf("%s\n\n\n\n",heads);
HINTERNET hRequest2 = HttpOpenRequest(hConnect, "POST","/", NULL, NULL, accept, 0, 0);
//ERROR_INSUFFICIENT_BUFFER (122) with "accept".
send=HttpSendRequest(hRequest2, hdrs, strlen(hdrs), frmdata,strlen(frmdata));
if(!send){
printf("HttpSendRequest failed, code=%d",GetLastError());
system("pause>nul");
return 0;
}
heads=getheaders(hRequest);
printf("%s\n\n\n\n",heads);
InternetCloseHandle(hRequest);
InternetCloseHandle(hRequest2);
InternetCloseHandle(hConnect);
InternetCloseHandle(hSession);
system("pause>nul");
return 0;
}
Your code is nearly correct, you must make sure of the following points:
char* hdrs="Content-Type: application/x-www-form-urlencoded";
you must make sure that your return object from POST message will be of type x-www-form-urlencoded or JSON . if it's JSON you
need to define char* hdrs="Content-Type: application/json\r\n";
Note: you must append \r\n to the hdrs.
try to call readFile method with buffer of size 10000 for example
and print buffer , it will print the output of the response to the
connection
In HINTERNET hRequest2 = HttpOpenRequest(hConnect, "POST","/", NULL, NULL, accept, 0, 0); instead of "/" you must call the path of
the requested API for example: .
In HINTERNET hRequest2 = HttpOpenRequest(hConnect, "POST", "/users/jsonlogin", NULL, NULL, accept, 0, 0);