Code review comment: Isn't idle timeout a little different from response timeout? From their docs, this will close the connection if the connection doesn't send or receive any data: https://vertx.io/docs/apidocs/io/vertx/core/http/HttpClientOptions.html#setIdleTimeout-int-

Code under review:
public Mono<HttpResponse> send(HttpRequest request, Context context) {
        boolean eagerlyReadResponse = (boolean) context.getData(HttpUtils.AZURE_EAGERLY_READ_RESPONSE).orElse(false);
        boolean ignoreResponseBody = (boolean) context.getData(HttpUtils.AZURE_IGNORE_RESPONSE_BODY).orElse(false);
        Long responseTimeout = context.getData(HttpUtils.AZURE_RESPONSE_TIMEOUT)
            .filter(timeoutDuration -> timeoutDuration instanceof Duration)
            .map(timeoutDuration -> ((Duration) timeoutDuration).toMillis())
            .orElse(null);

        ProgressReporter progressReporter = Contexts.with(context).getHttpRequestProgressReporter();

        RequestOptions options = new RequestOptions().setMethod(HttpMethod.valueOf(request.getHttpMethod().name()))
            .setAbsoluteURI(request.getUrl());

        if (responseTimeout != null) {
            options.setIdleTimeout(responseTimeout);
        }

        return Mono.create(sink -> client.request(options, requestResult -> {
            if (requestResult.failed()) {
                sink.error(wrapVertxException(requestResult.cause()));
                return;
            }

            HttpClientRequest vertxRequest = requestResult.result();
            for (HttpHeader header : request.getHeaders()) {
                
                
                vertxRequest.putHeader(header.getName(), header.getValuesList());
            }
            if (request.getHeaders().get(HttpHeaderName.CONTENT_LENGTH) == null) {
                vertxRequest.setChunked(true);
            }

            vertxRequest.response(event -> {
                if (event.succeeded()) {
                    HttpClientResponse vertxHttpResponse = event.result();
                    vertxHttpResponse.exceptionHandler(exception -> sink.error(wrapVertxException(exception)));

                    
                    
                    
                    if (eagerlyReadResponse || ignoreResponseBody) {
                        vertxHttpResponse.body(bodyEvent -> {
                            if (bodyEvent.succeeded()) {
                                sink.success(
                                    new BufferedVertxHttpResponse(request, vertxHttpResponse, bodyEvent.result()));
                            } else {
                                sink.error(wrapVertxException(bodyEvent.cause()));
                            }
                        });
                    } else {
                        sink.success(new VertxHttpAsyncResponse(request, vertxHttpResponse));
                    }
                } else {
                    sink.error(wrapVertxException(event.cause()));
                }
            });

            sendBody(sink, request, progressReporter, vertxRequest);
        }));
    }

Line commented on: options.setIdleTimeout(responseTimeout);

Revised code:
public Mono<HttpResponse> send(HttpRequest request, Context context) {
        return Mono.deferContextual(contextView -> Mono.fromFuture(sendInternal(request, context, contextView)))
            .onErrorMap(VertxUtils::wrapVertxException);
    }