:sourcedir: {http}/src/main/java
:examples-link: {reactor-netty-github-repo}/reactor-netty-examples/src/main/java/reactor/netty/examples/documentation/http/client
:examples-dir: {examples}/src/main/java/reactor/netty/examples/documentation/http/client
:wirelogger: reactor.netty.http.client.HttpClient

[[http-client]]
= HTTP Client

Reactor Netty provides the easy-to-use and easy-to-configure
{javadoc}/reactor/netty/http/client/HttpClient.html[`HttpClient`].
It hides most of the Netty functionality that is required to create an `HTTP` client
and adds Reactive Streams backpressure.

[[connect]]
== Connect

To connect the `HTTP` client to a given `HTTP` endpoint, you must create and configure a
{javadoc}/reactor/netty/http/client/HttpClient.html[`HttpClient`] instance.
By default, the host is configured for `localhost` and the port is `80`.
The following example shows how to do so:

{examples-link}/connect/Application.java
[%unbreakable]
----
include::{examples-dir}/connect/Application.java[lines=18..30]
----
<1> Creates a {javadoc}/reactor/netty/http/client/HttpClient.html[HttpClient]
instance ready for configuring.
<2> Specifies that `GET` method will be used.
<3> Specifies the path.
<4> Obtains the response {javadoc}/reactor/netty/http/client/HttpClientResponse.html[HttpClientResponse]


The following example uses `WebSocket`:

{examples-link}/websocket/Application.java
[%unbreakable]
----
include::{examples-dir}/websocket/Application.java[lines=18..42]
----

[[host-and-port]]
=== Host and Port

In order to connect to a specific host and port, you can apply the following configuration to the `HTTP` client:

{examples-link}/address/Application.java
[%unbreakable]
----
include::{examples-dir}/address/Application.java[lines=18..33]
----
<1> Configures the `HTTP` host
<2> Configures the `HTTP` port

NOTE: The port can be specified also with *PORT* environment variable.

[[eager-initialization]]
== Eager Initialization

By default, the initialization of the `HttpClient` resources happens on demand. This means that the `first
request` absorbs the extra time needed to initialize and load:

 * the event loop group
 * the host name resolver
 * the native transport libraries (when native transport is used)
 * the native libraries for the security (in case of `OpenSsl`)

When you need to preload these resources, you can configure the `HttpClient` as follows:

{examples-link}/warmup/Application.java
[%unbreakable]
----
include::{examples-dir}/warmup/Application.java[lines=18..36]
----
<1> Initialize and load the event loop group, the host name resolver, the native transport libraries and
the native libraries for the security
<2> Host name resolution happens with the first request.
In this example, a connection pool is used, so with the first request the connection to the URL is established,
the subsequent requests to the same URL reuse the connections from the pool.

[[writing-data]]
== Writing Data

To send data to a given `HTTP` endpoint, you can provide a `Publisher` by using the
{javadoc}/reactor/netty/http/client/HttpClient.RequestSender.html#send-org.reactivestreams.Publisher-[`send(Publisher)`] method.
By default, `Transfer-Encoding: chunked` is applied for those `HTTP` methods for which
a request body is expected. `Content-Length` provided through request headers disables `Transfer-Encoding: chunked`,
if necessary. The following example sends `hello`:

{examples-link}/send/Application.java
[%unbreakable]
----
include::{examples-dir}/send/Application.java[lines=18..33]
----
<1> Sends a `hello` string to the given `HTTP` endpoint

[[adding-headers-and-other-metadata]]
=== Adding Headers and Other Metadata

When sending data to a given `HTTP` endpoint, you may need to send additional headers, cookies and other metadata.
You can use the following configuration to do so:

{examples-link}/send/headers/Application.java
[%unbreakable]
----
include::{examples-dir}/send/headers/Application.java[lines=18..36]
----
<1> Disables `Transfer-Encoding: chunked` and provides `Content-Length` header.

[[compression]]
==== Compression

You can enable compression on the `HTTP` client, which means the request header
`Accept-Encoding` is added to the request headers. The following example shows how to do so:

{examples-link}/compression/Application.java
[%unbreakable]
----
include::{examples-dir}/compression/Application.java[lines=18..32]
----

[[auto-redirect-support]]
==== Auto-Redirect Support

You can configure the `HTTP` client to enable auto-redirect support.

