Sample code for 30+ languages & platforms
Unicode C

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 Unicode C Downloads

Unicode C
#include <C_CkHttpW.h>
#include <C_CkHttpResponseW.h>
#include <C_CkStringBuilderW.h>
#include <C_CkTaskW.h>
#include <C_CkFileAccessW.h>

void ChilkatSample(void)
    {
    BOOL success;
    HCkHttpW http;
    const wchar_t *url;
    HCkHttpResponseW resp;
    int remoteFileSize;
    int chunkSize;
    HCkHttpW http1;
    HCkHttpW http2;
    HCkHttpW http3;
    HCkHttpW http4;
    HCkStringBuilderW sbRange;
    int numReplaced;
    HCkTaskW task1;
    HCkTaskW task2;
    HCkTaskW task3;
    HCkTaskW task4;
    int numLive;
    int numErrors;
    HCkFileAccessW fac;
    BOOL bSame;

    success = FALSE;

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

    http = CkHttpW_Create();

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

    resp = CkHttpResponseW_Create();
    success = CkHttpW_HttpNoBody(http,L"HEAD",url,resp);
    if (success == FALSE) {
        wprintf(L"%s\n",CkHttpW_lastErrorText(http));
        CkHttpW_Dispose(http);
        CkHttpResponseW_Dispose(resp);
        return;
    }

    remoteFileSize = CkHttpResponseW_getContentLength(resp);

    wprintf(L"Downloading %d bytes...\n",remoteFileSize);

    // 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 = CkHttpW_Create();
    http2 = CkHttpW_Create();
    http3 = CkHttpW_Create();
    http4 = CkHttpW_Create();

    sbRange = CkStringBuilderW_Create();
    CkStringBuilderW_SetString(sbRange,L"bytes=<range-start>-<range-end>");
    numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-start>",0);
    numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-end>",chunkSize - 1);
    wprintf(L"%s\n",CkStringBuilderW_getAsString(sbRange));
    CkHttpW_SetRequestHeader(http1,L"Range",CkStringBuilderW_getAsString(sbRange));

    CkStringBuilderW_SetString(sbRange,L"bytes=<range-start>-<range-end>");
    numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-start>",chunkSize);
    numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-end>",2 * chunkSize - 1);
    wprintf(L"%s\n",CkStringBuilderW_getAsString(sbRange));
    CkHttpW_SetRequestHeader(http2,L"Range",CkStringBuilderW_getAsString(sbRange));

    CkStringBuilderW_SetString(sbRange,L"bytes=<range-start>-<range-end>");
    numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-start>",2 * chunkSize);
    numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-end>",3 * chunkSize - 1);
    wprintf(L"%s\n",CkStringBuilderW_getAsString(sbRange));
    CkHttpW_SetRequestHeader(http3,L"Range",CkStringBuilderW_getAsString(sbRange));

    CkStringBuilderW_SetString(sbRange,L"bytes=<range-start>-");
    numReplaced = CkStringBuilderW_ReplaceI(sbRange,L"<range-start>",3 * chunkSize);
    wprintf(L"%s\n",CkStringBuilderW_getAsString(sbRange));
    CkHttpW_SetRequestHeader(http4,L"Range",CkStringBuilderW_getAsString(sbRange));

    // Start each range download
    task1 = CkHttpW_DownloadAsync(http1,url,L"qa_output/chunk1.dat");
    CkTaskW_Run(task1);

    task2 = CkHttpW_DownloadAsync(http2,url,L"qa_output/chunk2.dat");
    CkTaskW_Run(task2);

    task3 = CkHttpW_DownloadAsync(http3,url,L"qa_output/chunk3.dat");
    CkTaskW_Run(task3);

    task4 = CkHttpW_DownloadAsync(http4,url,L"qa_output/chunk4.dat");
    CkTaskW_Run(task4);

    // Wait for the downloads to complete.
    numLive = 4;
    while (numLive > 0) {
        numLive = 0;
        if (CkTaskW_getLive(task1) == TRUE) {
            numLive = numLive + 1;
        }

        if (CkTaskW_getLive(task2) == TRUE) {
            numLive = numLive + 1;
        }

        if (CkTaskW_getLive(task3) == TRUE) {
            numLive = numLive + 1;
        }

        if (CkTaskW_getLive(task4) == 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..
            CkTaskW_SleepMs(task1,10);
        }

    }

    // All should be downloaded now..
    // Examine the result of each Download.
    numErrors = 0;
    if (CkTaskW_GetResultBool(task1) == FALSE) {
        wprintf(L"%s\n",CkTaskW_resultErrorText(task1));
        numErrors = numErrors + 1;
    }

    if (CkTaskW_GetResultBool(task2) == FALSE) {
        wprintf(L"%s\n",CkTaskW_resultErrorText(task2));
        numErrors = numErrors + 1;
    }

    if (CkTaskW_GetResultBool(task3) == FALSE) {
        wprintf(L"%s\n",CkTaskW_resultErrorText(task3));
        numErrors = numErrors + 1;
    }

    if (CkTaskW_GetResultBool(task4) == FALSE) {
        wprintf(L"%s\n",CkTaskW_resultErrorText(task4));
        numErrors = numErrors + 1;
    }

    if (numErrors > 0) {
        CkTaskW_Dispose(task1);
        CkTaskW_Dispose(task2);
        CkTaskW_Dispose(task3);
        CkTaskW_Dispose(task4);
        CkHttpW_Dispose(http);
        CkHttpResponseW_Dispose(resp);
        CkHttpW_Dispose(http1);
        CkHttpW_Dispose(http2);
        CkHttpW_Dispose(http3);
        CkHttpW_Dispose(http4);
        CkStringBuilderW_Dispose(sbRange);
        return;
    }

    // All downloads were successful.
    // Compose the file from the parts.
    fac = CkFileAccessW_Create();
    success = CkFileAccessW_ReassembleFile(fac,L"qa_output",L"chunk",L"dat",L"qa_output/hamlet.xml");
    if (success == FALSE) {
        wprintf(L"%s\n",CkFileAccessW_lastErrorText(fac));
    }
    else {
        wprintf(L"Success.\n");
    }

    CkTaskW_Dispose(task1);
    CkTaskW_Dispose(task2);
    CkTaskW_Dispose(task3);
    CkTaskW_Dispose(task4);

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

    // Compare files.
    bSame = CkFileAccessW_FileContentsEqual(fac,L"qa_output/hamlet.xml",L"qa_output/hamletRegular.xml");
    wprintf(L"bSame = %d\n",bSame);


    CkHttpW_Dispose(http);
    CkHttpResponseW_Dispose(resp);
    CkHttpW_Dispose(http1);
    CkHttpW_Dispose(http2);
    CkHttpW_Dispose(http3);
    CkHttpW_Dispose(http4);
    CkStringBuilderW_Dispose(sbRange);
    CkFileAccessW_Dispose(fac);

    }