Как установить ConnectTimeout / ReadTimeout в Indy SSL - PullRequest
4 голосов
/ 09 ноября 2019

Как я могу установить ConnectTimeout / ReadTimeout в Indy при использовании SSL?

MCVE:

program mcve;

uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}SysUtils, IdHTTP, IdSSLOpenSSL, DateUtils;

var
  HTTP    : TIdHTTP;
  SSL     : TIdSSLIOHandlerSocketOpenSSL;
  Started : TDateTime;
begin
  HTTP := TIdHTTP.Create();
  try
    HTTP.ReadTimeout            := 1000;
    HTTP.ConnectTimeout         := 2000;
    SSL                         := TIdSSLIOHandlerSocketOpenSSL.Create(HTTP);
    SSL.ConnectTimeout          := HTTP.ConnectTimeout;
    SSL.ReadTimeout             := HTTP.ReadTimeout;
    SSL.SSLOptions.SSLVersions  := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
    HTTP.IOHandler              := SSL;
    Started := Now;
    try
      HTTP.Get(ParamStr(1));
    except
      On E: Exception do WriteLn(E.Message);
    end;
    Writeln(FormatDateTime('hh:nn:ss', SecondsBetween(Started, Now) / SecsPerDay));
  finally
    HTTP.Free;
  end;
end.

При использовании http ConnectTimeout / ReadTimeout нормально работает проблема только при использовании https см. ниже:

:~$ ./mcve http://x.x.x.x
Read timed out.
00:00:01 <-- Correct.

:~$ ./mcve https://x.x.x.x
Socket Error # 0

00:03:38 <-- NOT Correct / More than SSL.ReadTimeout value.

Lazarus 2.0.6 Indy установлен из OPM версии 10.6.2.5494.

Примечание: В Windows тот же код с использованием Delphi с поставляемым Indy 10.6.2.5366, результаты работают как положено

1 Ответ

5 голосов
/ 09 ноября 2019

Вам не нужно вручную устанавливать ConnectTimeout и ReadTimeout на самом IOHandler, только на клиентском компоненте (в данном случае TIdHTTP). TIdTCPClient.Connect() назначит значения для IOHandler для вас.

ConnectTimeout применяется, когда базовый сокет подключается к серверу, до создания любого сеанса SSL / TLS, поэтому он работает одинаково, независимо от того,вы используете SSL / TLS или нет.

ReadTimeout применяется, когда Indy пытается прочитать байты из внутреннего соединения IOHandler. Когда SSL / TLS не используется, это означает, что он идет прямо в сокет и, таким образом, время ожидания истекает, когда в сокет не поступает никаких байтов. Но при использовании SSL / TLS Indy использует устаревшие SSL_...() API-интерфейсы OpenSSL, а не более новые BIO_...() API-интерфейсы, что означает, что OpenSSL выполняет собственное чтение сокетов и буферизацию от имени Indy, и, таким образом, тайм-аут Indy, когда OpenSSL не предоставляет никакихдешифрованные байты приложения.

Разница в том, как TIdSSLIOHandlerSocketOpenSSL работает на Windows по сравнению с другими платформами, состоит в том, что только на Windows Vista + TIdSSLIOHandlerSocketOpenSSL применяет ReadTimeout к базовым сокетам SO_RCVTIMEO и SO_SNDTIMEOтайм-ауты с помощью метода IOHandler Binding.SetSockOpt(), как обходной путь к ошибке OpenSSL в Windows. Для других платформ Indy в настоящее время не устанавливает эти два тайм-аута.

Хорошим местом для установки этих тайм-аутов вручную было бы событие IOHandler OnBeforeConnect, которое вызывается после подключения сокета к серверу идо создания любого сеанса SSL / TLS.

...