HTTP response 411: Length Required when communicating with

Viewed 1430

I am trying to send a soap request and keep getting HTTP response 411 error because of larger size of soap request. In most of the cases soap request length is more that 8k.

ERROR MESSAGE

2020-02-27 08:26:09,618 WARNING [100] [org.apache.cxf.phase.PhaseInterceptorChain] (my-thread-1) Interceptor for {http://example.com}CreationService#{http://cxf.apache.org/jaxws/dispatch}Invoke has thrown exception, unwinding now: org.apache.cxf.interceptor.Fault: Could not send Message.
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:64) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:514) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:423) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:324) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:277) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.invokeWrapped(ClientImpl.java:312) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:327) [cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
    at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:246) [cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
    ...
Caused by: org.apache.cxf.transport.http.HTTPException: HTTP response '411: Length Required' when communicating with http://192.100.110.17:8504/example/services/CreationREQ
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.doProcessResponseCode(HTTPConduit.java:1600) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1607) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1551) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1348) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:56) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:216) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:651) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62) [cxf-core-3.1.6.jar:3.1.6]
    ... 84 more

2020-02-27 08:26:09,621 ERROR [100] [org.jboss.as.ejb3.invocation] (my-thread-1) JBAS014134: EJB invocation failed on DaoFacade component for method public abstract void com.example.addon.core.dao.facade.DaoFacadeInterface.invokeExternalService(com.example.db.models.Synchronizable) throws com.example.addon.addon.SOAPException: javax.ejb.EJBException: javax.xml.ws.WebServiceException: Could not send Message.
    ...
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_79]
    at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_79]
Caused by: javax.xml.ws.WebServiceException: Could not send Message.
    at org.apache.cxf.jaxws.DispatchImpl.mapException(DispatchImpl.java:272) [cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
    at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:334) [cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
    at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:246) [cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
    ...
    at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:288) [jboss-invocation-1.1.2.Final-redhat-1.jar:1.1.2.Final-redhat-1]
    at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInOurTx(CMTTxInterceptor.java:280) [jboss-as-ejb3-7.5.0.Final-redhat-21.jar:7.5.0.Final-redhat-21]
    ... 40 more
Caused by: org.apache.cxf.transport.http.HTTPException: HTTP response '411: Length Required' when communicating with http://192.100.110.17:8504/example/services/CreationREQ
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.doProcessResponseCode(HTTPConduit.java:1600) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponseInternal(HTTPConduit.java:1607) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.handleResponse(HTTPConduit.java:1551) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.http.HTTPConduit$WrappedOutputStream.close(HTTPConduit.java:1348) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.io.CacheAndWriteOutputStream.postClose(CacheAndWriteOutputStream.java:56) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.io.CachedOutputStream.close(CachedOutputStream.java:216) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.AbstractConduit.close(AbstractConduit.java:56) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.transport.http.HTTPConduit.close(HTTPConduit.java:651) [cxf-rt-transports-http-3.1.6.jar:3.1.6]
    at org.apache.cxf.interceptor.MessageSenderInterceptor$MessageSenderEndingInterceptor.handleMessage(MessageSenderInterceptor.java:62) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.doInvoke(ClientImpl.java:514) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:423) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:324) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.invoke(ClientImpl.java:277) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.endpoint.ClientImpl.invokeWrapped(ClientImpl.java:312) [cxf-core-3.1.6.jar:3.1.6]
    at org.apache.cxf.jaxws.DispatchImpl.invoke(DispatchImpl.java:327) [cxf-rt-frontend-jaxws-3.1.6.jar:3.1.6]
    ... 77 more

Here is my soap client code looks like:

import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.GeneralSecurityException;

import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.stream.StreamSource;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Dispatch;
import javax.xml.ws.Service;
import javax.xml.ws.soap.SOAPBinding;

import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.DispatchImpl;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.apache.log4j.Logger;

public class SOAPClient {

    private static final String CXF_RESPONSE_CODE = "org.apache.cxf.message.Message.RESPONSE_CODE";
    private static final String JAXRS_RESPONSE_CODE = "javax.xml.ws.http.response.code";
    private static Logger logger = Logger.getLogger(SOAPClient.class);

    /**
     * Nested class only accessible after {@link SOAPClient#builder()} method call
     * <p>
     * It provides a Fluent Interface to make the client code more readable.
     */
    public static class Builder {
        private String endpoint;
        private String namespace;
        private String serviceName;
        private Boolean basicAuthentication = FALSE;
        private String username;
        private String password;
        private Long connectionTimeout;
        private Long receiveTimeout;
        private String portName;
        private String soapAction;
        private StreamSource soapRequest;
        private OutputStream soapResponse;
        private Dispatch<SOAPMessage> dispatch;
        private SOAPMessage requestSOAPMessage;
        private SOAPMessage returnedSOAPMessage;

