1313import org .apache .hc .client5 .http .classic .HttpClient ;
1414import org .apache .hc .core5 .http .ClassicHttpRequest ;
1515import org .apache .hc .core5 .http .ClassicHttpResponse ;
16+ import org .apache .hc .core5 .http .ContentType ;
1617import org .apache .hc .core5 .http .HttpHost ;
1718import org .apache .hc .core5 .http .HttpStatus ;
1819import org .apache .hc .core5 .http .io .HttpClientResponseHandler ;
20+ import org .apache .hc .core5 .http .io .entity .ByteArrayEntity ;
1921import org .apache .hc .core5 .http .io .entity .EntityUtils ;
2022import org .apache .hc .core5 .http .message .BasicClassicHttpResponse ;
2123import org .apache .hc .core5 .http .protocol .HttpContext ;
2729
2830import java .io .IOException ;
2931import java .net .URI ;
30- import java .util .concurrent .TimeUnit ;
3132import java .util .concurrent .locks .Lock ;
3233import java .util .concurrent .locks .ReadWriteLock ;
3334import java .util .concurrent .locks .ReentrantLock ;
@@ -141,7 +142,7 @@ private ClassicHttpResponse handleResponse(
141142 }
142143 }
143144 final ClassicHttpRequest retryRequest = cloneRequestWithNewTT (originalRequest , tt );
144- return this .httpClient .execute (httpHost , retryRequest , context , response -> response );
145+ return this .httpClient .execute (httpHost , retryRequest , context , response -> copyResponseEntity ( response ) );
145146 } else {
146147 tokenRefreshing = true ;
147148 }
@@ -175,7 +176,7 @@ private ClassicHttpResponse handleResponse(
175176 }
176177
177178 final ClassicHttpRequest retryRequest = cloneRequestWithNewTT (originalRequest , tt );
178- ClassicHttpResponse retryResponse = this .httpClient .execute (httpHost , retryRequest , context , response -> response );
179+ ClassicHttpResponse retryResponse = this .httpClient .execute (httpHost , retryRequest , context , response -> copyResponseEntity ( response ) );
179180
180181
181182 if (retryResponse .getCode () == HttpStatus .SC_UNAUTHORIZED &&
@@ -309,12 +310,7 @@ public ClassicHttpResponse execute(HttpHost target, ClassicHttpRequest request,
309310 request .addHeader (TT_HEADER , tt );
310311 }
311312
312- ClassicHttpResponse resp = this .httpClient .execute (
313- target ,
314- request ,
315- context ,
316- response -> response
317- );
313+ ClassicHttpResponse resp = this .httpClient .execute (target , request , context , response -> copyResponseEntity (response ));
318314
319315 if (resp .getCode () == HttpStatus .SC_UNAUTHORIZED ) {
320316 // 👇 Proper handling of InterruptedException
@@ -343,7 +339,7 @@ public ClassicHttpResponse execute(HttpHost target, ClassicHttpRequest request)
343339
344340
345341 public <T > T execute (HttpHost target , ClassicHttpRequest request , HttpContext context ,
346- HttpClientResponseHandler <? extends T > responseHandler ) throws IOException {
342+ HttpClientResponseHandler <? extends T > responseHandler ) throws IOException , org . apache . hc . core5 . http . HttpException {
347343 return httpClient .execute (target , request , context , responseHandler );
348344 }
349345 /**
@@ -354,4 +350,27 @@ private boolean isLogoutRequest(HttpHost target, ClassicHttpRequest request) {
354350 && "DELETE" .equals (request .getMethod ())
355351 && URI .create (request .getRequestUri ()).getPath ().startsWith (LOGIN_URL );
356352 }
353+
354+ /**
355+ * Helper method to copy response entity to avoid stream closure issues.
356+ * Returns a new response with the same properties but a copied entity.
357+ */
358+ private ClassicHttpResponse copyResponseEntity (ClassicHttpResponse response ) throws IOException {
359+ if (response .getEntity () == null ) {
360+ return response ;
361+ }
362+
363+ // Copy the entity content
364+ byte [] content = EntityUtils .toByteArray (response .getEntity ());
365+ ContentType contentType = ContentType .parseLenient (response .getEntity ().getContentType ());
366+
367+ // Create a new response with copied entity
368+ BasicClassicHttpResponse newResponse = new BasicClassicHttpResponse (response .getCode (), response .getReasonPhrase ());
369+ for (Header header : response .getHeaders ()) {
370+ newResponse .addHeader (header );
371+ }
372+ newResponse .setEntity (new ByteArrayEntity (content , contentType ));
373+
374+ return newResponse ;
375+ }
357376}
0 commit comments