Reactor Netty provides two different strategies for auto-redirect support:

* `followRedirect(boolean)`: Specifies whether HTTP auto-redirect support is enabled for statuses `301|302|303|307|308`.
When it is `303` status code, `GET` method is used for the redirect.
* `followRedirect(BiPredicate<HttpClientRequest, HttpClientResponse>)`: Enables auto-redirect support if the supplied
predicate matches.

The following example uses `followRedirect(true)`:

{examples-link}/redirect/Application.java
[%unbreakable]
----
include::{examples-dir}/redirect/Application.java[lines=18..32]
----

[[consuming-data]]
== Consuming Data

To receive data from a given `HTTP` endpoint, you can use one of the methods from
{javadoc}/reactor/netty/http/client/HttpClient.ResponseReceiver.html[`HttpClient.ResponseReceiver`].
The following example uses the `responseContent` method:

{examples-link}/read/Application.java
[%unbreakable]
----
include::{examples-dir}/read/Application.java[lines=18..33]
----
<1> Receives data from a given `HTTP` endpoint
<2> Aggregates the data
<3> Transforms the data as string

[[reading-headers-and-other-metadata]]
=== Reading Headers and Other Metadata

When receiving data from a given `HTTP` endpoint, you can check response headers, status code, and other metadata.
You can obtain this additional metadata by using
{javadoc}/reactor/netty/http/client/HttpClientResponse.html[`HttpClientResponse`].
The following example shows how to do so.

{examples-link}/read/status/Application.java
[%unbreakable]
----
include::{examples-dir}/read/status/Application.java[lines=18..34]
----
<1> Obtains the status code.

[[http-response-decoder]]
=== HTTP Response Decoder

By default, `Netty` configures some restrictions for the incoming responses, such as:

* The maximum length of the initial line.
* The maximum length of all headers.
* The maximum length of the content or each chunk.

For more information, see {nettyjavadoc}/io/netty/handler/codec/http/HttpResponseDecoder.html[HttpResponseDecoder]

By default, the `HTTP` client is configured with the following settings:

{http-source-link}/reactor/netty/http/HttpDecoderSpec.java
[%unbreakable]
----
include::{sourcedir}/reactor/netty/http/HttpDecoderSpec.java[lines=28..40]
----

{http-source-link}/reactor/netty/http/client/HttpResponseDecoderSpec.java
[%unbreakable]
----
include::{sourcedir}/reactor/netty/http/client/HttpResponseDecoderSpec.java[lines=42..50]
----

When you need to change these default settings, you can configure the `HTTP` client as follows:

{examples-link}/responsedecoder/Application.java
[%unbreakable]
----
include::{examples-dir}/responsedecoder/Application.java[lines=18..35]
----
<1> The maximum length of all headers will be `16384`.
When this value is exceeded, a
{nettyjavadoc}/io/netty/handler/codec/TooLongFrameException.html[TooLongFrameException]
is raised.

[[lifecycle-callbacks]]
== Lifecycle Callbacks

The following lifecycle callbacks are provided to let you extend the `HttpClient`.

[width="100%",options="header"]
|=======
| Callback | Description
| `doAfterRequest` | Invoked when the request has been sent.
| `doAfterResolve` | Invoked after the remote address has been resolved successfully.
| `doAfterResponseSuccess` | Invoked after the response has been fully received.
| `doOnChannelInit` | Invoked when initializing the channel.
| `doOnConnect` | Invoked when the channel is about to connect.
| `doOnConnected` | Invoked after the channel has been connected.
| `doOnDisconnected` | Invoked after the channel has been disconnected.
| `doOnError` | Invoked when the request has not been sent and when the response has not been fully received.
| `doOnRedirect` | Invoked when the response headers have been received, and the request is about to be redirected.
| `doOnRequest` | Invoked when the request is about to be sent.
| `doOnRequestError` | Invoked when the request has not been sent.
| `doOnResolve` | Invoked when the remote address is about to be resolved.
| `doOnResolveError` | Invoked in case the remote address hasn't been resolved successfully.
| `doOnResponse` | Invoked after the response headers have been received.
| `doOnResponseError` | Invoked when the response has not been fully received.
|=======

The following example uses the `doOnConnected` and `doOnChannelInit` callbacks:

