2011-05-16 24 views
4

tl; dr版本:有没有办法强制JAX-WS的严格模式拒绝无效的base64,因为base64Binary XSD数据类型?我可以在JAX-WS中强制执行base64Binary数据的严格验证吗?


加长版:我有收到这被映射到XSD类型base64Binary二进制数据的Web服务。在测试服务时,我发现JAX-WS在解析Base64字符串时非常宽松。无论输入是多么无效,我都无法让JAX-WS产生错误。

我创建了一个小型测试服务和客户端来说明问题。可以更多或更少的逐字拷贝:

服务接口:

@WebService 
public interface ITest2 { 
    @WebMethod 
    void foo(byte[] bs); 
} 

服务实现和测试:

@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 = { 
     "////==", 
     "///==", 
     "//==", 
     "/==", 
     "/==/==/==", 
     "&lt;&gt;", 
     "=====", 
     "%%%///%%%==%%" 
    }; 

    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 + "<"); 
    } 

} 

这产生/TMP下面的输出/输出(I” m使用Jetty,对控制台记录了相当多的内容,并且不想打扰):

[client] >////==< 
[server] ><null>< 
[client] >///==< 
[server] ><null>< 
[client] >/w==< 
[server] >/w==< 
[client] >/==< 
[server] ><null>< 
[client] >/==/==/==< 
[server] >/////w==< 
[client] >&lt;&gt;< 
[server] ><empty>< 
[client] >=====< 
[server] >/w==< 
[client] >%%%///%%%==%%< 
[server] >//8=< 

所以这是一个完整的混乱。有时我会收到null,有时候会出现空字符串,有时候垃圾被其他垃圾取代。而且每个请求都会产生一个HTTP答复200,所以没有人知道任何地方出了问题。

我知道您可以强制JAXB通过将模式添加到Unmarshaller来验证此情况。由于JAX-WS在内部使用JAXB,我希望有可能为Web服务打开它。有人知道这是可能的吗?

我在Ubuntu上使用Oracle Java 1.6.0_24的默认JAX-WS实现。

回答

1

您可以通过在端点实施Test2上添加com.sun.xml.internal.ws.developer.SchemaValidation annotation来在Metro(JAXWS-RI)中启用架构验证。

这将导致以下形式的SOAP错误:

... 
<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> 
... 

从技术上讲,我认为faultcode应该是S:Client,但我怎么知道。

据我所知,没有实现不可知的方式来做到这一点;所以如果您将代码部署到另一个JAX-WS容器中,则必须使用该容器的机制。

+0

这是一个令人失望的,你需要使用特定于实现的注释,但你能做什么。现在我只需要找出如何在OSGI容器中使用它,但这是另一个问题。我也认为你在包装上打了一个错字,我认为它应该是'com.sun.xml.ws.developer'。噢,我也分享你的担心,这应该是客户端错误... – musiKk 2011-05-17 08:48:46

+0

@musiKk - 谢谢 - 我错过了(IDE导入工具,然后cut'n'paste。)我期望这是重新部署的一部分,命名空间核心API开发人员在使用库时所做的。要在链接中使用命名空间,您可能需要下载RI并将其放入[认可](http://weblogs.java.net/blog/vivekp/archive/2006/12/webservices_in。html)部分类路径来覆盖默认实现。无论如何,如果您正在这样做,您可能需要选择一个不需要注释进行架构验证的实现。 – McDowell 2011-05-17 10:02:32

相关问题