🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.internet.web
11 messages
11 total messages Started by Boba Tue, 02 Jan 2007 06:21
downloading with wininet
#448
Author: Boba
Date: Tue, 02 Jan 2007 06:21
44 lines
2489 bytes
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
Re: downloading with wininet
#449
Author: Remy Lebeau (TeamB)
Date: Tue, 02 Jan 2007 09:27
35 lines
2154 bytes
"Boba" <Boba@somewhere.world> wrote in message
news:4599f9c5@newsgroups.borland.com...

> 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 };

>       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.

>           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
Re: downloading with wininet
#450
Author: Boba
Date: Tue, 02 Jan 2007 16:36
40 lines
2264 bytes
"Remy Lebeau (TeamB)" <no.spam@no.spam.com> wrote in message
news:459a2c13$1@newsgroups.borland.com...
> ...
> > 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.

>     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");

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

that's the way 'they' want.

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

InternetQueryDataAvailable() is supposed to do that.

> That way you know when to stop looping properly.

if no (more) data avalable, dwBytesDownloaded will be set 0
by the InternetReadFile() call.
Re: downloading with wininet
#451
Author: Remy Lebeau (TeamB)
Date: Tue, 02 Jan 2007 18:44
95 lines
4041 bytes
"Boba" <Boba@somewhere.world> wrote in message
news:459a89d6@newsgroups.borland.com...

> ...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.

> here's a sample call: DownloadFile("download.microsoft.com",
>
"/download/6/a/f/6af940c1-2774-4ebb-8546-2c83068af231/Windows2000-KB92
6247-x86-E
> 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");

> > 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
Re: downloading with wininet
#452
Author: Boba
Date: Tue, 02 Jan 2007 19:29
28 lines
2211 bytes
"Remy Lebeau (TeamB)" <no.spam@no.spam.com> wrote in message
news:459aac49$1@newsgroups.borland.com...
> ...
> 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.

> 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).

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

i will try it shortly.
Re: downloading with wininet
#453
Author: Remy Lebeau (TeamB)
Date: Tue, 02 Jan 2007 20:30
70 lines
3790 bytes
"Boba" <Boba@somewhere.world> wrote in message
news:459ab27c@newsgroups.borland.com...

> 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.

> 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.

> 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
Re: downloading with wininet
#455
Author: Remy Lebeau (TeamB)
Date: Tue, 02 Jan 2007 20:36
12 lines
1313 bytes
"Boba" <Boba@somewhere.world> wrote in message
news:459ac5e4@newsgroups.borland.com...

> 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
Re: downloading with wininet
#454
Author: Boba
Date: Tue, 02 Jan 2007 20:52
10 lines
1368 bytes
"Remy Lebeau (TeamB)" <no.spam@no.spam.com> wrote in message
news:459aac49$1@newsgroups.borland.com...
> ...
> 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.
Re: downloading with wininet
#456
Author: Boba
Date: Tue, 02 Jan 2007 21:13
22 lines
2149 bytes
"Remy Lebeau (TeamB)" <no.spam@no.spam.com> wrote in message
news:459ac541$1@newsgroups.borland.com...
> ...
> I am assuming that you have not read RFC 2616 yet:

you've got that right.

> 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.
Re: downloading with wininet
#457
Author: Remy Lebeau (TeamB)
Date: Wed, 03 Jan 2007 01:06
56 lines
3254 bytes
"Boba" <Boba@somewhere.world> wrote in message
news:459acad3@newsgroups.borland.com...

> 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.

> 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.

> 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
Re: downloading with wininet
#458
Author: Boba
Date: Wed, 03 Jan 2007 02:35
4 lines
1274 bytes
Thank you very much, Gambit.
The information you have provided during this conversation
was very helpful in resolving the problem with my code.
Boba
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads