spring-projects / spring-ws

Spring Web Services
https://spring.io/projects/spring-ws
Apache License 2.0
317 stars 309 forks source link

Get "Header Folding" error when setting a long soap action (SOAP 1.2) [SWS-1013] #1083

Open gregturn opened 6 years ago

gregturn commented 6 years ago

Johan Hoogenboezem opened SWS-1013 and commented

Hi, we frequently call SAP's SOAP web services and having SOAP actions in wsdls that are longer than 76 characters is not unusual. Example: http://sap.com/xi/FS-SPIM/Global/StandingPaymentInstructionProcessingManageStandingPaymentInstructionIn/CreateStandingPaymentInstructionRequest is a valid SOAP action for SAP Banking Services - for creating a Standing Order. When I use the SoapActionCallback to set the SOAP action, I get org.springframework.ws.client.WebServiceTransportException: Header Folding [400], at org.springframework.ws.client.core.WebServiceTemplate.handleError(WebServiceTemplate.java:699). I'm guessing it is because Spring WS doesn't like it when the toString() method com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ParameterList decides to insert \r\n\t every 76 characters. Steps to reproduce: use WebServiceTemplate to call a SOAP 1.2 service and try to set a long SOAP action - longer than 76 characters.


Affects: 2.4.0

gregturn commented 6 years ago

Greg Turnquist commented

I did read the code for com.sun.xml.internal.messaging.saaj.packaging.mime.internet.ParameterList, and can clearly see that "if len > 76" clause.

I visited the link and it no longer works. Are you able to supply some XML that could be used in a unit test instead of trying to remotely invoke a service that may/may not be there?

gregturn commented 5 years ago

Vineet commented

Hey Greg Turnquist

We are facing the similar problem when a header lenght is more than the certain length.

Our use case

 

Investigation results

Historically, HTTP header field values could be extended over multiple lines by preceding each extra line with at least one space or horizontal tab (obs-fold). This specification deprecates such line folding except within the message/http media type (Section 8.3.1). A sender MUST NOT generate a message that includes line folding (i.e., that has any field-value that contains a match to the obs-fold rule) unless the message is intended for packaging within the message/http media type.

 

I don't have an open webservice that you can make a call to but you can sure use wiremock without a need to implement of soap service.

Please use com.github.tomakehurst:wiremock-jre8-standalone:2.21.0 which uses the jetty server.

 

 

gregturn commented 5 years ago

Vineet commented

Here is this another link onjetty portal where a user raised the same issue

https://bugs.eclipse.org/bugs/show_bug.cgi?id=444222

 

kernalex-exx commented 2 years ago

Is there any workaround to "unfold" a header, like with an interceptor? An external API does not accept messages from a client anymore, since it violates the RFC spec.

gideaofranco commented 2 years ago

Hi guys. Is there any workaround suggested for this?

shayanAtLean commented 2 years ago

Any workarounds at all?

TheFracker commented 10 months ago

We ended in the same situation recently and found the following work around.

// This extends the implementation of the AbstractHttpSenderConnection that would normally be used
// with our own. The reason for doing this, is to give us more control over the connection. The only thing
// we want to do with the connection is to ensure the value of the headers are valid, as some server
// implementations do not like whitespace, or at least not new lines, in the header values. We are
// therefore removing all whitespace before setting the header value, to ensure this is not going to be a problem.
public class MyHttpUrlConnection extends HttpUrlConnection {
    protected NCTSHttpUrlConnection(HttpURLConnection connection) {
        super(connection);
    }

    @Override
    public void addRequestHeader(String name, String value) throws IOException {
        if (name.equals("Content-Type")) {
            value = value.replaceAll("\\s", "");
        }
        super.addRequestHeader(name, value);
    }
}

// This extends the implementation of the AbstractHttpWebServiceMessageSender that would normally be used
// with our own. The reason for doing this, is to give us more control over the connection, as we are creating
// our own version of that as well.
public class MyHttpUrlConnectionMessageSender extends HttpUrlConnectionMessageSender {
    @Override
    public WebServiceConnection createConnection(URI uri) throws IOException {
        URL url = uri.toURL();
        URLConnection connection = url.openConnection();
        if (!(connection instanceof HttpURLConnection)) {
            throw new HttpTransportException("URI [" + uri + "] is not an HTTP URL");
        } else {
            HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
            prepareConnection(httpURLConnection);
            return new NCTSHttpUrlConnection(httpURLConnection);
        }
    }
}

// The SoapClient that you should already have that needs to be updated.
public class SoapClient  {
    private final WebServiceTemplate soapWebServiceTemplate;

    public JAXBElement<ReturnType> queryCustomsCustomer(final QueryType queryType) {
        JAXBElement<QueryType> requestJAXBElement = new ObjectFactory()
                .createQuery(queryType);

        try {
            // Use our own implementation of AbstractHttpWebServiceMessageSender instead of the one provided
            // to ensure that we can set valid value for the request headers.
            soapWebServiceTemplate.setMessageSender(new NCTSHttpUrlConnectionMessageSender());

            return (JAXBElement<ReturnType>) soapWebServiceTemplate
                    .marshalSendAndReceive(requestJAXBElement, new SoapActionCallback(SOAP_ACTION));
        } catch (Exception exception) {
            throw exception;
        }
    }
}

I hope this helps anyone else getting the same error in the future.