Uploaded image for project: 'CXF'
  1. CXF
  2. CXF-7669

Cxf encodes escape caracters twice in JDK9.0.5 and JDK8_161

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Critical
    • Resolution: Fixed
    • 3.2.2
    • 3.2.3, 3.2.4
    • None
    • None
    • Unknown

    Description

      When our response text contains escape characters then those will be encoded twice. 

      For example when I return "hello > world". Cxf will encode this as "hello &> world"

      hello &> world

       

      Below a test with all the interceptors used in our setup on production: 

      package be.vlaanderen.omgeving.rest.controller.parameter.v1;
      
      import org.apache.cxf.Bus;
      import org.apache.cxf.BusFactory;
      import org.apache.cxf.binding.Binding;
      import org.apache.cxf.binding.BindingFactory;
      import org.apache.cxf.binding.BindingFactoryManager;
      import org.apache.cxf.binding.soap.SoapMessage;
      import org.apache.cxf.binding.soap.saaj.SAAJOutInterceptor;
      import org.apache.cxf.endpoint.Endpoint;
      import org.apache.cxf.endpoint.EndpointException;
      import org.apache.cxf.endpoint.EndpointImpl;
      import org.apache.cxf.jaxb.JAXBDataBinding;
      import org.apache.cxf.message.Exchange;
      import org.apache.cxf.message.ExchangeImpl;
      import org.apache.cxf.message.MessageImpl;
      import org.apache.cxf.phase.PhaseInterceptorChain;
      import org.apache.cxf.service.Service;
      import org.apache.cxf.service.model.BindingOperationInfo;
      import org.apache.cxf.service.model.EndpointInfo;
      import org.apache.cxf.staxutils.StaxUtils;
      import org.apache.cxf.wsdl.interceptors.BareOutInterceptor;
      import org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor;
      import org.apache.cxf.wsdl11.WSDLServiceFactory;
      import org.junit.Test;
      
      import javax.xml.bind.JAXBContext;
      import javax.xml.bind.JAXBException;
      import javax.xml.namespace.QName;
      import javax.xml.stream.XMLInputFactory;
      import javax.xml.stream.XMLOutputFactory;
      import javax.xml.stream.XMLStreamException;
      import javax.xml.stream.XMLStreamReader;
      import javax.xml.stream.XMLStreamWriter;
      import java.io.ByteArrayInputStream;
      import java.io.ByteArrayOutputStream;
      import java.util.List;
      import java.util.TreeSet;
      
      import static java.util.Collections.emptyList;
      import static org.apache.cxf.interceptor.AbstractOutDatabindingInterceptor.OUT_BUFFERING;
      import static org.assertj.core.api.Assertions.assertThat;
      import static org.mockito.BDDMockito.given;
      import static org.mockito.Mockito.mock;
      
      public class CxfIsUnstable {
          CxfFacade cxf = new CxfFacade();
      
          @Test
          public void givenAResponseWithAmpersans_whenMarshallingToXml_theAmpersandAreEncoded_onlyOnce() throws Exception {
              cxf.setupExampleService();
      
              String request = cxf.demarshallRequest("<request>hello &amp; world</request>");
              assertThat(request).isEqualTo("hello & world");
      
              String responseXml = cxf.marshallResponse("hello & world");
              assertThat(responseXml).isEqualTo("<response>hello &amp; world<</response>");
          }
      
          static class CxfFacade {
              private final SAAJOutInterceptor saajOutInterceptor = new SAAJOutInterceptor();
              private final BareOutInterceptor outInterceptor = new BareOutInterceptor();
              private final DocLiteralInInterceptor inInterceptor = new DocLiteralInInterceptor();
              private SoapMessage message;
      
              private List<Object> messageContents;
      
              public String demarshallRequest(String input) throws XMLStreamException {
                  message.setContent(XMLStreamReader.class, XMLInputFactory.newInstance().createXMLStreamReader(new ByteArrayInputStream(input.getBytes())));
                  StaxUtils.skipToStartOfElement(message.getContent(XMLStreamReader.class));
      
                  inInterceptor.handleMessage(message);
      
                  assertThat(message.getContent(Exception.class)).isNull();
                  messageContents = message.getContent(List.class);
                  String requestContent = (String) messageContents.get(0);
      
                  saajOutInterceptor.handleMessage(message);
                  return requestContent;
              }
      
              public String marshallResponse(String responseBody) throws Exception {
                  messageContents.set(0, responseBody);
      
                  ByteArrayOutputStream boas = new ByteArrayOutputStream();
                  XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newInstance();
                  XMLStreamWriter output = xmlOutputFactory.createXMLStreamWriter(boas);
                  message.setContent(XMLStreamWriter.class, output);
                  message.put(OUT_BUFFERING, "true");
                  outInterceptor.handleMessage(message);
                  output.flush();
                  boas.flush();
      
                  return boas.toString();
              }
      
              public void setupExampleService() throws JAXBException, EndpointException {
                  Bus bus = BusFactory.newInstance().createBus();
                  BindingFactoryManager bfm = bus.getExtension(BindingFactoryManager.class);
                  BindingFactory bf = mock(BindingFactory.class);
                  Binding binding = mock(Binding.class);
      
                  given(bf.createBinding(null)).willReturn(binding);
                  given(binding.getInFaultInterceptors()).willReturn(emptyList());
                  given(binding.getOutFaultInterceptors()).willReturn(emptyList());
      
                  bfm.registerBindingFactory("http://schemas.xmlsoap.org/wsdl/soap/", bf);
                  String ns = "http://webservice.example-V1.vlaanderen.be";
      
                  WSDLServiceFactory factory = new WSDLServiceFactory(bus, "classpath:/files/ExampleService.wsdl");
      
                  Service service = factory.create();
                  service.setDataBinding(new JAXBDataBinding(JAXBContext.newInstance()));
      
                  EndpointInfo endpointInfo = service.getEndpointInfo(new QName(ns, "exampleServicePort"));
                  EndpointImpl endpoint = new EndpointImpl(bus, service, endpointInfo);
      
                  BindingOperationInfo operation = endpointInfo.getBinding().getOperation(new QName(ns, "example"));
                  operation.getOperationInfo().getInput().getMessagePartByIndex(0).setTypeClass(String.class);
      
                  message = new SoapMessage(new MessageImpl());
                  Exchange exchange = new ExchangeImpl();
                  message.setExchange(exchange);
                  message.setInterceptorChain(new PhaseInterceptorChain(new TreeSet<>()));
      
                  exchange.put(Service.class, service);
                  exchange.put(Endpoint.class, endpoint);
                  exchange.put(Binding.class, endpoint.getBinding());
              }
          }
      }
      

      Attachments

        1. ExampleService.wsdl
          2 kB
          Mark Czubin

        Activity

          People

            dkulp Daniel Kulp
            czubinm Mark Czubin
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: