Support Apache HttpEntity as an entity type when using Apache Connector Signed-off-by: jansupol <jan.supol@oracle.com>
diff --git a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java index 83c15d2..9a7c3c7 100644 --- a/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java +++ b/connectors/apache-connector/src/main/java/org/glassfish/jersey/apache/connector/ApacheConnector.java
@@ -600,6 +600,10 @@ return null; } + if (HttpEntity.class.isInstance(entity)) { + return wrapHttpEntity(clientRequest, (HttpEntity) entity); + } + final AbstractHttpEntity httpEntity = new AbstractHttpEntity() { @Override public boolean isRepeatable() { @@ -639,6 +643,70 @@ } }; + return bufferEntity(httpEntity, bufferingEnabled); + } + + private HttpEntity wrapHttpEntity(final ClientRequest clientRequest, final HttpEntity originalEntity) { + final boolean bufferingEnabled = BufferedHttpEntity.class.isInstance(originalEntity); + + try { + clientRequest.setEntity(originalEntity.getContent()); + } catch (IOException e) { + throw new ProcessingException(LocalizationMessages.ERROR_READING_HTTPENTITY_STREAM(e.getMessage()), e); + } + + final AbstractHttpEntity httpEntity = new AbstractHttpEntity() { + @Override + public boolean isRepeatable() { + return originalEntity.isRepeatable(); + } + + @Override + public long getContentLength() { + return originalEntity.getContentLength(); + } + + @Override + public Header getContentType() { + return originalEntity.getContentType(); + } + + @Override + public Header getContentEncoding() { + return originalEntity.getContentEncoding(); + } + + @Override + public InputStream getContent() throws IOException, IllegalStateException { + return originalEntity.getContent(); + } + + @Override + public void writeTo(final OutputStream outputStream) throws IOException { + clientRequest.setStreamProvider(new OutboundMessageContext.StreamProvider() { + @Override + public OutputStream getOutputStream(final int contentLength) throws IOException { + return outputStream; + } + }); + clientRequest.writeEntity(); + } + + @Override + public boolean isStreaming() { + return originalEntity.isStreaming(); + } + + @Override + public boolean isChunked() { + return originalEntity.isChunked(); + } + }; + + return bufferEntity(httpEntity, bufferingEnabled); + } + + private static HttpEntity bufferEntity(HttpEntity httpEntity, boolean bufferingEnabled) { if (bufferingEnabled) { try { return new BufferedHttpEntity(httpEntity);
diff --git a/connectors/apache-connector/src/main/resources/org/glassfish/jersey/apache/connector/localization.properties b/connectors/apache-connector/src/main/resources/org/glassfish/jersey/apache/connector/localization.properties index 9977d76..f9f9b17 100644 --- a/connectors/apache-connector/src/main/resources/org/glassfish/jersey/apache/connector/localization.properties +++ b/connectors/apache-connector/src/main/resources/org/glassfish/jersey/apache/connector/localization.properties
@@ -15,6 +15,7 @@ # error.buffering.entity=Error buffering the entity. +error.reading.httpentity.stream=Error reading InputStream from HttpEntity: "{0}" failed.to.stop.client=Failed to stop the client. # {0} - property name, e.g. jersey.config.client.httpclient.connectionManager; {1}, {2} - full class name ignoring.value.of.property=Ignoring value of property "{0}" ("{1}") - not instance of "{2}".
diff --git a/connectors/apache-connector/src/test/java/org/glassfish/jersey/apache/connector/HttpEntityTest.java b/connectors/apache-connector/src/test/java/org/glassfish/jersey/apache/connector/HttpEntityTest.java new file mode 100644 index 0000000..f7d2b16 --- /dev/null +++ b/connectors/apache-connector/src/test/java/org/glassfish/jersey/apache/connector/HttpEntityTest.java
@@ -0,0 +1,82 @@ +/* + * Copyright (c) 2020 Oracle and/or its affiliates. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ + +package org.glassfish.jersey.apache.connector; + +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.InputStreamEntity; +import org.glassfish.jersey.client.ClientConfig; +import org.glassfish.jersey.logging.LoggingFeature; +import org.glassfish.jersey.server.ResourceConfig; +import org.glassfish.jersey.test.JerseyTest; +import org.junit.Assert; +import org.junit.Test; + +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import java.io.ByteArrayInputStream; +import java.util.logging.Logger; + +public class HttpEntityTest extends JerseyTest { + + private static final Logger LOGGER = Logger.getLogger(HttpEntityTest.class.getName()); + private static final String ECHO_MESSAGE = "ECHO MESSAGE"; + + @Path("/") + public static class Resource { + @POST + public String echo(String message) { + return message; + } + } + + @Override + protected Application configure() { + return new ResourceConfig(Resource.class) + .register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + } + + @Override + protected void configureClient(ClientConfig config) { + config.register(new LoggingFeature(LOGGER, LoggingFeature.Verbosity.PAYLOAD_ANY)); + config.connectorProvider(new ApacheConnectorProvider()); + } + + @Test + public void testInputStreamEntity() { + ByteArrayInputStream bais = new ByteArrayInputStream(ECHO_MESSAGE.getBytes()); + InputStreamEntity entity = new InputStreamEntity(bais); + + try (Response response = target().request().post(Entity.entity(entity, MediaType.APPLICATION_OCTET_STREAM))) { + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(ECHO_MESSAGE, response.readEntity(String.class)); + } + } + + @Test + public void testByteArrayEntity() { + ByteArrayEntity entity = new ByteArrayEntity(ECHO_MESSAGE.getBytes()); + + try (Response response = target().request().post(Entity.entity(entity, MediaType.APPLICATION_OCTET_STREAM))) { + Assert.assertEquals(200, response.getStatus()); + Assert.assertEquals(ECHO_MESSAGE, response.readEntity(String.class)); + } + } +}