Open Binary File then Upload via WinHttp.WinHttpRequest.5.1 object..

I'm having an issue with opening a file as binary then uploading via the WinHttp.WinHttpRequest.5.1 object.

I basiclly need something like below, but I can't use _bstr_t because it's binary..  I've tried doing this with pure char* but when I do that, I get nothing sent to the server.   At least the code below uploads something and the server receives it as a zip..   Only the zip will be corrupted for obvious reasons.

pIWinHttpRequest->SetRequestHeader("Content-Type", "multipart/form-data; boundary=Xu02=$");
 
std::ifstream file1(szFileName.c_str());
file1.read(buffer, CHUNK);
_bstr_t strBody = "--Xu02=$\r\nContent-Disposition: form-data; name=\"TestFile\"; filename=\"MyFile.zip\"\r\nContent-type: file\r\n\r\n";
strBody += buffer;
strBody += "\r\n--Xu02=$--";
 
hr = pIWinHttpRequest->Send(strBody);

Open in new window

LVL 4
ChizlAsked:
Who is Participating?
 
jkrConnect With a Mentor Commented:
You need to base64-encode your file and then add it to your 'strBody' variable when using a "POST" request. Check out e.g. the helper class at http://www.codeproject.com/KB/cpp/base64coding.aspx ("Base64 Encoding And Decoding")
0
 
ChizlAuthor Commented:
BTW I am using..
std::ifstream file1(szFileName.c_str(), std::ios::in|std::ios::binary);

I had commented it for testing different scenerios..
0
 
ChizlAuthor Commented:
Thanks, that code was for 2005 or 2008 and the portability to VC6 isn't working too well, so I'm looking at another Base64 encoding, which I have and the encoding seems to be working, but uploading is still failing at the moment..   I'm still trying to make sure it's not something I'm doing so I'll get back to you.
0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
jkrCommented:
The code should actually not require any special version of VC++ (except the project files, which you don't need to integrate it into your sources). Anyway, you'll find other examples at e.g. http://www.codeproject.com/KB/string/ammimeutils.aspx ("AMMimeUtils")
0
 
ChizlAuthor Commented:
Actually I'm using:
http://www.codeguru.com/cpp/cpp/algorithms/article.php/c5099/

Seems to work fine..     However when I try sending it as Base64 it never makes it to the server.    Senerio #1 below, I don't get  MyFile.zip file on the server.   Senerio #2 below, I do get MyFile.zip with the text of "Chizl" insize the zip file..
Senerio #1
-------------------------
CBase64 B64;
string szBase64FileName = szFileName;
szBase64FileName.append(".b64");
B64.EncodeFile ((char*)szFileName.c_str(), (char*)szBase64FileName.c_str());
 
ifstream file(szBase64FileName.c_str(), ios::in|ios::binary|ios::ate);
int lSize = file.tellg();
file.close();
 
char* buffer = new char[lSize];
 
ifstream file1(szBase64FileName.c_str(), ios::binary|ios::in);
int iSize = file1.tellg();
file1.read(buffer, iSize);
file1.close();
 
_bstr_t strBody = "--Xu02=$\r\nContent-Disposition: form-data; name=\"TestFile\"; filename=\"MyFile.zip\"\r\nContent-type: file\r\n\r\n";
strBody += buffer;
strBody += "\r\n--Xu02=$--";
hr = pIWinHttpRequest->Send(strBody);
 
delete[] buffer;
-------------------------
 
Senerio #2
-------------------------
CBase64 B64;
string szBase64FileName = szFileName;
szBase64FileName.append(".b64");
B64.EncodeFile ((char*)szFileName.c_str(), (char*)szBase64FileName.c_str());
 
ifstream file(szBase64FileName.c_str(), ios::in|ios::binary|ios::ate);
int lSize = file.tellg();
file.close();
 
char* buffer = new char[lSize];
 
ifstream file1(szBase64FileName.c_str(), ios::binary|ios::in);
int iSize = file1.tellg();
file1.read(buffer, iSize);
file1.close();
 
_bstr_t strBody = "--Xu02=$\r\nContent-Disposition: form-data; name=\"TestFile\"; filename=\"MyFile.zip\"\r\nContent-type: file\r\n\r\n";
strBody += "Chizl";
strBody += "\r\n--Xu02=$--";
hr = pIWinHttpRequest->Send(strBody);
 
delete[] buffer;
-------------------------

Open in new window

0
 
jkrCommented:
Hm, you aren't adding the buffer to the request body, are you? Also,

Content: application/octet-stream

is missing. In whole, the raw request should look like

POST /path/script.cgi HTTP/1.0
Content: application/octet-stream
Content-Length: [lSize here]
[basee64 encoded buffer data here]
0
 
ChizlAuthor Commented:
The POST /path/...  comes from the HTTP Object I'm using..   I've changed the Content-Type to application/octet-stream, I've added Content-Length.   It's W3C standard to have a /r/n/r/n between the header and the file/message.   I'm still getting the same issue.  No zip file is being uploaded, unless I replace the Base64 insert:
from
strBody += buffer;
to
strBody += "Chizl";

It's as if the Base64 is unrecognized.
0
 
ChizlAuthor Commented:
ok, I don't think that encoding it is correct.    I basiclly copied the base64 encoded file directly into the buffer.....
strBody += "UEsDBBQAAgAIAAKdPjgDjOHxoSEAADpSAQAUABEAUHJveHkuMDAwMDAwMDAwMC5sb2dVVA0AB/Mm\r\n";
strBody += "oUf3VapH91WqR+xda4/bOJb9vsD+B6K/rAuoqEiKkigBwSDPnmDyQqWDYLG9MGRbrtLGJXkkOZXq\r\n";
strBody += "X7+XpMuWbNKWLLksZ6bnkbRk3XsOeXl5+BBFMebPMHlGOSJOgP3Ati2b+ch+9u36I8KYYOLaBP4i\r\n";

Just for testing purposes, and the whole zip uploaded just fine, however the zip file on the server size is still Base64.    I'm using ASPUpload object to receive the file on the server side and when I upload other binary files they are in tact like they should be not encoded like this file is..   Which tells me when I do an HTTP Post of a file, it's not encoding it first.
0
 
jkrCommented:
Hm, are you passing the correct content length?
0
 
ChizlAuthor Commented:
Yep..
0
 
ChizlAuthor Commented:
Content-Length is everythoug except the header..   Which is basically only the zip file and I'm pulling that from file.tellg().  I did verify that that is coming across correctly..
0
 
jkrCommented:
>>Which is basically only the zip file

Err, the base64-encoded length of that file, which is 'iSize' in your code...
0
 
ChizlAuthor Commented:
What I meant..  I'm pulling the size of the file that I'm opening which is the zip file encoded.  
0
 
jkrCommented:
Err, no, you need

a) the base64 encoded file
b) its size

