A Python UPnP Media Server
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1025 lines
33 KiB

  1. # SOAPpy modules
  2. from Config import Config
  3. from Types import *
  4. from NS import NS
  5. from Utilities import *
  6. import string
  7. import fpconst
  8. import xml.sax
  9. from wstools.XMLname import fromXMLname
  10. try: from M2Crypto import SSL
  11. except: pass
  12. ident = '$Id: Parser.py,v 1.14 2004/01/31 04:20:05 warnes Exp $'
  13. from version import __version__
  14. ################################################################################
  15. # SOAP Parser
  16. ################################################################################
  17. class RefHolder:
  18. def __init__(self, name, frame):
  19. self.name = name
  20. self.parent = frame
  21. self.pos = len(frame)
  22. self.subpos = frame.namecounts.get(name, 0)
  23. def __repr__(self):
  24. return "<%s %s at %d>" % (self.__class__, self.name, id(self))
  25. def __str__(self):
  26. return "<%s %s at %d>" % (self.__class__, self.name, id(self))
  27. class SOAPParser(xml.sax.handler.ContentHandler):
  28. class Frame:
  29. def __init__(self, name, kind = None, attrs = {}, rules = {}):
  30. self.name = name
  31. self.kind = kind
  32. self.attrs = attrs
  33. self.rules = rules
  34. self.contents = []
  35. self.names = []
  36. self.namecounts = {}
  37. self.subattrs = []
  38. def append(self, name, data, attrs):
  39. self.names.append(name)
  40. self.contents.append(data)
  41. self.subattrs.append(attrs)
  42. if self.namecounts.has_key(name):
  43. self.namecounts[name] += 1
  44. else:
  45. self.namecounts[name] = 1
  46. def _placeItem(self, name, value, pos, subpos = 0, attrs = None):
  47. self.contents[pos] = value
  48. if attrs:
  49. self.attrs.update(attrs)
  50. def __len__(self):
  51. return len(self.contents)
  52. def __repr__(self):
  53. return "<%s %s at %d>" % (self.__class__, self.name, id(self))
  54. def __init__(self, rules = None):
  55. xml.sax.handler.ContentHandler.__init__(self)
  56. self.body = None
  57. self.header = None
  58. self.attrs = {}
  59. self._data = None
  60. self._next = "E" # Keeping state for message validity
  61. self._stack = [self.Frame('SOAP')]
  62. # Make two dictionaries to store the prefix <-> URI mappings, and
  63. # initialize them with the default
  64. self._prem = {NS.XML_T: NS.XML}
  65. self._prem_r = {NS.XML: NS.XML_T}
  66. self._ids = {}
  67. self._refs = {}
  68. self._rules = rules
  69. def startElementNS(self, name, qname, attrs):
  70. # Workaround two sax bugs
  71. if name[0] == None and name[1][0] == ' ':
  72. name = (None, name[1][1:])
  73. else:
  74. name = tuple(name)
  75. # First some checking of the layout of the message
  76. if self._next == "E":
  77. if name[1] != 'Envelope':
  78. raise Error, "expected `SOAP-ENV:Envelope', gto `%s:%s'" % \
  79. (self._prem_r[name[0]], name[1])
  80. if name[0] != NS.ENV:
  81. raise faultType, ("%s:VersionMismatch" % NS.ENV_T,
  82. "Don't understand version `%s' Envelope" % name[0])
  83. else:
  84. self._next = "HorB"
  85. elif self._next == "HorB":
  86. if name[0] == NS.ENV and name[1] in ("Header", "Body"):
  87. self._next = None
  88. else:
  89. raise Error, \
  90. "expected `SOAP-ENV:Header' or `SOAP-ENV:Body', " \
  91. "got `%s'" % self._prem_r[name[0]] + ':' + name[1]
  92. elif self._next == "B":
  93. if name == (NS.ENV, "Body"):
  94. self._next = None
  95. else:
  96. raise Error, "expected `SOAP-ENV:Body', got `%s'" % \
  97. self._prem_r[name[0]] + ':' + name[1]
  98. elif self._next == "":
  99. raise Error, "expected nothing, got `%s'" % \
  100. self._prem_r[name[0]] + ':' + name[1]
  101. if len(self._stack) == 2:
  102. rules = self._rules
  103. else:
  104. try:
  105. rules = self._stack[-1].rules[name[1]]
  106. except:
  107. rules = None
  108. if type(rules) not in (NoneType, DictType):
  109. kind = rules
  110. else:
  111. kind = attrs.get((NS.ENC, 'arrayType'))
  112. if kind != None:
  113. del attrs._attrs[(NS.ENC, 'arrayType')]
  114. i = kind.find(':')
  115. if i >= 0:
  116. kind = (self._prem[kind[:i]], kind[i + 1:])
  117. else:
  118. kind = None
  119. self.pushFrame(self.Frame(name[1], kind, attrs._attrs, rules))
  120. self._data = [] # Start accumulating
  121. def pushFrame(self, frame):
  122. self._stack.append(frame)
  123. def popFrame(self):
  124. return self._stack.pop()
  125. def endElementNS(self, name, qname):
  126. # Workaround two sax bugs
  127. if name[0] == None and name[1][0] == ' ':
  128. ns, name = None, name[1][1:]
  129. else:
  130. ns, name = tuple(name)
  131. name = fromXMLname(name) # convert to SOAP 1.2 XML name encoding
  132. if self._next == "E":
  133. raise Error, "didn't get SOAP-ENV:Envelope"
  134. if self._next in ("HorB", "B"):
  135. raise Error, "didn't get SOAP-ENV:Body"
  136. cur = self.popFrame()
  137. attrs = cur.attrs
  138. idval = None
  139. if attrs.has_key((None, 'id')):
  140. idval = attrs[(None, 'id')]
  141. if self._ids.has_key(idval):
  142. raise Error, "duplicate id `%s'" % idval
  143. del attrs[(None, 'id')]
  144. root = 1
  145. if len(self._stack) == 3:
  146. if attrs.has_key((NS.ENC, 'root')):
  147. root = int(attrs[(NS.ENC, 'root')])
  148. # Do some preliminary checks. First, if root="0" is present,
  149. # the element must have an id. Next, if root="n" is present,
  150. # n something other than 0 or 1, raise an exception.
  151. if root == 0:
  152. if idval == None:
  153. raise Error, "non-root element must have an id"
  154. elif root != 1:
  155. raise Error, "SOAP-ENC:root must be `0' or `1'"
  156. del attrs[(NS.ENC, 'root')]
  157. while 1:
  158. href = attrs.get((None, 'href'))
  159. if href:
  160. if href[0] != '#':
  161. raise Error, "Non-local hrefs are not yet suppported."
  162. if self._data != None and string.join(self._data, "").strip() != '':
  163. raise Error, "hrefs can't have data"
  164. href = href[1:]
  165. if self._ids.has_key(href):
  166. data = self._ids[href]
  167. else:
  168. data = RefHolder(name, self._stack[-1])
  169. if self._refs.has_key(href):
  170. self._refs[href].append(data)
  171. else:
  172. self._refs[href] = [data]
  173. del attrs[(None, 'href')]
  174. break
  175. kind = None
  176. if attrs:
  177. for i in NS.XSI_L:
  178. if attrs.has_key((i, 'type')):
  179. kind = attrs[(i, 'type')]
  180. del attrs[(i, 'type')]
  181. if kind != None:
  182. i = kind.find(':')
  183. if i >= 0:
  184. kind = (self._prem[kind[:i]], kind[i + 1:])
  185. else:
  186. # XXX What to do here? (None, kind) is just going to fail in convertType
  187. kind = (None, kind)
  188. null = 0
  189. if attrs:
  190. for i in (NS.XSI, NS.XSI2):
  191. if attrs.has_key((i, 'null')):
  192. null = attrs[(i, 'null')]
  193. del attrs[(i, 'null')]
  194. if attrs.has_key((NS.XSI3, 'nil')):
  195. null = attrs[(NS.XSI3, 'nil')]
  196. del attrs[(NS.XSI3, 'nil')]
  197. ## Check for nil
  198. # check for nil='true'
  199. if type(null) in (StringType, UnicodeType):
  200. if null.lower() == 'true':
  201. null = 1
  202. # check for nil=1, but watch out for string values
  203. try:
  204. null = int(null)
  205. except ValueError, e:
  206. if not e[0].startswith("invalid literal for int()"):
  207. raise e
  208. null = 0
  209. if null:
  210. if len(cur) or \
  211. (self._data != None and string.join(self._data, "").strip() != ''):
  212. raise Error, "nils can't have data"
  213. data = None
  214. break
  215. if len(self._stack) == 2:
  216. if (ns, name) == (NS.ENV, "Header"):
  217. self.header = data = headerType(attrs = attrs)
  218. self._next = "B"
  219. break
  220. elif (ns, name) == (NS.ENV, "Body"):
  221. self.body = data = bodyType(attrs = attrs)
  222. self._next = ""
  223. break
  224. elif len(self._stack) == 3 and self._next == None:
  225. if (ns, name) == (NS.ENV, "Fault"):
  226. data = faultType()
  227. self._next = ""
  228. break
  229. if cur.rules != None:
  230. rule = cur.rules
  231. if type(rule) in (StringType, UnicodeType):
  232. # XXX Need a namespace here
  233. rule = (None, rule)
  234. elif type(rule) == ListType:
  235. rule = tuple(rule)
  236. # XXX What if rule != kind?
  237. if callable(rule):
  238. data = rule(string.join(self._data, ""))
  239. elif type(rule) == DictType:
  240. data = structType(name = (ns, name), attrs = attrs)
  241. else:
  242. data = self.convertType(string.join(self._data, ""),
  243. rule, attrs)
  244. break
  245. if (kind == None and cur.kind != None) or \
  246. (kind == (NS.ENC, 'Array')):
  247. kind = cur.kind
  248. if kind == None:
  249. kind = 'ur-type[%d]' % len(cur)
  250. else:
  251. kind = kind[1]
  252. if len(cur.namecounts) == 1:
  253. elemsname = cur.names[0]
  254. else:
  255. elemsname = None
  256. data = self.startArray((ns, name), kind, attrs, elemsname)
  257. break
  258. if len(self._stack) == 3 and kind == None and \
  259. len(cur) == 0 and \
  260. (self._data == None or string.join(self._data, "").strip() == ''):
  261. data = structType(name = (ns, name), attrs = attrs)
  262. break
  263. if len(cur) == 0 and ns != NS.URN:
  264. # Nothing's been added to the current frame so it must be a
  265. # simple type.
  266. if kind == None:
  267. # If the current item's container is an array, it will
  268. # have a kind. If so, get the bit before the first [,
  269. # which is the type of the array, therefore the type of
  270. # the current item.
  271. kind = self._stack[-1].kind
  272. if kind != None:
  273. i = kind[1].find('[')
  274. if i >= 0:
  275. kind = (kind[0], kind[1][:i])
  276. elif ns != None:
  277. kind = (ns, name)
  278. if kind != None:
  279. try:
  280. data = self.convertType(string.join(self._data, ""),
  281. kind, attrs)
  282. except UnknownTypeError:
  283. data = None
  284. else:
  285. data = None
  286. if data == None:
  287. if self._data == None:
  288. data = ''
  289. else:
  290. data = string.join(self._data, "")
  291. if len(attrs) == 0:
  292. try: data = str(data)
  293. except: pass
  294. break
  295. data = structType(name = (ns, name), attrs = attrs)
  296. break
  297. if isinstance(data, compoundType):
  298. for i in range(len(cur)):
  299. v = cur.contents[i]
  300. data._addItem(cur.names[i], v, cur.subattrs[i])
  301. if isinstance(v, RefHolder):
  302. v.parent = data
  303. if root:
  304. self._stack[-1].append(name, data, attrs)
  305. if idval != None:
  306. self._ids[idval] = data
  307. if self._refs.has_key(idval):
  308. for i in self._refs[idval]:
  309. i.parent._placeItem(i.name, data, i.pos, i.subpos, attrs)
  310. del self._refs[idval]
  311. self.attrs[id(data)] = attrs
  312. if isinstance(data, anyType):
  313. data._setAttrs(attrs)
  314. self._data = None # Stop accumulating
  315. def endDocument(self):
  316. if len(self._refs) == 1:
  317. raise Error, \
  318. "unresolved reference " + self._refs.keys()[0]
  319. elif len(self._refs) > 1:
  320. raise Error, \
  321. "unresolved references " + ', '.join(self._refs.keys())
  322. def startPrefixMapping(self, prefix, uri):
  323. self._prem[prefix] = uri
  324. self._prem_r[uri] = prefix
  325. def endPrefixMapping(self, prefix):
  326. try:
  327. del self._prem_r[self._prem[prefix]]
  328. del self._prem[prefix]
  329. except:
  330. pass
  331. def characters(self, c):
  332. if self._data != None:
  333. self._data.append(c)
  334. arrayre = '^(?:(?P<ns>[^:]*):)?' \
  335. '(?P<type>[^[]+)' \
  336. '(?:\[(?P<rank>,*)\])?' \
  337. '(?:\[(?P<asize>\d+(?:,\d+)*)?\])$'
  338. def startArray(self, name, kind, attrs, elemsname):
  339. if type(self.arrayre) == StringType:
  340. self.arrayre = re.compile (self.arrayre)
  341. offset = attrs.get((NS.ENC, "offset"))
  342. if offset != None:
  343. del attrs[(NS.ENC, "offset")]
  344. try:
  345. if offset[0] == '[' and offset[-1] == ']':
  346. offset = int(offset[1:-1])
  347. if offset < 0:
  348. raise Exception
  349. else:
  350. raise Exception
  351. except:
  352. raise AttributeError, "invalid Array offset"
  353. else:
  354. offset = 0
  355. try:
  356. m = self.arrayre.search(kind)
  357. if m == None:
  358. raise Exception
  359. t = m.group('type')
  360. if t == 'ur-type':
  361. return arrayType(None, name, attrs, offset, m.group('rank'),
  362. m.group('asize'), elemsname)
  363. elif m.group('ns') != None:
  364. return typedArrayType(None, name,
  365. (self._prem[m.group('ns')], t), attrs, offset,
  366. m.group('rank'), m.group('asize'), elemsname)
  367. else:
  368. return typedArrayType(None, name, (None, t), attrs, offset,
  369. m.group('rank'), m.group('asize'), elemsname)
  370. except:
  371. raise AttributeError, "invalid Array type `%s'" % kind
  372. # Conversion
  373. class DATETIMECONSTS:
  374. SIGNre = '(?P<sign>-?)'
  375. CENTURYre = '(?P<century>\d{2,})'
  376. YEARre = '(?P<year>\d{2})'
  377. MONTHre = '(?P<month>\d{2})'
  378. DAYre = '(?P<day>\d{2})'
  379. HOURre = '(?P<hour>\d{2})'
  380. MINUTEre = '(?P<minute>\d{2})'
  381. SECONDre = '(?P<second>\d{2}(?:\.\d*)?)'
  382. TIMEZONEre = '(?P<zulu>Z)|(?P<tzsign>[-+])(?P<tzhour>\d{2}):' \
  383. '(?P<tzminute>\d{2})'
  384. BOSre = '^\s*'
  385. EOSre = '\s*$'
  386. __allres = {'sign': SIGNre, 'century': CENTURYre, 'year': YEARre,
  387. 'month': MONTHre, 'day': DAYre, 'hour': HOURre,
  388. 'minute': MINUTEre, 'second': SECONDre, 'timezone': TIMEZONEre,
  389. 'b': BOSre, 'e': EOSre}
  390. dateTime = '%(b)s%(sign)s%(century)s%(year)s-%(month)s-%(day)sT' \
  391. '%(hour)s:%(minute)s:%(second)s(%(timezone)s)?%(e)s' % __allres
  392. timeInstant = dateTime
  393. timePeriod = dateTime
  394. time = '%(b)s%(hour)s:%(minute)s:%(second)s(%(timezone)s)?%(e)s' % \
  395. __allres
  396. date = '%(b)s%(sign)s%(century)s%(year)s-%(month)s-%(day)s' \
  397. '(%(timezone)s)?%(e)s' % __allres
  398. century = '%(b)s%(sign)s%(century)s(%(timezone)s)?%(e)s' % __allres
  399. gYearMonth = '%(b)s%(sign)s%(century)s%(year)s-%(month)s' \
  400. '(%(timezone)s)?%(e)s' % __allres
  401. gYear = '%(b)s%(sign)s%(century)s%(year)s(%(timezone)s)?%(e)s' % \
  402. __allres
  403. year = gYear
  404. gMonthDay = '%(b)s--%(month)s-%(day)s(%(timezone)s)?%(e)s' % __allres
  405. recurringDate = gMonthDay
  406. gDay = '%(b)s---%(day)s(%(timezone)s)?%(e)s' % __allres
  407. recurringDay = gDay
  408. gMonth = '%(b)s--%(month)s--(%(timezone)s)?%(e)s' % __allres
  409. month = gMonth
  410. recurringInstant = '%(b)s%(sign)s(%(century)s|-)(%(year)s|-)-' \
  411. '(%(month)s|-)-(%(day)s|-)T' \
  412. '(%(hour)s|-):(%(minute)s|-):(%(second)s|-)' \
  413. '(%(timezone)s)?%(e)s' % __allres
  414. duration = '%(b)s%(sign)sP' \
  415. '((?P<year>\d+)Y)?' \
  416. '((?P<month>\d+)M)?' \
  417. '((?P<day>\d+)D)?' \
  418. '((?P<sep>T)' \
  419. '((?P<hour>\d+)H)?' \
  420. '((?P<minute>\d+)M)?' \
  421. '((?P<second>\d*(?:\.\d*)?)S)?)?%(e)s' % \
  422. __allres
  423. timeDuration = duration
  424. # The extra 31 on the front is:
  425. # - so the tuple is 1-based
  426. # - so months[month-1] is December's days if month is 1
  427. months = (31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)
  428. def convertDateTime(self, value, kind):
  429. def getZoneOffset(d):
  430. zoffs = 0
  431. try:
  432. if d['zulu'] == None:
  433. zoffs = 60 * int(d['tzhour']) + int(d['tzminute'])
  434. if d['tzsign'] != '-':
  435. zoffs = -zoffs
  436. except TypeError:
  437. pass
  438. return zoffs
  439. def applyZoneOffset(months, zoffs, date, minfield, posday = 1):
  440. if zoffs == 0 and (minfield > 4 or 0 <= date[5] < 60):
  441. return date
  442. if minfield > 5: date[5] = 0
  443. if minfield > 4: date[4] = 0
  444. if date[5] < 0:
  445. date[4] += int(date[5]) / 60
  446. date[5] %= 60
  447. date[4] += zoffs
  448. if minfield > 3 or 0 <= date[4] < 60: return date
  449. date[3] += date[4] / 60
  450. date[4] %= 60
  451. if minfield > 2 or 0 <= date[3] < 24: return date
  452. date[2] += date[3] / 24
  453. date[3] %= 24
  454. if minfield > 1:
  455. if posday and date[2] <= 0:
  456. date[2] += 31 # zoffs is at most 99:59, so the
  457. # day will never be less than -3
  458. return date
  459. while 1:
  460. # The date[1] == 3 (instead of == 2) is because we're
  461. # going back a month, so we need to know if the previous
  462. # month is February, so we test if this month is March.
  463. leap = minfield == 0 and date[1] == 3 and \
  464. date[0] % 4 == 0 and \
  465. (date[0] % 100 != 0 or date[0] % 400 == 0)
  466. if 0 < date[2] <= months[date[1]] + leap: break
  467. date[2] += months[date[1] - 1] + leap
  468. date[1] -= 1
  469. if date[1] > 0: break
  470. date[1] = 12
  471. if minfield > 0: break
  472. date[0] -= 1
  473. return date
  474. try:
  475. exp = getattr(self.DATETIMECONSTS, kind)
  476. except AttributeError:
  477. return None
  478. if type(exp) == StringType:
  479. exp = re.compile(exp)
  480. setattr (self.DATETIMECONSTS, kind, exp)
  481. m = exp.search(value)
  482. try:
  483. if m == None:
  484. raise Exception
  485. d = m.groupdict()
  486. f = ('century', 'year', 'month', 'day',
  487. 'hour', 'minute', 'second')
  488. fn = len(f) # Index of first non-None value
  489. r = []
  490. if kind in ('duration', 'timeDuration'):
  491. if d['sep'] != None and d['hour'] == None and \
  492. d['minute'] == None and d['second'] == None:
  493. raise Exception
  494. f = f[1:]
  495. for i in range(len(f)):
  496. s = d[f[i]]
  497. if s != None:
  498. if f[i] == 'second':
  499. s = float(s)
  500. else:
  501. try: s = int(s)
  502. except ValueError: s = long(s)
  503. if i < fn: fn = i
  504. r.append(s)
  505. if fn > len(r): # Any non-Nones?
  506. raise Exception
  507. if d['sign'] == '-':
  508. r[fn] = -r[fn]
  509. return tuple(r)
  510. if kind == 'recurringInstant':
  511. for i in range(len(f)):
  512. s = d[f[i]]
  513. if s == None or s == '-':
  514. if i > fn:
  515. raise Exception
  516. s = None
  517. else:
  518. if i < fn:
  519. fn = i
  520. if f[i] == 'second':
  521. s = float(s)
  522. else:
  523. try:
  524. s = int(s)
  525. except ValueError:
  526. s = long(s)
  527. r.append(s)
  528. s = r.pop(0)
  529. if fn == 0:
  530. r[0] += s * 100
  531. else:
  532. fn -= 1
  533. if fn < len(r) and d['sign'] == '-':
  534. r[fn] = -r[fn]
  535. cleanDate(r, fn)
  536. return tuple(applyZoneOffset(self.DATETIMECONSTS.months,
  537. getZoneOffset(d), r, fn, 0))
  538. r = [0, 0, 1, 1, 0, 0, 0]
  539. for i in range(len(f)):
  540. field = f[i]
  541. s = d.get(field)
  542. if s != None:
  543. if field == 'second':
  544. s = float(s)
  545. else:
  546. try:
  547. s = int(s)
  548. except ValueError:
  549. s = long(s)
  550. if i < fn:
  551. fn = i
  552. r[i] = s
  553. if fn > len(r): # Any non-Nones?
  554. raise Exception
  555. s = r.pop(0)
  556. if fn == 0:
  557. r[0] += s * 100
  558. else:
  559. fn -= 1
  560. if d.get('sign') == '-':
  561. r[fn] = -r[fn]
  562. cleanDate(r, fn)
  563. zoffs = getZoneOffset(d)
  564. if zoffs:
  565. r = applyZoneOffset(self.DATETIMECONSTS.months, zoffs, r, fn)
  566. if kind == 'century':
  567. return r[0] / 100
  568. s = []
  569. for i in range(1, len(f)):
  570. if d.has_key(f[i]):
  571. s.append(r[i - 1])
  572. if len(s) == 1:
  573. return s[0]
  574. return tuple(s)
  575. except Exception, e:
  576. raise Error, "invalid %s value `%s' - %s" % (kind, value, e)
  577. intlimits = \
  578. {
  579. 'nonPositiveInteger': (0, None, 0),
  580. 'non-positive-integer': (0, None, 0),
  581. 'negativeInteger': (0, None, -1),
  582. 'negative-integer': (0, None, -1),
  583. 'long': (1, -9223372036854775808L,
  584. 9223372036854775807L),
  585. 'int': (0, -2147483648L, 2147483647),
  586. 'short': (0, -32768, 32767),
  587. 'byte': (0, -128, 127),
  588. 'nonNegativeInteger': (0, 0, None),
  589. 'non-negative-integer': (0, 0, None),
  590. 'positiveInteger': (0, 1, None),
  591. 'positive-integer': (0, 1, None),
  592. 'unsignedLong': (1, 0, 18446744073709551615L),
  593. 'unsignedInt': (0, 0, 4294967295L),
  594. 'unsignedShort': (0, 0, 65535),
  595. 'unsignedByte': (0, 0, 255),
  596. }
  597. floatlimits = \
  598. {
  599. 'float': (7.0064923216240861E-46, -3.4028234663852886E+38,
  600. 3.4028234663852886E+38),
  601. 'double': (2.4703282292062327E-324, -1.7976931348623158E+308,
  602. 1.7976931348623157E+308),
  603. }
  604. zerofloatre = '[1-9]'
  605. def convertType(self, d, t, attrs, config=Config):
  606. return self.convertToBasicTypes(d, t, attrs, config)
  607. def convertToSOAPpyTypes(self, d, t, attrs, config=Config):
  608. pass
  609. def convertToBasicTypes(self, d, t, attrs, config=Config):
  610. dnn = d or ''
  611. if t[0] in NS.EXSD_L:
  612. if t[1] == "integer":
  613. try:
  614. d = int(d)
  615. if len(attrs):
  616. d = long(d)
  617. except:
  618. d = long(d)
  619. return d
  620. if self.intlimits.has_key (t[1]): # integer types
  621. l = self.intlimits[t[1]]
  622. try: d = int(d)
  623. except: d = long(d)
  624. if l[1] != None and d < l[1]:
  625. raise UnderflowError, "%s too small" % d
  626. if l[2] != None and d > l[2]:
  627. raise OverflowError, "%s too large" % d
  628. if l[0] or len(attrs):
  629. return long(d)
  630. return d
  631. if t[1] == "string":
  632. if len(attrs):
  633. return unicode(dnn)
  634. try:
  635. return str(dnn)
  636. except:
  637. return dnn
  638. if t[1] == "boolean":
  639. d = d.strip().lower()
  640. if d in ('0', 'false'):
  641. return 0
  642. if d in ('1', 'true'):
  643. return 1
  644. raise AttributeError, "invalid boolean value"
  645. if t[1] in ('double','float'):
  646. l = self.floatlimits[t[1]]
  647. s = d.strip().lower()
  648. d = float(s)
  649. if config.strict_range:
  650. if d < l[1]: raise UnderflowError
  651. if d > l[2]: raise OverflowError
  652. else:
  653. # some older SOAP impementations (notably SOAP4J,
  654. # Apache SOAP) return "infinity" instead of "INF"
  655. # so check the first 3 characters for a match.
  656. if s == "nan":
  657. return fpconst.NaN
  658. elif s[0:3] in ("inf", "+inf"):
  659. return fpconst.PosInf
  660. elif s[0:3] == "-inf":
  661. return fpconst.NegInf
  662. if fpconst.isNaN(d):
  663. if s != 'nan':
  664. raise ValueError, "invalid %s: %s" % (t[1], s)
  665. elif fpconst.isNegInf(d):
  666. if s != '-inf':
  667. raise UnderflowError, "%s too small: %s" % (t[1], s)
  668. elif fpconst.isPosInf(d):
  669. if s != 'inf':
  670. raise OverflowError, "%s too large: %s" % (t[1], s)
  671. elif d < 0 and d < l[1]:
  672. raise UnderflowError, "%s too small: %s" % (t[1], s)
  673. elif d > 0 and ( d < l[0] or d > l[2] ):
  674. raise OverflowError, "%s too large: %s" % (t[1], s)
  675. elif d == 0:
  676. if type(self.zerofloatre) == StringType:
  677. self.zerofloatre = re.compile(self.zerofloatre)
  678. if self.zerofloatre.search(s):
  679. raise UnderflowError, "invalid %s: %s" % (t[1], s)
  680. return d
  681. if t[1] in ("dateTime", "date", "timeInstant", "time"):
  682. return self.convertDateTime(d, t[1])
  683. if t[1] == "decimal":
  684. return float(d)
  685. if t[1] in ("language", "QName", "NOTATION", "NMTOKEN", "Name",
  686. "NCName", "ID", "IDREF", "ENTITY"):
  687. return collapseWhiteSpace(d)
  688. if t[1] in ("IDREFS", "ENTITIES", "NMTOKENS"):
  689. d = collapseWhiteSpace(d)
  690. return d.split()
  691. if t[0] in NS.XSD_L:
  692. if t[1] in ("base64", "base64Binary"):
  693. if d:
  694. return base64.decodestring(d)
  695. else:
  696. return ''
  697. if t[1] == "hexBinary":
  698. if d:
  699. return decodeHexString(d)
  700. else:
  701. return
  702. if t[1] == "anyURI":
  703. return urllib.unquote(collapseWhiteSpace(d))
  704. if t[1] in ("normalizedString", "token"):
  705. return collapseWhiteSpace(d)
  706. if t[0] == NS.ENC:
  707. if t[1] == "base64":
  708. if d:
  709. return base64.decodestring(d)
  710. else:
  711. return ''
  712. if t[0] == NS.XSD:
  713. if t[1] == "binary":
  714. try:
  715. e = attrs[(None, 'encoding')]
  716. if d:
  717. if e == 'hex':
  718. return decodeHexString(d)
  719. elif e == 'base64':
  720. return base64.decodestring(d)
  721. else:
  722. return ''
  723. except:
  724. pass
  725. raise Error, "unknown or missing binary encoding"
  726. if t[1] == "uri":
  727. return urllib.unquote(collapseWhiteSpace(d))
  728. if t[1] == "recurringInstant":
  729. return self.convertDateTime(d, t[1])
  730. if t[0] in (NS.XSD2, NS.ENC):
  731. if t[1] == "uriReference":
  732. return urllib.unquote(collapseWhiteSpace(d))
  733. if t[1] == "timePeriod":
  734. return self.convertDateTime(d, t[1])
  735. if t[1] in ("century", "year"):
  736. return self.convertDateTime(d, t[1])
  737. if t[0] in (NS.XSD, NS.XSD2, NS.ENC):
  738. if t[1] == "timeDuration":
  739. return self.convertDateTime(d, t[1])
  740. if t[0] == NS.XSD3:
  741. if t[1] == "anyURI":
  742. return urllib.unquote(collapseWhiteSpace(d))
  743. if t[1] in ("gYearMonth", "gMonthDay"):
  744. return self.convertDateTime(d, t[1])
  745. if t[1] == "gYear":
  746. return self.convertDateTime(d, t[1])
  747. if t[1] == "gMonth":
  748. return self.convertDateTime(d, t[1])
  749. if t[1] == "gDay":
  750. return self.convertDateTime(d, t[1])
  751. if t[1] == "duration":
  752. return self.convertDateTime(d, t[1])
  753. if t[0] in (NS.XSD2, NS.XSD3):
  754. if t[1] == "token":
  755. return collapseWhiteSpace(d)
  756. if t[1] == "recurringDate":
  757. return self.convertDateTime(d, t[1])
  758. if t[1] == "month":
  759. return self.convertDateTime(d, t[1])
  760. if t[1] == "recurringDay":
  761. return self.convertDateTime(d, t[1])
  762. if t[0] == NS.XSD2:
  763. if t[1] == "CDATA":
  764. return collapseWhiteSpace(d)
  765. raise UnknownTypeError, "unknown type `%s'" % (t[0] + ':' + t[1])
  766. ################################################################################
  767. # call to SOAPParser that keeps all of the info
  768. ################################################################################
  769. def _parseSOAP(xml_str, rules = None):
  770. try:
  771. from cStringIO import StringIO
  772. except ImportError:
  773. from StringIO import StringIO
  774. parser = xml.sax.make_parser()
  775. t = SOAPParser(rules = rules)
  776. parser.setContentHandler(t)
  777. e = xml.sax.handler.ErrorHandler()
  778. parser.setErrorHandler(e)
  779. inpsrc = xml.sax.xmlreader.InputSource()
  780. inpsrc.setByteStream(StringIO(xml_str))
  781. # turn on namespace mangeling
  782. parser.setFeature(xml.sax.handler.feature_namespaces,1)
  783. try:
  784. parser.parse(inpsrc)
  785. except xml.sax.SAXParseException, e:
  786. parser._parser = None
  787. raise e
  788. return t
  789. ################################################################################
  790. # SOAPParser's more public interface
  791. ################################################################################
  792. def parseSOAP(xml_str, attrs = 0):
  793. t = _parseSOAP(xml_str)
  794. if attrs:
  795. return t.body, t.attrs
  796. return t.body
  797. def parseSOAPRPC(xml_str, header = 0, body = 0, attrs = 0, rules = None):
  798. #config=Config, unwrap_outer=1):
  799. t = _parseSOAP(xml_str, rules = rules)
  800. p = t.body[0]
  801. # Empty string, for RPC this translates into a void
  802. if type(p) in (type(''), type(u'')) and p in ('', u''):
  803. name = "Response"
  804. for k in t.body.__dict__.keys():
  805. if k[0] != "_":
  806. name = k
  807. p = structType(name)
  808. if header or body or attrs:
  809. ret = (p,)
  810. if header : ret += (t.header,)
  811. if body: ret += (t.body,)
  812. if attrs: ret += (t.attrs,)
  813. return ret
  814. else:
  815. return p