🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.internet.web
Article #735

Re: Downloading and resuming

#735
From: Remy Lebeau (TeamB)
Date: Mon, 06 Nov 2006 21:14
221 lines
8072 bytes
"Will Bright" <no@spam.com> wrote in message
news:454f7d80$1@newsgroups.borland.com...

> I am trying to resume the download so it can continue on, but
> my code does not seem to be doing just that.

Why not?  Please be more specific.  What EXACTLY do you see happening?

> InternetSetFilePointer(hFile, dwBytesRead, NULL, FILE_CURRENT, 0);

You are not doing any error checking to ensure that operation is succeeding.
Not all servers support resuming.  For those that don't,
InternetSetFilePointer() invokes some pretty bad performance penalties as
the original data is re-downloaded from the beginning and simply discarded
until the resume position is reached.

There is a more efficient way to handle resuming on a server that supporting
resuming - use HttpAddRequestHeaders() to add a 'Range' header to the
request, specifying the bytes you want.  You will have to change your code
to use HttpOpenRequest() instead of InternetOpenURL(), though.

> FileStream->Write(Data, dwRead);

Write() returns the actual number of bytes written.  You are not verifying
that the number of bytes written actually matches the number of bytes read
from the connection.

> ProgressBar->Position += dwRead;

You cannot use compund assignment operators with VCL properties.  You must
use the '=' and '+' operators separately.

    ProgressBar->Position = ProgressBar->Position + dwRead;

Or simply:

    ProgressBar->StepBy(dwRead);

