Getting encrypted body response WinHttp HTTPS - c++

I'm trying to connect with google.com with port 443 SSL but when i call to WinHttpReadData returns encrypted text, but with WinHttpQueryHeaders i'm getting plain/text response headers from server.
Not sure at all why happens that, im referring to Headers no encrypted and Body yes, my objective is get the response body decrypted.
The source is here:
// ConsoleApplication3.cpp : Este archivo contiene la función "main". La ejecución del programa comienza y termina ahí.
//
#include "pch.h"
#include <windows.h>
#include <winhttp.h>
#include <iostream>
#include <string>
#include <algorithm>
int main(){
DWORD dwSize = 2000;
DWORD dwDownloaded = 0;
LPSTR pszOutBuffer;
DWORD headerSize = 0;
char * lpOutBuffer = new char[dwSize / sizeof(char)];
HINTERNET hSession = NULL;
HINTERNET hConnect = NULL;
HINTERNET 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);
// Specify an HTTP server.
if (hSession)
hConnect = WinHttpConnect(hSession, L"google.com",
443, 0); //443 port for SSL/TLS
std::cout << "hConnect " << hConnect << std::endl;
// Create an HTTP request handle.
if (hConnect)
hRequest = WinHttpOpenRequest(hConnect, L"GET", L"/",
L"HTTP/1.1", WINHTTP_NO_REFERER,
NULL,
WINHTTP_FLAG_SECURE); //SECURE FLAG
std::cout << "hRequest " << hRequest << std::endl;
if (hRequest) { //Adding Headers
std::cout << "Añadiendo headers!\n";
WinHttpAddRequestHeaders(hRequest,
L"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
-1L,
WINHTTP_ADDREQ_FLAG_ADD);
WinHttpAddRequestHeaders(hRequest,
L"Accept-Encoding: gzip, deflate, br",
-1L,
WINHTTP_ADDREQ_FLAG_ADD);
WinHttpAddRequestHeaders(hRequest,
L"Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3",
-1L,
WINHTTP_ADDREQ_FLAG_ADD);
WinHttpAddRequestHeaders(hRequest,
L"Connection: keep-alive",
-1L,
WINHTTP_ADDREQ_FLAG_ADD);
WinHttpAddRequestHeaders(hRequest,
L"Host: google.com",
-1L,
WINHTTP_ADDREQ_FLAG_ADD);
WinHttpAddRequestHeaders(hRequest,
L"Upgrade-Insecure-Requests: 1",
-1L,
WINHTTP_ADDREQ_FLAG_ADD);
WinHttpAddRequestHeaders(hRequest,
L"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:76.0) Gecko/20100101 Firefox/76.0",
-1L,
WINHTTP_ADDREQ_FLAG_ADD);
}
// Send a request.
BOOL bResults;
if (hRequest)
bResults = WinHttpSendRequest(hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0,
0, 0);
std::cout << "bResults " << bResults << " " << GetLastError() << std::endl;
if (bResults)
bResults = WinHttpReceiveResponse(hRequest, NULL);
std::cout << "bResults " << bResults << " " << GetLastError() << std::endl;
if (bResults)
{
WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS,
WINHTTP_HEADER_NAME_BY_INDEX, NULL,
&dwSize, WINHTTP_NO_HEADER_INDEX);
printf("Tamaño de los headers: %d", dwSize);
// Allocate memory for the buffer.
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
lpOutBuffer = new char[dwSize / sizeof(char)];
// Now, use WinHttpQueryHeaders to retrieve the header.
bResults = WinHttpQueryHeaders(hRequest, WINHTTP_QUERY_RAW_HEADERS,
WINHTTP_HEADER_NAME_BY_INDEX,
lpOutBuffer, &dwSize,
WINHTTP_NO_HEADER_INDEX);
if (bResults){
char * headers_aqui = new char[dwSize / sizeof(char)];
int dwSize2 = 0;
for (int i = 0,i2 = 0; i < dwSize; i++) {
//std::cout << (int)str[i] << std::endl;
if ((int)lpOutBuffer[i] != 0) {
headers_aqui[i2] = lpOutBuffer[i];
dwSize2 = i2;
i2++;
}
}
std::cout << "Tamaño ahora: " << dwSize2 << std::endl;
std::string str(headers_aqui, dwSize2);
std::cout << "Header contents: \n" << str << "\n\n\n\n\n"; //No encrypted or compressed.
}
}
}
if (bResults)
{
do
{
// Check for available data.
dwSize = 0;
if (!WinHttpQueryDataAvailable(hRequest, &dwSize))
printf("Error %u 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))
printf("Error %u in WinHttpReadData.\n", GetLastError());
else
printf("%s", pszOutBuffer); //Encrypted or compressed, think SSL encryption.
// Free the memory allocated to the buffer.
delete[] pszOutBuffer;
}
} while (dwSize > 0);
}
// Report any errors.
if (!bResults)
printf("Error %d has occurred.\n", GetLastError());
// Close any open handles.
if (hRequest) WinHttpCloseHandle(hRequest);
if (hConnect) WinHttpCloseHandle(hConnect);
if (hSession) WinHttpCloseHandle(hSession);
//std::cout << "Hello World!\n";
}
Output here: https://pastebin.com/cSkEugDT
I read the documentation but don't find anything about decryption of content in WinHttpReadData, obviously this happens only with https, when i test http it's return plain/text.
I suspect about some parameter to before calls to WinHttpReadData.

