Dear Apache CXF Development Team,

I would like to report a bug in the `HttpClientWrappedOutputStream` class
within the `org.apache.cxf.transport.http` package. The issue occurs during
the handling of an `IOException` when the `close` method is invoked.

**Description of the Issue:**

When the `close` method of the parent class
`org.apache.cxf.transport.http.HTTPConduit.WrappedOutputStream` is called,
a timeout occurs at line 1420, resulting in an `IOException`. This
exception is caught at line 1428 and subsequently rethrown to the upper
layer.

The upper layer, specifically the `close` method in
`org.apache.cxf.transport.http.HttpClientHTTPConduit.HttpClientWrappedOutputStream`,
does not properly handle the exception. As a result, the `pout` resource
(which corresponds to the socket for writing) is not released, leading to a
connection leak.

**Steps to Reproduce:**

1. Invoke the `close` method on an instance of
`HttpClientWrappedOutputStream`.
2. Simulate a timeout condition that triggers an `IOException` in the
parent class's `close` method.
3. Observe that the `pout` resource is not released, causing a connection
leak.
4. The relevant Java exception stack trace is as follows:
Caused by: java.net.http.HttpTimeoutException: HttpTimeoutException
invoking
https://reporting.api.bingads.microsoft.com/Reporting/v13/GenerateReport/Poll:
Timeout
at
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native
Method)
at
java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:77)
at
java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at
java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:499)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:480)
at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.mapException(HTTPConduit.java:1452)
at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1433)
at
org.apache.cxf.transport.http.HttpClientHTTPConduit$HttpClientWrappedOutputStream.close(HttpClientHTTPConduit.java:824)
at
org.apache.cxf.io.AbstractWrappedOutputStream.close(AbstractWrappedOutputStream.java:77)
at
org.apache.cxf.io.AbstractWrappedOutputStream.close(AbstractWrappedOutputStream.java:77)
at
org.apache.cxf.io.AbstractThresholdOutputStream.close(AbstractThresholdOutputStream.java:102)
at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56)
at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:717)
at
org.apache.cxf.transport.http.HttpClientHTTPConduit.close(HttpClientHTTPConduit.java:261)
at
org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:63)
at
org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:307)
at
org.apache.cxf.jaxrs.client.AbstractClient.doRunInterceptorChain(AbstractClient.java:717)
at
org.apache.cxf.jaxrs.client.WebClient.doChainedInvocation(WebClient.java:1085)
... 17 more
Caused by: java.net.http.HttpTimeoutException: Timeout
at
org.apache.cxf.transport.http.HttpClientHTTPConduit$HttpClientWrappedOutputStream.getResponse(HttpClientHTTPConduit.java:1074)
at
org.apache.cxf.transport.http.HttpClientHTTPConduit$HttpClientWrappedOutputStream.getResponseCode(HttpClientHTTPConduit.java:1081)
at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.doProcessResponseCode(HTTPConduit.java:1653)
at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1684)
at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1626)
at
org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1420)
... 28 more
Caused by: java.util.concurrent.TimeoutException
at
java.base/java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1960)
at
java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2095)
at
org.apache.cxf.transport.http.HttpClientHTTPConduit$HttpClientWrappedOutputStream.getResponse(HttpClientHTTPConduit.java:1052)
... 33 more



**Expected Behavior:**

The `close` method in `HttpClientWrappedOutputStream` should ensure that
all resources, including `pout`, are properly released even if an
`IOException` is thrown by the parent class's `close` method.

**Proposed Fix:**

The `close` method in `HttpClientWrappedOutputStream` should be modified to
include a `finally` block that guarantees the release of the `pout`
resource, regardless of whether an exception is thrown. Here is a suggested
code snippet:

```java
@Override
public void close() throws IOException {
    try {
        super.close();
    } finally {
        if (pout != null) {
            try {
                pout.close();
            } catch (IOException e) {
                // Log the exception if necessary
            }
        }
    }
}
```

This ensures that `pout` is always closed, preventing connection leaks.

**Environment:**

- Apache CXF Version: 4.0.5
- Java Version: OpenJDK 17.0.12
- Operating System: Ubuntu 18.04 AMD 64

**Additional Information:**

Please let me know if you need any further details or if there is any
additional information I can provide to assist in resolving this issue.

Thank you for your attention to this matter.

Best regards,
suxuan

Reply via email to