I have some API URL that returns JSON data like this:
{"data":[{"id":"1","param":"value1"},{"id":"2","param":"value2"}, ... {"id":"N","param":"valueN"}]}
Every id should be unique.
When i'm requesting this API URL through browser (Firefox or Chrome) it returns valid data, i.e. every id is unique and non of the parts of data is duplicated.
But when i'm requesting this API URL through my own function based on WinInet it duplicates some parts of data. It still is valid JSON, but some of id's are duplicated and some of them not. Just like this:
{"data":[{"id":"1","param":"value1"},{"id":"1","param":"value1"},{"id":"2","param":"value2"},{"id":"3","param":"value3"},{"id":"3","param":"value3"} ... {"id":"N","param":"valueN"}]}
I'm using GET method. Here is my WinInet function:
using namespace std;
enum EMethod {M_UNKNOWN, M_POST, M_GET, M_DELETE};
enum EProtocol {P_UNKNOWN, P_HTTP, P_HTTPS};
// |example:|
/*
string responce = SendInetRequest(
P_HTTPS, M_GET, "www.site.com", "page.php", "param1=val1¶m2=val2");
*/
string SendInetRequest(const EProtocol _eProtocol,
const EMethod _eMethod,
const string& _server,
const string& _page,
const string& _params = "")
{
char szData[1024];
string recvStr;
// initialize WinInet
HINTERNET hInternet = ::InternetOpenA("WinInet Test",
INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInternet != NULL)
{
INTERNET_PORT port = NULL;
DWORD flags = NULL;
switch (_eProtocol)
{
case P_HTTP:
port = INTERNET_DEFAULT_HTTP_PORT;
flags = /*INTERNET_FLAG_KEEP_CONNECTION*/
INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_PRAGMA_NOCACHE;
break;
case P_HTTPS:
port = INTERNET_DEFAULT_HTTPS_PORT;
flags = INTERNET_FLAG_SECURE |
INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_PRAGMA_NOCACHE;
break;
default:
return NULL;
}
// open HTTP session
HINTERNET hConnect = ::InternetConnectA(hInternet,
_server.c_str(), port, NULL,NULL, INTERNET_SERVICE_HTTP, 0, 1);
if (hConnect != NULL)
{
string request;
string method;
string headers;
string data;
switch (_eMethod)
{
case M_GET:
method = "GET";
request = _page +
(_params.empty() ? "" : ("?" + _params));
break;
case M_POST:
method = "POST";
request = _page;
headers = "Content-Type: application/x-www-form-urlencoded";
data = _params.empty() ? "" : _params;
break;
case M_DELETE:
method = "DELETE";
request = _page +
(_params.empty() ? "" : ("?" + _params));
break;
default:
return NULL;
}
// open request
HINTERNET hRequest = ::HttpOpenRequestA(hConnect, method.c_str(),
(LPCSTR)request.c_str() ,NULL, NULL, 0, flags, 1);
if (hRequest != NULL)
{
// send request
BOOL isSend = ::HttpSendRequestA(hRequest, headers.c_str(),
headers.length(), (LPVOID)data.c_str(), data.length());
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
recvStr.append(szData, dwByteRead);
szData[dwByteRead] = 0;
}
}
// close request
::InternetCloseHandle(hRequest);
}
// close session
::InternetCloseHandle(hConnect);
}
// close WinInet
::InternetCloseHandle(hInternet);
}
return recvStr;
}
So what is wrong with my function? Why does it duplicate some parts of responce JSON data unlike normal browsers?
You need to add the null terminator byte to szData before you append it to recvStr, so that you only append the data that was just received.
// saving result
szData[dwByteRead] = 0;
recvStr.append(szData, dwByteRead);
Related
I'm trying to send message to telegram chat from bot using winapi and c++.
Here is my code
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, L"api.telegram.org", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, 1);
if (hConnect != NULL)
{
wstring request = L"/bot<bot_id>/sendMessage";
// open request
HINTERNET hRequest = ::HttpOpenRequest(hConnect, L"GET", (LPCWSTR)request.c_str(), NULL, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE, 1);
if (hRequest != NULL)
{
// send request
const wchar_t* params = L"?chat_id=<chat_id>&text=test";
BOOL isSend = ::HttpSendRequest(hRequest, NULL, 0, (LPVOID)params, wcslen(params));
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;
But I've got {"ok":false,"error_code":400,"description":"Bad Request: message text is empty"} response. <chat_id> is id consisted of digits(12345678).
If I run this request in postman or in browser - then everything is ok.
I also tried to run this request using WinHttp* methods and result is the same.
What should I change in my request parameters to make it work?
There are a number of issues with this code:
You don't need to typecast the return value of wstring::c_str() to LPCWSTR (aka const wchar_t*), as it is already that type.
You can't send body data in a GET request. The Telegram Bot API expects body data to be sent in a POST request instead.
You are telling HttpSendRequest() to send body data from a wchar_t* UTF-16 string, but that is not the correct encoding that the server is expecting. You need to use a char* UTF-8 string instead.
You are not sending a Content-Type request header to tell the server what the format of the body data is. The API supports several different formats. In this case, since you are sending the data in application/x-www-form-urlencoded format, you need to add a Content-Type: application/x-www-form-urlencoded header to the request.
With all of that said, try this instead:
// initialize WinInet
HINTERNET hInternet = ::InternetOpenW(L"WinInet Test", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInternet == NULL) ... // error handling
// open HTTP session
HINTERNET hConnect = ::InternetConnectW(hInternet, L"api.telegram.org", INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, NULL, 1);
if (hConnect == NULL) ... // error handling
// open request
wstring wsResource = L"/bot<bot_id>/sendMessage";
HINTERNET hRequest = ::HttpOpenRequestW(hConnect, L"POST", wsResource.c_str(), NULL, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION | INTERNET_FLAG_SECURE, 1);
if (hRequest == NULL) ... // error handling
// send request
string sBody = u8"chat_id=<chat_id>&text=test";
BOOL isSend = ::HttpSendRequestW(hRequest, L"Content-Type: application/x-www-form-urlencoded", -1L, sBody.c_str(), sBody.size());
if (!isSend) ... // error handling
string sReply;
char szData[1024];
DWORD dwByteRead;
while (::InternetReadFile(hRequest, szData, sizeof(szData), &dwByteRead) && dwByteRead != 0)
{
// saving result
sReply.append(szData, dwByteRead);
}
...
// use sReply as needed ...
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 am trying to retrieve the source code of a web page using WinHTTP. Reading from this page: http://msdn.microsoft.com/en-us/library/windows/desktop/aa384110(v=vs.85).aspx
I was able to come up with this code. The HTTP status code is 200 which means the request was completed correctly. I end up getting the source code for the login page instead of my intended web page behind it.
Should I send a httprequest to the login page and then to the file path?
Here is the code:
#include <windows.h>
#include <winhttp.h>
#include <string>
#include <stdio.h>
#include <iostream>
#include <fstream>
using namespace std;
#pragma comment(lib, "winhttp.lib")
DWORD ChooseAuthScheme(DWORD dwSupportedSchemes)
{
// It is the server's responsibility only to accept
// authentication schemes that provide a sufficient
// level of security to protect the servers resources.
//
// The client is also obligated only to use an authentication
// scheme that adequately protects its username and password.
//
// Thus, this sample code does not use Basic authentication
// becaus Basic authentication exposes the client's username
// and password to anyone monitoring the connection.
if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NEGOTIATE)
return WINHTTP_AUTH_SCHEME_NEGOTIATE;
else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_NTLM)
return WINHTTP_AUTH_SCHEME_NTLM;
else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_PASSPORT)
return WINHTTP_AUTH_SCHEME_PASSPORT;
else if (dwSupportedSchemes & WINHTTP_AUTH_SCHEME_DIGEST)
return WINHTTP_AUTH_SCHEME_DIGEST;
else
return 0;
}
struct SWinHttpSampleGet
{
LPCWSTR szServer;
LPCWSTR szPath;
BOOL fUseSSL;
LPCWSTR szServerUsername;
LPCWSTR szServerPassword;
LPCWSTR szProxyUsername;
LPCWSTR szProxyPassword;
};
void WinHttpAuthSample(IN SWinHttpSampleGet *pGetRequest)
{
string contents;
DWORD dwStatusCode = 0;
DWORD dwSupportedSchemes;
DWORD dwFirstScheme;
DWORD dwSelectedScheme;
DWORD dwTarget;
DWORD dwLastStatus = 0;
DWORD dwSize = sizeof(DWORD);
BOOL bResults = FALSE;
BOOL bDone = FALSE;
DWORD dwProxyAuthScheme = 0;
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
// Use WinHttpOpen to obtain a session handle.
hSession = WinHttpOpen(L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
INTERNET_PORT nPort = (pGetRequest->fUseSSL) ?
INTERNET_DEFAULT_HTTPS_PORT :
INTERNET_DEFAULT_HTTP_PORT;
// Specify an HTTP server.
if (hSession)
hConnect = WinHttpConnect(hSession,
pGetRequest->szServer,
nPort, 0);
// Create an HTTP request handle.
if (hConnect)
hRequest = WinHttpOpenRequest(hConnect,
L"GET",
pGetRequest->szPath,
NULL,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
(pGetRequest->fUseSSL) ?
WINHTTP_FLAG_SECURE : 0);
// Continue to send a request until status code
// is not 401 or 407.
if (hRequest == NULL)
bDone = TRUE;
while (!bDone)
{
// If a proxy authentication challenge was responded to, reset
// those credentials before each SendRequest, because the proxy
// may require re-authentication after responding to a 401 or
// to a redirect. If you don't, you can get into a
// 407-401-407-401- loop.
if (dwProxyAuthScheme != 0)
bResults = WinHttpSetCredentials(hRequest,
WINHTTP_AUTH_TARGET_PROXY,
dwProxyAuthScheme,
pGetRequest->szProxyUsername,
pGetRequest->szProxyPassword,
NULL);
// Send a request.
bResults = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
WINHTTP_NO_REQUEST_DATA,
0,
0,
0);
// End the request.
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
// Resend the request in case of
// ERROR_WINHTTP_RESEND_REQUEST error.
if (!bResults && GetLastError() == ERROR_WINHTTP_RESEND_REQUEST)
continue;
// Check the status code.
if (bResults)
bResults = WinHttpQueryHeaders(hRequest,
WINHTTP_QUERY_STATUS_CODE |
WINHTTP_QUERY_FLAG_NUMBER,
NULL,
&dwStatusCode,
&dwSize,
NULL);
DWORD dwSize = 0;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
if (bResults)
{
switch (dwStatusCode)
{
case 200:
// The resource was successfully retrieved.
// You can use WinHttpReadData to read the
// contents of the server's response.
printf("The resource was successfully retrieved.\n");
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
{
printf("Error %u in WinHttpQueryDataAvailable.\n",
GetLastError());
break;
}
// No more available data.
if (!dwSize)
break;
// Allocate space for the buffer.
pszOutBuffer = new char[dwSize + 1];
if (!pszOutBuffer)
{
printf("Out of memory\n");
break;
}
// Read the Data.
ZeroMemory(pszOutBuffer, dwSize + 1);
if (!WinHttpReadData(hRequest, (LPVOID)pszOutBuffer,
dwSize, &dwDownloaded))
{
printf("Error %u in WinHttpReadData.\n", GetLastError());
}
else
{
printf("%s", pszOutBuffer);
contents += pszOutBuffer;
}
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
// This condition should never be reached since WinHttpQueryDataAvailable
// reported that there are bits to read.
if (!dwDownloaded)
break;
} while (dwSize > 0);
bDone = true;
break;
case 401:
// The server requires authentication.
printf(" The server requires authentication. Sending credentials...\n");
// Obtain the supported and preferred schemes.
bResults = WinHttpQueryAuthSchemes(hRequest,
&dwSupportedSchemes,
&dwFirstScheme,
&dwTarget);
// Set the credentials before resending the request.
if (bResults)
{
dwSelectedScheme = ChooseAuthScheme(dwSupportedSchemes);
if (dwSelectedScheme == 0)
bDone = TRUE;
else
bResults = WinHttpSetCredentials(hRequest,
dwTarget,
dwSelectedScheme,
pGetRequest->szServerUsername,
pGetRequest->szServerPassword,
NULL);
}
// If the same credentials are requested twice, abort the
// request. For simplicity, this sample does not check
// for a repeated sequence of status codes.
if (dwLastStatus == 401)
bDone = TRUE;
break;
case 407:
// The proxy requires authentication.
printf("The proxy requires authentication. Sending credentials...\n");
// Obtain the supported and preferred schemes.
bResults = WinHttpQueryAuthSchemes(hRequest,
&dwSupportedSchemes,
&dwFirstScheme,
&dwTarget);
// Set the credentials before resending the request.
if (bResults)
dwProxyAuthScheme = ChooseAuthScheme(dwSupportedSchemes);
// If the same credentials are requested twice, abort the
// request. For simplicity, this sample does not check
// for a repeated sequence of status codes.
if (dwLastStatus == 407)
bDone = TRUE;
break;
default:
// The status code does not indicate success.
printf("Error. Status code %d returned.\n", dwStatusCode);
bDone = TRUE;
}
}
// Keep track of the last status code.
dwLastStatus = dwStatusCode;
// If there are any errors, break out of the loop.
if (!bResults)
bDone = TRUE;
}
// Report any errors.
if (!bResults)
{
DWORD dwLastError = GetLastError();
printf("Error %d has occurred.\n", dwLastError);
}
ofstream fout("Output.txt");
fout << contents;
fout.close();
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
}
int main()
{
wstring Server = L"moodle.redlands.edu";
wstring Path = L"/course/view.php?id=2213/";
wstring User = L"test";
wstring Pass = L"password";
wstring User_Proxy = L"test";
wstring Pass_Proxy = L"password";
SWinHttpSampleGet Lawl{
Server.c_str(),
Path.c_str(),
1,
User.c_str(),
Pass.c_str(),
User_Proxy.c_str(), Pass_Proxy.c_str()
};
WinHttpAuthSample(&Lawl);
system("PAUSE");
return 0;
}
I'm struggling how must I add the response from a TSA server to my CryptSignMessage?
Using PKCS#7. I currently have my message digest and I successfully sign it with CryptSignMessage from crypto api. Like so:
// Initialize the signature structure.
CRYPT_SIGN_MESSAGE_PARA SigParams;
SigParams.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
SigParams.dwMsgEncodingType = MY_ENCODING_TYPE;
SigParams.pSigningCert = hContext;
SigParams.HashAlgorithm.pszObjId = szOID_RSA_SHA1RSA;
SigParams.HashAlgorithm.Parameters.cbData = NULL;
SigParams.cMsgCert = 1;
SigParams.rgpMsgCert = &hContext;
SigParams.dwInnerContentType = 0;
SigParams.cMsgCrl = 0;
SigParams.cUnauthAttr = 0;
SigParams.dwFlags = 0;
SigParams.pvHashAuxInfo = NULL;
SigParams.cAuthAttr = 0;
SigParams.rgAuthAttr = NULL;
// First, get the size of the signed BLOB.
if(CryptSignMessage(
&SigParams,
FALSE,
1,
MessageArray,
MessageSizeArray,
NULL,
&cbSignedMessageBlob))
{
printf("%d bytes needed for the encoded BLOB.", cbSignedMessageBlob);
}
else
{
MyHandleError();
fReturn = false;
exit_SignMessage();
}
// Allocate memory for the signed BLOB.
if(!(pbSignedMessageBlob =
(BYTE*)malloc(cbSignedMessageBlob)))
{
MyHandleError();
exit_SignMessage();
}
// Get the signed message BLOB.
if(CryptSignMessage(
&SigParams,
TRUE,
1,
MessageArray,
MessageSizeArray,
pbSignedMessageBlob,
&cbSignedMessageBlob))
{
printf("The message was signed successfully. \n");
// pbSignedMessageBlob now contains the signed BLOB.
fReturn = true;
}
else
{
MyHandleError();
fReturn = false;
exit_SignMessage();
}
Now I want to use a TSA server to timestamp my digest, but I'm not really sure how to include this. Say I have a rfc3161 TimeStamp request; I send this to my TSA and I receive a rfc3161 TimeStamp response (probably using libcurl). How should incorporate the response into my SigParams? Must I extract the TimeStampToken and then store that as an unauthenticated counter signature? Something like:
CRYPT_ATTR_BLOB cablob[1];
CRYPT_ATTRIBUTE ca[1];
cablob[0].cbData = tstResponseSize;
cablob[0].pbData = tstResponse; // the response from TSA
ca[0].pszObjId = "1.2.840.113549.9.6"; // object identifier for counter signature
ca[0].cValue = 1;
ca[0].rgValue = cablob;
And then set the SigParams:
SigParams.cUnauthAtt = 1;
SigParams.rgUnauthAttr = ca;
Any advice would be greatly appreciated.
Thanks,
Magda
I struggled with this for a couple of days. There are not that many examples out there, so here is my solution. Hope it helps :)
HCRYPTMSG hMsg = ::CryptMsgOpenToDecode(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, CMSG_DETACHED_FLAG, 0, NULL, NULL, NULL);
if (NULL == hMsg)
{
throw std::exception("Failed to open messsage to decode");
}
if (!::CryptMsgUpdate(hMsg, signedData.pbData, signedData.cbData, TRUE))
{
throw std::exception("Failed to add signature block to message");
}
//get the digest from the signature
PCRYPT_TIMESTAMP_CONTEXT pTsContext = NULL;
DWORD encDigestSize = 0;
if (::CryptMsgGetParam(hMsg, CMSG_ENCRYPTED_DIGEST, 0, NULL, &encDigestSize))
{
std::unique_ptr<BYTE> pEncDigest(new BYTE[encDigestSize]);
if (::CryptMsgGetParam(hMsg, CMSG_ENCRYPTED_DIGEST, 0, pEncDigest.get(), &encDigestSize))
{
//get timestamp
if (::CryptRetrieveTimeStamp(L"http://sha256timestamp.ws.symantec.com/sha256/timestamp",
TIMESTAMP_NO_AUTH_RETRIEVAL,
0, //timeout?????
szOID_NIST_sha256,
NULL,
pEncDigest.get(),
encDigestSize,
&pTsContext,
NULL,
NULL))
{
CRYPT_ATTR_BLOB cryptBlob = {};
cryptBlob.cbData = pTsContext->cbEncoded;
cryptBlob.pbData = pTsContext->pbEncoded;
CRYPT_ATTRIBUTE cryptAttribute = {};
cryptAttribute.pszObjId = "1.2.840.113549.1.9.16.2.14"; //id-smime-aa-timeStampToken
cryptAttribute.cValue = 1;
cryptAttribute.rgValue = &cryptBlob;
DWORD encodedAttributeSize = 0;
std::unique_ptr<BYTE> encodedAttribute;
if (::CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_ATTRIBUTE, &cryptAttribute, NULL, &encodedAttributeSize))
{
encodedAttribute.reset(new BYTE[encodedAttributeSize]);
if (::CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS_ATTRIBUTE, &cryptAttribute, encodedAttribute.get(), &encodedAttributeSize))
{
CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA unauthenticatedParam = { 0 };
unauthenticatedParam.cbSize = sizeof(unauthenticatedParam);
unauthenticatedParam.dwSignerIndex = 0; //only have 1 cert
unauthenticatedParam.blob.cbData = encodedAttributeSize;
unauthenticatedParam.blob.pbData = encodedAttribute.get();
if (::CryptMsgControl(hMsg, 0, CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, &unauthenticatedParam))
{
DWORD encodedMessageLength = 0;
if (::CryptMsgGetParam(hMsg, CMSG_ENCODED_MESSAGE, 0, NULL, &encodedMessageLength))
{
std::unique_ptr<BYTE> pData(new BYTE[encodedMessageLength]);
if (::CryptMsgGetParam(hMsg, CMSG_ENCODED_MESSAGE, 0, pData.get(), &encodedMessageLength))
{
//save pData/encodedMessageLength here to file
}
}
}
}
}
}
}
}
if (NULL != pTsContext)
{
::CryptMemFree(pTsContext);
}
if (NULL != hMsg)
{
::CryptMsgClose(hMsg);
}
Hey all i want to login onto my works webpage with wininet, this is my current code:
int main()
{
HINTERNET hInet = InternetOpenA("UserAgent/1.0", INTERNET_OPEN_TYPE_PRECONFIG,0, 0, 0 );
if(!hInet)
{
printf("hInet Failed!\n");
return -1;
}
HINTERNET hConnection = InternetConnectA( hInet,"app.tamigo.com",INTERNET_DEFAULT_HTTPS_PORT,"","", INTERNET_SERVICE_HTTP,0,0);
if (!hConnection)
{
InternetCloseHandle(hInet);
printf("InternetConnectA failed!\n");
return -1;
}
HINTERNET hRequest = HttpOpenRequestA( hConnection, "Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",NULL,"https://app.tamigo.com/Home/Pages/Login.aspx", NULL, INTERNET_FLAG_KEEP_CONNECTION, 0 );
if (!hRequest)
{
printf("BuildRequestHeader failed %d!\n",GetLastError());
InternetCloseHandle(hConnection);
InternetCloseHandle(hInet);
return -1;
}
HttpSendRequestA(hRequest, NULL, 0, NULL, 0);
DWORD dwInfoLevel = HTTP_QUERY_RAW_HEADERS_CRLF;
DWORD dwInfoBufferLength = 10;
BYTE *pInfoBuffer = (BYTE *)malloc(dwInfoBufferLength+1);
while (!HttpQueryInfo(hRequest, dwInfoLevel, pInfoBuffer, &dwInfoBufferLength, NULL))
{
DWORD dwError = GetLastError();
if (dwError == ERROR_INSUFFICIENT_BUFFER)
{
free(pInfoBuffer);
pInfoBuffer = (BYTE *)malloc(dwInfoBufferLength+1);
}
else
{
fprintf(stderr, "HttpQueryInfo failed, error = %d (0x%x)\n",
GetLastError(), GetLastError());
break;
}
}
pInfoBuffer[dwInfoBufferLength] = '\0';
printf("%s", pInfoBuffer);
free(pInfoBuffer);
cin.get();
return 1;
}
if this code is right, i have to login with my username and pass,i got a cookie using "Firefox plugin Tamper Data". How can i set this cookie with wininet?
Thanks alot for reading and for your time
If the cookie already exists from a previous WinInet request, then WinInet will send it automatically. However, if the cookie does not exist in WinInet's cookie cache (if instance, if you got the cookie from another source), then you will have to use HttpAddRequestHeaders() to provide your own Cookie: request header before calling HttpSendRequest().