        public Builder endpoint(String endpoint) {
            this.endpoint = endpoint;
            return this;
        }

        public Builder namespace(String namespace) {
            this.namespace = namespace;
            return this;
        }

        public Builder serviceName(String serviceName) {
            this.serviceName = serviceName;
            return this;
        }

        public Builder portName(String portName) {
            this.portName = portName;
            return this;
        }

        public Builder soapAction(String soapAction) {
            this.soapAction = soapAction;
            return this;
        }

        public Builder basicAuthentication(Boolean basicAuthentication) {
            this.basicAuthentication = basicAuthentication;
            return this;
        }

        public Builder username(String username) {
            this.username = username;
            return this;
        }

        public Builder password(String password) {
            this.password = password;
            return this;
        }

        public Builder connectionTimeout(Long connectionTimeout) {
            this.connectionTimeout = connectionTimeout;
            return this;
        }

        public Builder receiveTimeout(Long receiveTimeout) {
            this.receiveTimeout = receiveTimeout;
            return this;
        }       

        public Builder soapRequest(File soapRequest) throws IOException {
            if (soapRequest == null)
                throw new IllegalStateException("soapRequest not set");
            InputStream is = Files.newInputStream(soapRequest.toPath());
            this.soapRequest = new StreamSource(is, StandardCharsets.UTF_8.name());
            return this;
        }

        public Builder soapRequest(InputStream soapRequest) {
            this.soapRequest = new StreamSource(soapRequest);
            return this;
        }

        public Builder soapRequest(Reader soapRequest) {
            this.soapRequest = new StreamSource(soapRequest);
            return this;
        }

        public int execute(File soapResponse) throws IOException, SOAPException, GeneralSecurityException {
            if (soapResponse == null)
                throw new IllegalStateException("soapResponse not set");
            this.soapResponse = Files.newOutputStream(soapResponse.toPath());
            return execute();
        }

        public int execute(OutputStream soapResponse) throws IOException, SOAPException, GeneralSecurityException {
            if (soapResponse == null)
                throw new IllegalStateException("soapResponse not set");
            this.soapResponse = soapResponse;
            return execute();
        }

        private int execute() throws SOAPException, IOException, GeneralSecurityException {
            createDispatch();
            addBasicAuthentication();
            addSoapAction();
            addTimeouts();
            setSOAPMessage();
            returnedSOAPMessage = dispatch.invoke(requestSOAPMessage);
            returnedSOAPMessage.writeTo(soapResponse);
            return Integer.parseInt(getResponseCode());
        }

        private String getResponseCode() {
            Object responseCode = dispatch.getResponseContext().get(CXF_RESPONSE_CODE);
            if (responseCode != null)
                return responseCode.toString();
            else {
                responseCode = dispatch.getResponseContext().get(JAXRS_RESPONSE_CODE);
                if (responseCode != null)
                    return responseCode.toString();
                else
                    return "-1";
            }
        }

        private void createDispatch() {
            if (endpoint == null || endpoint.isEmpty())
                throw new IllegalStateException("endpoint not set");

            QName serviceQName = new QName(namespace, serviceName);
            logger.debug("Creating the Service QName, " + serviceQName);

            // Add a separate name space for method if required
            QName portQName = new QName(namespace, portName);

            logger.debug("Creating port QName, " + portQName);

            Service serviceRef = Service.create(serviceQName);
            serviceRef.addPort(portQName, SOAPBinding.SOAP11HTTP_BINDING, endpoint);

            dispatch = serviceRef.createDispatch(portQName, SOAPMessage.class, Service.Mode.MESSAGE);
        }

        private void addBasicAuthentication() throws GeneralSecurityException {
            if (basicAuthentication)
                setBasicAuthentication();
        }

        private void setBasicAuthentication() throws GeneralSecurityException {
            if (username == null || username.isEmpty())
                throw new IllegalStateException("username not set with BasicAuthentication");

            if (password == null || password.isEmpty())
                throw new IllegalStateException("password not set with BasicAuthentication");

            dispatch.getRequestContext().put(BindingProvider.USERNAME_PROPERTY, username);
            dispatch.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, JcodificaLib.decrypt(password));
        }

        private void addSoapAction() {
            if (soapAction != null)
                setSoapAction();
        }

        private void setSoapAction() {
            logger.debug("SoapAction:" + soapAction);
            dispatch.getRequestContext().put(BindingProvider.SOAPACTION_USE_PROPERTY, TRUE);
            dispatch.getRequestContext().put(BindingProvider.SOAPACTION_URI_PROPERTY, soapAction);
        }

