Class TCastleDownload

Unit

Declaration

type TCastleDownload = class(TComponent)

Description

Download an URL (possibly making an HTTP(S) request) asynchronously, without blocking the application. You can register a callback OnFinish or watch when the Status property changes from dsDownloading to dsError or dsSuccess to detect when this finished downloading.

Features:

  • The download can be observed (looking at Status, DownloadedBytes, TotalBytes).

  • When the downlad is finished, look at Contents (if success) or ErrorMessage (if error, that is Status = dsError).

  • We can read MIME type from server (can be used throughout our engine to designate file type).

  • For downloading (making a request) using HTTP, this is a handful of additional features, to support downloading from modern web servers and using REST APIs:

    • First of all, we support both HTTP and HTTPS on all platforms and compilers, through various backend (FpHttpClient, Indy, Delphi Net Client).

    • You can provide arbitrary HTTP headers using HttpHeader. For example, various REST APIs require you to provide some key to authenticate through a custom HTTP header.

    • You can specify any HttpMethod, like GET, POST, PUT and more. Default is naturally GET which is the standard method to just download the data.

    • For HTTP POST method, you can provide form data as HttpPostData.

    • You can provide input data for any request using HttpRequestBody. The most common use case is to provide a body for PUT requests, but it can be used for any request, e.g. to provide POST body overriding the HttpPostData.

    • Once the download finishes, you can read HttpResponseCode and HttpResponseHeaders.

    • By default, we follow HTTP/HTTPS redirects.

See examples:

  • asynchronous_download to download resources asynchronously, downloading a few URLs and at the same time displaying an animation and progress bar.

  • remote_logging to send logs to a remote server, using HTTP POST.

  • put_data to send HTTP PUT request.

  • And other examples in examples/network subdirectory.

Usage:

The download starts when you call Start. Be sure to configure the properties, including OnFinish, before calling Start, because in case of some protocols Start may immediately read everything and finish. When the download ends, the OnFinish is called and Status changes.

You can always just free an instance of this class, this will break the download immediately, if it's still in-progress.

The download continues while your application is running, because we use ApplicationProperties.OnUpdate mechanism. If your application uses TCastleWindow or TCastleControl, then this just works. Note that if you just want to wait for download to finish, you can use WaitForFinish method or just call simpler Download routine.

Do not worry whether this uses threads (or not) internally. All the methods and properties of this class should be accessed from the main thread, the same thread you use for all Castle Game Engine functions. And the OnFinish is called in the main thread, so you can handle it without worrying about threading.

Hierarchy

  • TObject
  • TPersistent
  • TComponent
  • TCastleDownload

Overview

Methods

Protected procedure DoFinish; virtual;
Public constructor Create(AOwner: TComponent); override;
Public destructor Destroy; override;
Public procedure Start;
Public procedure WaitForFinish;
Public function HttpPostData: TStrings;
Public function PostData: TStrings; deprecated 'use HttpPostData';
Public function HttpRequestBody: TMemoryStream;
Public procedure HttpHeader(const AKey, AValue: String);
Public procedure AddHeader(const AKey, AValue: String); deprecated 'use HttpHeader';

Properties

Public property Url: String read FUrl write SetUrl;
Public property FinalUrl: String read FFinalUrl;
Public property Options: TStreamOptions read FOptions write SetOptions;
Public property HttpMethod: THttpMethod read FHttpMethod write SetHttpMethod default hmGet;
Public property OnFinish: TDownloadFinishedEvent read FOnFinish write SetOnFinish;
Public property Status: TDownloadStatus read FStatus;
Public property ErrorMessage: String read FErrorMessage;
Public property Contents: TStream read FContents;
Public property OwnsContents: boolean read FOwnsContents write FOwnsContents default true;
Public property DownloadedBytes: Int64 read FDownloadedBytes;
Public property TotalBytes: Int64 read FTotalBytes;
Public property MimeType: String read FMimeType;
Public property HttpResponseCode: Integer read FHttpResponseCode;
Public property HttpResponseHeaders: TStrings read FHttpResponseHeaders;

Description

Methods

Protected procedure DoFinish; virtual;

Note that this may destroy our own instance. So never access our own fields / virtual methods after calling this.

Public constructor Create(AOwner: TComponent); override;

This item has no description.

Public destructor Destroy; override;

This item has no description.

Public procedure Start;

Get the data. This starts downloading. Be sure to set Url and other necessary properties before calling this.

Public procedure WaitForFinish;

Wait until status is no longer dsDownloading.

Public function HttpPostData: TStrings;

Form data to send when HttpMethod = hmPost. Initially empty. Use the TStrings name/value mechanism to set the form, like

// Advised:
Download.HttpPostData.Values['my-form-key'] := 'my-form-value';
// This also works, it is equivalent to above if key didn't already exist
Download.HttpPostData.Append('my-form-key-2=my-form-value-2');

Public function PostData: TStrings; deprecated 'use HttpPostData';

Warning: this symbol is deprecated: use HttpPostData

This item has no description.

Public function HttpRequestBody: TMemoryStream;

Request body to send along with the request. Most useful with PUT (to send data to save on the server side). May also be useful with POST (only when the HttpPostData key-value is not flexible enough) or other requests.

You can use various TStream methods to set the stream, like TStream.CopyFrom. The CastleClassUtils also has various helpers for stream, e.g. to write a String (AnsiString, UTF-8 encoding) to a stream use WriteStr(Download.HttpRequestBody, 'My content').

Example usage:

