Show the code where you call IWinHttpRequest::Send. My guess is, you are
doing something that causes the content to be terminated by the first
zero byte, e.g. handling a BSTR carelessly.
--
With best wishes,
Igor Tandetnik
With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925
I hate posting code, because everyone wants to point out 40 other ways to do
something else that I may be doing, instead of responding to the question I
asked.. However, I'll clean this up, because this is a test app so I can
post it.. Do you know off hand if you can post as binary or do I need to
encode it?
No, you don't need to encode, as far as I can tell.
This is exactly what Igor predicted, ending the string at the first embedded
NUL. I guess there oughtn't to be any in the header, but you can save a
copy and handle embedded NUL all at once thusly:
CComBSTR bstrBody = SysAllocStringLen(NULL, szHeader.length());
MultiByteToWideChar(CP_UTF8, 0, szHeader.c_str(), szHeader.length(),
(BSTR)bstrBody, szHeader.length());
But why are UNICODE strings involved in an HTTP transaction to begin with?
HTTP is purely 8-bit by definition.
Because the OP uses IWinHttpRequest, which is an automation-compatible
wrapper around WinHTTP API.
The header is never going to have any null terminators in it, so this will
not ever be a problem.
But this will:
bstrBody.Append(strInput);
CComBSTR::Append(char*) has no choice but to treat its parameter as a
NUL-terminated string. This may truncate the data at best, and cause a
buffer overrun at worst (since strInput is not in fact NUL-terminated,
Append() may run off the end into uncharted memory).
Added
> For binary data, I'd personally drop down to raw WinHTTP API. See
> WinHttpWriteData.
Ok, I've created a Win32 Test app and this is what I have:
http://www.chizl.com/aspuploaded/WinHTTP.cpp
This seems to be only getting worst.. It keeps failing while setting the
header:
bResults = WinHttpSendRequest( hRequest,
L"multipart/form-data: boundary=Xu02=$\r\n",
-1L,
WINHTTP_NO_REQUEST_DATA,
0,
lBodySize,
0);
"Igor Tandetnik" <itand...@mvps.org> wrote in message
news:uWBQIemb...@TK2MSFTNGP03.phx.gbl...
Your header text is wrong. Taken from your own earlier post, the correct
header is
Content-Type: multipart/form-data; boundary=Xu02=$; Charset=UTF-8
You should call WinHttpSendRequest only once. Collect all headers in a
single string, separated by \r\n
You should call WinHttpWriteData on raw data as read from the file, not
on the contents of BSTR (where the data is already converted to
Unicode). Remove the whole BSTR-building code, you don't need it. You
are using the API directly now - just send raw bytes. No more COM stuff.
--
Still fails on the same call..:
CComBSTR bstrHeader;
bstrHeader.Append("Content-Length: ");
bstrHeader.Append(pSize);
bstrHeader.Append("Cache-Control: no-cache\r\n");
bstrHeader.Append("Content-Type: multipart/form-data; boundary=Xu02=$;
Charset=UTF-8\r\n");
if (hRequest)
bResults = WinHttpSendRequest( hRequest,
bstrHeader,
Is this more of what your talking about? I'm getting a 500 back from IIS,
but at least I'm getting the header information and data to send..
http://www.chizl.com/aspuploaded/WinHTTP.cpp
BTW: how do I get the status code back from the web server using the raw
socket?
I'm not really an expert on WinHTTP. Consider asking in
microsoft.public.winhttp newsgroup.
> BTW: how do I get the status code back from the web server using the
> raw socket?
By "raw socket", do you mean WinHTTP API or literally using WinSock to
program at the socket level? With WinHTTP, you send the request, wait
for response with WinHttpReceiveResponse, then call
WinHttpQueryHeaders(WINHTTP_QUERY_STATUS_CODE |
WINHTTP_QUERY_FLAG_NUMBER)
No, not BSTR. That's what Igor has been telling you. BSTR is UNICODE, HTTP
uses single byte characters.
Use std::string or CStringA instead.
"Ben Voigt [C++ MVP]" <r...@nospam.nospam> wrote in message
news:u%23pKzaob...@TK2MSFTNGP02.phx.gbl...
> Chizl wrote:
>> "Igor Tandetnik" <itand...@mvps.org> wrote in message
>> news:OYYI4ymb...@TK2MSFTNGP06.phx.gbl...
>>> Chizl <Ch...@NoShitMail.com> wrote:
>> CComBSTR bstrHeader;
>> bstrHeader.Append("Content-Length: ");
>> bstrHeader.Append(pSize);
>> bstrHeader.Append("Cache-Control: no-cache\r\n");
>> bstrHeader.Append("Content-Type: multipart/form-data; boundary=Xu02=$;
>> Charset=UTF-8\r\n");
>
> No, not BSTR. That's what Igor has been telling you. BSTR is UNICODE,
> HTTP uses single byte characters.
>
> Use std::string or CStringA instead.
When I try using an STL String I get errors.. WinHttpAddRequestHeaders()
second param requires a const unsigned short *. Best that I know is to
T2OLE(char*), but that's basically doing the same thing I'm already doing.
I've updated the file...
http://www.chizl.com/aspuploaded/WinHTTP.cpp
I'm receiving no errors, everything seems to do what it supposed to do
through IIS, however the server never saves the file.. Based on the code,
I've added a totalbytes sent and it shows all data was sent.. I'm not
seeing where the problem is..
----------
POST /DER/Upload.asp HTTP/1.1
Content-Length: 1410
Cache-Control: no-cache
Content-Type: multipart/form-data; boundary=Xu02=$; Charset=UTF-8
User-Agent: A WinHTTP Example Program/1.0
Host: 127.0.0.1:5000
Connection: Keep-Alive
--Xu02=$
Content-Type: application/octet-stream
Content-Disposition: multipart/form-data; name="PostData";
filename="1234567890.zip"
Content-Length: 1234
PK @tK8#?T T Y
1234567890.cfg?V?n?6 }
--Xu02=$--
----------
http://www.codeguru.com/cpp/i-n/internet/http/article.php/c6209/
Drew
"Chizl" <Ch...@NoShitMail.com> wrote in message
news:%23NSYYSp...@TK2MSFTNGP06.phx.gbl...
All this Unicode stuff in WinHttp is really stupid (the library, not you),
there is no Unicode in HTTP, there's 8-bit headers and binary payload.
But I checked and WinHttp seems to be Unicode-only. Try WinInet instead
(looks like the same usage pattern, you'd use HttpOpenRequestA,
HttpAddRequestHeadersA, etc).
WinInet, the control? I used that back many years ago and there was some
major issue with it, so I ended up going direct to Winsock.. So am I
understanding the only way I can really do this is go directly to Winsock?
No, WinInet, the API. Which probably is the library used by some wininet
ActiveX control, so whatever bug you ran into might exist in the underlying
API as well.
You might want to use a purpose-designed third party HTTP wrapper such as
libcurl if you need proxy or encryption support, otherwise sockets would be
straightforward.
Thanks for everyone's help, I finally got to a point this works..
It was the headers that were not right. After playing with the headers for
a few hours I fell across it..
Since no one on the web has this code example anywhere, I'm going to post it
on my www.chizl.com/dev/c++ and www.karland.com/code/cplusplus server..
I went FROM:
-------------------------------------------------------
char *pstrPostHeaderTemplate =
"Content-Length: %d\r\n"
"Cache-Control: no-cache\r\n"
"Content-Type: multipart/form-data; boundary=Xu02=$; Charset=UTF-8\r\n";
char *pstrFileHeaderTemplate =
"--Xu02=$\r\n"
"Content-Type: application/octet-stream\r\n"
"Content-Disposition: multipart/form-data; name=\"PostData\";
filename=\"%s\"\r\n"
"Content-Length: %d\r\n\r\n";
char *pstrFileFooterTemplate =
"\r\n\r\n--Xu02=$--\r\n";
-------------------------------------------------------
TO
-------------------------------------------------------
char *pstrPostHeaderTemplate =
"Content-Length: %d\r\n"
"Cache-Control: no-cache\r\n"
"Content-Type: multipart/form-data; boundary=Xu02=$\r\n";
char *pstrFileHeaderTemplate =
"--Xu02=$\r\n"
"Content-Type: multipart/form-data; Charset=UTF-8; name=\"PostData\";
filename=\"%s\"\r\n"
"Content-Length: %d\r\n\r\n";
char *pstrFileFooterTemplate =
"\r\n\r\n--Xu02=$--\r\n";
-------------------------------------------------------
The changes I see are adding Charset=UTF-8 and rolling the
Content-Disposition into the Content-Type, any others?
Nope, that's about it.. I actually moved the UTF-8, from the main header
to the file header. I started just searching around for headers and
moving things around based on email header etc until something worked..
Thanks again..
Chizl