{examples-link}/lifecycle/Application.java
[%unbreakable]
----
include::{examples-dir}/lifecycle/Application.java[lines=18..39]
----
<1> `Netty` pipeline is extended with `ReadTimeoutHandler` when the channel has been connected.
<2> `Netty` pipeline is extended with `LoggingHandler` when initializing the channel.

[[tcp-level-configuration]]
== TCP-level Configuration

When you need configurations on a TCP level, you can use the following snippet
to extend the default `TCP` client configuration (add an option, bind address etc.):

{examples-link}/channeloptions/Application.java
[%unbreakable]
----
include::{examples-dir}/channeloptions/Application.java[lines=18..54]
----
<1> Configures the connection establishment timeout to 10 seconds.
<2> Enables TCP `keepalive`. This means that TCP starts sending `keepalive` probes when a connection is idle for some time.
<3> The connection needs to remain idle for 5 minutes before TCP starts sending `keepalive` probes.
<4> Configures the time between individual `keepalive` probes to 1 minute.
<5> Configures the maximum number of TCP `keepalive` probes to 8.

See xref:tcp-client.adoc[TCP Client] for more about `TCP` level configurations.

include::partial$wire-logger.adoc[]

include::partial$eventloop.adoc[]

include::partial$http-client-conn-provider.adoc[]

[[ssl-and-tls]]
== SSL and TLS
When you need SSL or TLS, you can apply the configuration shown in the next example.
By default, if `OpenSSL` is available, a
{nettyjavadoc}/io/netty/handler/ssl/SslProvider.html#OPENSSL[SslProvider.OPENSSL]
provider is used as a provider. Otherwise, a
{nettyjavadoc}/io/netty/handler/ssl/SslProvider.html#JDK[SslProvider.JDK] provider is used
You can switch the provider by using
{nettyjavadoc}/io/netty/handler/ssl/SslContextBuilder.html#sslProvider-io.netty.handler.ssl.SslProvider-[SslContextBuilder]
or by setting `-Dio.netty.handler.ssl.noOpenSsl=true`.
The following example uses `SslContextBuilder`:

{examples-link}/security/Application.java
[%unbreakable]
----
include::{examples-dir}/security/Application.java[lines=18..35]
----

[[server-name-indication]]
=== Server Name Indication
By default, the `HTTP` client sends the remote host name as `SNI` server name.
When you need to change this default setting, you can configure the `HTTP` client as follows:

{examples-link}/sni/Application.java
[%unbreakable]
----
include::{examples-dir}/sni/Application.java[lines=18..39]
----

[[retry-strategies]]
== Retry Strategies
By default, the `HTTP` client retries the request once if it was aborted on the `TCP` level.

[[HTTP2]]
== HTTP/2

By default, the `HTTP` client supports `HTTP/1.1`. If you need `HTTP/2`, you can get it through configuration.
In addition to the protocol configuration, if you need `H2` but not `H2C (cleartext)`, you must also configure SSL.

NOTE: As Application-Layer Protocol Negotiation (ALPN) is not supported "`out-of-the-box`" by JDK8 (although some vendors backported ALPN to JDK8), you need an additional dependency to a native library that
supports it -- for example, https://netty.io/wiki/forked-tomcat-native.html[`netty-tcnative-boringssl-static`].

The following listing presents a simple `H2` example:

{examples-link}/http2/H2Application.java
[%unbreakable]
----
include::{examples-dir}/http2/H2Application.java[lines=18..42]
----
<1> Configures the client to support only `HTTP/2`
<2> Configures `SSL`

The following listing presents a simple `H2C` example:

{examples-link}/http2/H2CApplication.java
[%unbreakable]
----
include::{examples-dir}/http2/H2CApplication.java[lines=18..41]
----

[[protocol-selection]]
=== Protocol Selection

{http-source-link}/reactor/netty/http/HttpProtocol.java
[%unbreakable]
----
include::{sourcedir}/reactor/netty/http/HttpProtocol.java[lines=26..61]
----

[[HTTP3]]
== HTTP/3
By default, the `HTTP` client supports `HTTP/1.1`. If you need `HTTP/3`, you can get it through configuration.
In addition to the protocol configuration, you need to add dependency to `io.netty.incubator:netty-incubator-codec-http3`.

The following listing presents a simple `HTTP3` example:

{examples-link}/http3/Application.java
----
include::{examples-dir}/http3/Application.java[lines=18..46]
----
<1> Configures the client to support only `HTTP/3`
<2> Configures `HTTP/3` settings

