diff --git a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java
index d36f1510..98270aa2 100644
--- a/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java
+++ b/core/src/main/java/org/springframework/ws/soap/saaj/SaajSoapMessageFactory.java
@@ -16,8 +16,10 @@
package org.springframework.ws.soap.saaj;
+import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.PushbackInputStream;
import java.util.Iterator;
import java.util.StringTokenizer;
import javax.xml.soap.MessageFactory;
@@ -146,21 +148,9 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB
}
public WebServiceMessage createWebServiceMessage(InputStream inputStream) throws IOException {
- MimeHeaders mimeHeaders = new MimeHeaders();
- if (inputStream instanceof TransportInputStream) {
- TransportInputStream transportInputStream = (TransportInputStream) inputStream;
- for (Iterator headerNames = transportInputStream.getHeaderNames(); headerNames.hasNext();) {
- String headerName = (String) headerNames.next();
- for (Iterator headerValues = transportInputStream.getHeaders(headerName); headerValues.hasNext();) {
- String headerValue = (String) headerValues.next();
- StringTokenizer tokenizer = new StringTokenizer(headerValue, ",");
- while (tokenizer.hasMoreTokens()) {
- mimeHeaders.addHeader(headerName, tokenizer.nextToken().trim());
- }
- }
- }
- }
+ MimeHeaders mimeHeaders = parseMimeHeaders(inputStream);
try {
+ inputStream = checkForUtf8ByteOrderMark(inputStream);
return new SaajSoapMessage(messageFactory.createMessage(mimeHeaders, inputStream));
}
catch (SOAPException ex) {
@@ -182,6 +172,42 @@ public class SaajSoapMessageFactory implements SoapMessageFactory, InitializingB
}
}
+ private MimeHeaders parseMimeHeaders(InputStream inputStream) throws IOException {
+ MimeHeaders mimeHeaders = new MimeHeaders();
+ if (inputStream instanceof TransportInputStream) {
+ TransportInputStream transportInputStream = (TransportInputStream) inputStream;
+ for (Iterator headerNames = transportInputStream.getHeaderNames(); headerNames.hasNext();) {
+ String headerName = (String) headerNames.next();
+ for (Iterator headerValues = transportInputStream.getHeaders(headerName); headerValues.hasNext();) {
+ String headerValue = (String) headerValues.next();
+ StringTokenizer tokenizer = new StringTokenizer(headerValue, ",");
+ while (tokenizer.hasMoreTokens()) {
+ mimeHeaders.addHeader(headerName, tokenizer.nextToken().trim());
+ }
+ }
+ }
+ }
+ return mimeHeaders;
+ }
+
+ /**
+ * Checks for the UTF-8 Byte Order Mark, and removes it if present. The SAAJ RI cannot cope with these BOMs.
+ *
+ * @see SWS-393
+ * @see UTF-8 BOMs
+ */
+ private InputStream checkForUtf8ByteOrderMark(InputStream inputStream) throws IOException {
+ PushbackInputStream pushbackInputStream = new PushbackInputStream(new BufferedInputStream(inputStream), 3);
+ byte[] bom = new byte[3];
+ if (pushbackInputStream.read(bom) != -1) {
+ // check for the UTF-8 BOM, and remove it if there. See SWS-393
+ if (!(bom[0] == (byte) 0xEF && bom[1] == (byte) 0xBB && bom[2] == (byte) 0xBF)) {
+ pushbackInputStream.unread(bom);
+ }
+ }
+ return pushbackInputStream;
+ }
+
public String toString() {
StringBuffer buffer = new StringBuffer("SaajSoapMessageFactory[");
buffer.append(SaajUtils.getSaajVersionString());
diff --git a/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11MessageFactoryTestCase.java b/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11MessageFactoryTestCase.java
index 0c6c67c3..ca1fd971 100644
--- a/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11MessageFactoryTestCase.java
+++ b/core/src/test/java/org/springframework/ws/soap/soap11/AbstractSoap11MessageFactoryTestCase.java
@@ -39,7 +39,7 @@ public abstract class AbstractSoap11MessageFactoryTestCase extends AbstractSoapM
public void testCreateSoapMessageNoAttachment() throws Exception {
InputStream is = AbstractSoap11MessageFactoryTestCase.class.getResourceAsStream("soap11.xml");
- final Properties headers = new Properties();
+ Properties headers = new Properties();
headers.setProperty("Content-Type", "text/xml");
String soapAction = "http://springframework.org/spring-ws/Action";
headers.setProperty("SOAPAction", soapAction);
@@ -112,5 +112,35 @@ public abstract class AbstractSoap11MessageFactoryTestCase extends AbstractSoapM
assertNotNull("No attachment read", attachment);
}
+ public void testCreateSoapMessageUtf8ByteOrderMark() throws Exception {
+ InputStream is = AbstractSoap11MessageFactoryTestCase.class.getResourceAsStream("soap11-utf8-bom.xml");
+ Properties headers = new Properties();
+ headers.setProperty("Content-Type", "text/xml; charset=UTF-8");
+ TransportInputStream tis = new MockTransportInputStream(is, headers);
+
+ SoapMessage message = (SoapMessage) messageFactory.createWebServiceMessage(tis);
+ assertEquals("Invalid soap version", SoapVersion.SOAP_11, message.getVersion());
+ }
+
+ public void testCreateSoapMessageUtf16BigEndianByteOrderMark() throws Exception {
+ InputStream is = AbstractSoap11MessageFactoryTestCase.class.getResourceAsStream("soap11-utf16-be-bom.xml");
+ Properties headers = new Properties();
+ headers.setProperty("Content-Type", "text/xml; charset=UTF-16");
+ TransportInputStream tis = new MockTransportInputStream(is, headers);
+
+ SoapMessage message = (SoapMessage) messageFactory.createWebServiceMessage(tis);
+ assertEquals("Invalid soap version", SoapVersion.SOAP_11, message.getVersion());
+ }
+
+ public void testCreateSoapMessageUtf16LittleEndianByteOrderMark() throws Exception {
+ InputStream is = AbstractSoap11MessageFactoryTestCase.class.getResourceAsStream("soap11-utf16-le-bom.xml");
+ Properties headers = new Properties();
+ headers.setProperty("Content-Type", "text/xml; charset=UTF-16");
+ TransportInputStream tis = new MockTransportInputStream(is, headers);
+
+ SoapMessage message = (SoapMessage) messageFactory.createWebServiceMessage(tis);
+ assertEquals("Invalid soap version", SoapVersion.SOAP_11, message.getVersion());
+ }
+
}
diff --git a/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-utf16-be-bom.xml b/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-utf16-be-bom.xml
new file mode 100644
index 00000000..1517963e
Binary files /dev/null and b/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-utf16-be-bom.xml differ
diff --git a/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-utf16-le-bom.xml b/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-utf16-le-bom.xml
new file mode 100644
index 00000000..454ee138
Binary files /dev/null and b/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-utf16-le-bom.xml differ
diff --git a/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-bom.xml b/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-utf8-bom.xml
similarity index 68%
rename from core/src/test/resources/org/springframework/ws/soap/soap11/soap11-bom.xml
rename to core/src/test/resources/org/springframework/ws/soap/soap11/soap11-utf8-bom.xml
index 1fba6b1f..fa22ad85 100644
--- a/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-bom.xml
+++ b/core/src/test/resources/org/springframework/ws/soap/soap11/soap11-utf8-bom.xml
@@ -1,6 +1,5 @@
-
+
DIS