2

Using TIdHTTPServer (Indy 10.6), how do track how many bytes are sent to the client (user browser) for each request (on close connection)?

procedure onCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo;
begin
    AResponseInfo.ContentStream := TFileStream.Create('C:/HugeFile.zip', fmOpenRead or fmShareCompat);
    AResponseInfo.ContentLength := AResponseInfo.ContentStream.Size;
    AResponseInfo.WriteHeader;
    AResponseInfo.WriteContent;
    AResponseInfo.ContentStream.Free;
    AResponseInfo.ContentStream := nil;
end;

eg, in a log file:

2014-11-06 20:32:00 - IPAddress 84.XXX.XXX.XXX download 1000000 Bytes (100%)
2014-11-05 16:05:00 - IPAddress 72.XXX.XXX.XXX download 500000  Bytes (50%)
Simone Nigro
  • 4,717
  • 2
  • 37
  • 72
  • What Indy version are you using? What would downloading 50% of a file represent? Are you wanting to log incremental progress (eg., IPAddress 72.xxx.xxx.xxx download 100000 bytes (10%), IPAddress 72.xxx.xxx.xxx download 150000 bytes (15%), etc)? – Ken White Nov 06 '14 at 21:49
  • 3
    Your code can be shortened: only `AResponseInfo.ContentStream := TFileStream.Create(...)` is required. Indy configures and writes the response, and releases the stream. – mjn Nov 07 '14 at 05:09
  • @KenWhite `What Indy version are you using?` 10.6; `What would downloading 50% of a file represent?` client close connection at 50% of download; – Simone Nigro Nov 07 '14 at 12:55

1 Answers1

3

If you just want to output a log at the end of the transfer saying how many bytes were sent, you can derive a new class from TFileStream and override its destructor to output a log message showing the stream's current Position relative to its Size. Whatever other information you need to log can be passed to the constructor and saved so the destructor can use it.

For example:

type
  TMyFileStream = class(TFileStream)
  private
    FContext: TIdContext;
  public
    constructor Create(const AFileName: string; AContext: TIdContext);
    destructor Destroy; override;
  end;

constructor TMyFileStream.Create(const AFileName: string; AContext: TIdContext);
begin
  inherited Create(AFileName, fmOpenRead or fmShareCompat);
  FContext := AContext;
end;

destructor TMyFileStream.Destroy;
var
  LPos, LSize: Int64;
  LPercent: Integer;
begin
  LPos := Position;
  LSize := Size;
  if LSize <> 0 then
    LPercent := (LPosition * 100) div LSize
  else
    LPercent := 100;
  MyLogFile.WriteLine(Format('%s IPAddress %s download %d Bytes (%d%%)', [FormatDateTime('YYYY-MM-DD HH:NN:SS', Now), AContext.Binding.PeerIP, LPos, LPercent]);
  inherited;
end;

procedure onCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo;
begin
  AResponseInfo.ContentStream := TMyFileStream.Create('C:/HugeFile.zip', AContext);
end;
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • to track downloads with OnCommandGet I found :`AContext.Connection.OnWorkBegin := OnWorkBegin;`, `AContext.Connection.OnWork := OnWork;`, `AContext.Connection.OnWorkEnd := OnWorkEnd;`. The `OnWork..` events have an `AWorkMode` parameter to tell you which direction data is flowing - `wmWrite` (downloading) or `wmRead` (uploading) and `AWorkCountMax` the number of bytes uploaded or downloaded – Simone Nigro Nov 08 '14 at 09:05
  • alternatively I can use onWorkBegin, onWork, onWorkEnd?? – Simone Nigro Nov 10 '14 at 19:34
  • 1
    If you need live statistics while the transfer is in progress, yes. – Remy Lebeau Nov 10 '14 at 21:23