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;
TimeOut := 2000; // in milleseconds.

(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).