include::partial$proxy.adoc[]

[[metrics]]
== Metrics
The HTTP client supports built-in integration with https://micrometer.io/[`Micrometer`].
It exposes all metrics with a prefix of `reactor.netty.http.client`.

The following table provides information for the HTTP client metrics:

[width="100%",options="header"]
|=======
| metric name | type | description
| reactor.netty.http.client.data.received | DistributionSummary | Amount of the data received, in bytes.
See xref:observability.adoc#observability-metrics-data-received[Data Received]
| reactor.netty.http.client.data.sent | DistributionSummary | Amount of the data sent, in bytes.
See xref:observability.adoc#observability-metrics-data-sent[Data Sent]
| reactor.netty.http.client.errors | Counter | Number of errors that occurred.
See xref:observability.adoc#observability-metrics-errors-count[Errors Count]
| reactor.netty.http.client.tls.handshake.time | Timer | Time spent for TLS handshake.
See xref:observability.adoc#observability-metrics-tls-handshake-time[Tls Handshake Time]
| reactor.netty.http.client.connect.time | Timer | Time spent for connecting to the remote address.
See xref:observability.adoc#observability-metrics-connect-time[Connect Time]
| reactor.netty.http.client.address.resolver | Timer | Time spent for resolving the address.
See xref:observability.adoc#observability-metrics-hostname-resolution-time[Hostname Resolution Time]
| reactor.netty.http.client.data.received.time | Timer | Time spent in consuming incoming data.
See xref:observability.adoc#observability-metrics-http-client-data-received-time[Http Client Data Received Time]
| reactor.netty.http.client.data.sent.time | Timer | Time spent in sending outgoing data.
See xref:observability.adoc#observability-metrics-http-client-data-sent-time[Http Client Data Sent Time]
| reactor.netty.http.client.response.time | Timer | Total time for the request/response
See xref:observability.adoc#observability-metrics-http-client-response-time[Http Client Response Time]
|=======

These additional metrics are also available:

include::partial$conn-provider-metrics.adoc[]

The following table provides information for the HTTP client metrics when it is configured to serve `HTTP/2` traffic:

[width="100%",options="header"]
|=======
| metric name | type | description
| reactor.netty.connection.provider.active.streams | Gauge | The number of the active HTTP/2 streams.
See xref:observability.adoc#observability-metrics-active-streams[Active Streams]
| reactor.netty.connection.provider.pending.streams | Gauge | The number of requests that are waiting for opening HTTP/2 stream.
See xref:observability.adoc#observability-metrics-pending-streams[Pending Streams]
|=======

include::partial$alloc-metrics.adoc[]
include::partial$eventloop-metrics.adoc[]


The following example enables that integration:

{examples-link}/metrics/Application.java
[%unbreakable]
----
include::{examples-dir}/metrics/Application.java[lines=18..51]
----
<1> Applies upper limit for the meters with `URI` tag
<2> Templated URIs will be used as a URI tag value when possible
<3> Enables the built-in integration with Micrometer

NOTE: In order to avoid a memory and CPU overhead of the enabled metrics, it is important to convert the real URIs to templated URIs when possible.
Without a conversion to a template-like form, each distinct URI leads to the creation of a distinct tag, which takes a lot of memory for the metrics.

NOTE: Always apply an upper limit for the meters with URI tags. Configuring an upper limit on the number of meters can help in cases when the real URIs cannot be templated.
You can find more information at https://micrometer.io/docs/concepts#_denyaccept_meters[`maximumAllowableTags`].

When HTTP client metrics are needed for an integration with a system other than `Micrometer` or you want
to provide your own integration with `Micrometer`, you can provide your own metrics recorder, as follows:

{examples-link}/metrics/custom/Application.java
[%unbreakable]
----
include::{examples-dir}/metrics/custom/Application.java[lines=18..35]
----
<1> Enables HTTP client metrics and provides {javadoc}/reactor/netty/http/client/HttpClientMetricsRecorder.html[`HttpClientMetricsRecorder`] implementation.

[[tracing]]
== Tracing
The HTTP client supports built-in integration with https://micrometer.io/docs/tracing[`Micrometer Tracing`].

The following table provides information for the HTTP client spans:

