BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

downloading with wininet

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Internet Web)
View previous topic :: View next topic  
Author Message
Boba
Guest





PostPosted: Tue Jan 02, 2007 9:10 am    Post subject: downloading with wininet Reply with quote



Happy New Year!
I'm trying to figure out what's wrong with the following code.
Please help. Thanks.

void DownloadFile( LPCSTR szServerName, LPCSTR szFileName ){
HINTERNET hHttpNet, hHttpSession, hHttpRequest;
DWORD dwDataSize, dwBytesDownloaded;
LPCSTR szAcceptTypes[] = { "*.*", NULL };
BYTE Buffer[1024];

hHttpNet = InternetOpen( "Microsoft Internet Explorer",
INTERNET_OPEN_TYPE_PRECONFIG,
NULL, NULL, 0 );
if( hHttpNet ){
hHttpSession = InternetConnect( hHttpNet, szServerName,
INTERNET_DEFAULT_HTTP_PORT,
"anonymous", "",
INTERNET_SERVICE_HTTP, 0, 0 );
if( hHttpSession ){
hHttpRequest = HttpOpenRequest( hHttpSession, "GET", szFileName,
"HTTP/1.1", NULL, szAcceptTypes,
INTERNET_FLAG_RELOAD, 0 );
if( hHttpRequest ){
if( HttpSendRequest( hHttpRequest, NULL, 0, NULL, 0 ) ){

do{
if( InternetQueryDataAvailable( hHttpRequest, &dwDataSize, 0, 0 ) ){
if( InternetReadFile( hHttpRequest, (LPVOID)Buffer,
sizeof(Buffer),
&dwBytesDownloaded ) ){
/*write the data*/
}//if( InternetReadFile
}//if( InternetQueryDataAvailable(
} while( dwBytesDownloaded );

}//if( HttpSendRequest
InternetCloseHandle( hHttpRequest );
}//if( hHttpRequest )
InternetCloseHandle( hHttpSession );
}//if( hHttpSession )
InternetCloseHandle( hHttpNet );
}//if( hHttpNet )

}//DownloadFile
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Tue Jan 02, 2007 3:27 pm    Post subject: Re: downloading with wininet Reply with quote



"Boba" <Boba (AT) somewhere (DOT) world> wrote in message
news:4599f9c5 (AT) newsgroups (DOT) borland.com...

Quote:
LPCSTR szAcceptTypes[] = { "*.*", NULL };

That is wrong. HttpOpenRequest() expects a media ContentType mask,
not a filename mask. At the verly least, you need to change *.*" to
"*/*", ie:

LPCSTR szAcceptTypes[] = { "*/*", NULL };

Quote:
hHttpRequest = HttpOpenRequest( hHttpSession, "GET",
szFileName,
"HTTP/1.1", NULL,
szAcceptTypes,
INTERNET_FLAG_RELOAD, 0 );

What exactly are you passing as the szFileName? It needs to be a URL
relative to the root of the server, not a local file path. Why are
you passing the server name separately from the filename in the first
place? You should use InternetCraskUrl() to convert a single full URL
string into the individual parts that InternetOpen(),
InternetConnect(), and HttpOpenRequest() are all expecting.

