Sample code for 30+ languages & platforms
Go

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

Go
    success := false

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

    http := chilkat.NewHttp()

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

    resp := chilkat.NewHttpResponse()
    success = http.HttpNoBody("HEAD",url,resp)
    if success == false {
        fmt.Println(http.LastErrorText())
        http.DisposeHttp()
        resp.DisposeHttpResponse()
        return
    }

    remoteFileSize := resp.ContentLength()

    fmt.Println("Downloading ", remoteFileSize, " bytes...")

    // Let's download in 4 chunks.
    // (the last chunk will be whatever remains after the 1st 3 equal sized chunks)
    chunkSize := remoteFileSize / 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..
    http1 := chilkat.NewHttp()
    http2 := chilkat.NewHttp()
    http3 := chilkat.NewHttp()
    http4 := chilkat.NewHttp()

    sbRange := chilkat.NewStringBuilder()
    sbRange.SetString("bytes=<range-start>-<range-end>")
    numReplaced := sbRange.ReplaceI("<range-start>",0)
    numReplaced = sbRange.ReplaceI("<range-end>",chunkSize - 1)
    fmt.Println(*sbRange.GetAsString())
    http1.SetRequestHeader("Range",*sbRange.GetAsString())

    sbRange.SetString("bytes=<range-start>-<range-end>")
    numReplaced = sbRange.ReplaceI("<range-start>",chunkSize)
    numReplaced = sbRange.ReplaceI("<range-end>",2 * chunkSize - 1)
    fmt.Println(*sbRange.GetAsString())
    http2.SetRequestHeader("Range",*sbRange.GetAsString())

    sbRange.SetString("bytes=<range-start>-<range-end>")
    numReplaced = sbRange.ReplaceI("<range-start>",2 * chunkSize)
    numReplaced = sbRange.ReplaceI("<range-end>",3 * chunkSize - 1)
    fmt.Println(*sbRange.GetAsString())
    http3.SetRequestHeader("Range",*sbRange.GetAsString())

    sbRange.SetString("bytes=<range-start>-")
    numReplaced = sbRange.ReplaceI("<range-start>",3 * chunkSize)
    fmt.Println(*sbRange.GetAsString())
    http4.SetRequestHeader("Range",*sbRange.GetAsString())

    // Start each range download
    c := make(chan *chilkat.Task)
    go http1.DownloadAsync(url,"qa_output/chunk1.dat",c)
    task1 := <-c

    c := make(chan *chilkat.Task)
    go http2.DownloadAsync(url,"qa_output/chunk2.dat",c)
    task2 := <-c

    c := make(chan *chilkat.Task)
    go http3.DownloadAsync(url,"qa_output/chunk3.dat",c)
    task3 := <-c

    c := make(chan *chilkat.Task)
    go http4.DownloadAsync(url,"qa_output/chunk4.dat",c)
    task4 := <-c

    // Wait for the downloads to complete.
    numLive := 4
    for numLive > 0 {
        numLive = 0
        if task1.Live() == true {
            numLive = numLive + 1
        }

        if task2.Live() == true {
            numLive = numLive + 1
        }

        if task3.Live() == true {
            numLive = numLive + 1
        }

        if task4.Live() == true {
            numLive = numLive + 1
        }

        if numLive > 0 {
            // SleepMs is a convenience method to cause the caller to sleep for N millisec.
            // It does not cause the given task to sleep..
            task1.SleepMs(10)
        }

    }

    // All should be downloaded now..
    // Examine the result of each Download.
    numErrors := 0
    if task1.GetResultBool() == false {
        fmt.Println(task1.ResultErrorText())
        numErrors = numErrors + 1
    }

    if task2.GetResultBool() == false {
        fmt.Println(task2.ResultErrorText())
        numErrors = numErrors + 1
    }

    if task3.GetResultBool() == false {
        fmt.Println(task3.ResultErrorText())
        numErrors = numErrors + 1
    }

    if task4.GetResultBool() == false {
        fmt.Println(task4.ResultErrorText())
        numErrors = numErrors + 1
    }

    if numErrors > 0 {
        task1.DisposeTask()
        task2.DisposeTask()
        task3.DisposeTask()
        task4.DisposeTask()
        http.DisposeHttp()
        resp.DisposeHttpResponse()
        http1.DisposeHttp()
        http2.DisposeHttp()
        http3.DisposeHttp()
        http4.DisposeHttp()
        sbRange.DisposeStringBuilder()
        task1.DisposeTask()
        task2.DisposeTask()
        task3.DisposeTask()
        task4.DisposeTask()
        return
    }

    // All downloads were successful.
    // Compose the file from the parts.
    fac := chilkat.NewFileAccess()
    success = fac.ReassembleFile("qa_output","chunk","dat","qa_output/hamlet.xml")
    if success == false {
        fmt.Println(fac.LastErrorText())
    } else {
        fmt.Println("Success.")
    }

    task1.DisposeTask()
    task2.DisposeTask()
    task3.DisposeTask()
    task4.DisposeTask()

    // Let's download in the regular way, and then compare files..
    success = http.Download(url,"qa_output/hamletRegular.xml")

    // Compare files.
    bSame := fac.FileContentsEqual("qa_output/hamlet.xml","qa_output/hamletRegular.xml")
    fmt.Println("bSame = ", bSame)

    http.DisposeHttp()
    resp.DisposeHttpResponse()
    http1.DisposeHttp()
    http2.DisposeHttp()
    http3.DisposeHttp()
    http4.DisposeHttp()
    sbRange.DisposeStringBuilder()
    task1.DisposeTask()
    task2.DisposeTask()
    task3.DisposeTask()
    task4.DisposeTask()
    fac.DisposeFileAccess()