使用Python SimpleXMLRPCServer的无效Unicode / XML?

当我将无效的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,如何获得理智的服务器端处理? 我可以清理这个数据服务器端吗?怎么样?     
已邀请:
首先,你的例子也不适合我。我不知道你问的是“如果输入包含无效的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>
所以,你看到你的错误信息。 现在,根据XML-RPC规范,      字符串中允许哪些字符?不可打印的字符?空字符?可以使用“字符串”来保存任意二进制数据块吗?         字符串中允许使用任何字符,但&lt;和&amp;,编码为&amp; lt;和&amp; amp;字符串可用于编码二进制数据。 好的,但这是XML,并且根据XML规范:   合法字符包括制表符,回车符,换行符以及Unicode和ISO / IEC 10646的合法字符。      Char :: =#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整理(例如,参见BeautifulSoup)。而是首先通过禁用无效输入来解决问题。     
Thanatos在他的帖子中完美地解释了你的问题的原因。 至于解决此问题的解决方案:您可以使用xmlrpclib.Binary对要发送的数据进行base64编码。 (对于PY3K:xmlrpc.client.Binary)     

要回复问题请先登录注册