Quote:
do{
if( InternetQueryDataAvailable( hHttpRequest,
&dwDataSize, 0, 0 ) ){


I suggest you use HttpQueryInfo() to retreive the size of the data
before then entering the loop. That way you know when to stop looping
properly.


Gambit
Back to top
Boba
Guest





PostPosted: Tue Jan 02, 2007 10:36 pm    Post subject: Re: downloading with wininet Reply with quote



"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in message
news:459a2c13$1 (AT) newsgroups (DOT) borland.com...
Quote:
...
LPCSTR szAcceptTypes[] = { "*.*", NULL };

That is wrong. HttpOpenRequest() expects a media ContentType mask,
not a filename mask. At the verly least, you need to change *.*" to
"*/*", ie:

....hmmm... both gave the same result. i wish i knew why.

Quote:
LPCSTR szAcceptTypes[] = { "*/*", NULL };

hHttpRequest = HttpOpenRequest( hHttpSession, "GET",
szFileName,
"HTTP/1.1", NULL,
szAcceptTypes,
INTERNET_FLAG_RELOAD, 0 );

What exactly are you passing as the szFileName? It needs to be a URL
relative to the root of the server, not a local file path.

here's a sample call: DownloadFile("download.microsoft.com",
"/download/6/a/f/6af940c1-2774-4ebb-8546-2c83068af231/Windows2000-KB926247-x86-E
NU.EXE");

Quote:
Why are you passing the server name separately from the filename in the first
place?

that's the way 'they' want.

Quote:
I suggest you use HttpQueryInfo() to retreive the size of the data
before then entering the loop.

InternetQueryDataAvailable() is supposed to do that.

Quote:
That way you know when to stop looping properly.

if no (more) data avalable, dwBytesDownloaded will be set 0
by the InternetReadFile() call.
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Wed Jan 03, 2007 12:44 am    Post subject: Re: downloading with wininet Reply with quote

"Boba" <Boba (AT) somewhere (DOT) world> wrote in message
news:459a89d6 (AT) newsgroups (DOT) borland.com...

Quote:
...hmmm... both gave the same result. i wish i knew why.

Considering that none of your code is doing any error handling, you
did not specify the contents of the values you are passing, and you
did not specify on which line the failure is actually occuring, there
is no way to diagnose your problem. You need to provide more
information.

Quote:
here's a sample call: DownloadFile("download.microsoft.com",

"/download/6/a/f/6af940c1-2774-4ebb-8546-2c83068af231/Windows2000-KB92

6247-x86-E
Quote:
NU.EXE");

Ok so far. Though again, there is no reason to separate the server
from the path like that. You should be passing it as a single
complete URL string, ie:


DownloadFile("http://download.microsoft.com/download/6/a/f/6af940c1-27
74-4ebb-8546-2c83068af231/Windows2000-KB926247-x86-ENU.EXE");

Quote:
I suggest you use HttpQueryInfo() to retreive the size of the data
before then entering the loop.

InternetQueryDataAvailable() is supposed to do that.

Your looping code is wrong anyway. You are not using the value that
InternetQueryDataAvailable() returns. You must read everything that
InternetQueryDataAvailable() reports, or else it cannot report more
data later. This is clearly stated in the documentation. You need to
change your loop to something more like the following instead:

BYTE Buffer[1024];
DWORD dwDataSize, dwBytesToRead, dwBytesRead, dwBytesDownloaded;

dwBytesDownloaded = 0;

while( InternetQueryDataAvailable(hHttpRequest, &dwDataSize, 0,
0) )
{
if( dwDataSize == 0 )
break;

do
{
dwNumToRead = min(dwDataSize, sizeof(Buffer));

if( !InternetReadFile(hHttpRequest, Buffer, dwBytesToRead,
&dwBytesRead) )
break;

// write the data...
dwDataSize -= dwBytesRead;
dwBytesDownloaded += dwBytesRead;
}
while( dwDataSize != 0 );
}


However, I strongly suggest you use HttpQueryInfo() instead of
InternetQueryDataAvailable(). Then you need only 1 loop instead of 2,
since the download already knows the full size of the data ahead of
time, ie:

BYTE Buffer[1024];
DWORD dwDataSize, dwBytesToRead, dwBytesRead, dwBytesDownloaded,
dwIndex = 0;
DWORD dwLen = sizeof(dwDataSize);

dwBytesDownloaded = 0;

if( HttpQueryInfo(hHttpRequest, HTTP_QUERY_CONTENT_LENGTH |
HTTP_QUERY_FLAG_NUMBER, &dwDataSize, &dwLen, &dwIndex) )
{
while( dwDataSize != 0 )
{
dwNumToRead = min(dwDataSize, sizeof(Buffer));

if( !InternetReadFile(hHttpRequest, Buffer, dwBytesToRead,
&dwBytesRead) )
break;

// write the data...
dwDataSize -= dwBytesRead;
dwBytesDownloaded += dwBytesRead;
}
}


Gambit
Back to top
Boba
Guest





PostPosted: Wed Jan 03, 2007 1:29 am    Post subject: Re: downloading with wininet Reply with quote

"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in message
news:459aac49$1 (AT) newsgroups (DOT) borland.com...
Quote:
...
Considering that none of your code is doing any error handling, you
did not specify the contents of the values you are passing, and you
did not specify on which line the failure is actually occuring, there
is no way to diagnose your problem. You need to provide more
information.

the error checking has been stripped off to simplify the post.
there is no code line where it fails: it is the result of downloading
that is sometimes wrong. at random, the file i get is the 406 error
message (none of the code lines report a failure). some servers never
send 406; others - like the one in my sample - do it at no obvious
reason for that. let say i call the function 5 times in a raw on the
same file and 2 times i may get a 406.html file instead.

Quote:
Your looping code is wrong anyway. You are not using the value that
InternetQueryDataAvailable() returns. You must read everything that
InternetQueryDataAvailable() reports, or else it cannot report more
data later.

i do read everything (not shown for the sake of simplicity).

Quote:
However, I strongly suggest you use HttpQueryInfo() instead of
InternetQueryDataAvailable().

i will try it shortly.
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Wed Jan 03, 2007 2:30 am    Post subject: Re: downloading with wininet Reply with quote

"Boba" <Boba (AT) somewhere (DOT) world> wrote in message
news:459ab27c (AT) newsgroups (DOT) borland.com...

Quote:
the error checking has been stripped off to simplify the post.
there is no code line where it fails: it is the result of
downloading
that is sometimes wrong. at random, the file i get is the 406 error
message (none of the code lines report a failure).

Well, you are not checking the actual response code to begin with
before downloading the file. 406 is a "not acceptable" error. You
have to use HttpQueryInfo() to verify the server's reply before you
can decide whether the file is ok to download or not.

Quote:
some servers never send 406; others - like the one in my
sample - do it at no obvious reason for that.

I am assuming that you have not read RFC 2616 yet:

Hypertext Transfer Protocol -- HTTP/1.1
http://www.ietf.org/rfc/rfc2616.txt

10.4.7 406 Not Acceptable

The resource identified by the request is only capable of
generating
response entities which have content characteristics not
acceptable
according to the accept headers sent in the request.

Unless it was a HEAD request, the response SHOULD include an
entity
containing a list of available entity characteristics and
location(s)
from which the user or user agent can choose the one most
appropriate. The entity format is specified by the media type
given
in the Content-Type header field. Depending upon the format
and the
capabilities of the user agent, selection of the most
appropriate
choice MAY be performed automatically. However, this
specification
does not define any standard for such automatic selection.

Note: HTTP/1.1 servers are allowed to return responses which
are
not acceptable according to the accept headers sent in the
request. In some cases, this may even be preferable to sending
a
406 response. User agents are encouraged to inspect the
headers of
an incoming response to determine if it is acceptable.

If the response could be unacceptable, a user agent SHOULD
temporarily stop receipt of more data and query the user for a
decision on further actions.

Quote:
i do read everything (not shown for the sake of simplicity).

You are calling InternetReadFile() once, and only once, for each call
to InternetQueryDataAvailable(). If the size of the available data is
larger than your buffer, or InterntReadFile() cannot return that much
data in a single call, then you are NOT reading all of the available
data properly. That is why you must loop the call to
InterntReadFile() to ensure all available data is read in full.


Gambit
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Wed Jan 03, 2007 2:36 am    Post subject: Re: downloading with wininet Reply with quote

"Boba" <Boba (AT) somewhere (DOT) world> wrote in message
news:459ac5e4 (AT) newsgroups (DOT) borland.com...

Quote:
i'm getting exactly the same behavior: once in a while the file
downloaded is just a 406.html message.

That is because your requests are wrong to begin with, and you are not
checking the server's response code. Please see my other reply.


Gambit
Back to top
Boba
Guest





PostPosted: Wed Jan 03, 2007 2:52 am    Post subject: Re: downloading with wininet Reply with quote

"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in message
news:459aac49$1 (AT) newsgroups (DOT) borland.com...
Quote:
...
However, I strongly suggest you use HttpQueryInfo() instead of
InternetQueryDataAvailable().

i'm getting exactly the same behavior: once in a while the file
downloaded is just a 406.html message. so, how do i tell the server
that my client is aware of all these MIME settings and that it does
accept the MIME type of the requested page.
Back to top
Boba
Guest





PostPosted: Wed Jan 03, 2007 3:13 am    Post subject: Re: downloading with wininet Reply with quote

"Remy Lebeau (TeamB)" <no.spam (AT) no (DOT) spam.com> wrote in message
news:459ac541$1 (AT) newsgroups (DOT) borland.com...
Quote:
...
I am assuming that you have not read RFC 2616 yet:

you've got that right.

Quote:
You are calling InternetReadFile() once, and only once, for each call
to InternetQueryDataAvailable(). If the size of the available data is
larger than your buffer, or InterntReadFile() cannot return that much
data in a single call, then you are NOT reading all of the available
data properly. That is why you must loop the call to
InterntReadFile() to ensure all available data is read in full.

i do loop InternetReadFile untill dwBytesDownloaded becomes 0.
my problem is not in reading the file, but in convincing the
server in client's ability to accept that type of file. the
server responds with 406 in a very strange inconsistency,
which means i've got to tell it first that i am aware of
teh potential MIME problems. i don't understand why the
server is not pursistant in its response and how do i
create my request header properly.
Back to top
Remy Lebeau (TeamB)
Guest





PostPosted: Wed Jan 03, 2007 7:06 am    Post subject: Re: downloading with wininet Reply with quote

"Boba" <Boba (AT) somewhere (DOT) world> wrote in message
news:459acad3 (AT) newsgroups (DOT) borland.com...

Quote:
i do loop InternetReadFile untill dwBytesDownloaded becomes 0.

No, you are not. I quote your original code:

do{
if( InternetQueryDataAvailable( hHttpRequest, &dwDataSize, 0,
0 ) ){
if( InternetReadFile( hHttpRequest, (LPVOID)Buffer,
sizeof(Buffer), &dwBytesDownloaded ) ){
/*write the data*/
}//if( InternetReadFile
}//if( InternetQueryDataAvailable(
} while( dwBytesDownloaded );

You are looping InternetQueryDataAvailable(), not InternetReadFile().
Again, if you do not read ALL of the data that
InternetQueryDataAvailable() reports in a single call, it CANNOT
report more data until the previous data queue is emptied. This is
clearly stated by Microsoft's documentation:

InternetQueryDataAvailable
http://msdn2.microsoft.com/en-us/library/aa385100.aspx

"This function returns the number of bytes of data that are
available to be read immediately by a subsequent call to
InternetReadFile. If there is currently no data available and the end
of the file has not been reached, the request waits until data becomes
available. The amount of data remaining will not be recalculated until
all available data indicated by the call to InternetQueryDataAvailable
is read."

Read the last sentence very carefully. After you call
InternetQueryDataAvailable(), you must read ALL available data before
you can call InternetQueryDataAvailable() again.

Quote:
my problem is not in reading the file

It may not be the original problem you were asking about, but it is
another problem in your code nontheless that you must address
properly.

Quote:
but in convincing the server in client's ability to accept that type
of file.


Had you read the RFC that I pointed you to, you would see that when a
406 reply is returned by the server, the reply data includes
alternative characteristics and locations that you must use to
download the content, as the original criteria you provided will not
work for what you are trying to download.


Gambit
Back to top
Boba
Guest





PostPosted: Wed Jan 03, 2007 8:35 am    Post subject: Re: downloading with wininet Reply with quote

Thank you very much, Gambit.
The information you have provided during this conversation
was very helpful in resolving the problem with my code.
Boba
Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> C++ Builder (Internet Web) All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.