My Delphi 12 project is using the NetHTTPClient component to download a 2GB file.
The download progresses quickly and without a break but after 60 seconds (around third of the download) it raises an exception saying the connect has timed out.
I adjusted the three time settings (ResponseTimeout, SendTimeout, and ConnectionTimeout) from the default values of 60,000 (one minute) to 600,000 and that worked around this issue because the download takes about three minutes.
How can I get it so that it only raises a connection timeout when the connection truly times out?
On most platforms, the ResponseTimeout
is the maximum allowed time for a response to complete. The default is 1 minute. By setting it to 10 minutes instead, you are giving enough time for your download to finish.
The ResponseTimeout
behavior depends on which platform your code is running on.
On Windows, TNetHTTPClient
uses WinHTTP
, and MSDN docs say the following for the WinHTTPSetTimeouts()
function:
[in] nReceiveTimeout
A value of type integer that specifies the time-out value, in milliseconds, to receive a response to a request. If a response takes longer than this time-out value, the request is canceled. The initial value is 30,000 (30 seconds).
...
A value of 0 or -1 sets a time-out to wait infinitely. A value greater than 0 sets the time-out value in milliseconds. For example, 30,000 would set the time-out to 30 seconds. All negative values other than -1 cause the function to fail with ERROR_INVALID_PARAMETER.
On Linux, TNetHTTPClient
uses Curl
, and the Curl docs say the following for the CURLOPT_TIMEOUT
/CURLOPT_TIMEOUT_MS
option:
the maximum time in [milli]seconds that you allow the entire transfer operation to take. The whole thing, from start to end. Normally, name lookups can take a considerable time and limiting operations risk aborting perfectly normal operations.
...
The connection timeout set with CURLOPT_CONNECTTIMEOUT is included in this general all-covering timeout.
If ResponseTimeout
is less than 0, TNetHTTPClient
will set the CURLOPT_TIMEOUT_MS
option to 0, ie infinite.
On MacOS and iOS, TNetHTTPClient
uses URLSession
, and Apple docs say the following for the URLSessionConfiguration.timeoutIntervalForResource
property:
The maximum amount of time that a resource request should be allowed to take.
This property determines the resource timeout interval for all tasks within sessions based on this configuration. The resource timeout interval controls how long (in seconds) to wait for an entire resource to transfer before giving up. The resource timer starts when the request is initiated and counts until either the request completes or this timeout interval is reached, whichever comes first.
If ResponseTimeout
is less than 0, TNetHTTPClient
will set the timeoutIntervalForResource
to 1 year.
On Android, TNetHTTPClient
uses URLConnection
, and the Android Java docs say the following for the URLConnection.setReadTimeout()
method:
Sets the read timeout to a specified timeout, in milliseconds. A non-zero value specifies the timeout when reading from Input stream when a connection is established to a resource. If the timeout expires before there is data available for read, a java.net.SocketTimeoutException is raised. A timeout of zero is interpreted as an infinite timeout.
This means the ResponseTimeout
is actually a per-byte timeout rather than a maximum response time, like on the other platforms. See: understanding URLConnection.setReadTimeout().
So, to answer your question, if you set the ResponseTimeout
to <= 0
on all platforms then TNetHTTPClient
will wait indefinitely (or close to it) for the response to complete. But, since you are expecting the download to complete in 3 minutes, then setting a 10 minute timeout is reasonable.
Similar rules apply to the ConnectTimeout
property (max time to connect to the server) and SendTimeout
property (max time to send a request) - except that TNetHTTPClient
does not appear to implement SendTimeout
for Android and Linux at this time, only Windows and MacOS/iOS.