Sample code for 30+ languages & platforms
Delphi DLL

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 Delphi DLL Downloads

Delphi DLL
uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Http, StringBuilder, Task, HttpResponse, FileAccess;

...

procedure TForm1.Button1Click(Sender: TObject);
var
success: Boolean;
http: HCkHttp;
url: PWideChar;
resp: HCkHttpResponse;
remoteFileSize: Integer;
chunkSize: Integer;
http1: HCkHttp;
http2: HCkHttp;
http3: HCkHttp;
http4: HCkHttp;
sbRange: HCkStringBuilder;
numReplaced: Integer;
task1: HCkTask;
task2: HCkTask;
task3: HCkTask;
task4: HCkTask;
numLive: Integer;
numErrors: Integer;
fac: HCkFileAccess;
bSame: Boolean;

begin
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) then
  begin
    Memo1.Lines.Add(CkHttp__lastErrorText(http));
    Exit;
  end;

remoteFileSize := CkHttpResponse_getContentLength(resp);

Memo1.Lines.Add('Downloading ' + IntToStr(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 := 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);
Memo1.Lines.Add(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);
Memo1.Lines.Add(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);
Memo1.Lines.Add(CkStringBuilder__getAsString(sbRange));
CkHttp_SetRequestHeader(http3,'Range',CkStringBuilder__getAsString(sbRange));

CkStringBuilder_SetString(sbRange,'bytes=<range-start>-');
numReplaced := CkStringBuilder_ReplaceI(sbRange,'<range-start>',3 * chunkSize);
Memo1.Lines.Add(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 do
  begin
    numLive := 0;
    if (CkTask_getLive(task1) = True) then
      begin
        numLive := numLive + 1;
      end;
    if (CkTask_getLive(task2) = True) then
      begin
        numLive := numLive + 1;
      end;
    if (CkTask_getLive(task3) = True) then
      begin
        numLive := numLive + 1;
      end;
    if (CkTask_getLive(task4) = True) then
      begin
        numLive := numLive + 1;
      end;
    if (numLive > 0) then
      begin
        // 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);
      end;
  end;

// All should be downloaded now..
// Examine the result of each Download.
numErrors := 0;
if (CkTask_GetResultBool(task1) = False) then
  begin
    Memo1.Lines.Add(CkTask__resultErrorText(task1));
    numErrors := numErrors + 1;
  end;
if (CkTask_GetResultBool(task2) = False) then
  begin
    Memo1.Lines.Add(CkTask__resultErrorText(task2));
    numErrors := numErrors + 1;
  end;
if (CkTask_GetResultBool(task3) = False) then
  begin
    Memo1.Lines.Add(CkTask__resultErrorText(task3));
    numErrors := numErrors + 1;
  end;
if (CkTask_GetResultBool(task4) = False) then
  begin
    Memo1.Lines.Add(CkTask__resultErrorText(task4));
    numErrors := numErrors + 1;
  end;
if (numErrors > 0) then
  begin
    CkTask_Dispose(task1);
    CkTask_Dispose(task2);
    CkTask_Dispose(task3);
    CkTask_Dispose(task4);
    Exit;
  end;

// 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) then
  begin
    Memo1.Lines.Add(CkFileAccess__lastErrorText(fac));
  end
else
  begin
    Memo1.Lines.Add('Success.');
  end;

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');
Memo1.Lines.Add('bSame = ' + IntToStr(Ord(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);

end;