I'm getting "Socket Error # 10054 Connection reset by peer" in Indy using TIdHTTP to GET an HTTPS url

462 views Asked by At

I have what seems to be a simple task - to make an HTTPS request, but I encountered an error:

Socket Error #10054 Connection reset by peer

Moreover, this error does not occur every time; out of 30 attempts, it may occur 2-3 times, maybe once, or not at all.

I'm using Delphi XE7. I have already tried using the latest DLL files from the Indy library, but it didn't have any effect. I obtained the DLL files from here: https://indy.fulgan.com/SSL/

Here is my code:

try
  IdSSLIOHandlerSocketOpenSSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  with IdSSLIOHandlerSocketOpenSSL1 do
  begin
    //SSLOptions.Method := sslvTLSv1_1;  //sslvSSLv23
    SSLOptions.SSLVersions := [sslvSSLv2, sslvSSLv3, sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
    SSLOptions.Mode := sslmClient;
    SSLOptions.VerifyMode := [];
    SSLOptions.VerifyDepth := 0;
  end;
except
  on E: Exception do
    Showmessage(e.Message);
end;
try
  IdHTTP1 := TIdHTTP.Create(nil);
  with IdHTTP1 do
  begin
    IOHandler := IdSSLIOHandlerSocketOpenSSL1;
    AllowCookies := True;
    HandleRedirects := true;
    ProxyParams.BasicAuthentication := false;
    ProxyParams.ProxyPort := 0;
    Request.CharSet := 'utf-8';
    Request.ContentType := 'application/json';
    Request.Ranges.Units := 'bytes';
    HTTPOptions := [];
    Intercept := IdLogEvent1;
    IOHandler.DefStringEncoding := enUTF8;
  end;
  //IdLogEvent1.Active := True;
except
  on E: Exception do
    ShowMessage(e.Message);
end;
cnt := 0;
repeat
  try
    if IdHTTP1 = nil then
      createIDHTTP;

    auth := ConvertToBase64('login1'+':'+'pass1');
    IdHTTP1.Request.CustomHeaders.FoldLines := False;
    IdHTTP1.Request.CustomHeaders.Clear;
    IdHTTP1.ConnectTimeout := 10000;
    IdHTTP1.Request.CustomHeaders.Add('Authorization: Basic ' + auth);
    IdHTTP1.Request.CustomHeaders.Add('User-Agent: PostmanRuntime/7.29.2');
    IdHTTP1.Request.CustomHeaders.Add('Accept: */*');
    IdHTTP1.Request.CustomHeaders.Add('Accept-Encoding: gzip, deflate, br');
    IdHTTP1.Request.CustomHeaders.Add('Connection: keep-alive');

    res := IdHTTP1.Get('https://isms.center/api/sms/report?message_id=61');
    memo2.Lines.Add(cnt.ToString() + ' ' +  GetJSONValue(res, 'status'));
    Sleep(1000);
  except
    on E: Exception do
    begin
      memo2.Lines.Add(cnt.ToString() + ' ' +  e.ClassName + ' error: ' + e.Message);
    end;
  end;
  DestroyIDHTTP;
  Inc(cnt);
until cnt > 30;

Where did I go wrong?

1

There are 1 answers

3
Remy Lebeau On

XE7 was released almost a decade ago. If you are using the version of Indy that shipped with it, then you need to upgrade to the latest version from Indy's GitHub repo (see Updating Indy).

Also, the Fulgan mirror was decommissioned several years ago, so make sure you are using OpenSSL DLLs from Indy's OpenSSL binaries GitHub repo. The TIdSSLIOHandlerSocketOpenSSL component supports up to OpenSSL 1.0.2u.

As for the code you have shown, I see a few problems with it:

  • you should not be enabling sslvSSLv2 or sslvSSLv3 at all, as they represent dead SSL versions that were compromised a long time ago. Nobody uses them anymore.

  • you should not be using the TIdHTTP.Request.CustomHeaders property to setup any of the HTTP headers you are configuring. TIdHTTP has properties for all of those headers.

  • you should not be telling the server that you accept the gzip, deflate, or br encodings, since your code is not setup to actually handle them at all. In fact, don't even set the Accept-Encoding header manually at all, let TIdHTTP manage that internally for you. The correct way to accept compressed responses is to assign a TIdZLibCompressorBase-derived component to the TIdHTTP.Compressor property, such as TIdCompressorZLib.

After making sure you have everything up to date, try this code instead:

try
  IdHTTP1 := TIdHTTP.Create(nil);
  IdSSLIOHandlerSocketOpenSSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
  with IdSSLIOHandlerSocketOpenSSL1 do
  begin
    SSLOptions.SSLVersions := [sslvTLSv1, sslvTLSv1_1, sslvTLSv1_2];
    SSLOptions.Mode := sslmClient;
    SSLOptions.VerifyMode := [];
    SSLOptions.VerifyDepth := 0;
    DefStringEncoding := enUTF8;
  end;
  with IdHTTP1 do
  begin
    ConnectTimeout := 10000;
    AllowCookies := True;
    HandleRedirects := True;
    HTTPOptions := [hoInProcessAuth];
    Request.BasicAuthentication := True;
    IOHandler := IdSSLIOHandlerSocketOpenSSL1;
    Intercept := IdLogEvent1;
  end;
  //IdLogEvent1.Active := True;
except
  on E: Exception do
    ShowMessage(e.Message);
end;
cnt := 0;
repeat
  try
    if IdHTTP1 = nil then
      createIDHTTP;

    IdHTTP1.Request.Clear;
    IdHTTP1.Request.Username := 'login1';
    IdHTTP1.Request.Password := 'pass1';
    IdHTTP1.Request.UserAgent := 'PostmanRuntime/7.29.2';
    IdHTTP1.Request.Accept := '*/*';
    IdHTTP1.Request.Connection :='keep-alive';

    res := IdHTTP1.Get('https://isms.center/api/sms/report?message_id=61');
    memo2.Lines.Add(cnt.ToString() + ' ' +  GetJSONValue(res, 'status'));
    Sleep(1000);
  except
    on E: Exception do
    begin
      memo2.Lines.Add(cnt.ToString() + ' ' +  e.ClassName + ' error: ' + e.Message);
    end;
  end;
  DestroyIDHTTP;
  Inc(cnt);
until cnt > 30;