HTTP is a text-based protocol, thus the whole thing about the encoding (you cannot transfer binary data like a .zip-file).
0
 
ChizlAuthor Commented:
Well, sending it like that sends the file, but it's still encoded when it's stored on the web server HD..  If I use a web page to post the same file to the same web server, it's not encoded on the server, it's the zip that I posted.

For now until I figure out what's going on, I'm just decoding it on the web server and that seems to work for now, but there is still something missing.

I'm using this to encode and upload it..
CBase64 B64;
string szBase64FileName = szFileName;
szBase64FileName = szFileName;
szBase64FileName.append(".b64");
B64.EncodeFile ((char*)szFileName.c_str(), (char*)szBase64FileName.c_str());
 
char pSize[10] = {0};
char* pszFile = (char*)szBase64FileName.c_str();
 
int iLoc = szBase64FileName.find_last_of("\\");
 
struct _stat buf;
_stat(pszFile, &buf);
int iSize = buf.st_size;
itoa(iSize, pSize, sizeof(pSize));
 
_bstr_t strBody = "--Xu02=$\r\n";
strBody += "Content-Disposition: multipart/form-data; name=\"ZipFile\"; filename=\"";
strBody += &pszFile[iLoc];
strBody += "\"\r\n";
strBody += "Content-Type: application/octet-stream\r\n";
strBody += "Content-Length: ";
strBody += pSize;
strBody += "\r\n";
 
std::string line;
std::ifstream infile (szBase64FileName.c_str());
while (getline(infile, line, '\n'))
{
	strBody += "\r\n";
	strBody += line.c_str();
}
strBody += "\r\n--Xu02=$--";
infile.close();
 
hr = pIWinHttpRequest->Send(strBody);

Open in new window

0
 
jkrCommented:
>>but it's still encoded when it's stored on the web server HD