Finally i get the mistake, this was on header Accept-Encoding
WinHttpAddRequestHeaders(hRequest,
L"Accept-Encoding: gzip, deflate, br",
-1L,
WINHTTP_ADDREQ_FLAG_ADD);
I commented and fix the issue. GZIP is a compression algorithm whos made this compressed text (deflate and br another algorithms with same purpose).
About Accept-Encoding header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Encoding

Related

Issues sending HTTP requests to the discord api using Winsock2.h C++

I have been digging for a while to see if I can find any fixes for this but I have seemed to hit a wall.
At this point, I am not sure what the issue is. Every other host I have tried has worked except for discord.
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
cout << "WSAStartup failed.\n";
system("pause");
return 1;
}
SOCKET Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct hostent* host;
host = gethostbyname("discordapp.com");
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(80);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
cout << "Connecting...\n";
if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0) {
cout << "Could not connect";
system("pause");
return 1;
}
cout << "Connected.\n";
send(Socket, "GET /api/ HTTP/1.1\r\nHost: discordapp.com\r\nConnection: close\r\n\r\n", strlen("GET /api/ HTTP/1.1\r\nHost: discordapp.com\r\nConnection: close\r\n\r\n"), 0);
char buffer[10000];
int nDataLength;
while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0) {
int i = 0;
while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
cout << buffer[i];
i += 1;
}
}
closesocket(Socket);
WSACleanup();
system("pause");
return 0;
I keep getting this response no matter what I try:
HTTP/1.1 301 Moved Permanently
Date: Mon, 10 Feb 2020 21:16:57 GMT
Transfer-Encoding: chunked
Connection: close
Cache-Control: max-age=3600
Expires: Mon, 10 Feb 2020 22:16:57 GMT
Location: https://discordapp.com/api/
Set-Cookie: __cfruid=17e1ccd526aa851f5d5563850c5793a999f859c0-1581369417; path=/; domain=.discordapp.com; HttpOnly
Server: cloudflare
CF-RAY: 56311b6b0baba67b-DUB`
Is there something I am missing? The ultimate goal is to be able to post to a webhook using the api.
You are connecting to port 80 making a plain (unencrypted) HTTP GET request.
The server replies with an HTTP redirect to https://discordapp.com/api/ i.e. switching protocols to secure HTTP (HTTPS).
Apparently the server is not allowing unencrypted traffic. You could try establishing a secure HTTP connection by connecting to port 443 and performing a TLS handshake and validating the server certificate (e.g. using schannel), but that wouldn't be productive. Even if successful, you'll have to additionally implement HTTP 1.1 chunked transfer-encoding and other protocol specifics (most of which you could skip by sending an HTTP/1.0 request, by that's not the point).
The point is, use a proper HTTP client library for making HTTP calls. Windows has a built-in one called WinInet.
For example, like this
#include <windows.h>
#include <wininet.h>
#include <iostream>
#pragma comment(lib, "wininet.lib")
int fail(const char* fmt, ...);
int main() {
HANDLE ih = InternetOpenA("Mozilla/4.0 (compatible)", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (!ih) return fail("InternetOpen failed");
HINTERNET ch = InternetConnectA(ih, "discordapp.com", 443, NULL, NULL,
INTERNET_SERVICE_HTTP, 0, 0);
if (!ch) return fail("InternetConnect failed");
const char* acceptTypes[] = { "*/*", NULL };
HINTERNET req = HttpOpenRequestA(ch, NULL, "/api/", NULL, NULL, acceptTypes,
INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_UI, 0);
if (!req) return fail("HttpOpenRequest failed");
if (!HttpSendRequestA(req, NULL, 0, NULL, 0)) return fail("HttpSendRequest failed");
char buffer[4096];
DWORD n;
while (InternetReadFile(req, &buffer, 1, &n)) {
if (n == 0)
break;
std::cout.write(buffer, n);
}
std::cout << std::endl;
InternetCloseHandle(ch);
InternetCloseHandle(req);
InternetCloseHandle(ih);
return 0;
}
// helper function for printing the error message
int fail(const char* fmt, ...) {
DWORD lastError = GetLastError();
LPSTR lpMsgBuf = nullptr;
if (lastError)
FormatMessageA(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle("wininet.dll"), lastError,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&lpMsgBuf, 0, NULL);
va_list va;
va_start(va, fmt);
char buf[1024];
_vsnprintf(buf, sizeof(buf), fmt, va);
va_end(va);
buf[1023] = 0;
std::string msg = buf;
if (lpMsgBuf) {
msg += ": ";
auto len = strlen(lpMsgBuf);
while (len && (lpMsgBuf[len - 1] == '\r' || lpMsgBuf[len - 1] == '\n'))
lpMsgBuf[--len] = 0;
msg += lpMsgBuf;
LocalFree(lpMsgBuf);
}
std::cerr << msg << std::endl;
return 1;
}

HTTP POST request via Wininet

In VC++, I am trying to send an HTTP POST request and get its response.
I have the below code, which compiles successfully, yet fails to POST.
First I try to send the POST request to the request bin for testing purpose
int main(int argc, _TCHAR* argv[])
{
static CHAR hdrs[] = "Content-Type: application/x-www-form-urlencoded";
static CHAR frmdata[] = "name=John+Doe&userid=hithere&other=P%26Q";
HINTERNET hSession = InternetOpenA("MyAgent", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
HINTERNET hConnect = InternetConnect(hSession "pipedream.com", 8733, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 1);
HINTERNET hRequest = HttpOpenRequestA(hConnect, "POST", "/r/enj77inn26shk", NULL, NULL, NULL, 0, 1);
HttpSendRequestA(hRequest, hdrs, strlen(hdrs), frmdata, strlen(frmdata));
Then read the response using
DWORD dwContentLen;
DWORD dwBufLen = sizeof(dwContentLen);
if (HttpQueryInfo(hRequest,
HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
(LPVOID)&dwContentLen,
&dwBufLen,
0))
{
char *pData = (char*)GlobalAlloc(GMEM_FIXED, dwContentLen + 1);
DWORD dwReadSize = dwContentLen / 10; // We will read 10% of data
// with each read.
DWORD cReadCount;
DWORD dwBytesRead;
char *pCopyPtr = pData;
for (cReadCount = 0; cReadCount < 10; cReadCount++)
{
InternetReadFile(hRequest, pCopyPtr, dwReadSize, &dwBytesRead);
pCopyPtr = pCopyPtr + dwBytesRead;
}
// extra read to account for integer division round off
InternetReadFile(hRequest,
pCopyPtr,
dwContentLen - (pCopyPtr - pData),
&dwBytesRead);
// Null terminate data
pData[dwContentLen] = 0;
std::cout << pData << std::endl;
system("pause");
}
return 0;
}
The endpoint I'm posting to

data download with set user-agent c++

I have a function to upload information to a byte array, but it ends with - if (!Httpsendrequest(httprequest, szHeaders, strlen(szhheaders), szRequest, strlen(szRequest)))
string GetUrlData(const string& url, LPCSTR host, string& output)
{
string request_data = "";
output = "";
HINTERNET hIntSession = InternetOpenA("token", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hIntSession)
{
return request_data;
}
HINTERNET hHttpSession = InternetConnectA(hIntSession, host, 80, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);
if (!hHttpSession)
{
return request_data;
}
HINTERNET hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", url.c_str()
, 0, 0, 0, INTERNET_FLAG_RELOAD, 0);
if (!hHttpSession)
{
return request_data;
}
char* szHeaders = ("Content-Type: text/html\r\nUser-Agent: License");
char szRequest[1024] = { 0 };
if (!HttpSendRequestA(hHttpRequest, szHeaders, strlen(szHeaders), szRequest, strlen(szRequest)))
{
qDebug()<<"BLYA";
return request_data;
}
CHAR szBuffer[1024] = { 0 };
DWORD dwRead = 0;
while (InternetReadFile(hHttpRequest, szBuffer, sizeof(szBuffer) - 1, &dwRead) && dwRead)
{
request_data.append(szBuffer, dwRead);
}
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
output = request_data;
}
The failure might have something to do with the fact that szHeaders is missing \r\n on the User-Agent header. Every header you send ust be terminated with \r\n. And BTW, there is no reason to send a Content-Type header in a GET request, since there is no message body being sent to the server.
Also, your code has a bunch of memory leaks if anything goes wrong. You need to close every handle you successfully open.
Also, there is no point in having both a return value and an output parameter that return the same data. Pick one or the other. I would suggest using a bool return value and a string output parameter.
Try something more like this:
bool GetUrlData(const string& resource, const string& host)
{
output.clear();
bool result = false;
HINTERNET hIntSession = InternetOpenA("token", INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if (!hIntSession) {
qDebug() << "InternetOpen failed, error: " << GetLastError();
return false;
}
HINTERNET hHttpSession = InternetConnectA(hIntSession, host.c_str(), 80, 0, 0, INTERNET_SERVICE_HTTP, 0, NULL);
if (!hHttpSession) {
qDebug() << "InternetConnect failed, error: " << GetLastError();
InternetCloseHandle(hIntSession);
return false;
}
HINTERNET hHttpRequest = HttpOpenRequestA(hHttpSession, "GET", resource.c_str(), 0, 0, 0, INTERNET_FLAG_RELOAD, 0);
if (!hHttpRequest) {
qDebug() << "HttpOpenRequest failed, error: " << GetLastError();
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
return false;
}
const char* szHeaders = "User-Agent: License\r\n";
if (!HttpSendRequestA(hHttpRequest, szHeaders, -1, NULL, 0)) {
qDebug() << "HttpSendRequest failed, error: " << GetLastError();
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
return false;
}
char szBuffer[1024];
DWORD dwRead = 0;
do {
if (!InternetReadFile(hHttpRequest, szBuffer, sizeof(szBuffer), &dwRead)) {
qDebug() << "InternetReadFile failed, error: " << GetLastError();
InternetCloseHandle(hHttpRequest);
InternetCloseHandle(hHttpSession);
InternetCloseHandle(hIntSession);
return false;
}
if (dwRead == 0)
break;
output.append(szBuffer, dwRead);
}
while (true);
return true;
}

WinInet upload file

I wrote a C++ function to perform uploading file using WinInet Library. The code is compiled and executed without returning error, but I can't handle the file in the server side. Both the php and the python server don't recognize file.
Here is the code :
#define DEFAULT_USERAGENT "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"
#define MY_HOST "192.168.1.101"
#define ALT_HTTP_PORT 8080
#define METHOD_POST "POST"
#define BUFSIZE 1024
void UploadFile()
{
char szHeaders[] = "Content-Type: multipart/form-data; boundary=---------------------------974767299852498929531610575";
char szContent[] = "---------------------------974767299852498929531610575\r\nContent-Disposition: form-data; name=\"file\"; filename=\"main.cpp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
char szEndData[] = "\r\n---------------------------974767299852498929531610575--\r\n";
unsigned char c;
char szBuffer[BUFSIZE];
memset(szBuffer, 0, BUFSIZE);
char* szData = NULL;
DWORD dwBytes;
HANDLE hIn = CreateFile("main.cpp", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
for(int i = 0; i < BUFSIZE - 1 ; i++){
ReadFile(hIn, &c, 1, NULL, NULL);
szBuffer[i] = c;
}
szBuffer[BUFSIZE - 1] = '\0';
CloseHandle(hIn);
size_t sDataSize = strlen(szBuffer) + strlen(szContent) + strlen(szEndData) + 1;
szData = new char[sDataSize];
SecureZeroMemory(szData, sizeof(szData));
strcat(szData, szContent);
strcat(szData, szBuffer);
strcat(szData, szEndData);
szData[sDataSize] = '\0';
HINTERNET io = InternetOpen(DEFAULT_USERAGENT, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0);
if(!io){
std::cerr << "InternetOpen Error" << std::endl;
return;
}
HINTERNET ic = InternetConnect(io, MY_HOST, ALT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
if(!ic){
std::cerr << "InternetConnect Error" << std::endl;
return;
}
HINTERNET hreq = HttpOpenRequest(ic, METHOD_POST, "/upload", NULL,NULL, NULL, 0, 0);
if(!hreq){
std::cerr << "HttpOpenRequest Error" << std::endl;
return;
}
HttpSendRequest(hreq, szHeaders, strlen(szHeaders), szData, strlen(szData));
InternetCloseHandle(io);
InternetCloseHandle(ic);
InternetCloseHandle(hreq);
delete[] szData;
}
Your MIME boundary lines in szContent and szEndData are wrong. Read RFC 2046. A boundary line in the content data begins with two - characters, followed by the text specified in the boundary parameter of the Content-Type header (and in the case of an ending boundary line, then followed by two more - characters).
The boundary lines you are using in your content data are missing those two leading - characters. You have 27 leading dashes in the boundary header, so you need 29 leading dashes in the content, not 27 like you have.
Also, you are assuming the input file is exactly 1023 bytes in size. But, more importantly, you are not doing any error handling on the CreateFile() call to make sure the file is actually open, or any error handling on the ReadFile() call to make sure data is actually being read in (hint: the 4th parameter cannot be NULL when the 5th parameter is NULL).
You are trying to read the entire file (well, up to 1023 bytes, anyway) into memory, and then send it. At the very least, you should use GetFileSize() to get the actual file size, and then allocate szData accordingly and read directly into it. You don't need szBuffer at all.
There are other minor errors in your code, too. Like misusing sizeof(), assuming that the file data does not contain any null bytes in it, leaking memory, etc.
Try something more like this instead:
#define DEFAULT_USERAGENT "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"
#define MY_HOST "192.168.1.101"
#define ALT_HTTP_PORT 8080
#define METHOD_POST "POST"
#include <vector>
#include <memory>
struct FileCloser
{
typedef HANDLE pointer;
void operator()(HANDLE h)
{
if (h != INVALID_HANDLE_VALUE)
CloseHandle(h);
}
};
struct InetCloser
{
typedef HINTERNET pointer;
void operator()(HINTERNET h)
{
if (h != NULL)
InternetCloseHandle(h);
}
};
void UploadFile()
{
const char *szHeaders = "Content-Type: multipart/form-data; boundary=----974767299852498929531610575";
const char *szContent = "------974767299852498929531610575\r\nContent-Disposition: form-data; name=\"file\"; filename=\"main.cpp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
const char *szEndData = "\r\n------974767299852498929531610575--\r\n";
std::unique_ptr<HANDLE, FileCloser> hIn(CreateFile("main.cpp", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL));
if (hIn.get() == INVALID_HANDLE_VALUE)
{
std::cerr << "CreateFile Error" << std::endl;
return;
}
DWORD dwFileSize = GetFileSize(hIn.get(), NULL);
if (dwFileSize == INVALID_FILE_SIZE)
{
std::cerr << "GetFileSize Error" << std::endl;
return;
}
size_t sContentSize = strlen(szContent);
size_t sEndDataSize = strlen(szEndData);
std::vector<char> vBuffer(sContentSize + dwFileSize + sEndDataSize);
char *szData = &vBuffer[0];
memcpy(szData, szContent, sContentSize);
szData += sContentSize;
DWORD dw = 0, dwBytes;
while (dw < dwFileSize)
{
if (!ReadFile(hIn.get(), szData, dwFileSize-dw, &dwBytes, NULL))
{
std::cerr << "ReadFile Error" << std::endl;
return;
}
szData += dwBytes;
dw += dwBytes;
}
hIn.reset();
memcpy(szData, szEndData, sEndDataSize);
std::unique_ptr<HINTERNET, InetCloser> io(InternetOpen(DEFAULT_USERAGENT, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0));
if (io.get() == NULL)
{
std::cerr << "InternetOpen Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> ic(InternetConnect(io.get(), MY_HOST, ALT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0));
if (ic.get() == NULL)
{
std::cerr << "InternetConnect Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> hreq(HttpOpenRequest(ic.get(), METHOD_POST, "/upload", NULL, NULL, NULL, 0, 0));
if (hreq.get() == NULL)
{
std::cerr << "HttpOpenRequest Error" << std::endl;
return;
}
if (!HttpSendRequest(hreq.get(), szHeaders, -1, &vBuffer[0], vBuffer.size()))
std::cerr << "HttpSendRequest Error" << std::endl;
}
An alternative option is to use HttpSendRequestEx() instead, so you can then use InternetWriteFile() in a loop to read+send the file in chunks on each loop iteration. That way, you do not have to read the entire file into memory before sending:
#define DEFAULT_USERAGENT "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:40.0) Gecko/20100101 Firefox/40.1"
#define MY_HOST "192.168.1.101"
#define ALT_HTTP_PORT 8080
#define METHOD_POST "POST"
#define BUFSIZE 1024
#include <memory>
#include <algorithm>
struct FileCloser
{
typedef HANDLE pointer;
void operator()(HANDLE h)
{
if (h != INVALID_HANDLE_VALUE)
CloseHandle(h);
}
};
struct InetCloser
{
typedef HINTERNET pointer;
void operator()(HINTERNET h)
{
if (h != NULL)
InternetCloseHandle(h);
}
};
bool WriteToInternet(HINTERNET hInet, const void *Data, DWORD DataSize)
{
const BYTE *pData = (const BYTE *) Data;
DWORD dwBytes;
while (DataSize > 0)
{
if (!InternetWriteFile(hInet, pData, DataSize, &dwBytes))
return false;
pData += dwBytes;
DataSize -= dwBytes;
}
return true;
}
void UploadFile()
{
const char *szHeaders = "Content-Type: multipart/form-data; boundary=----974767299852498929531610575";
const char *szContent = "------974767299852498929531610575\r\nContent-Disposition: form-data; name=\"file\"; filename=\"main.cpp\"\r\nContent-Type: application/octet-stream\r\n\r\n";
const char *szEndData = "\r\n------974767299852498929531610575--\r\n";
std::unique_ptr<HANDLE, FileCloser> hIn(CreateFile("main.cpp", GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL));
if (hIn.get() == INVALID_HANDLE_VALUE)
{
std::cerr << "CreateFile Error" << std::endl;
return;
}
DWORD dwFileSize = GetFileSize(hIn.get(), NULL);
if (dwFileSize == INVALID_FILE_SIZE)
{
std::cerr << "GetFileSize Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> io(InternetOpen(DEFAULT_USERAGENT, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0));
if (io.get() == NULL)
{
std::cerr << "InternetOpen Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> ic(InternetConnect(io.get(), MY_HOST, ALT_HTTP_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0));
if (ic.get() == NULL)
{
std::cerr << "InternetConnect Error" << std::endl;
return;
}
std::unique_ptr<HINTERNET, InetCloser> hreq(HttpOpenRequest(ic.get(), METHOD_POST, "/upload", NULL, NULL, NULL, 0, 0));
if (hreq.get() == NULL)
{
std::cerr << "HttpOpenRequest Error" << std::endl;
return;
}
if (!HttpAddRequestHeaders(hreq.get(), szHeaders, -1, HTTP_ADDREQ_FLAG_REPLACE | HTTP_ADDREQ_FLAG_ADD))
{
std::cerr << "HttpAddRequestHeaders Error" << std::endl;
return;
}
size_t sContentSize = strlen(szContent);
size_t sEndDataSize = strlen(szEndData);
INTERNET_BUFFERS bufferIn = {};
bufferIn.dwStructSize = sizeof(INTERNET_BUFFERS);
bufferIn.dwBufferTotal = sContentSize + dwFileSize + sEndDataSize;
if (!HttpSendRequestEx(hreq.get(), &bufferIn, NULL, HSR_INITIATE, 0))
{
std::cerr << "HttpSendRequestEx Error" << std::endl;
return;
}
if (!WriteToInternet(hreq.get(), szContent, sContentSize)))
{
std::cerr << "InternetWriteFile Error" << std::endl;
return;
}
char szData[BUFSIZE];
DWORD dw = 0, dwBytes;
while (dw < dwFileSize)
{
if (!ReadFile(hIn.get(), szData, std::min(dwFileSize-dw, sizeof(szData)), &dwBytes, NULL))
{
std::cerr << "ReadFile Error" << std::endl;
return;
}
if (!WriteToInternet(hreq.get(), szData, dwBytes))
{
std::cerr << "InternetWriteFile Error" << std::endl;
return;
}
dw += dwBytes;
}
if (!WriteToInternet(hreq.get(), szEndData, sEndDataSize))
{
std::cerr << "InternetWriteFile Error" << std::endl;
return;
}
if (!HttpEndRequest(hreq.get(), NULL, HSR_INITIATE, 0))
std::cerr << "HttpEndRequest Error" << std::endl;
}

msdn upload image with winhttp c++

I have been trying this the whole day but no luck i want to upload an image file to a php file which i have created but when ever i try to do that winhttpsendrequest throws 183 error that means cannot send file that is already sent please can someone point out where i am wrong
c++ code:
int _tmain(int argc, _TCHAR* argv[]) {
HINTERNET hSession = NULL,
hConnect = NULL,
hRequest = NULL;
BOOL bResults = FALSE;
FILE *pFile;
long lSize;
char *buffer;
size_t result;
pFile = fopen("blog.jpg", "rb");
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);
rewind(pFile);
buffer = (char *) malloc(sizeof(char) * lSize);
result = fread(buffer, 1, lSize, pFile);
fclose(pFile);
hSession = WinHttpOpen( L"WinHTTP Example/1.0",
WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
WINHTTP_NO_PROXY_NAME,
WINHTTP_NO_PROXY_BYPASS, 0);
if (hSession)
hConnect = WinHttpConnect(hSession, L"localhost",
INTERNET_DEFAULT_HTTP_PORT, 0);
if (hConnect)
hRequest = WinHttpOpenRequest(hConnect, L"POST", L"locker/upload.php",
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_REFRESH);
static WCHAR frmdata[2048] = L"Connection: keep-alive\r\nContent-Type: multipart/form-data; -----------------------------7d82751e2bc0858\r\nContent-Disposition: form-data; name=\"file\"; filename=\"blog.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n";
bResults = WinHttpSendRequest(hRequest,
frmdata, wcslen(frmdata), buffer,
lSize, wcslen(frmdata)+lSize, 0);
if (bResults) {
/*
DWORD dwBytesWritten = 0;
bResults = WinHttpWriteData(hRequest, buffer,
lSize,
&dwBytesWritten);
if (bResults) {
printf_s("Data: %d", dwBytesWritten);
}
*/
} else {
printf_s("SendReq: %d", GetLastError());
}
free(buffer);
if (hRequest) { WinHttpCloseHandle(hRequest); }
if (hConnect) { WinHttpCloseHandle(hConnect); }
if (hSession) { WinHttpCloseHandle(hSession); }
getchar();
return 0;
}
php code:
if (isset($_FILES["file"])) {
$target_path = "uploads/";
$target_path = $target_path . basename( $_FILES['file']['name']);
if(move_uploaded_file($_FILES['file']['tmp_name'], $target_path)) {
echo "The file ". basename( $_FILES['file']['name']). " has been uploaded";
} else{
echo "There was an error uploading the file, please try again!";
}
}
Keshav Nair.
try to this code:
CHAR postData[1024];
CHAR postData2[1024];
ZeroMemory(&postData,1024);
ZeroMemory(&postData2,1024);
WinHttpAddRequestHeaders(hRequest,L"Content-Type: multipart/form-data; boundary=----OiRBxC0fjdSEpqhd",-1L,WINHTTP_ADDREQ_FLAG_ADD);
wsprintfA(postData,"%s","----OiRBxC0fjdSEpqhd\r\nContent-Disposition: form-data; name=\"file\"; filename=\"blog.jpg\"\r\nContent-Type: image/jpeg\r\n\r\n");
wsprintfA(postData2,"%s","\r\n----OiRBxC0fjdSEpqhd\r\nContent-Disposition: form-data; name=\"submit\"\r\n\r\nSubmit\r\n----OiRBxC0fjdSEpqhd--\r\n");
bResults = WinHttpSendRequest( hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS,
0, WINHTTP_NO_REQUEST_DATA, 0,
lstrlenA(postData)+lstrlenA(postData2)+lSize, NULL);
if (bResults)
{
bResults=WinHttpWriteData(hRequest,LPCVOID)postData,lstrlenA(postData),NULL);
bResults = WinHttpWriteData(hRequest, buffer, lSize, &dwBytesWritten);
bResults=WinHttpWriteData(hRequest,(LPCVOID)postData2,lstrlenA(postData2),NULL);
}
WinHttpWriteData:
POST data - postData, postData2 must be 8 bit encoding.