Jump to content
Skrim

Error using Indy

Recommended Posts

I upload Xml files to a remote service using Indy.

 

Most of the time it's working just fine, but sometimes there is an error returning error code -1.

(Unknown error?)

 

When I say "not working" the file connection/transfer is not accepted by the remote service.

 

It's just on a few pc's it's not working, could it be those pc's are missing required files (dll)?

 

Using OpenSSL/Indy, what files do I have to distrbute in my Win32 application?

 

uses

  SysUtils,
  IdIOHandler,
  IdIOHandlerSocket,
  IdSSLOpenSSLHeaders,
  idHTTP,
  IdContext,
  IdLogBase,
  IdLogFile,
  IdSSLOpenSSL,
  IdHTTPHeaderInfo,
  IdMultipartFormData,
  IdURI;

 

 

 

Share this post


Link to post
3 hours ago, Skrim said:

Most of the time it's working just fine, but sometimes there is an error returning error code -1.

(Unknown error?)

What exactly is reporting that error? Can you provide the exact and complete error message? And what does your code look like?

3 hours ago, Skrim said:

When I say "not working" the file connection/transfer is not accepted by the remote service.

That is not very helpful.

3 hours ago, Skrim said:

It's just on a few pc's it's not working, could it be those pc's are missing required files (dll)?

Anything is possible, though you should be getting a different error if that were the case.  More likely, those PCs are probably running firewalls that are blocking your connection.

3 hours ago, Skrim said:

Using OpenSSL/Indy, what files do I have to distrbute in my Win32 application?

The 2 OpenSSL DLLs, libeay32.dll and ssleay32.dll. And make sure they are for OpenSSL 1.0.2u or earlier, as TIdSSLIOHandlerSocketOpenSSL does not support newer versions. You can get those DLLs from https://github.com/IndySockets/OpenSSL-Binaries If you want to use newer DLLs, use this WIP SSLIOHandler instead.

Share this post


Link to post

Several clients connect to one remote server/service.

 

Some clients receive error, most works just fine. Clients are on several dfferent locations. Could it be the clients firewall is blocking sending?

 

Here is some of my code.

 

procedure TFormSend.HttpFinish(ASender: TObject);
begin
  LogMemo.Lines.Add(Format('Finished. Http status code : %d',[(ASender as TxxxxxUpload).ResponseCode]));
  if (ASender as TxxxxxUpload).ResponseCode=201 then
  showmessage('Invoice delivered')
  else
  showmessage('Error : Invoice could not be delivered');
end;

 

procedure TMyClient.SendFile;
var
  tmpstream: TStringStream;
  Params: TIdMultipartFormDataStream;
  FIdSSLIOHandler: TIdSSLIOHandlerSocketOpenSSL;
  FidHttp: TIdHTTP;
  FIdURI: TIdURI;
  FURL: string;
