Недопустимый Unicode / XML с Python SimpleXMLRPCServer?

я получаю следующую ошибку на стороне клиента, когда я передаю недопустимые символы 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 -

почему нет ошибки на стороне сервера? Как я диагностировать, что происходит?

и я получаю следующий traceback на стороне клиента:

/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? Могу ли я очистить эту сторону сервера данных? Как?

3 ответов


во-первых, ваш пример не работает для меня, либо. Я не знаю, что вы спрашиваете о "нормальной обработке на стороне сервера, если вход содержит недопустимый XML" - вы отправляете недопустимый XML-код сервера, и он возвращает вам ошибку... чего ты еще хочешь?

во-вторых, stick a print 'hi there' на tt, вы увидите, что tt не вызывается, когда вы отправляете unichr(0x8). Точный ответ (a 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,

  • какие символы разрешены в строках? Непечатаемые символы? Нулевые символы? Можно ли использовать" строку " для хранения произвольного куска двоичных данных?

любые символы в строке, Кроме

Ok, но это XML, и в соответствии с XML spec:

юридические символы-это вкладка, возврат каретки, подача строки и юридические символы 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 для клиента. Хотя это может звучать хорошо на первый взгляд (?), есть минусы, чтобы рассмотреть:

  • Как вы знаете, что вы можете раздеться? Может быть!--5-->ты сбросишь то, что было бы важно, но клиент отправляет его плохо закодированным и т. д.

  • представьте, что изначально вы поддерживаете запрос с одной конкретной аномалией. Зато пользователи начинают отправлять вам мальформацию второго типа, и вы добавляете исключение для этого тоже (после добавления для первого, почему бы и нет?). Это долгий путь вниз по дороге...

  • лучше позволить вещам потерпеть неудачу как можно скорее, и пусть с ними разбираются там, где это должно быть. На этот раз реализация клиента неверна, поэтому пусть клиент исправит это. Так будет лучше для вас обоих.

Если вы управляете кодом клиента также, тогда вы можете в последнюю очередь прибегнуть к нажатию некоторого XML tidy на нем (см. BeautifulSoup например). Но вместо этого решите проблему, отключив неверный ввод в первую очередь.


Танатос прекрасно объяснил причину вашей проблемы в своем в должности.

Что касается решения этой проблемы: вы можете использовать xmlrpclib.Двоичный to base64-кодировать отправляемые данные. (Для PY3K: файла xmlrpc.клиент.Двоичный)