spring-ws icon indicating copy to clipboard operation
spring-ws copied to clipboard

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

Open gregturn opened this issue 7 years ago • 7 comments

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 avatar Feb 16 '18 11:02 gregturn

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 avatar Sep 13 '18 17:09 gregturn

Vineet commented

Hey Greg Turnquist

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

Our use case
  • Using java11, org.springframework.ws:spring-ws-security:3.0.4.RELEASE, com.sun.xml.messaging.saaj:saaj-impl:1.5.0
  • We are using WebServiceTemplate as a client to request the soap service.
  • The soap service version is 1.2 which means soap action is the part of header content-type
  • When the soap action has value is http://www.myowndomainiscustom.se/FTB/getlistitem, the content-type header has value (observer value has no line break)
    • Content-Type: application/soap+xml; charset=utf-8;action=http://www.myowndomainiscustom.se/FTB/getlistitem
  • When the soap action has value is http://www.myowndomainiscustom.se/FTBKPSU/12/getlistitem, the content-type header has value (observer value has a line break)
    • Content-Type: application/soap+xml; charset=utf-8; action=http://www.myowndomainiscustom.se/FTBKPSU/12/getlistitem

 

Investigation results
  • The problem lies with content-type header value contains whitespace
  • According to rfc7230, header value shouldn't contain any whitespace. Please refer to https://tools.ietf.org/html/rfc7230#section-3.2.4

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.

  • Jetty server has implementation that it rejects requests which has header value containing whitespace. Please refer to https://bugs.eclipse.org/bugs/show_bug.cgi?id=483795

 

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 avatar Feb 12 '19 10:02 gregturn

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

 

gregturn avatar Feb 12 '19 11:02 gregturn

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.

kernalex-exx avatar Mar 24 '22 15:03 kernalex-exx

Hi guys. Is there any workaround suggested for this?

gideaofranco avatar Apr 22 '22 15:04 gideaofranco

Any workarounds at all?

shayanAtLean avatar Sep 01 '22 18:09 shayanAtLean

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.

TheFracker avatar Nov 22 '23 15:11 TheFracker