3
votes

I'm trying to download a file using indy10 http components TIdHttp while getting the progress , I have just setted the libraries in the application folder while using the code for http URL it works and progress but with https it simply does nothing and it doesn't raises any exception :/

 with TIdHTTP.Create(nil) do
   begin
    IOHndl:=TIdSSLIOHandlerSocketOpenSSL.Create(nil);
    Request.BasicAuthentication:=True;
    HandleRedirects:=True;
    IOHandler:=IOHndl;
    OnWork:=FOnWork;
    OnWorkBegin:=FOnWorkBegin;
    OnWorkEnd:=FOnWorkEnd;
    Get(FUrl,FStream);
end;

Best Regards

1
The only time the program truly "does nothing" is when it's terminated. Use the debugger to pause your program and look at the call stack. That will show you what the program's really doing.Rob Kennedy
@RobKennedy most people knows what he means. And don't have to troll the questionJens Borrisholt
Maybe "most people" know, but I don't, @Jens. We don't need more imprecise questions here. I pointed out how it's imprecise, and gave advice for how to fix it. If you know, then maybe you can explain for me: What's the program actually doing?Rob Kennedy
If you can give me a file to download over SSL then I can.Jens Borrisholt
@Jens, you claim that most people know what this user means when saying that the program "does nothing," and I assume you include yourself in that group. If you know what it means, why do you need more information in order to tell me what it means? (If you really need an arbitrary HTTPS address, the address of this very page will do.)Rob Kennedy

1 Answers

2
votes

First you have to create a small class to wrap the HTTP component:

unit IdHTTPProgressU;

interface

uses
  Classes, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdSSLOpenSSL;

{$M+}

type
  TIdHTTPProgress = class(TIdHTTP)
  private
    FProgress: Integer;
    FBytesToTransfer: Int64;
    FOnChange: TNotifyEvent;
    IOHndl: TIdSSLIOHandlerSocketOpenSSL;
    procedure HTTPWorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
    procedure HTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
    procedure HTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode);
    procedure SetProgress(const Value: Integer);
    procedure SetOnChange(const Value: TNotifyEvent);
  public
    Constructor Create(AOwner: TComponent);
    procedure DownloadFile(const aFileUrl: string; const aDestinationFile: String);
  published
    property Progress: Integer read FProgress write SetProgress;
    property BytesToTransfer: Int64 read FBytesToTransfer;
    property OnChange: TNotifyEvent read FOnChange write SetOnChange;
  end;

implementation

uses
  Sysutils;
{ TIdHTTPProgress }

constructor TIdHTTPProgress.Create(AOwner: TComponent);
begin
  inherited;
  IOHndl := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  Request.BasicAuthentication := True;
  HandleRedirects := True;
  IOHandler := IOHndl;
  ReadTimeout := 30000;
  OnWork := HTTPWork;
  OnWorkBegin := HTTPWorkBegin;
  OnWorkEnd := HTTPWorkEnd;
end;

procedure TIdHTTPProgress.DownloadFile(const aFileUrl: string; const aDestinationFile: String);
var
  LDestStream: TFileStream;
  aPath: String;
begin
  Progress := 0;
  FBytesToTransfer := 0;
  aPath := ExtractFilePath(aDestinationFile);
  if aPath <> '' then
    ForceDirectories(aPath);

  LDestStream := TFileStream.Create(aDestinationFile, fmCreate);
  try
    Get(aFileUrl, LDestStream);
  finally
    FreeAndNil(LDestStream);
  end;
end;

procedure TIdHTTPProgress.HTTPWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
begin
  if BytesToTransfer = 0 then // No Update File
    Exit;

  Progress := Round((AWorkCount / BytesToTransfer) * 100);
end;

procedure TIdHTTPProgress.HTTPWorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64);
begin
  FBytesToTransfer := AWorkCountMax;
end;

procedure TIdHTTPProgress.HTTPWorkEnd(Sender: TObject; AWorkMode: TWorkMode);
begin
  FBytesToTransfer := 0;
  Progress := 100;
end;

procedure TIdHTTPProgress.SetOnChance(const Value: TNotifyEvent);
begin
  FOnChance := Value;
end;

procedure TIdHTTPProgress.SetProgress(const Value: Integer);
begin
  FProgress := Value;
  if Assigned(FOnChance) then
    FOnChance(Self);
end;

end.

I wont go in to details with the calss: Just say that it bacally wraps a TIdhttp component in and assign the 3 events: OnBegin, onWork and OnEnd

The Method DownloadFile does the actually download,

Then when you have to use it you could do like this:
Place a Button and a PrograssBar on an empty form. Add IdHTTPProgressU to the uses list.

Declare a vaiable of TIdHTTPProgress and a local onChangeEvent

Your form definition should lokke like this:

type
  TForm1 = class(TForm)
    Button1: TButton;
    ProgressBar1: TProgressBar;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
    procedure IdHTTPProgressOnChange(Sender : TObject);
  public
    IdHTTPProgress: TIdHTTPProgress;
  end;

Then you just have to implement the methods:

    { TForm1 }

    procedure TForm1.Button1Click(Sender: TObject);
    begin
       IdHTTPProgress.OnChange := IdHTTPProgressOnChance;
          IdHTTPProgress.OnChance := IdHTTPProgressOnChance;
   IdHTTPProgress.DownloadFile('https://wordpress.org/latest.zip', 'latest.zip');
    end;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      IdHTTPProgress := TIdHTTPProgress.Create(Self);
    end;

    procedure TForm1.IdHTTPProgressOnChance(Sender: TObject);
    begin
      ProgressBar1.Position := TIdHTTPProgress(Sender).Progress;
      Application.ProcessMessages;
    end;

Thats about it. Give it at try.