With that said, try something more like the following (untested):

    bool GetHttpInfoString(HINTERNET hInfo, DWORD dwValue, AnsiString &Data)
    {
        DWORD dwLength = 0;
        DWORD dwIndex = 0;

        Data = "";

        HttpQueryInfo(hInfo, dwValue, NULL, &dwLength, &dwIndex);
        if( GetLastError() != ERROR_INSUFFICIENT_BUFFER )
            return false;

        LPTSTR buffer = (LPTSTR) LocalAlloc(LPTR, dwLength+1);
        if( !buf )
            return false;

        dwIndex = 0;
        if( !HttpQueryInfo(hInfo, dwValue, buffer, &dwLength, &dwIndex) )
        {
            LocalFree(buffer);
            return false;
        }

        try
        {
            Data = buffer;
        }
        catch(const Exception &)
        {
            LocalFree(buffer);
            return false;
        }

        LocalFree(buffer);
        return true;
    }

    {
        HINTERNET hSession = NULL;
        HINTERNET hFile = NULL;
        DWORD dwContentLen;
        DWORD dwBufLen = sizeof(dwContentLen);
        DWORD dwRead;
        LPTSTR* szAcceptTypes = {"*.*", NULL};
        int iWritten;

        BYTE Data[1024];
        LPBYTE DataPtr;

        AnsiString AcceptRanges;
        AnsiString FileName;
        bool bIsResuming = false;

        TSaveDialog* SaveDialog;
        TFileStream* FileStream;

        try
        {
            hSession = InternetOpen("Windows Internet Explorer",
INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
            if( !hSession )
                throw Exception("unable to to create internet session");

            hFile = HttpOpenRequest(hSession, "HEAD", edtURL->Text.c_str(),
"HTTP/1.1", NULL, szAcceptTypes, INTERNET_FLAG_RELOAD, 0);
            if( !hFile )
                throw Exception("unable to create info request for the url:
" + edtURL->Text);

            if( !HttpSendRequest(hFile, NULL, 0, NULL, 0) )
                throw Exception("unable to send info request to the
server");

            if( !HttpQueryInfo(hFile, HTTP_QUERY_CONTENT_LENGTH |
HTTP_QUERY_FLAG_NUMBER, (LPVOID)&dwContentLen,
&dwBufLen, 0) )
                throw Exception("Failed to obtain the length of the file");

            if( !GetHttpInfoString(hFile, HTTP_QUERY_ACCEPT_RANGES,
AcceptRanges) )
                throw Exception("Failed to obtain if the server supports
ranges");

            InternetCloseHandle(hFile);
            hFile = HttpOpenRequest(hSession, "GET", edtURL->Text.c_str(),
"HTTP/1.1", NULL, szAcceptTypes, INTERNET_FLAG_RELOAD, 0);
            if( !hFile )
                throw Exception("unable to create file request for the url:
" + edtURL->Text);

            SaveDialog = new TSaveDialog(NULL);
            try
            {
                if( SaveDialog->Execute() )
                    FileName = SaveDialog->FileName;
            }
            __finally {
                delete SaveDialog;
            }

            if( FileName != "" )
            {
                if( FileExists(FileName) )
                {
                    if( AcceptRanges.Pos("bytes") != 0 )
                    {
                        AnsiString Range = ("Range: bytes=" +
AnsiString(FileStream->Size) + "-\r\n");
                        if( !HttpAddRequestHeaders(hFile, Range.c_str(), -1,
HTTP_ADDREQ_FLAG_ADD) )
                            throw Exception("unable to add range header to
file request");
                        bIsResuming = true;
                    }
                }

                if( !HttpSendRequest(hFile, NULL, 0, NULL, 0) )
                    throw Exception("unable to send file request to the
server");

                if( bIsResuming )
                    FileStream = new TFileStream(FileName, fmOpenReadWrite |
fmShareDenyWrite);
                else
                    FileStream = new TFileStream(FileName, fmCreate);

                try
                {
                    if( bIsResuming )
                    {
                        FileStream->Seek(0, soFromEnd);
                        dwBytesRead = FileStream->Position;
                    }
                    else
                        dwBytesRead

                    ProgressBar->Position = (dwBytesRead * 100 / dwBufLen);
                    ProgressBar->Max = dwContentLen;

                    while( InternetReadFile(hFile, Data, 1024, &dwRead) )
                    {
                        if( dwRead == 0 )
                            break;

                        iWritten = 0;
                        DataPtr = Data;

                        do
                        {
                            iWritten = FileStream->Write(DataPtr, dwRead);
                            if( iWritten < 1 )
                                throw Exception("unable to write to local
file");

                            DataPtr += iWritten;
                            dwRead -= iWritten;

                            ProgressBar->StepBy(iWritten);
                            Application->ProcessMessages();
                        }
                        while( dwRead != 0 );
                    }

                    if( FileStream->Size != dwContentLen )
                        throw Exception("File saved is incomplete");
                }
                __finally {
                    delete FileStream;
                }
            }
        }
        __finally
        {
            if(hFile) InternetCloseHandle(hFile);
            if(hInfo) InternetCloseHandle(hInfo);
            if(hSession) InternetCloseHandle(hSession);
        }
    }


Gambit
Technical Details
Message-ID: <454fa637$1@newsgroups.borland.com>
Path: arc1-ca.pugleaf.net!g2news2.google.com!news4.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail
References: <454f7d80$1@newsgroups.borland.com>

Show Full Headers
Complete Article Headers
X-Google-Thread: feeec,f20f86396ab98121
X-Google-Attributes: gidfeeec,public
X-Google-Language: ENGLISH,ASCII-7-bit
From: "Remy Lebeau \(TeamB\)" <no.spam@no.spam.com>
Newsgroups: borland.public.cppbuilder.internet.web
References: <454f7d80$1@newsgroups.borland.com>
Subject: Re: Downloading and resuming
Date: Mon, 6 Nov 2006 13:14:13 -0800
Lines: 223
X-Priority: 3
X-MSMail-Priority: Normal
X-Newsreader: Microsoft Outlook Express 6.00.2800.1409
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1409
NNTP-Posting-Host: 69.169.4.232
Message-ID: <454fa637$1@newsgroups.borland.com>
X-Trace: newsgroups.borland.com 1162847799 69.169.4.232 (6 Nov 2006 13:16:39 -0700)
Path: arc1-ca.pugleaf.net!g2news2.google.com!news4.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail