问题
I'm using the Indy 10 Http Client (latest SVN build) and a SSL Handler (Delphi 7) to get the content of the https://www.webtide.com/choose/jetty.jsp website.
It works fine on Windows 7 x64 (tested on two systems), but on WindowsXP x86 (tested on 3 systems) the test app simply hangs on TIdHTTP.Get() without the possibility of a recovery (meaning even disconnecting in a worker-procedure/thread does not work!). The test app cannot be recovered and must be closed with the task manager.
The SSL libraries (32bit x86!) are from here: http://slproweb.com/products/Win32OpenSSL.html but I've tried 5 other versions from different sites, with the same results.
Here is a zip package with source code, compiled executable, and the SSL libraries:
https://www.dropbox.com/s/pd5soxon0qbnnl0/IndyTest.zip
And here is the source code (the form has a button and two memos):
procedure TForm1.Button1Click(Sender: TObject);
var IdHTTP1: TIdHTTP;
sl : TStringList;
SSL1: TIdSSLIOHandlerSocketOpenSSL;
begin
try
try
IdHTTP1 := TIdHTTP.Create(nil);
sl := TStringList.Create;
SSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
SSL1.SSLOptions.Method := sslvSSLv23;
with IdHTTP1 do
begin
ConnectTimeout := 10 * 1000;
ReadTimeout := 10 * 1000;
IOHandler := SSL1;
Request.UserAgent := 'Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 (Ubuntu)';
Memo2.Text := 'connecting...';
Application.ProcessMessages;
Memo1.Text := Get('https://www.webtide.com/choose/jetty.jsp');
Memo1.Lines.Add ('response: '+ResponseText);
Memo2.Text := 'connected or timeout...';
end;
except
On e: Exception do
Memo2.Text := 'Exception: '+e.Message;
end;
finally
IdHTTP1.Free;
SSL1.Free;
sl.Free;
end;
end;
Why does it crash/hang on WindowsXP?
回答1:
Indy's ConnectTimeout
property only applies to the socket API connect()
function when establishing the underlying TCP/IP connection. SSL_connect()
is called at a later time to initiate the SSL handshake, which is application data and thus is not subject to the ConnectTimeout
.
Indy does use its ReadTimeout
property to assign socket level read/write timeouts on OpenSSL connections, but only on Vista+ as a workaround for an OpenSSL bug. On XP and earlier, default socket read/write timeouts apply. The ReadTimeout
only tells Indy how long to wait when reading data, but it is not applied to the socket itself. If you want to do that, you can do it manually by calling the TIdSocketHandle.SetSockOpt()
method after establishing the TCP/IP connection but before beginning the SSL handshake, for example:
procedure TForm1.Button1Click(Sender: TObject);
var
IdHTTP1: TIdHTTP;
SSL1: TIdSSLIOHandlerSocketOpenSSL;
begin
try
IdHTTP1 := TIdHTTP.Create(nil);
try
SSL1 := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP1);
SSL1.SSLOptions.Method := sslvSSLv23;
with IdHTTP1 do
begin
ConnectTimeout := 10 * 1000;
ReadTimeout := 10 * 1000;
IOHandler := SSL1;
OnConnected := IdHTTPConnected;
OnStatus := IdHTTPStatus;
Request.UserAgent := 'Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.7.3) Gecko/20040924 Epiphany/1.4.4 (Ubuntu)';
Memo1.Text := Get('https://www.webtide.com/choose/jetty.jsp');
Memo1.Lines.Add('response: '+ ResponseText);
Memo2.Text := 'finished...';
end;
finally
IdHTTP1.Free;
end;
except
on e: Exception do
Memo2.Text := 'Exception: ' + e.Message;
end;
end;
procedure TForm1.IdHTTPStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: string);
begin
case AStatus of
hsResolving: Memo2.Text := 'resolving...';
hsConnecting: Memo2.Text := 'connecting...';
hsConnected: Memo2.Text := 'connected...';
hsDisconnecting: Memo2.Text := 'disconnecting...';
hsDisconnected: Memo2.Text := 'disconnected...';
end;
Update;
end;
procedure TForm1.IdHTTPConnected(Sender: TObject);
begin
with TIdHTTP(Sender).Socket.Binding do
begin
SetSockOpt(Id_SOL_SOCKET, Id_SO_RCVTIMEO, 10 * 1000);
SetSockOpt(Id_SOL_SOCKET, Id_SO_SNDTIMEO, 10 * 1000);
end;
end;
来源:https://stackoverflow.com/questions/15363043/indy-10-ssl-works-in-windows-7-does-not-work-on-xp