Reputation: 441
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;
Upvotes: 0
Views: 3515
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
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