Asynchronous HTTP download

 
This sample utilizes the TclHttp component for downloading URLs, the TclThreadPool class for implementing the threading functionality, the TclThreadSynchronizer class for synchronizing threads with the main application thread (it is necessary for updating VCL form controls) and, finally, the TclCookieManager component.
 
The sample allows adding multiple download tasks to the list, start and stop them. For working in threads, the special object, TclDownloadWorkItem, is queued to the thread pool. The implementation is simple and does not require to inherit from the TThread class.
The TclDownloadInfo class keeps information about downloaded URL and its status. When you click the Stop button, the download item is marked as stopped (see the IsStop property of the TclDownloadInfo class). The IsStop property is checked inside the TclDownloadWorkItem when the OnReceiveProgress event of the TclHttp component occurs (see the DoProgress event handler method of the TclDownloadWorkItem class). This is the best way to call the Close method and interrupt the downloading of the resource. You cannot call the Close method inside the main VCL thread because the TclHttp component members are not thread-safe. This behavior is by design in order to improve the downloading speed.
 
Also, all created instances of the TclHttp component share the same instance of TclCookieManager. We added special TMemo control on the form for displaying cookies. This memo is updated automatically when the TclCookieManager list is changed.
 
procedure TForm1.AddDownload(const AURL, AFileName: string);
var
  info: TclDownloadInfo;
begin
  info := TclDownloadInfo.Create(AURL, AFileName);
  lbDownloads.Items.AddObject(info.Display, info);
end;
 
procedure TForm1.StartDownloads;
var
  i: Integer;
begin
  for i := 0 to lbDownloads.Items.Count  - 1 do
  begin
    if (TclDownloadInfo(lbDownloads.Items.Objects[i])).Status = dsReady then
    begin
      FThreadPool.QueueWorkItem(TclDownloadWorkItem.Create
      (TclDownloadInfo(lbDownloads.Items.Objects[i]), clCookieManager1));
    end;
  end;
end;
 
procedure TclDownloadWorkItem.Execute(AThread: TThread);
var
  http: TclHttp;
  stream: TStream;
begin
  try
    http := nil;
    stream := nil;
    try
      http := TclHttp.Create(nil);
      http.CookieManager := FCookies;
 
      stream := TFileStream.Create(FInfo.FileName, fmCreate);
      http.Get(FInfo.URL, stream);
    finally
      stream.Free();
      http.Free();
    end;
  except
    //ChangeStatus(dsError);
  end;
end;

Add Feedback