Thursday, November 16, 2006

Setting timeouts in Delphi SOAP

If you want to timeout your webservice call - either connecting, sending or receiving, you may be tempted to use the HttpRio.HttpWebNode properties: ConnectTimeout, SendTimeout and ReceiveTimeout. You will then face this error:

"The data area passed to a system call is too small. - URL:{some url here} - SOAPAction:{some other text here}"

The problem here is that calls made to InternetSetOption (in SOAPHTTPTrans.pas in the THTTPReqResp.Send procedure) is throwing an error. This is weird because although it returns an error code it does exactly what you want! There are calls to check the return code in the above file, and those checks fail.

Well, I'm not going to ask you to change the Borland source code this time. There's a way around it.

The way for you to do this is:
1) Do not set the ReceiveTimeout or the ConnectTimeout or other timeout properties of HTTPRio.HTTPWebNode.

2) Handle HTTPRio.HttpWebNode.BeforePost event and do this:

procedure TForm2.HTTPRIO1HTTPWebNode1BeforePost(
const HTTPReqResp: THTTPReqResp; Data: Pointer);
var TimeOut : integer;
begin
TimeOut := 2000; // in milleseconds.
InternetSetOption(Data,
INTERNET_OPTION_RECEIVE_TIMEOUT,
Pointer(@TimeOut),
SizeOf(TimeOut));
end;


(Do not check the return code of InternetSetOption above. It returns an error although everything's fine)

Note: This only works for INTERNET_OPTION_RECEIVE_TIMEOUT. The connect timeout (INTERNET_OPTION_CONNECT_TIMEOUT) and Send Timeout (INTERNET_OPTION_SEND_TIMEOUT) are broken with WinInet in synchronous mode (as HTTPRio uses) - check this Microsoft Support article. That means if you want to configure Send or Connect timeouts, you must use a different thread or use WinInet asynchronously (which is not at all an easy thing with HttpRio).

7 Comments:

Blogger Raghu said...

hi deepak,

I am raghuvir. do u have any idea abt a soap fault that I am getting. the fault code is receiveTimeOut.
Any idea why this fault occurs?

10:38 PM  
Blogger ibrahim said...

Another solution published on borland site. It is include "connect" and "Send" Timeout too.

http://qc.borland.com/wc/qcmain.aspx?d=49636

Before calling the web service call InternetSetOption with the following parameters:

InternetSetOption(nil, INTERNET_OPTION_CONNECT_TIMEOUT, Pointer(@conntimeout), SizeOf(conntimeout));
InternetSetOption(nil, INTERNET_OPTION_SEND_TIMEOUT, Pointer(@sendtimeout), SizeOf(sendtimeout));
InternetSetOption(nil, INTERNET_OPTION_RECEIVE_TIMEOUT, Pointer(@recvtimeout), SizeOf(recvtimeout));

İbrahim KAZANCI

2:58 AM  
Blogger Nisse J said...

Does anybody know how you would do that in Delphi 6?

3:05 AM  
Blogger Xebas said...

You are awesome, It still works that way in RADStudio 2007. Your solution is perfect. Thanks you very much

6:17 AM  
Blogger Lukáš said...

In Delphi 6 is situation similar. Just use BeforeExecute event.

procedure TXyz.HTTPRIOBeforeExecute(const MethodName: String;
var SOAPRequest: WideString);
var
iTimeOut: Integer;
begin
iTimeOut := 5000;
InternetSetOption(nil, INTERNET_OPTION_CONNECT_TIMEOUT, Pointer(@iTimeOut),
SizeOf(iTimeOut));

InternetSetOption(nil, INTERNET_OPTION_SEND_TIMEOUT, Pointer(@iTimeOut),
SizeOf(iTimeOut));

InternetSetOption(nil, INTERNET_OPTION_RECEIVE_TIMEOUT, Pointer(@iTimeOut),
SizeOf(iTimeOut));
end;

8:05 AM  
Blogger Jan said...

Many thanks. Solved my timeout problem. A Delphi 2009 project

6:02 AM  
Blogger ravi4u said...

Thanks for your help but dont forget to include WinInet package where InternetOpionSet is to be called

8:08 AM  

Post a Comment

<< Home