9

I have the following task: download a file using HTTPS and authentication. Indy seems the way to go but for some reason it doesn't work so far. I have the following in place:

  • a TIdHTTP component which I use for downloading
  • a TIdURI component used to create the URL
  • a TIdSSLIOHandlerSocketOpenSSL component which should provide the secure connection. The required DLLs are in the binary folder.

The site also requires authentication and I included the user/pass in the URL as in the example below. In short this is the code:

URI := TIdURI.Create('https://test.example.com/');
URI.Username := ParamUserName;
URI.Password := ParamPassword;

HTTP := TIdHTTP.Create(nil);
if URI.Protocol = 'https' then
begin
  IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  IOHandler.SSLOptions.Method := sslvSSLv3;
  HTTP.IOHandler := IOHandler;
end;

HTTP.Get(URI.GetFullURI([ofAuthInfo]), FileStream);

Using this code I get a "Read Timeout" EIdReadTimeout exception very fast. Testing the URL in a browser works without problem. Any ideas on what's missing or what I did wrong?

Tihauan
  • 2,780
  • 2
  • 26
  • 29
  • Is there a firewall / a proxy in between the application and the server? 'Browser works' doesn't mean there is a direct Internet connection. – mjn Feb 11 '10 at 14:16
  • @mjustin If I look in the browser settings there's no proxy defined. Also, the fact that the WinInet approach works without setting any proxy tells me that that is not the problem. – Tihauan Feb 12 '10 at 08:31
  • 3
    Don't use the TIdURI.Username/password properties in this situation. You have to use the TIdHTTP.Username/Password properties instead. – Remy Lebeau Feb 12 '10 at 10:17

3 Answers3

12

I finally abandoned Indy and OpenSSL and used WinInet for downloading. This is the code that worked for me:

function Download(URL, User, Pass, FileName: string): Boolean;
const
  BufferSize = 1024;
var
  hSession, hURL: HInternet;
  Buffer: array[1..BufferSize] of Byte;
  BufferLen: DWORD;
  F: File;
begin
   Result := False;
   hSession := InternetOpen('', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0) ;

   // Establish the secure connection
   InternetConnect (
     hSession,
     PChar(FullURL),
     INTERNET_DEFAULT_HTTPS_PORT,
     PChar(User),
     PChar(Pass),
     INTERNET_SERVICE_HTTP,
     0,
     0
   );

  try
    hURL := InternetOpenURL(hSession, PChar(URL), nil, 0, 0, 0) ;
    try
      AssignFile(f, FileName);
      Rewrite(f,1);
      try
        repeat
          InternetReadFile(hURL, @Buffer, SizeOf(Buffer), BufferLen) ;
          BlockWrite(f, Buffer, BufferLen)
        until BufferLen = 0;
      finally
        CloseFile(f) ;
        Result := True;
      end;
    finally
      InternetCloseHandle(hURL)
    end
  finally
    InternetCloseHandle(hSession)
  end;
end;
Tihauan
  • 2,780
  • 2
  • 26
  • 29
  • A word of caution regarding the code above: you should always use INTERNET_FLAG_RELOAD parameter to force a download from the server and not the cache.So I would advise you to change your code to: hURL := InternetOpenURL(hSession, PChar(fullURL), nil, 0, INTERNET_FLAG_RELOAD, 0) ; – user2858981 Nov 10 '16 at 15:11
  • Add `Winapi.WinInet` to `uses`. – James L. Dec 08 '20 at 21:20
2

I have seen the same thing. Setting the TIdHTTP.ReadTimeout to zero fixes the problem for me.

...
HTTP.IOHandler := IOHandler;
HTTP.ReadTimeout := 0;
jasonpenny
  • 2,999
  • 1
  • 24
  • 23
  • ReadTimeout=0 is the default timeout value, and it represents an infinite timeout. – Remy Lebeau Feb 12 '10 at 10:15
  • Yes, but setting it in code after attaching the IOHandler seems to stop the EIdReadTimeout exception from being thrown. (At least in my experience, with the Indy versions that ship with Delphi) – jasonpenny Feb 12 '10 at 13:20
1

All SSL related functions for secure connections will fail unless some additional libraries are installed properly.

1.) Download libraries

2.) unzip and copy both DLLs to your project folder (or somewhere in the PATH of your system)

with that your code from the question works fine for me.

--reinhard

macf00bar
  • 673
  • 1
  • 14
  • 32
  • Thank you for your answer. I had the DLLs in place and it seems they were loaded correctly. The read timeout seems to be caused by something else. The WinInet approach works with the same server. – Tihauan Feb 11 '10 at 13:25