【问题标题】:Non-valid Unicode/XML with Python SimpleXMLRPCServer?使用 Python SimpleXMLRPCServer 的无效 Unicode/XML?
【发布时间】:2011-05-21 09:03:10
【问题描述】:

当我将无效的 XML 字符传递给 Python SimpleXMLRPCServer 时,我在客户端收到以下错误:

Fault: <Fault 1: "<class 'xml.parsers.expat.ExpatError'>:not well-formed (invalid token): line 6, column 15">

为什么?我是否必须更改 SimpleXMLRPCServer 库代码才能解决此问题?

这是我的 XML-RPC 服务器代码:

from SimpleXMLRPCServer import SimpleXMLRPCServer

import logging
logging.basicConfig(level=logging.DEBUG)

def tt(text):
    return "cool"

server = SimpleXMLRPCServer(("0.0.0.0", 9000))
server.register_introspection_functions()
server.register_function(tt)

# Run the server's main loop
server.serve_forever()

这是我的 XML-RPC 客户端代码:

s = xmlrpclib.ServerProxy('http://localhost:9000')
s.tt(unichr(0x8))

在服务器端,我没有收到任何错误或回溯:

liXXXXXX.members.linode.com - - [06/Dec/2010 23:19:40] "POST /RPC2 HTTP/1.0" 200 -

为什么服务器端没有错误?如何诊断发生了什么?

我在客户端得到以下回溯:

/usr/lib/python2.6/xmlrpclib.pyc in __call__(self, *args)
   1197         return _Method(self.__send, "%s.%s" % (self.__name, name))
   1198     def __call__(self, *args):
-> 1199         return self.__send(self.__name, args)
   1200 
   1201 ##


/usr/lib/python2.6/xmlrpclib.pyc in __request(self, methodname, params)
   1487             self.__handler,
   1488             request,
-> 1489             verbose=self.__verbose
   1490             )
   1491 

/usr/lib/python2.6/xmlrpclib.pyc in request(self, host, handler, request_body, verbose)
   1251             sock = None
   1252 
-> 1253         return self._parse_response(h.getfile(), sock)
   1254 
   1255     ##


/usr/lib/python2.6/xmlrpclib.pyc in _parse_response(self, file, sock)
   1390         p.close()
   1391 
-> 1392         return u.close()
   1393 
   1394 ##


/usr/lib/python2.6/xmlrpclib.pyc in close(self)
    836             raise ResponseError()
    837         if self._type == "fault":
--> 838             raise Fault(**self._stack[0])
    839         return tuple(self._stack)
    840 

Fault: <Fault 1: "<class 'xml.parsers.expat.ExpatError'>:not well-formed (invalid token): line 6, column 15">

如果输入包含无效的 XML,我如何获得健全的服务器端处理? 我可以清理这个数据服务器端吗?怎么样?

【问题讨论】:

    标签: python unicode xml-rpc simplexmlrpcserver


    【解决方案1】:

    Thanatos 在他的post 中完美地解释了你的问题的原因。

    关于解决此问题的解决方案:您可以使用xmlrpclib.Binary 对要发送的数据进行base64 编码。 (对于 PY3K:xmlrpc.client.Binary

    【讨论】:

      【解决方案2】:

      您在评论中表示您希望为客户端处理尽可能多的 XML。虽然这听起来不错(?),但也有一些缺点需要考虑:

      • 你怎么知道你可以剥离什么?可能您剥离了一些本来很重要的东西,但客户端发送的内容编码错误,等等。

      • 想象一下,您最初支持具有一种特定畸形的请求。但是随后用户开始向您发送第二种类型的异常,您也为该异常添加了异常(一旦您为第一种添加了异常,为什么不呢?)。这条路还很长……

      • 最好让事情尽快失败,让他们在应该的地方处理。这次客户端实现是错误的,所以让客户端修复它。从长远来看,对你们俩都更好。

      如果您也管理客户端代码,那么您可能会在最后采取一些 XML 整洁的方法(例如,参见 BeautifulSoup)。而是首先通过禁用无效输入来解决问题。

      【讨论】:

        【解决方案3】:

        首先,您的示例也不适用于我。我不知道你在问什么“如果输入包含无效的 XML,则进行合理的服务器端处理”——你向服务器发送了无效的 XML,它给你一个错误......你还想要什么?

        其次,在tt 中粘贴一个print 'hi there',您会看到发送unichr(0x8) 时不会调用tt。服务器的确切响应(200)是:

        HTTP/1.0 200 OK
        Server: BaseHTTP/0.3 Python/2.6.5
        Date: Tue, 07 Dec 2010 07:33:09 GMT
        Content-type: text/xml
        Content-length: 350
        
        <?xml version='1.0'?>
        <methodResponse>
        <fault>
        <value><struct>
        <member>
        <name>faultCode</name>
        <value><int>1</int></value>
        </member>
        <member>
        <name>faultString</name>
        <value><string>&lt;class 'xml.parsers.expat.ExpatError'&gt;:not well-formed (invalid token): line 6, column 15</string></value>
        </member>
        </struct></value>
        </fault>
        </methodResponse>
        

        所以,你看到了你的错误信息。

        现在,根据the XML-RPC spec

        • 字符串中允许使用哪些字符?不可打印的字符?空字符?可以使用“字符串”来保存任意块二进制数据吗?

        字符串中可以有任何字符,除了

        好的,但这是 XML,根据XML spec

        合法字符包括制表符、回车、换行以及 Unicode 和 ISO/IEC 10646 的合法字符。

        字符 ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]

        其中不包括 0x08,并且似乎与 XML-RPC 规范完全矛盾!因此,它会看到您的 XML 解析器正在相当严格地实现 XML 规范(从错误来看,它看起来是 expat)。由于 XML 不允许 0x08,因此您无法发送 0x08,而且确实会返回错误。

        如果我们这样做:

        data = "<?xml version='1.0'?>\n<methodCall>\n<methodName>tt</methodName>\n<params>\n<param>\n<value><string>\x08</string></value>\n</param>\n</params>\n</methodCall>"
        p = xml.parsers.expat.ParserCreate()
        p.Parse(data, True)
        

        ...我们收到您的错误。同样,您将垃圾 XML 传递给服务器,服务器将错误消息传回给您,而中间的 Python 将该错误作为异常呈现给您。你期望什么行为?

        【讨论】:

        • 是的,感谢您的调查。正如我所指出的,我知道这不是有效的 XML。我希望能够在服务器端捕获错误(而不是静默失败),然后去除输入中的任何无效字符。我不写客户端,如果他们向我传递包含一两个无效字符的 XML,我想为客户提供尽可能好的部分结果。
        猜你喜欢
        • 1970-01-01
        • 2010-09-12
        • 2011-08-10
        • 2013-09-10
        • 1970-01-01
        • 1970-01-01
        • 2011-09-05
        • 1970-01-01
        • 2015-09-16
        相关资源
        最近更新 更多