[width="100%",options="header"]
|=======
| contextual name | description
| HTTP <HTTP METHOD> | Information and total time for the request.
See xref:observability.adoc#observability-spans-http-client-response-span[Http Client Response Span].
| hostname resolution | Information and time spent for resolving the address.
See xref:observability.adoc#observability-spans-hostname-resolution-span[Hostname Resolution Span].
| connect | Information and time spent for connecting to the remote address.
See xref:observability.adoc#observability-spans-connect-span[Connect Span].
| tls handshake | Information and time spent for TLS handshake.
See xref:observability.adoc#observability-spans-tls-handshake-span[Tls Handshake Span].
|=======

The following example enables that integration. This concrete example uses `Brave` and reports the information to `Zipkin`.
See the https://micrometer.io/docs/tracing#_micrometer_tracing_opentelemetry_setup[`Micrometer Tracing`] documentation for `OpenTelemetry` setup.

{examples-link}/tracing/Application.java
----
include::{examples-dir}/tracing/Application.java[lines=18..90]
----
<1> Initializes Brave, Zipkin, and the Observation registry.
<2> Templated URIs are used as an URI tag value when possible.
<3> Enables the built-in integration with Micrometer.

The result in `Zipkin` looks like:

image::http-client-tracing.png[role="invert-dark"]

[[access-current-observation]]
=== Access Current Observation
Project Micrometer provides https://micrometer.io/docs/contextPropagation[`a library`] that assists with context propagation across
different types of context mechanisms such as `ThreadLocal`, `Reactor Context` and others.

The following example shows how to use this library in a custom `ChannelHandler`:

{examples-link}/tracing/custom/Application.java
----
include::{examples-dir}/tracing/custom/Application.java[lines=18..85]
----
<1> Initializes Brave, Zipkin, and the Observation registry.
<2> Templated URIs are used as an URI tag value when possible.
<3> Enables the built-in integration with Micrometer.
<4> Custom `ChannelHandler` that uses context propagation library. This concrete example overrides only
`ChannelOutboundHandlerAdapter#write`, if it is needed, the same logic can be used for the rest of the methods.
Also, this concrete example sets all `ThreadLocal` values for which there is a value in the given `Channel`,
if another behaviour is needed please check https://micrometer.io/docs/contextPropagation[`context propagation library API`].
For example, you may want to set only some of the `ThreadLocal` values.

NOTE: When you enable Reactor Netty tracing within a framework, you may need to let Reactor Netty use the `ObservationRegistry` created by this framework.
For this purpose you need to invoke {javadoc}/reactor/netty/Metrics.html#observationRegistry-io.micrometer.observation.ObservationRegistry-[`reactor.netty.Metrics#observationRegistry`].
You may also need to configure the Reactor Netty `ObservationHandlers` using the API provided by the framework.

[[unix-domain-sockets]]
== Unix Domain Sockets
The `HTTP` client supports Unix Domain Sockets (UDS) when native transport is in use for all java versions
and when NIO transport is in use for java 17 and above.

The following example shows how to use UDS support:

{examples-link}/uds/Application.java
----
include::{examples-dir}/uds/Application.java[lines=18..38]
----
<1> Specifies `DomainSocketAddress` that will be used

[[host-name-resolution]]
== Host Name Resolution
By default, the `HttpClient` uses Netty's domain name lookup mechanism that resolves a domain name asynchronously.
This is as an alternative of the JVM's built-in blocking resolver.

When you need to change the default settings, you can configure the `HttpClient` as follows:

{examples-link}/resolver/Application.java
----
include::{examples-dir}/resolver/Application.java[lines=18..39]
----
<1> The timeout of each DNS query performed by this resolver will be 500ms.

The following listing shows the available configurations.
Additionally, https://tools.ietf.org/html/rfc7766[`TCP fallback`] is enabled by default.


