This is an automated email from the ASF dual-hosted git repository. ffang pushed a commit to branch 3.4.x-fixes in repository https://gitbox.apache.org/repos/asf/cxf.git
commit bb7754baeb5e839061249ba32a48ba5f83bcb5e3 Author: Tim Ward <[email protected]> AuthorDate: Wed Jul 21 14:47:59 2021 +0100 [CXF-8565] Add support for requests with no body to the netty client transport There were several issues with the netty client transport: * Several NPE locations due to setting or removing null headers * No call to connect when there is no OutputStream to write a body * No call to write the request when there is no OutputStream to close Signed-off-by: Tim Ward <[email protected]> (cherry picked from commit fc5b8fd8689815ee3bff284b89ac8d9cb897e83b) --- .../http/netty/client/NettyHttpConduit.java | 62 +++++++++++++++++++--- 1 file changed, 54 insertions(+), 8 deletions(-) diff --git a/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpConduit.java b/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpConduit.java index f5d4e7a..cd358d4 100644 --- a/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpConduit.java +++ b/rt/transports/http-netty/netty-client/src/main/java/org/apache/cxf/transport/http/netty/client/NettyHttpConduit.java @@ -32,6 +32,8 @@ import java.net.URI; import java.net.URISyntaxException; import java.security.Principal; import java.security.cert.Certificate; +import java.util.Arrays; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -78,6 +80,9 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif public static final String MAX_RESPONSE_CONTENT_LENGTH = "org.apache.cxf.transport.http.netty.maxResponseContentLength"; static final Integer DEFAULT_MAX_RESPONSE_CONTENT_LENGTH = 1048576; + private static final Set<String> KNOWN_HTTP_VERBS_WITH_NO_CONTENT = + new HashSet<>(Arrays.asList(new String[]{"GET", "HEAD", "OPTIONS", "TRACE"})); + final NettyHttpConduitFactory factory; private Bootstrap bootstrap; @@ -197,7 +202,10 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif entity.createRequest(out.getOutBuffer()); // TODO need to check how to set the Chunked feature //request.getRequest().setChunked(true); - entity.getRequest().headers().set(Message.CONTENT_TYPE, message.get(Message.CONTENT_TYPE)); + Object contentType = message.get(Message.CONTENT_TYPE); + if (contentType != null) { + entity.getRequest().headers().set(Message.CONTENT_TYPE, contentType); + } return out; } return super.createOutputStream(message, needToCacheRequest, isChunking, chunkThreshold); @@ -314,7 +322,7 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif synchronized (entity) { Channel syncChannel = getChannel(); - ChannelFuture channelFuture = syncChannel.write(entity); + ChannelFuture channelFuture = syncChannel.writeAndFlush(entity); channelFuture.addListener(listener); outputStream.close(); } @@ -328,6 +336,11 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif wrappedStream = cachedStream; } } + + @Override + protected void handleNoOutput() throws IOException { + connect(false); + } protected TLSClientParameters findTLSClientParameters() { TLSClientParameters clientParameters = outMessage.get(TLSClientParameters.class); @@ -378,11 +391,6 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif connFuture.addListener(listener); - if (!output) { - entity.getRequest().headers().remove("Transfer-Encoding"); - entity.getRequest().headers().remove("Content-Type"); - entity.getRequest().headers().remove(null); - } // setup the CxfResponseCallBack CxfResponseCallBack callBack = new CxfResponseCallBack() { @@ -398,6 +406,29 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif }; entity.setCxfResponseCallback(callBack); + if (!output) { + entity.getRequest().headers().remove("Transfer-Encoding"); + entity.getRequest().headers().remove("Content-Type"); + + ChannelFutureListener writeFailureListener = new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (!future.isSuccess()) { + setException(future.cause()); + } + } + }; + + connFuture.addListener(new ChannelFutureListener() { + @Override + public void operationComplete(ChannelFuture future) throws Exception { + if (future.isSuccess()) { + ChannelFuture channelFuture = future.channel().writeAndFlush(entity); + channelFuture.addListener(writeFailureListener); + } + } + }); + } } @Override @@ -434,7 +465,7 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif @Override protected void setProtocolHeaders() throws IOException { Headers h = new Headers(outMessage); - entity.getRequest().headers().set(Message.CONTENT_TYPE, h.determineContentType()); + setContentTypeHeader(h); boolean addHeaders = MessageUtils.getContextualBoolean(outMessage, Headers.ADD_HEADERS_PROPERTY, false); for (Map.Entry<String, List<String>> header : h.headerMap().entrySet()) { @@ -460,6 +491,21 @@ public class NettyHttpConduit extends URLConnectionHTTPConduit implements BusLif } } } + + private void setContentTypeHeader(Headers headers) { + if (outMessage.get(Message.CONTENT_TYPE) == null) { + // if no content type is set then check for a request body + Object requestMethod = outMessage.get(Message.HTTP_REQUEST_METHOD); + boolean emptyRequest = KNOWN_HTTP_VERBS_WITH_NO_CONTENT.contains(requestMethod) + || PropertyUtils.isTrue(outMessage.get(Headers.EMPTY_REQUEST_PROPERTY)); + // If it is not an empty request then add a content type + if (!emptyRequest) { + entity.getRequest().headers().set(Message.CONTENT_TYPE, headers.determineContentType()); + } + } else { + entity.getRequest().headers().set(Message.CONTENT_TYPE, headers.determineContentType()); + } + } @Override protected void setFixedLengthStreamingMode(int i) {