begin

  HttpStart(Self);
  FResponseCode := 600;
  if DoCheckParams then
  begin
    Params := TIdMultipartFormDataStream.Create;
    FidHttp := TIdHTTP.Create(nil);
    FIdSSLIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
    FIdURI := TIdURI.Create(FEndPoint);
    tmpstream := TStringStream.Create(Trim(FDocumentID));
    try
      with FidHttp do
      begin
        ReadTimeout := 30000; // 0
        ConnectTimeout := 30000;
        HTTPOptions := [hoKeepOrigProtocol];
        // hoKeepOrigProtocol,hoForceEncodeParams
        HandleRedirects := true;
        RedirectMaximum := 5;
        ProtocolVersion := pv1_1;
        AllowCookies := true;
        OnWork          := WorkEvent;
        OnWorkBegin     := WorkBegin;
        OnWorkEnd       := WorkEnd;
        OnStatus        := StatusEvent;
        with Request do
        begin
          UserAgent := FUserAgent;
          BasicAuthentication := true;
          RawHeaders.FoldLines := false;
          Accept := 'application/xml';
          Connection := 'keep-alive';
        end;
      end;
      with (FIdSSLIOHandler as TIdSSLIOHandlerSocketOpenSSL) do
      begin
        with SSLOptions do
        begin
          Method := sslvTLSv1;
          SSLVersions := [sslvTLSv1];
          Mode := sslmUnassigned;
          VerifyMode := [];
          VerifyDepth := 2;
        end;
        port := 443;
        host := FIdURI.host;
      end;
      FidHttp.IOHandler := FIdSSLIOHandler;
      Params.AddFile('file', FXMLfile, 'application/xml');
      Params.AddFormField('SenderID', FSenderID);
      Params.AddFormField('RecipientID', FRecipientID);
      Params.AddFormField('ChannelID', FChannelID);
      Params.AddFormField('ProcessID', FProcessID);
      Params.AddFormField('DocumentID', '', '', tmpstream).ContentTransfer  := '8bit';
      FIdURI.Username := FUser;
      FIdURI.Password := FPassword;
      FURL := FIdURI.GetFullURI();
      Params.Seek(0, soFromBeginning);
      try
        FidHttp.Post(FURL, Params, FResponse);
        FResponseCode := FidHttp.ResponseCode;
        FResponse.Seek(0, soFromBeginning);
      except
        on E1: EIdHTTPProtocolException do
        begin
          FResponseCode := FidHttp.ResponseCode;
          ErrorEvent(Self,'IdHTTPProtocol Protocol Exception:' + #$D#$A + StringReplace(E1.ErrorMessage, #10, #$D#$A, [rfReplaceAll]));
          ErrorEvent(Self,'IdHTTPProtocol RawHeaders=' + #$D#$A + FidHttp.Request.RawHeaders.Text);
        end;
        on E2: Exception do

        begin
          FResponseCode := FidHttp.ResponseCode;
          ErrorEvent(Self,'IdHTTPProtocol Unknown Exception: ' + E2.Message);
        end;
      end;
    finally
      Params.Free;
      FIdSSLIOHandler.Free;
      FidHttp.Free;
      FIdURI.Free;
      tmpstream.Free;
    end;
  end
  else ErrorEvent(Self,'Some required params are missed');
  HttpFinish(Self);

end;

Share this post


Link to post
2 hours ago, Remy Lebeau said:

What exactly is reporting that error? Can you provide the exact and complete error message? And what does your code look like? 

The error code is just -1. Nothing more, not very helpful :classic_sad:

From Windows?

Edited by Skrim

Share this post


Link to post

Solved.

 

On those pc's giving an error both libeay32.dll and ssleay32.dll were missing.

 

Would be nice with a message "Cannot find file xxxx.dll", not just -1 🙂

 

Share this post


Link to post
On 5/14/2023 at 8:11 AM, Skrim said:

Solved.

 

On those pc's giving an error both libeay32.dll and ssleay32.dll were missing.

 

Would be nice with a message "Cannot find file xxxx.dll", not just -1 🙂

When your code is calling TIdHTTP.Post(), if it catches any non-HTTP exception, it is reading the TIdHTTP.ResponseCode property, which won't have a valid number in that case and so returns -1.

 

Indy does, in fact, raise an exception if the OpenSSL DLLs are missing or otherwise are unable to be loaded - EIdOSSLCouldNotLoadSSLLibrary.  After that exception is raised, you can call Indy's WhichFailedToLoad() function in the IdSSLOpenSSLHeaders unit, and it will tell you whether the DLLs themselves could not be loaded, or whether any of the required exports are missing (ie, because the DLLs are the wrong version for what Indy is expecting).

 

There are other exception classes you can catch for other OpenSSL-related errors, too.  Most of them derive from either EIdOpenSSLAPISSLError or EIdOpenSSLAPICryptoError, both of which provide error codes.

 

For example:

try
  FidHttp.Post(FURL, Params, FResponse);
  FResponseCode := FidHttp.ResponseCode;
  FResponse.Seek(0, soFromBeginning);
except
  on E: EIdHTTPProtocolException do
  begin
    FResponseCode := E.ErrorCode;
    ErrorEvent(Self, 'HTTP Protocol Exception:' + #$D#$A + AdjustLineBreaks(E.ErrorMessage, tlbsCRLF));
    ErrorEvent(Self, 'HTTP Protocol RawHeaders=' + #$D#$A + FidHttp.Request.RawHeaders.Text);
  end;
  on E: EIdOSSLCouldNotLoadSSLLibrary do
  begin
    FResponseCode := -1; // or whatever you want
    ErrorEvent(Self, 'SSL/TLS Library Exception: ' + E.Message);
    ErrorEvent(Self, 'SSL/TLS Didnt Load=' + #$D#$A + WhichFailedToLoad);
  end;
  on E: EIdOpenSSLAPISSLError do
  begin
    FResponseCode := -1; // or whatever you want
    ErrorEvent(Self, 'SSL/TLS API Exception: [' + E.ClassName + '] ' + E.Message);
    ErrorEvent(Self, 'SSL/TLS API ErrorCode=' + IntToStr(E.ErrorCode));
    ErrorEvent(Self, 'SSL/TLS API RetCode=' + IntToStr(E.RetCode));
  end;
  on E: EIdOpenSSLAPICryptoError do
  begin
    FResponseCode := -1; // or whatever you want
    ErrorEvent(Self, 'SSL/TLS Crypto Exception: [' + E.ClassName + '] ' + E.Message);
    ErrorEvent(Self, 'SSL/TLS Crypto ErrorCode=' + IntToStr(E.ErrorCode));
  end;
  on E: Exception do
  begin
    FResponseCode := -1; // or whatever you want
    ErrorEvent(Self, 'Unknown Exception: [' + E.ClassName + '] ' + E.Message);
  end;
end;

 

Edited by Remy Lebeau

Share this post


Link to post

Thanks Remy, appreciate your answer. I will try it out.

 

Regards,

Ole

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×