[width="100%",options="header"]
|=======
| Configuration name | Description
| `bindAddressSupplier` | The supplier of the local address to bind to.
| `cacheMaxTimeToLive` | The max time to live of the cached DNS resource records (resolution: seconds).
If the time to live of the DNS resource record returned by the DNS server is greater
than this max time to live, this resolver ignores the time to live from
the DNS server and uses this max time to live.
Default to `Integer.MAX_VALUE`.
| `cacheMinTimeToLive` | The min time to live of the cached DNS resource records (resolution: seconds).
If the time to live of the DNS resource record returned by the DNS server is less
than this min time to live, this resolver ignores the time to live from
the DNS server and uses this min time to live.
Default: 0.
| `cacheNegativeTimeToLive` | The time to live of the cache for the failed DNS queries (resolution: seconds). Default: 0.
| `completeOncePreferredResolved` | When this setting is enabled, the resolver notifies as soon as all queries for the preferred address type are complete.
When this setting is disabled, the resolver notifies when all possible address types are complete.
This configuration is applicable for `DnsNameResolver#resolveAll(String)`. By default, this setting is enabled.
| `disableOptionalRecord` | Disables the automatic inclusion of an optional record that tries to give a hint to the remote DNS server about
how much data the resolver can read per response. By default, this setting is enabled.
| `disableRecursionDesired` | Specifies whether this resolver has to send a DNS query with the recursion desired (RD) flag set.
By default, this setting is enabled.
| `dnsAddressResolverGroupProvider` | Sets a custom function to create a `DnsAddressResolverGroup` given a `DnsNameResolverBuilder`
| `hostsFileEntriesResolver` | Sets a custom {nettyjavadoc}/io/netty/resolver/HostsFileEntriesResolver.html[`HostsFileEntriesResolver`] to be used for hosts file entries.
Default: {nettyjavadoc}/io/netty/resolver/DefaultHostsFileEntriesResolver.html[`DefaultHostsFileEntriesResolver`].
| `maxPayloadSize` | Sets the capacity of the datagram packet buffer (in bytes). Default: 4096.
| `maxQueriesPerResolve` | Sets the maximum allowed number of DNS queries to send when resolving a host name. Default: 16.
| `ndots` | Sets the number of dots that must appear in a name before an initial absolute query is made.
Default: -1 (to determine the value from the OS on Unix or use a value of 1 otherwise).
| `queryTimeout` | Sets the timeout of each DNS query performed by this resolver (resolution: milliseconds). Default: 5000.
| `resolveCache` | The cache to use to store resolved DNS entries.
| `resolvedAddressTypes` | The list of the protocol families of the resolved address.
| `retryTcpOnTimeout` | Specifies whether this resolver will also fallback to TCP if a timeout is detected.
By default, the resolver will only try to use TCP if the response is marked as truncated.
| `roundRobinSelection` | Enables an
{nettyjavadoc}/io/netty/resolver/AddressResolverGroup.html[`AddressResolverGroup`] of
{nettyjavadoc}/io/netty/resolver/dns/DnsNameResolver.html[`DnsNameResolver`] that supports random selection
of destination addresses if multiple are provided by the nameserver.
See {nettyjavadoc}/io/netty/resolver/dns/RoundRobinDnsAddressResolverGroup.html[`RoundRobinDnsAddressResolverGroup`].
Default: {nettyjavadoc}/io/netty/resolver/dns/DnsAddressResolverGroup.html[`DnsAddressResolverGroup`]
| `runOn` | Performs the communication with the DNS servers on the given
{javadoc}/reactor/netty/resources/LoopResources.html[`LoopResources`]. By default, the LoopResources
specified on the client level are used.
| `searchDomains` | The list of search domains of the resolver.
By default, the effective search domain list is populated by using the system DNS search domains.
| `trace` | A specific logger and log level to be used by this resolver when generating detailed trace
information in case of resolution failure.
|=======

Sometimes, you may want to switch to the JVM built-in resolver. To do so, you can configure the `HttpClient` as follows:

{examples-link}/resolver/custom/Application.java
----
include::{examples-dir}/resolver/custom/Application.java[lines=18..38]
----
<1> Sets the JVM built-in resolver.

[[timeout-configuration]]
== Timeout Configuration
This section describes various timeout configuration options that can be used in `HttpClient`.
Configuring a proper timeout may improve or solve issues in the communication process.
The configuration options can be grouped as follows:

* xref:http-client.adoc#connection-pool-timeout[Connection Pool Timeout]
* xref:http-client.adoc#http-client-timeout[HttpClient Timeout]
** xref:http-client.adoc#response-timeout[Response Timeout]
** xref:http-client.adoc#connection-timeout[Connection Timeout]
** xref:http-client.adoc#ssl-tls-timeout[SSL/TLS Timeout]
** xref:http-client.adoc#proxy-timeout[Proxy Timeout]
** xref:http-client.adoc#dns-timeout[Host Name Resolution Timeout]