program put_data;

{ Send PUT request with JSON body.
  Note: to send non-trivial JSON, better create it with proper JSON library
  like FpJson. }

{$apptype console}

uses
  {$ifdef UNIX} CThreads, {$endif} // necessary to have asynchronous downloading on Unix
  SysUtils,
  {$ifdef FPC} OpenSSLSockets, {$endif} // support HTTPS
  CastleUtils, CastleDownload, CastleClassUtils;

var
  D: TCastleDownload;
begin
  D := TCastleDownload.Create(nil);
  try
    D.Url := 'https://castle-engine.io/miscella/test_put.php';
    D.HttpMethod := hmPut;
    WriteStr(D.HttpRequestBody, '{ "test": "value" }');
    D.Start;
    D.WaitForFinish;
    case D.Status of
      dsError: Writeln('Error: ', D.ErrorMessage);
      dsSuccess: Writeln('Success');
      else raise EInternalError.Create('Unexpected status');
    end;
    Writeln('Response code: ', D.HttpResponseCode);
    Writeln('Response body: ', ReadGrowingStreamToDefaultString(D.Contents));
  finally FreeAndNil(D) end;
end.

Note: For some requests you may want to add HTTP headers like Content-Type etc. Do this using HttpHeader.

In case of POST requests, when this stream has non-empty contents (stream size > 0), it overrules the HttpPostData. That is, HttpPostData is completely ignored in this case. Reason: Internally, HttpPostData is just an alternative way to set HttpRequestBody. TODO: We may change this behavior in the future, to make it such that using HttpPostData will automatically override HttpPostData. For now, never use both HttpPostData and HttpRequestBody at the same time.

TODO: For now this is supported only when using FPC (not Delphi) and only on desktop platforms (not mobile). It should be trivial to make it work in other cases too, just let us know ( https://castle-engine.io/talk.php ).

Public procedure HttpHeader(const AKey, AValue: String);

Add additional HTTP headers, e.g. User-Agent.

Public procedure AddHeader(const AKey, AValue: String); deprecated 'use HttpHeader';

Warning: this symbol is deprecated: use HttpHeader

This item has no description.

Properties

Public property Url: String read FUrl write SetUrl;

URL to read or write. Supports all protocols, like file, http, https, castle-data and other documented on https://castle-engine.io/manual_network.php .

Can only change when there is no download in progress (Status is dsNotStarted or dsSuccess).

Public property FinalUrl: String read FFinalUrl;

When the download has finished (with success or error), this is updated to "final" URL, after resolving HTTP/HTTPS redirects and castle-data:/ protocol.

Public property Options: TStreamOptions read FOptions write SetOptions;

Options that configure the output stream. See TStreamOption for details.

Public property HttpMethod: THttpMethod read FHttpMethod write SetHttpMethod default hmGet;

In case of HTTP and HTTPS protocols, choose the http request method (verb). See https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods and https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods for description.

Can only change when there is no download in progress (Status is not dsDownloading).

Public property OnFinish: TDownloadFinishedEvent read FOnFinish write SetOnFinish;

Event called when we finish downloading.

Can only change when there is no download in progress (Status is not dsDownloading).

Public property Status: TDownloadStatus read FStatus;

Whether we finished the download (and if yes, was it an error or success).

Public property ErrorMessage: String read FErrorMessage;

If the Status is dsError, this contains a detailed error message.

Public property Contents: TStream read FContents;

The downloaded contents.

If the Status is dsSuccess, this is always set (never Nil). In case of some protocols and some failures, the contents may be available (not Nil) even when error occurred, that is when Status is dsError. E.g. when HTTP server returns an error, like 404, it also still sends the response contents.

This stream is owned by default (if OwnsContents) by this TCastleDownload instance, so it will become invalid when the TCastleDownload instance is freed.

Public property OwnsContents: boolean read FOwnsContents write FOwnsContents default true;

Is the Contents owned by this TCastleDownload instance. Set this to False to be able to free this TCastleDownload instance and still keep the stream reference. It is your responsibility then to keep and free the Contents stream whenever you want.

Public property DownloadedBytes: Int64 read FDownloadedBytes;

How many bytes were downloaded. Together with TotalBytes, you can use it e.g. to show a progress bar when downloading. This is always >= 0.

Public property TotalBytes: Int64 read FTotalBytes;

How many bytes are expected to be downloaded, in total. -1 if unknown. Depending on the server answer, this may be known fairly quickly after starting the download, or if may not be known at all (until we finish the download). It's guaranteed that this is known (not -1) when Status = dsSuccess, in all other cases always be prepared that this may be equal -1.

Public property MimeType: String read FMimeType;

As soon as the MIME type of the downloaded contents is known, this is set. It is guaranteed to be set when Status is dsSuccess, it *may* be determined earlier (when dsDownloading).

Public property HttpResponseCode: Integer read FHttpResponseCode;

When Status is dsSuccess or dsError, and request was using HTTP or HTTPS, this contains the HTTP status code. It is always 200 on success.

Public property HttpResponseHeaders: TStrings read FHttpResponseHeaders;

When Status is dsSuccess or dsError, and request was using HTTP or HTTPS, this contains the HTTP response headers. The NameValueSeparator is set to ':' which means you can use TStrings name/value mechanism to read the data, like this:

LastModified := Download.HttpResponseHeaders.Values['Last-Modified'];

Note that it is Nil in case of non-HTTP/HTTPS requests.


Generated by PasDoc 0.16.0-snapshot.