Sample code for 30+ languages & platforms
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 C Downloads

C
#include <C_CkHttp.h>
#include <C_CkHttpResponse.h>
#include <C_CkStringBuilder.h>
#include <C_CkTask.h>
#include <C_CkFileAccess.h>

void ChilkatSample(void)
    {
    BOOL success;
    HCkHttp http;
    const char *url;
    HCkHttpResponse resp;
    int remoteFileSize;
    int chunkSize;
    HCkHttp http1;
    HCkHttp http2;
    HCkHttp http3;
    HCkHttp http4;
    HCkStringBuilder sbRange;
    int numReplaced;
    HCkTask task1;
    HCkTask task2;
    HCkTask task3;
    HCkTask task4;
    int numLive;
    int numErrors;
    HCkFileAccess fac;
    BOOL bSame;

    success = FALSE;

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

    http = CkHttp_Create();

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

    resp = CkHttpResponse_Create();
    success = CkHttp_HttpNoBody(http,"HEAD",url,resp);
    if (success == FALSE) {
        printf("%s\n",CkHttp_lastErrorText(http));
        CkHttp_Dispose(http);
        CkHttpResponse_Dispose(resp);
        return;
    }

    remoteFileSize = CkHttpResponse_getContentLength(resp);

    printf("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 = CkHttp_Create();
    http2 = CkHttp_Create();
    http3 = CkHttp_Create();
    http4 = CkHttp_Create();

    sbRange = CkStringBuilder_Create();
    CkStringBuilder_SetString(sbRange,"bytes=<range-start>-<range-end>");
    numReplaced = CkStringBuilder_ReplaceI(sbRange,"<range-start>",0);
    numReplaced = CkStringBuilder_ReplaceI(sbRange,"<range-end>",chunkSize - 1);
    printf("%s\n",CkStringBuilder_getAsString(sbRange));
    CkHttp_SetRequestHeader(http1,"Range",CkStringBuilder_getAsString(sbRange));

    CkStringBuilder_SetString(sbRange,"bytes=<range-start>-<range-end>");
    numReplaced = CkStringBuilder_ReplaceI(sbRange,"<range-start>",chunkSize);
    numReplaced = CkStringBuilder_ReplaceI(sbRange,"<range-end>",2 * chunkSize - 1);
    printf("%s\n",CkStringBuilder_getAsString(sbRange));
    CkHttp_SetRequestHeader(http2,"Range",CkStringBuilder_getAsString(sbRange));

    CkStringBuilder_SetString(sbRange,"bytes=<range-start>-<range-end>");
    numReplaced = CkStringBuilder_ReplaceI(sbRange,"<range-start>",2 * chunkSize);
    numReplaced = CkStringBuilder_ReplaceI(sbRange,"<range-end>",3 * chunkSize - 1);
    printf("%s\n",CkStringBuilder_getAsString(sbRange));
    CkHttp_SetRequestHeader(http3,"Range",CkStringBuilder_getAsString(sbRange));

    CkStringBuilder_SetString(sbRange,"bytes=<range-start>-");
    numReplaced = CkStringBuilder_ReplaceI(sbRange,"<range-start>",3 * chunkSize);
    printf("%s\n",CkStringBuilder_getAsString(sbRange));
    CkHttp_SetRequestHeader(http4,"Range",CkStringBuilder_getAsString(sbRange));

    // Start each range download
    task1 = CkHttp_DownloadAsync(http1,url,"qa_output/chunk1.dat");
    CkTask_Run(task1);

    task2 = CkHttp_DownloadAsync(http2,url,"qa_output/chunk2.dat");
    CkTask_Run(task2);

    task3 = CkHttp_DownloadAsync(http3,url,"qa_output/chunk3.dat");
    CkTask_Run(task3);

    task4 = CkHttp_DownloadAsync(http4,url,"qa_output/chunk4.dat");
    CkTask_Run(task4);

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

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

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

        if (CkTask_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..
            CkTask_SleepMs(task1,10);
        }

    }

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

    if (CkTask_GetResultBool(task2) == FALSE) {
        printf("%s\n",CkTask_resultErrorText(task2));
        numErrors = numErrors + 1;
    }

    if (CkTask_GetResultBool(task3) == FALSE) {
        printf("%s\n",CkTask_resultErrorText(task3));
        numErrors = numErrors + 1;
    }

    if (CkTask_GetResultBool(task4) == FALSE) {
        printf("%s\n",CkTask_resultErrorText(task4));
        numErrors = numErrors + 1;
    }

    if (numErrors > 0) {
        CkTask_Dispose(task1);
        CkTask_Dispose(task2);
        CkTask_Dispose(task3);
        CkTask_Dispose(task4);
        CkHttp_Dispose(http);
        CkHttpResponse_Dispose(resp);
        CkHttp_Dispose(http1);
        CkHttp_Dispose(http2);
        CkHttp_Dispose(http3);
        CkHttp_Dispose(http4);
        CkStringBuilder_Dispose(sbRange);
        return;
    }

    // All downloads were successful.
    // Compose the file from the parts.
    fac = CkFileAccess_Create();
    success = CkFileAccess_ReassembleFile(fac,"qa_output","chunk","dat","qa_output/hamlet.xml");
    if (success == FALSE) {
        printf("%s\n",CkFileAccess_lastErrorText(fac));
    }
    else {
        printf("Success.\n");
    }

    CkTask_Dispose(task1);
    CkTask_Dispose(task2);
    CkTask_Dispose(task3);
    CkTask_Dispose(task4);

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

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


    CkHttp_Dispose(http);
    CkHttpResponse_Dispose(resp);
    CkHttp_Dispose(http1);
    CkHttp_Dispose(http2);
    CkHttp_Dispose(http3);
    CkHttp_Dispose(http4);
    CkStringBuilder_Dispose(sbRange);
    CkFileAccess_Dispose(fac);

    }