[[connection-pool-timeout]]
=== Connection Pool Timeout
By default, `HttpClient` uses a connection pool. When a request is completed successfully and if the connection is not scheduled for closing,
the connection is returned to the connection pool and can thus be reused for processing another request. The connection may
be reused immediately for another request or may stay idle in the connection pool for some time.

The following list describes the available timeout configuration options:

* `maxIdleTime` - The maximum time (resolution: ms) that this connection stays idle in the connection pool. By default,
{javadoc}/reactor/netty/resources/ConnectionProvider.ConnectionPoolSpec.html#maxIdleTime-java.time.Duration-[`maxIdleTime`] is not specified.

NOTE: When you configure `maxIdleTime`, you should consider the idle timeout configuration on the target server.
Choose a configuration that is equal to or less than the one on the target server. By doing so, you can reduce the I/O
issues caused by a connection closed by the target server.

* `maxLifeTime` - The maximum time (resolution: ms) that this connection stays alive. By default,
{javadoc}/reactor/netty/resources/ConnectionProvider.ConnectionPoolSpec.html#maxLifeTime-java.time.Duration-[`maxLifeTime`] is not specified.
* `pendingAcquireTimeout` - The maximum time (resolution: ms) after which a pending acquire operation must complete, or
a `PoolAcquireTimeoutException` is thrown. Default: 45s.

By default, these timeouts are checked on connection `release` or `acquire` operations and, if some timeout is reached, the connection is closed and removed from the connection pool.
However, you can also configure the connection pool, by setting `evictInBackground`, to perform periodic checks on connections.

To customize the default settings, you can configure `HttpClient` as follows:

{examples-link}/pool/Application.java
----
include::{examples-dir}/pool/config/Application.java[lines=18..50]
----
<1> Configures the maximum time for a connection to stay idle to 20 seconds.
<2> Configures the maximum time for a connection to stay alive to 60 seconds.
<3> Configures the maximum time for the pending acquire operation to 60 seconds.
<4> Every two minutes, the connection pool is regularly checked for connections that are applicable for removal.

[[http-client-timeout]]
=== HttpClient Timeout
This section provides information for the various timeout configuration options at the `HttpClient` level.

NOTE: Reactor Netty uses Reactor Core as its Reactive Streams implementation, and you may want to use the `timeout` operator that `Mono` and `Flux` provide.
Keep in mind, however, that it is better to use the more specific timeout configuration options available in Reactor Netty, since they provide more control for a specific purpose and use case.
By contrast, the `timeout` operator can only apply to the operation as a whole, from establishing the connection to the remote peer to receiving the response.

[[response-timeout]]
==== Response Timeout
`HttpClient` provides an API for configuring a default response timeout for all requests. You can change this default response timeout
through an API for a specific request. By default,
{javadoc}/reactor/netty/http/client/HttpClient.html#responseTimeout-java.time.Duration-[`responseTimeout`] is not specified.

NOTE: It is always a good practice to configure a response timeout.

To customize the default settings, you can configure `HttpClient` as follows:

{examples-link}/read/timeout/Application.java
----
include::{examples-dir}/read/timeout/Application.java[lines=18..55]
----
<1> Configures the default response timeout to 1 second.
<2> Configures a response timeout for a specific request to 2 seconds.

[[connection-timeout]]
==== Connection Timeout
The following listing shows all available connection timeout configuration options, but some of them may apply only to a specific transport.

