abcd
abcd

Reputation: 441

Error downloading protocol with https : // - Delphi

I wonder how do I download files with protocol https: // in Delphi . I'm using idhttp , but when I click to download it returns an error code :

-1

After clicking the button, a few seconds it terminates the application.

uses: IdHTTP, IdSSLOpenSSL;

IdHTTP1 := TIdHTTP.create(nil);
 try
            IdHTTP1.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);  
            IdHTTP1.Request.Accept := 'text/html, */*';
            IdHTTP1.Request.UserAgent := 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/12.0';
            IdHTTP1.Request.ContentType := 'application/x-www-form-urlencoded';
            IdHTTP1.HandleRedirects := True;
            IdHTTP1.get(FNomeArq,MS);
            Ms.Seek(0,soFromBeginning);
            header := IdHTTP1.Response.ContentType;
 except on E : EIdHTTPProtocolException do begin
             showmessage(intToStr(IdHTTP1.ResponseCode));
            end;
            on E: EIdSocketError do begin
                showmessage(intToStr(IdHTTP1.ResponseCode));
            end;
            on E: Exception do begin
              showmessage(intToStr(IdHTTP1.ResponseCode));
            end;
 end;

enter image description here

Upvotes: 0

Views: 3515

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 596001

First, your error handling is wrong. You are displaying only the TIdHTTP.ResponseCode property value and nothing else. The only exception where the ResponseCode will have a meaningful value is EIdHTTPProtocolException (and even then, you should get the value from the EIdHTTPProtocolException.ErrorCode property). The ResponseCode is not likely to be populated on any other exception, which is clearly the case in your situation. Since you are going to the trouble of catching different types of exceptions, you should display error messages that are meaningful to those particular types, eg:

except
  on E: EIdHTTPProtocolException do begin
    ShowMessage('HTTP request failed'#13 + IntToStr(E.ErrorCode) + ' ' + E.Message);
  end;
  on E: EIdOpenSSLAPISSLError do
  begin
    ShowMessage('OpenSSL API failure'#13 + E.ClassName + #13'Result Code: ' + IntToStr(E.RetCode) + #13'Error Code: ' + IntToStr(E.ErrorCode));
  end;
  on E: EIdOpenSSLAPICryptoError do
  begin
    ShowMessage('OpenSSL crypto failure'#13 + E.ClassName + #13'Error Code: ' + IntToStr(E.ErrorCode));
  end;
  on E: EIdOpenSSLError do
  begin
    ShowMessage('Unknown OpenSSL error'#13 + E.ClassName + #13 + E.Message);
  end;
  on E: EIdSocketError do begin
    ShowMessage('Socket error'#13 + E.ClassName + #13'Error Code: ' + IntToStr(E.LastError) + ' ' + E.Message);
  end;
  on E: Exception do begin
    ShowMessage('Unexpected error'#13 + E.ClassName + #13 + E.Message);
  end;
end;

Second, if you are running your app on a desktop system (Windows or OSX), you are leaking your TIdSSLIOHandlerSocketOpenSSL object, as you are not assigning an Owner to it, and TIdHTTP does not take ownership of it. If you are running your app on a mobile system instead (iOS or Android), your code will crash, because there is no reference to keep the TIdSSLIOHandlerSocketOpenSSL object alive after it is created. The TIdTCPConnection.IOHandler and TIdTCPConnection.Socket properties use weak referencing on those platforms, so the object's reference count will not be incremented, and it will end up being destroyed prematurely. If you don't assign an Owner, you need to free the object explicitly, such as in a try/finally like Zam's answer demonstrates.

Alternatively, if you are using an up-to-date version of Indy, you can take advantage of a new HTTPS feature that was added to TIdHTTP earlier this year so you don't have to create the IOHandler object explicitly:

New HTTPS functionality for TIdHTTP

Third, regarding the actual exception you are getting, EIdOSSLCouldNotLoadSSLLibrary means exactly what its name suggests. The OpenSSL libraries could not be loaded. This means either the DLLs (libeay32.dll and ssleay32.dll) could not be found, or they do not export everything that Indy looks for. You can call the WhichFailedToLoad() function in the IdSSLOpenSSLHeaders unit to find out why OpenSSL could not be loaded:

except
  //...
  on E: EIdOSSLCouldNotLoadSSLLibrary do
  begin
    ShowMessage('Could not load OpenSSL library'#13'Failed to load: ' + WhichFailedToLoad);
  end;
  //...
end;

Make sure you have a compatible version of the OpenSSL DLLs installed, either in your application's folder, in a folder on the OS search path, or in a folder that you specify to Indy via its IdOpenSSLSetLibPath() function in the IdSSLOpenSSLHeaders unit. Typically, you should strive to always use the latest OpenSSL version that is available (which, at the time of this writing, is 1.0.2d).

Upvotes: 5

Zam
Zam

Reputation: 2940

First of all, you are not using all required units.

uses
    IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL;

This is working sample, tested under Delphi XE7 and XE8. FMX platform.

var
    FResponse: TMemoryStream;

procedure Load;
var
    LUrl: String;
    IdHTTP: TIdHTTP;
    IdSSLIOHandlerSocketOpenSSL: TIdSSLIOHandlerSocketOpenSSL;
begin
    LUrl := 'https://google.lv/';

    IdHTTP := TIdHTTP.Create(nil);
    try
      IdSSLIOHandlerSocketOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
      try
        IdHTTP.IOHandler := IdSSLIOHandlerSocketOpenSSL;
        try
          IdHTTP.Get(LUrl, FResponse);
        except
          { We are hiding error }
        end;
      finally
        IdSSLIOHandlerSocketOpenSSL.Free;
      end;
    finally
      IdHTTP.Free;
    end;
end;

do not forget to create FResponse by using FResponse := TMemoryStream.Create;

and last: make sure you are using correct OpenSSL library for Indy 10.6.1.5182 i am using:

[WIN][x86] OpenSSL Shared Library 1.0.1.7; The OpenSSL Toolkit 1.0.1g;

libeay32.dll
1 281 024 bytes

ssleay32.dll
270 336 bytes

[WIN][x64] OpenSSL Shared Library 1.0.1.7; The OpenSSL Toolkit 1.0.1g;

libeay32.dll
1 817 088 bytes

ssleay32.dll
371 200 bytes

Upvotes: 2

Related Questions