        private void addTimeouts() {
            if (receiveTimeout != null) {
                setReceiveTimeout();
            }

            if (connectionTimeout != null) {
                setConnectionTimeout();
            }
        }

        private void setConnectionTimeout() {
            logger.debug("connectionTimeout:" + connectionTimeout);
            dispatch.getRequestContext().put("javax.xml.ws.client.connectionTimeout", connectionTimeout);
        }

        private void setReceiveTimeout() {
            logger.debug("receiveTimeout:" + receiveTimeout);
            dispatch.getRequestContext().put("javax.xml.ws.client.receiveTimeout", receiveTimeout);
        }

        private void setSOAPMessage() throws SOAPException {
            MessageFactory messageFactory = MessageFactory.newInstance();
            requestSOAPMessage = messageFactory.createMessage();
            SOAPPart soapPart = requestSOAPMessage.getSOAPPart();
            soapPart.setContent(soapRequest);
        }   

    }

    public static SOAPClient.Builder builder() {
        return new SOAPClient.Builder();
    }
}

I tried fixing the issue by enabling chunking and setting chunking threshold to 8192 as below, but I am getting the same error message:

private void setHttpClientPolicies() {
        final Client client = ((DispatchImpl<SOAPMessage>) dispatch).getClient();
        final HTTPConduit httpConduit = (HTTPConduit) client.getConduit();
        final HTTPClientPolicy httpClientPolicy = httpConduit.getClient();
        httpConduit.setClient(httpClientPolicy);

        httpClientPolicy.setAllowChunking(TRUE);
        httpClientPolicy.setChunkingThreshold(8192);
}

Any clue how to fix the issue ?

4 Answers

I suspect you may try to set the content length in the header. IE, the size of of your request using Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing. I would guess that if you correctly identified the size of the request the server might not choke on it. Worth a try.

Content-Length: SIZE OF REQUIRED DATA IN BYTES \n\n

It may require accessing some lower level portions of your request framework. References: https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Length

I would try the contrary of what you did. I suspect the server is not supporting chunking. Therefore, you should configure CXF to disable (and not enable!) chunking, like the doc suggests it:

If you are getting strange errors (generally not soap faults, but other HTTP type errors) when trying to interact with a service, try turning off chunking to see if that helps.

SOAP request by org.apache.http.client.HttpClient(4.1) You have to specify data length. req_xml.length() // SOAP request(xml) read-in File req_xml = new File("test/xml/request.xml");

 // SOAP request send
 HttpPost post = new HttpPost("http://localhost:8080/test/api/");
 post.setEntity(new InputStreamEntity(new FileInputStream(req_xml), **req_xml.length()**));
 post.setHeader("Content-type", "text/xml; charset=UTF-8");
 post.setHeader("SOAPAction", "");
 HttpClient client = new DefaultHttpClient();
 HttpResponse response = client.execute(post);

 // SOAP response(xml) get
 String res_xml = EntityUtils.toString(response.getEntity());

Check that working code just supply xml and change web path. You have whole builder code where I don't understand are you doing post/get.By Default everything is http get.

createDispatch();
            addBasicAuthentication();
            addSoapAction();
            addTimeouts();
            setSOAPMessage();
            returnedSOAPMessage = dispatch.invoke(requestSOAPMessage);
            returnedSOAPMessage.writeTo(soapResponse);
            return Integer.parseInt(getResponseCode());

Answering my own question.

The answers posted here are pointing correctly that by disabling chunking or adding Content-Length the issue can be resolved. But my challenge was that I wasn't able to disable the chunking as it can be seen in my question description.

So I was trying to add Content-Length to http header and as you can see I'm not using any Apache library to write my soap client code so it was difficult to figure out how to add the Content-Length to the HTTP Header. Lastly I found a way to do so. The code snippet can be found below:

private void setSOAPMessage() throws SOAPException {
        MessageFactory messageFactory = MessageFactory.newInstance();
        requestSOAPMessage = messageFactory.createMessage();
        SOAPPart soapPart = requestSOAPMessage.getSOAPPart();
        soapPart.setContent(soapRequest);

        // Added Content-Length to HTTP Header
        Map<String, List<String>> requestHeaderMap = new HashMap<String, List<String>>();
        requestHeaderMap.put("Content-Length", Collections.singletonList(String.valueOf(soapRequestXMLSize)));
        dispatch.getRequestContext().put(MessageContext.HTTP_REQUEST_HEADERS, requestHeaderMap);
}

Here the soapRequestXMLSize was calculated from the actual soap request xml which is stored as String in my case.

Integer soapRequestSize = soapRequestXML.length();
Related