2010-02-11 4 views
9

Ho il seguente compito: scaricare un file usando HTTPS e autenticazione. Indy sembra la strada da percorrere, ma per qualche motivo non funziona fino ad ora. Ho il seguente al suo posto:Come scaricare un file su HTTPS usando Indy 10 e OpenSSL?

  • un componente TIdHTTP che uso per il download
  • un componente TIdURI utilizzato per creare l'URL
  • un componente TIdSSLIOHandlerSocketOpenSSL che dovrebbe fornire la connessione sicura. Le DLL richieste si trovano nella cartella binaria.

Il sito richiede anche l'autenticazione e ho incluso l'utente/pass nell'URL come nell'esempio seguente. In breve questo è il codice:

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); 

Utilizzando questo codice ottengo un'eccezione EIdReadTimeout "Leggi Timeout" molto veloce. Testare l'URL in un browser funziona senza problemi. Qualche idea su cosa manca o cosa ho fatto di sbagliato?

+0

C'è un firewall/proxy tra l'applicazione e il server? 'Browser funziona' non significa che ci sia una connessione Internet diretta. – mjn

+0

@mjustin Se guardo nelle impostazioni del browser non è definito alcun proxy. Inoltre, il fatto che l'approccio WinInet funzioni senza impostare alcun proxy mi dice che non è questo il problema. – Tihauan

+3

Non utilizzare le proprietà TIdURI.Username/password in questa situazione. Devi invece utilizzare le proprietà TIdHTTP.Username/Password. –

risposta

9

Ho infine abbandonato Indy e OpenSSL e ho utilizzato WinInet per il download. Questo è il codice che ha funzionato per 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; 
+0

Una parola di cautela riguardo al codice qui sopra: dovresti sempre usare il parametro INTERNET_FLAG_RELOAD per forzare un download dal server e non dalla cache. Quindi ti consiglierei di cambiare il tuo codice in: hURL: = InternetOpenURL (hSession, PChar (fullURL) , nil, 0, INTERNET_FLAG_RELOAD, 0); – user2858981

0

Tutti SSL funzioni correlate per connessioni sicure non riuscirà a meno che alcune librerie aggiuntive siano installati correttamente.

1.) Download libraries

2.) Scompatta e copia entrambe le DLL nella cartella di progetto (o da qualche parte nel percorso del vostro sistema)

con il che il codice dalla questione funziona bene per me.

--reinhard

+0

Grazie per la risposta. Ho avuto le DLL sul posto e sembra che siano stati caricati correttamente. Il timeout di lettura sembra essere causato da qualcos'altro. L'approccio WinInet funziona con lo stesso server. – Tihauan

1

Ho visto la stessa cosa. L'impostazione di TIdHTTP.ReadTimeout su zero risolve il problema per me.

... 
HTTP.IOHandler := IOHandler; 
HTTP.ReadTimeout := 0; 
+0

ReadTimeout = 0 è il valore di timeout predefinito e rappresenta un timeout infinito. –

+0

Sì, ma impostarlo in codice dopo aver collegato l'IOHandler sembra fermare l'eccezione EIdReadTimeout dall'essere lanciata. (Almeno nella mia esperienza, con le versioni di Indy fornite con Delphi) – jasonpenny