Yes, the server will need to decode it upon saving, that is not done automatically. Usually the script that is specified in the URL does that (or any other module that is responsible for that)
0
 
ChizlAuthor Commented:
That's not true..    I have an HTML page that posts to the EXACT same asp page my EXE is and every file I post there from the HTML page, the binary file is exactly as it was without encoding or decoding it on the server.   Now, if IE is encoding it, then I should see it encoded on the server side and I'm not.
0
 
jkrCommented:
HTML is not encoded, but plain text, that's the difference. You can send that directly (thus store 'as-is'), which you cannot do with binaries.
0
 
ChizlAuthor Commented:
Not sure you understand what I'm saying..    I have an HTML Page that has a form post..   In this HTML Form Post, I have the ability to select binary files and post them to the exact same ASP page that is accepting the binaries from my EXE.    When I do this the binaries are not decoded on the server side, because they are received as the normal binary.
0
 
jkrCommented:
Hm, have you tried to check the difference between these POST requests?
0
 
ChizlAuthor Commented:
The difference is the HTTP side is done by IE7, the other is me trying to do what IE is doing.    That's my problem, I need to understand how IE does it so I too can..  
0
 
jkrCommented:
Hm, I meant more like the actual request that is being sent, you can log that with various tools (OK, Wireshark might be overkill, but is the 1st to come into my mind)
0
 
ChizlAuthor Commented:
I still don't think I should have to decode it on the server side.     Encoding it, uploading it, decoding it seems to work so I'll go ahead a close this out..   Thanks.
0
 
ChizlAuthor Commented:
jkr, I found the solution..  You do NOT have to Encode the file..
//const int MAX_READ = 64;
//string szFileName = "C:\\TEST\\MyFile.zip";
 
//get file size
struct _stat buf;
_stat(szFileName.c_str(), &buf);
int iFileSize = buf.st_size;
 
//declare
int iBodySize = 0;
int iHeaderSize = 0;
char* pszFile = (char*)szFileName.c_str();
char strHeader[1024] = {0};
char* strInput = new char[MAX_READ];
 
//get file name from file passed in
int iSize = szFileName.length();
int iLoc = szFileName.find_last_of("\\")+1;
iSize -= iLoc;
memcpy(pszFile, &pszFile[iLoc], iSize);
pszFile[iSize]=0;
 
//create the header
memcpy(strHeader, "--Xu02=$\r\n", 10);
iHeaderSize = strlen(strHeader);
memcpy(&strHeader[iHeaderSize], "Content-Disposition: multipart/form-data; name=\"PostData\"; filename=\"", 69);
iHeaderSize = strlen(strHeader);
memcpy(&strHeader[iHeaderSize], pszFile, strlen(pszFile));
iHeaderSize = strlen(strHeader);
memcpy(&strHeader[iHeaderSize], "\"\r\n\r\n", 5);
iHeaderSize = strlen(strHeader);
 
//allocate body data
char* strBody = new char[iFileSize+iHeaderSize];
memset(strBody, 0, iFileSize+iHeaderSize);
memcpy(strBody, strHeader, iHeaderSize);
 
iBodySize = iHeaderSize;
 
//load file into array
while(!infile.eof()) 
{
	memset(strInput, 0, MAX_READ);
	infile.read(strInput, MAX_READ);
 
	unsigned int iBytesRead = 0;
	iBytesRead = infile.gcount();
 
	memcpy(&strBody[iBodySize], strInput, iBytesRead);
	iBodySize+=iBytesRead;
}
 
//close file
infile.close();
 
//send data
hr = pIWinHttpRequest->Send(strBody);
 
delete[] strBody;
delete[] strInput;

Open in new window

0
 
ChizlAuthor Commented:
I take it back, the above looked like it worked out, but the file is getting corrupted..    
0
 
jkrCommented:
That's more than surprising. Since HTTP is a text-based protocol, transferring unencoded binary files will fail at the 1st NULL byte...
0
 
ChizlAuthor Commented:
Actually, we tell it what the content type is going to be, and it's transfer as so.   I'm working with a guy that has done this in the past and he said that I'm not supposed to send as encoded.   I'm still working with him on getting it to work..  I'll post the solution..
0
 
ChizlAuthor Commented:
Binary solution, works perfectly..
WinHTTP.txt
0
All Courses

From novice to tech pro — start learning today.