Sample code for 30+ languages & platforms
Visual FoxPro

HTTP Download in Parallel with Simultaneous Range Requests

See more HTTP Examples

Demonstrates how to download a large file with parallel simultaneous requests, where each request downloads a segment (range) of the remote file.

Chilkat Visual FoxPro Downloads

Visual FoxPro
LOCAL lnSuccess
LOCAL loHttp
LOCAL lcUrl
LOCAL loResp
LOCAL lnRemoteFileSize
LOCAL lnChunkSize
LOCAL loHttp1
LOCAL loHttp2
LOCAL loHttp3
LOCAL loHttp4
LOCAL loSbRange
LOCAL lnNumReplaced
LOCAL loTask1
LOCAL loTask2
LOCAL loTask3
LOCAL loTask4
LOCAL lnNumLive
LOCAL lnNumErrors
LOCAL loFac
LOCAL lnBSame

lnSuccess = 0

* This requires the Chilkat API to have been previously unlocked.
* See Global Unlock Sample for sample code.

loHttp = CreateObject('Chilkat.Http')

* First get the size of the file to be downloaded.
lcUrl = "https://www.chilkatsoft.com/hamlet.xml"

loResp = CreateObject('Chilkat.HttpResponse')
lnSuccess = loHttp.HttpNoBody("HEAD",lcUrl,loResp)
IF (lnSuccess = 0) THEN
    ? loHttp.LastErrorText
    RELEASE loHttp
    RELEASE loResp
    CANCEL
ENDIF

lnRemoteFileSize = loResp.ContentLength

? "Downloading " + STR(lnRemoteFileSize) + " bytes..."

* Let's download in 4 chunks.
* (the last chunk will be whatever remains after the 1st 3 equal sized chunks)
lnChunkSize = lnRemoteFileSize / 4

* The Range header is used to download a range from a resource
* Range: bytes=<range-start>-<range-end>
* or
* Range: bytes=<range-start>-

* We're writing code this way for clarity..
loHttp1 = CreateObject('Chilkat.Http')
loHttp2 = CreateObject('Chilkat.Http')
loHttp3 = CreateObject('Chilkat.Http')
loHttp4 = CreateObject('Chilkat.Http')

loSbRange = CreateObject('Chilkat.StringBuilder')
loSbRange.SetString("bytes=<range-start>-<range-end>")
lnNumReplaced = loSbRange.ReplaceI("<range-start>",0)
lnNumReplaced = loSbRange.ReplaceI("<range-end>",lnChunkSize - 1)
? loSbRange.GetAsString()
loHttp1.SetRequestHeader("Range",loSbRange.GetAsString())

loSbRange.SetString("bytes=<range-start>-<range-end>")
lnNumReplaced = loSbRange.ReplaceI("<range-start>",lnChunkSize)
lnNumReplaced = loSbRange.ReplaceI("<range-end>",2 * lnChunkSize - 1)
? loSbRange.GetAsString()
loHttp2.SetRequestHeader("Range",loSbRange.GetAsString())

loSbRange.SetString("bytes=<range-start>-<range-end>")
lnNumReplaced = loSbRange.ReplaceI("<range-start>",2 * lnChunkSize)
lnNumReplaced = loSbRange.ReplaceI("<range-end>",3 * lnChunkSize - 1)
? loSbRange.GetAsString()
loHttp3.SetRequestHeader("Range",loSbRange.GetAsString())

loSbRange.SetString("bytes=<range-start>-")
lnNumReplaced = loSbRange.ReplaceI("<range-start>",3 * lnChunkSize)
? loSbRange.GetAsString()
loHttp4.SetRequestHeader("Range",loSbRange.GetAsString())

* Start each range download
loTask1 = loHttp1.DownloadAsync(lcUrl,"qa_output/chunk1.dat")
loTask1.Run()

loTask2 = loHttp2.DownloadAsync(lcUrl,"qa_output/chunk2.dat")
loTask2.Run()

loTask3 = loHttp3.DownloadAsync(lcUrl,"qa_output/chunk3.dat")
loTask3.Run()

loTask4 = loHttp4.DownloadAsync(lcUrl,"qa_output/chunk4.dat")
loTask4.Run()

* Wait for the downloads to complete.
lnNumLive = 4
DO WHILE lnNumLive > 0
    lnNumLive = 0
    IF (loTask1.Live = 1) THEN
        lnNumLive = lnNumLive + 1
    ENDIF

    IF (loTask2.Live = 1) THEN
        lnNumLive = lnNumLive + 1
    ENDIF

    IF (loTask3.Live = 1) THEN
        lnNumLive = lnNumLive + 1
    ENDIF

    IF (loTask4.Live = 1) THEN
        lnNumLive = lnNumLive + 1
    ENDIF

    IF (lnNumLive > 0) THEN
        * SleepMs is a convenience method to cause the caller to sleep for N millisec.
        * It does not cause the given task to sleep..
        loTask1.SleepMs(10)
    ENDIF

ENDDO

* All should be downloaded now..
* Examine the result of each Download.
lnNumErrors = 0
IF (loTask1.GetResultBool() = 0) THEN
    ? loTask1.ResultErrorText
    lnNumErrors = lnNumErrors + 1
ENDIF

IF (loTask2.GetResultBool() = 0) THEN
    ? loTask2.ResultErrorText
    lnNumErrors = lnNumErrors + 1
ENDIF

IF (loTask3.GetResultBool() = 0) THEN
    ? loTask3.ResultErrorText
    lnNumErrors = lnNumErrors + 1
ENDIF

IF (loTask4.GetResultBool() = 0) THEN
    ? loTask4.ResultErrorText
    lnNumErrors = lnNumErrors + 1
ENDIF

IF (lnNumErrors > 0) THEN
    RELEASE loTask1
    RELEASE loTask2
    RELEASE loTask3
    RELEASE loTask4
    RELEASE loHttp
    RELEASE loResp
    RELEASE loHttp1
    RELEASE loHttp2
    RELEASE loHttp3
    RELEASE loHttp4
    RELEASE loSbRange
    CANCEL
ENDIF

* All downloads were successful.
* Compose the file from the parts.
loFac = CreateObject('Chilkat.FileAccess')
lnSuccess = loFac.ReassembleFile("qa_output","chunk","dat","qa_output/hamlet.xml")
IF (lnSuccess = 0) THEN
    ? loFac.LastErrorText
ELSE
    ? "Success."
ENDIF

RELEASE loTask1
RELEASE loTask2
RELEASE loTask3
RELEASE loTask4

* Let's download in the regular way, and then compare files..
lnSuccess = loHttp.Download(lcUrl,"qa_output/hamletRegular.xml")

* Compare files.
lnBSame = loFac.FileContentsEqual("qa_output/hamlet.xml","qa_output/hamletRegular.xml")
? "bSame = " + STR(lnBSame)

RELEASE loHttp
RELEASE loResp
RELEASE loHttp1
RELEASE loHttp2
RELEASE loHttp3
RELEASE loHttp4
RELEASE loSbRange
RELEASE loFac