* `CONNECT_TIMEOUT_MILLIS` - If the connection establishment attempt to the remote peer does not finish within the configured connect timeout (resolution: ms),
the connection establishment attempt fails. Default: 30s.
* `SO_KEEPALIVE` - When the connection stays idle for some time (the time is implementation dependent, but the default is typically two hours),
TCP automatically sends a `keepalive` probe to the remote peer.
By default, https://docs.oracle.com/javase/8/docs/api/java/net/SocketOptions.html#SO_KEEPALIVE[`SO_KEEPALIVE`] is not enabled.
When you run with `Epoll`/`NIO` (https://bugs.openjdk.java.net/browse/JDK-8194298[since *Java 11* on *Mac or Linux*]) transport, you may also configure:
** `TCP_KEEPIDLE` - The maximum time (resolution: seconds) that this connection stays idle before TCP starts sending `keepalive` probes,
if `SO_KEEPALIVE` has been set. The maximum time is implementation dependent, but the default is typically two hours.
** `TCP_KEEPINTVL` (Epoll)/`TCP_KEEPINTERVAL` (NIO) - The time (resolution: seconds) between individual `keepalive` probes.
** `TCP_KEEPCNT` (Epoll)/`TCP_KEEPCOUNT` (NIO) - The maximum number of `keepalive` probes TCP should send before dropping the connection.

NOTE: Sometimes, between the client and the server, you may have a network component that silently drops the idle connections without sending a response.
From the Reactor Netty point of view, in this use case, the remote peer just does not respond.
To be able to handle such a use case you may consider configuring
https://docs.oracle.com/javase/8/docs/technotes/guides/net/socketOpt.html[`SO_KEEPALIVE`].

To customize the default settings, you can configure `HttpClient` as follows:

{examples-link}/channeloptions/Application.java
----
include::{examples-dir}/channeloptions/Application.java[lines=18..54]
----
<1> Configures the connection establishment timeout to 10 seconds.
<2> Enables TCP `keepalive`. This means that TCP starts sending `keepalive` probes when a connection is idle for some time.
<3> The connection needs to remain idle for 5 minutes before TCP starts sending `keepalive` probes.
<4> Configures the time between individual `keepalive` probes to 1 minute.
<5> Configures the maximum number of TCP `keepalive` probes to 8.

[[ssl-tls-timeout]]
==== SSL/TLS Timeout
`HttpClient` supports the SSL/TLS functionality provided by Netty.

The following list describes the available timeout configuration options:

* `handshakeTimeout` - Use this option to configure the SSL handshake timeout (resolution: ms). Default: 10s.

NOTE: You should consider increasing the SSL handshake timeout when expecting slow network connections.

* `closeNotifyFlushTimeout` - Use this option to configure the SSL `close_notify` flush timeout (resolution: ms). Default: 3s.
* `closeNotifyReadTimeout` - Use this option to configure the SSL `close_notify` read timeout (resolution: ms). Default: 0s.

To customize the default settings, you can configure `HttpClient` as follows:

{examples-link}/security/custom/Application.java
----
include::{examples-dir}/security/custom/Application.java[lines=18..45]
----
<1> Configures the SSL handshake timeout to 30 seconds.
<2> Configures the SSL `close_notify` flush timeout to 10 seconds.
<3> Configures the SSL `close_notify` read timeout to 10 seconds.

[[proxy-timeout]]
==== Proxy Timeout
`HttpClient` supports the proxy functionality provided by Netty and provides a way to specify the
{javadoc}/reactor/netty/transport/ProxyProvider.Builder.html#connectTimeoutMillis-long-[connection establishment timeout].
If the connection establishment attempt to the remote peer does not finish within the timeout,
the connection establishment attempt fails. Default: 10s.

To customize the default settings, you can configure `HttpClient` as follows:

{examples-link}/proxy/Application.java
----
include::{examples-dir}/proxy/Application.java[lines=18..42]
----
<1> Configures the connection establishment timeout to 20 seconds.

[[dns-timeout]]
==== Host Name Resolution Timeout
By default, the `HttpClient` uses Netty’s domain name lookup mechanism to resolve a domain name asynchronously.

The following list describes the available timeout configuration options:

* `cacheMaxTimeToLive` - The maximum time to live of the cached DNS resource records (resolution: seconds).
If the time to live of the DNS resource record returned by the DNS server is greater
than this maximum time to live, this resolver ignores the time to live from
the DNS server and uses this maximum time to live. Default: `Integer.MAX_VALUE`.
* `cacheMinTimeToLive` - The minimum time to live of the cached DNS resource records (resolution: seconds).
If the time to live of the DNS resource record returned by the DNS server is less
than this minimum time to live, this resolver ignores the time to live from
the DNS server and uses this minimum time to live. Default: 0s.
* `cacheNegativeTimeToLive` - The time to live of the cache for the failed DNS queries (resolution: seconds). Default: 0s.
* `queryTimeout` - Sets the timeout of each DNS query performed by this resolver (resolution: milliseconds). Default: 5s.

To customize the default settings, you can configure `HttpClient` as follows:

{examples-link}/resolver/Application.java
----
include::{examples-dir}/resolver/Application.java[lines=18..39]
----
<1> The timeout of each DNS query performed by this resolver will be 500ms.
