Can I enforce strict validation of base64Binary data in JAX-WS?
tl;dr version: Is there a way to force a strict mode for JAX-WS that rejects invalid base64 for the base64Binary
XSD data type?
Longer version: I have a web service that receives binary data which gets mapped to the XSD type base64Binary
. While testing the service I found out that JAX-WS is very lenient when it comes to parsing of Base64 strings. No matter how invalid my input was, I could not get JAX-WS to produce an error.
I created a small test service and client that illustrates the problem. It can be copied more or less verbatim:
Service interface:
@WebService
public interface ITest2 {
@WebMethod
void foo(byte[] bs);
}
Service implementation and test:
@WebService(endpointInterface="foo.bar.ITest2")
public class Test2 implements ITest2 {
private static final String requestTemplate = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:bar=\"http://bar.foo/\">" +
"<soapenv:Header/>" +
"<soapenv:Body>" +
"<bar:foo>" +
"<arg0>%s</arg0>" +
"</bar:foo>" +
"</soapenv:Body>" +
"</soapenv:Envelope>";
private static final String[] testVector = {
"////==",
"///==",
"//==",
"/==",
"/==/==/==",
"<>",
"=====",
"%%%///%%%==%%"
};
private static PrintWriter pw;
static {
try {
pw = new PrintWriter("/tmp/output");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
Endpoint e = Endpoint.publish("http://localhost:54321/foo", new Test2());
URL requestUrl = new URL("http://localhost:54321/foo");
for(String testVal : testVector) {
pw.println("[client] >" + testVal + "<");
HttpURLConnection urlc = (HttpURLConnection) requestUrl.openConnection();
urlc.setRequestProperty("Content-Type", "text/xml;charset=UTF-8");
urlc.setDoOutput(true);
OutputStream out = urlc.getOutputStream();
String request = String.format(requestTemplate, testVal);
out.write(request.getBytes());
out.flush();
InputStream in = urlc.getInputStream();
int read = -1;
byte[] buf = new byte[1024];
while((read = in.read(buf)) != -1) {
System.err.print(new String(buf, 0, read));
}
System.err.println();
}
pw.flush();
pw.close();
}
@Override
public void foo(byte[] bs) {
String encoded;
if(bs == null) {
encoded = "<null>";
} else if(bs.length == 0) {
encoded = "<empty>";
} else {
encoded = new String(Base64.encodeBase64(bs));
}
pw.println("[server] >" + encoded + "<");
}
}
This produces the following output 开发者_运维问答in /tmp/output (I'm using Jetty which logs quite a lot to the console and didn't want to bother with that):
[client] >////==<
[server] ><null><
[client] >///==<
[server] ><null><
[client] >/w==<
[server] >/w==<
[client] >/==<
[server] ><null><
[client] >/==/==/==<
[server] >/////w==<
[client] ><><
[server] ><empty><
[client] >=====<
[server] >/w==<
[client] >%%%///%%%==%%<
[server] >//8=<
So it's a complete mess. Sometimes I receive null
, sometimes an empty string and sometimes garbage gets replaced by other garbage. Also every request produces an HTTP reply 200 so nobody knows that anywhere something went wrong.
I know that you can force JAXB to validate this by adding a schema to an Unmarshaller
. Since JAX-WS uses JAXB internally I hope that there is a possibility to turn that on for web services as well. Does anybody know if that's possible and how?
I use the default JAX-WS implementation from Oracle Java 1.6.0_24 on Ubuntu.
You can enable schema validation in Metro (the JAXWS-RI) by adding the com.sun.xml.internal.ws.developer.SchemaValidation
annotation on your endpoint implementation - Test2
.
This causes a SOAP fault of the form:
...
<S:Fault xmlns:ns4="http://www.w3.org/2003/05/soap-envelope">
<faultcode>S:Server</faultcode>
<faultstring>com.sun.istack.internal.XMLStreamException2:
org.xml.sax.SAXParseException: cvc-datatype-valid.1.2.1:
'foo' is not a valid value for 'base64Binary'.</faultstring>
...
Technically, I believe that faultcode should be S:Client
, but what do I know.
To the best of my knowledge there is no implementation agnostic way to do this; so if you deploy the code in another JAX-WS container, you'll have to use the mechanism for that container.
精彩评论