I've been looking into an issue with TLS handshake timeouts on the
async client (see
https://github.com/apache/httpcomponents-client/pull/118), and I think
that this topic might benefit from a broader audit.

Currently, there are three types of timeouts we expose through RequestConfig:

1. Connection request timeout (defined as the time to wait when
requesting a connection from the connection manager)
2. Connect timeout (defined as the time to wait until a new connection
is fully established)
3. Response timeout (defined as the time to wait until arrival of a
response from the opposite endpoint); this is basically a reboot of
the "socket timeout" value exposed in previous versions

Since all of these definitions are fairly high-level, they are tricky
to implement correctly in terms of low-level IO timeouts. For example,
implementing a connection timeout in terms of a socket timeout has
surprising implications, because establishing a TLS connection
requires multiple operations on the socket (TCP handshake, followed by
two round trips for the TLS handshake). If I specify a connection
timeout of 2.5 seconds, and each round trip to the remote host takes 2
seconds, will the connection attempt actually time out as it ought to?
(This scenario can be made almost arbitrarily complicated by adding
proxy hops to the route, HTTP auth challenge/response steps, and so
forth.)

A similar point applies to the response timeout: the definition is
somewhat ambiguous, because "the arrival of a response" can be
interpreted as (1) the initial bytes of the response, (2) the end of
the response, or (3) the next packet of the response (i.e. max wait
time per read operation, which is basically the definition of
socketTimeout). These definitions are only approximately the same in
the case of relatively short and simple responses, not long-running
streams.

Interactions are another subtlety: timeouts can interact with each
other, as well as with other client features. Is the connection
request considered part of the connection phase, or are they logically
separate? Is it meaningful for the connection request timeout to be
longer than the request timeout? If I hit the connectionTimeout, what
does the DefaultHttpRequestRetryHandler do?

Finally, there's the question of synchronous versus asynchronous IO.
Do we expect to be able to implement the exact same timeout behavior
on NIO and BIO, or will we have to make compromises somewhere?

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to