2010-12-07 59 views
6

我收到的客戶端以下錯誤,當我通過無效XML字符爲Python SimpleXMLRPCServer:無效的Unicode/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? 我可以清理這個數據服務器端嗎?怎麼樣?

回答

3

首先,您的示例對我也不起作用。如果輸入包含無效的XML,我不知道你在問什麼「理智的服務器端處理」 - 你發送服務器無效的XML,並且它給你回錯誤......你還想要什麼?

其次,在tt中粘貼print 'hi there',您會發送tt在發送unichr(0x8)時未被調用。服務器的確切響應(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

  • 被允許在字符串中的字符是什麼?不可打印的字符?空字符?可以使用「字符串」來保存任意大小的二進制數據嗎?

的任何字符被允許在除了<和&一個字符串,它被編碼爲& LT;和& amp ;.一個字符串可以用來編碼二進制數據。

好,但這是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將該錯誤作爲異常呈現給您。你期望什麼行爲?

+0

所以是的,謝謝你的調查。正如我所表明的,我明白這不是有效的XML。我希望能夠捕獲錯誤服務器端(而不是靜默失敗),然後去除輸入中的任何無效字符。我不寫客戶端,如果他們通過我有一個或兩個無效字符的XML,我想爲客戶提供最好的部分結果。 – 2010-12-14 06:30:52

0

您在評論中指出,您希望儘可能多地爲客戶端處理XML。雖然這聽起來可能一見鍾情(?),但有一些缺點值得考慮:

  • 你怎麼知道你能剝離什麼?也許你去掉了本來很重要的東西,但是客戶端發送了嚴重的代碼等。

  • 想象一下,你最初支持一種特定畸形的請求。但是隨後用戶開始向您發送第二種類型的畸形,並且您也爲此添加了異常(一旦您添加了第一個異常,爲什麼不呢?)。這是一條漫長的路...

  • 最好讓事情儘快失敗,並讓它們處理它應該在哪裏。這次客戶端實現是錯誤的,所以讓客戶端修復它。長遠來看,這對你們兩個都更好。

如果你太管理客戶端的代碼,那麼你可能最後的手段來推動一些XML就可以了整潔(見BeautifulSoup爲例)。而是首先通過禁用無效輸入來處理這個問題。