Sample code for 30+ languages & platforms
Lianja

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 Lianja Downloads

Lianja
llSuccess = .F.

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

loHttp = createobject("CkHttp")

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

loResp = createobject("CkHttpResponse")
llSuccess = loHttp.HttpNoBody("HEAD",lcUrl,loResp)
if (llSuccess = .F.) then
    ? loHttp.LastErrorText
    release loHttp
    release loResp
    return
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("CkHttp")
loHttp2 = createobject("CkHttp")
loHttp3 = createobject("CkHttp")
loHttp4 = createobject("CkHttp")

loSbRange = createobject("CkStringBuilder")
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 = .T.) then
        lnNumLive = lnNumLive + 1
    endif

    if (loTask2.Live = .T.) then
        lnNumLive = lnNumLive + 1
    endif

    if (loTask3.Live = .T.) then
        lnNumLive = lnNumLive + 1
    endif

    if (loTask4.Live = .T.) 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() = .F.) then
    ? loTask1.ResultErrorText
    lnNumErrors = lnNumErrors + 1
endif

if (loTask2.GetResultBool() = .F.) then
    ? loTask2.ResultErrorText
    lnNumErrors = lnNumErrors + 1
endif

if (loTask3.GetResultBool() = .F.) then
    ? loTask3.ResultErrorText
    lnNumErrors = lnNumErrors + 1
endif

if (loTask4.GetResultBool() = .F.) 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
    return
endif

// All downloads were successful.
// Compose the file from the parts.
loFac = createobject("CkFileAccess")
llSuccess = loFac.ReassembleFile("qa_output","chunk","dat","qa_output/hamlet.xml")
if (llSuccess = .F.) 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..
llSuccess = loHttp.Download(lcUrl,"qa_output/hamletRegular.xml")

// Compare files.
llBSame = loFac.FileContentsEqual("qa_output/hamlet.xml","qa_output/hamletRegular.xml")
? "bSame = " + str(llBSame)


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