From 1eade1304c35162f925b88f54acd2b02875bfd90 Mon Sep 17 00:00:00 2001 From: Asish Kumar Date: Mon, 25 May 2026 03:11:36 +0530 Subject: [PATCH] ISSUE-466 # Handle unknown-length empty HTTP responses --- .../core/httpclient/BasicHttpClient.java | 21 +++++++++++++-- .../core/httpclient/BasicHttpClientTest.java | 27 ++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/org/jsmart/zerocode/core/httpclient/BasicHttpClient.java b/core/src/main/java/org/jsmart/zerocode/core/httpclient/BasicHttpClient.java index 07b603e37..d83401bc0 100644 --- a/core/src/main/java/org/jsmart/zerocode/core/httpclient/BasicHttpClient.java +++ b/core/src/main/java/org/jsmart/zerocode/core/httpclient/BasicHttpClient.java @@ -1,5 +1,6 @@ package org.jsmart.zerocode.core.httpclient; +import java.io.EOFException; import java.io.IOException; import java.net.URISyntaxException; import java.nio.charset.Charset; @@ -186,14 +187,30 @@ public Response handleResponse(CloseableHttpResponse httpResponse) throws IOExce */ public Response createCharsetResponse(CloseableHttpResponse httpResponse) throws IOException { HttpEntity entity = httpResponse.getEntity(); - Charset charset = ContentType.getOrDefault(httpResponse.getEntity()).getCharset(); + Charset charset = entity == null ? null : ContentType.getOrDefault(entity).getCharset(); charset = (charset == null) ? Charset.defaultCharset() : charset; return Response .status(httpResponse.getStatusLine().getStatusCode()) - .entity(entity != null ? IOUtils.toString(entity.getContent(), charset) : null) + .entity(readResponseEntity(entity, charset)) .build(); } + private String readResponseEntity(HttpEntity entity, Charset charset) throws IOException { + if (entity == null || entity.getContentLength() == 0) { + return null; + } + + try { + return IOUtils.toString(entity.getContent(), charset); + } catch (EOFException ex) { + if (entity.getContentLength() < 0) { + LOGGER.warn("Received EOF while reading response body with unknown content length. Treating body as empty."); + return null; + } + throw ex; + } + } + /** * If(optionally) query parameters was sent as a JSON in the request below, this gets available to this method * for processing them with the url. diff --git a/core/src/test/java/org/jsmart/zerocode/core/httpclient/BasicHttpClientTest.java b/core/src/test/java/org/jsmart/zerocode/core/httpclient/BasicHttpClientTest.java index 60d0deb75..5568db28a 100644 --- a/core/src/test/java/org/jsmart/zerocode/core/httpclient/BasicHttpClientTest.java +++ b/core/src/test/java/org/jsmart/zerocode/core/httpclient/BasicHttpClientTest.java @@ -2,6 +2,7 @@ import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.junit.WireMockRule; +import java.io.EOFException; import java.io.IOException; import java.net.URISyntaxException; import java.util.HashMap; @@ -9,6 +10,9 @@ import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; +import org.apache.http.Header; +import org.apache.http.HttpEntity; +import org.apache.http.StatusLine; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.RequestBuilder; @@ -28,6 +32,8 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNot.not; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class BasicHttpClientTest { private BasicHttpClient basicHttpClient; @@ -216,4 +222,23 @@ public void willMockDefaultResponseEncoding() throws Exception { final String responseBodyActual = (String) basicHttpClient.handleResponse(closeableHttpResponse).getEntity(); assertThat(responseBodyActual, CoreMatchers.is(response)); } -} \ No newline at end of file + + @Test + public void willHandleUnknownLengthEmptyResponse() throws Exception { + CloseableHttpResponse closeableHttpResponse = mock(CloseableHttpResponse.class); + StatusLine statusLine = mock(StatusLine.class); + HttpEntity entity = mock(HttpEntity.class); + + when(closeableHttpResponse.getStatusLine()).thenReturn(statusLine); + when(closeableHttpResponse.getEntity()).thenReturn(entity); + when(closeableHttpResponse.getAllHeaders()).thenReturn(new Header[0]); + when(statusLine.getStatusCode()).thenReturn(401); + when(entity.getContentLength()).thenReturn(-1L); + when(entity.getContent()).thenThrow(new EOFException()); + + javax.ws.rs.core.Response handledResponse = basicHttpClient.handleResponse(closeableHttpResponse); + + assertThat(handledResponse.getStatus(), is(401)); + assertThat(handledResponse.getEntity(), is((Object) null)); + } +}