-
Bug
-
Resolution: Done
-
Major
-
6.2.6.Final
-
None
When a jax-rs client sends an empty InputStream as a request body; then the apache http client throws:
org.jboss.resteasy.test.client.InputStreamResourceTest.testClientResponse -- Time elapsed: 73.75 s <<< ERROR! jakarta.ws.rs.ProcessingException: RESTEASY004655: Unable to invoke request: org.apache.http.client.ClientProtocolException at org.jboss.resteasy.client.jaxrs.engines.ManualClosingApacheHttpClient43Engine.invoke(ManualClosingApacheHttpClient43Engine.java:361) Caused by: org.apache.http.client.ClientProtocolException at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:187) Caused by: org.apache.http.ProtocolException: Content-Length header already present at org.apache.http.protocol.RequestContent.process(RequestContent.java:97)
The cause is the fix for RESTEASY-204, in org.jboss.resteasy.plugins.providers.InputStreamProvider#writeTo:
try { int c = inputStream.read(); if (c == -1) { httpHeaders.putSingle(HttpHeaderNames.CONTENT_LENGTH, Integer.toString(0)); entityStream.write(new byte[0]); // fix RESTEASY-204 return; } else entityStream.write(c); ProviderHelper.writeTo(inputStream, entityStream); } finally { inputStream.close(); }
This set the content length header in the request context.
However, later on, apache http client expects this header to still be unset when processing the request content at org.apache.http.protocol.RequestContent#process:
if (request instanceof HttpEntityEnclosingRequest) { if (this.overwrite) { request.removeHeaders(HTTP.TRANSFER_ENCODING); request.removeHeaders(HTTP.CONTENT_LEN); } else { if (request.containsHeader(HTTP.TRANSFER_ENCODING)) { throw new ProtocolException("Transfer-encoding header already present"); } if (request.containsHeader(HTTP.CONTENT_LEN)) { throw new ProtocolException("Content-Length header already present"); } }
Reverting org.jboss.resteasy.plugins.providers.InputStreamProvider#writeTo fixes this issue, but I haven't tested if RESTEASY-204 is still impacted yet.
EDIT: EmptyInputStreamMultipartProviderTest seems to pass without the workaround implemented, so with this implementation:
public void writeTo(InputStream inputStream, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException { LogMessages.LOGGER.debugf("Provider : %s, Method : writeTo", getClass().getName()); try { ProviderHelper.writeTo(inputStream, entityStream); } finally { inputStream.close(); } }
I think the use cases are not quite common, but an empty InputStream is as valid as one containing content, and having this ProtocolException thrown is quite misleading.
- is triggering
-
RESTEASY-3562 Regression in writing empty multipart content
- Resolved