Skip to content

Commit

Permalink
Deal with iLO bugs that cause non-ascii data in XML
Browse files Browse the repository at this point in the history
The data returned by the iLO must be ascii-only, with non-ascii
characters replaced with xml charrefs. Unfortunately, this is not done
consistently. FOr example, the serial number is not escaped, but put in
raw, so if the serialnumber is broken (I've had reports of it being set
to U+0090), the XML is broken. Work around this by detecting non-ascii
data, replacing that data and warning if we do so.
  • Loading branch information
seveas committed Apr 26, 2016
1 parent 312d4f4 commit cc9a0dc
Showing 1 changed file with 21 additions and 4 deletions.
25 changes: 21 additions & 4 deletions hpilo.py
Expand Up @@ -3,6 +3,7 @@

__version__ = "3.7"

import codecs
import os
import errno
import platform
Expand Down Expand Up @@ -111,6 +112,22 @@ def _write(self, file, node, encoding, namespaces):
else:
raise RuntimeError("Don't know how to monkeypatch XML serializer workarounds. Please report a bug at https://github.com/seveas/python-hpilo")

# We handle non-ascii characters in the returned XML by replacing them with XML
# character references. This likely results in bogus data, but avoids crashes.
# The iLO should never do this, but firmware bugs may cause it to do so.
def iloxml_replace(error):
ret = ""
for pos in range(error.start, len(error.object)):
b = error.object[pos]
if not isinstance(b, int):
b = ord(b)
if b < 128:
break
ret += u'?'
warnings.warn("Invalid ascii data found: %s, replaced with %s" % (repr(error.object[error.start:pos]), ret), IloWarning)
return (ret, pos)
codecs.register_error('iloxml_replace', iloxml_replace)

# Which protocol to use
ILO_RAW = 1
ILO_HTTP = 2
Expand Down Expand Up @@ -222,7 +239,7 @@ def __str__(self):

def _debug(self, level, message):
if message.__class__.__name__ == 'bytes':
message = message.decode('latin-1')
message = message.decode('ascii')
if self.debug >= level:
if self._protect_passwords:
message = re.sub(r'PASSWORD=".*?"', 'PASSWORD="********"', message)
Expand Down Expand Up @@ -319,7 +336,7 @@ def _upload_file(self, filename, progress):
try:
while True:
d = sock.read()
data += d.decode('latin-1')
data += d.decode('ascii')
if not d:
break
except socket.sslerror: # Connection closed
Expand Down Expand Up @@ -454,7 +471,7 @@ def _communicate(self, xml, protocol, progress=None, save=True):
data = ''
try:
while True:
d = sock.read().decode('latin-1')
d = sock.read().decode('ascii', 'iloxml_replace')
data += d
if not d:
break
Expand Down Expand Up @@ -1889,7 +1906,7 @@ def xmldata(self, item='all'):
opener = urllib2.build_opener(urllib2.ProxyHandler({}))
req = opener.open(url, None, self.timeout)
data = req.read()
self._debug(1, str(req.headers).rstrip() + "\n\n" + data.decode('utf-8', 'replace'))
self._debug(1, str(req.headers).rstrip() + "\n\n" + data.decode('ascii', 'iloxml_replace'))
if self.save_response:
fd = open(self.save_response, 'a')
fd.write(data)
Expand Down

0 comments on commit cc9a0dc

Please sign in to comment.