def __init__(self, header, attrs): for i in header.__dict__.keys(): if i[0] == "_": continue d = getattr(header, i) try: fault = int(attrs[id(d)][(NS.ENV, 'mustUnderstand')]) except Exception: fault = 0 if fault: raise faultType("%s:MustUnderstand" % NS.ENV_T, "Required Header Misunderstood", "%s" % i)
def do_POST(self): global _contexts status = 500 try: if self.server.config.dumpHeadersIn: s = 'Incoming HTTP headers' debugHeader(s) print self.raw_requestline.strip() print "\n".join(map (lambda x: x.strip(), self.headers.headers)) debugFooter(s) data = self.rfile.read(int(self.headers["Content-length"])) if self.server.config.dumpSOAPIn: s = 'Incoming SOAP' debugHeader(s) print data, if data[-1] != '\n': print debugFooter(s) (r, header, body, attrs) = \ parseSOAPRPC(data, header = 1, body = 1, attrs = 1) method = r._name args = r._aslist() kw = r._asdict() if Config.simplify_objects: args = simplify(args) kw = simplify(kw) # Handle mixed named and unnamed arguments by assuming # that all arguments with names of the form "v[0-9]+" # are unnamed and should be passed in numeric order, # other arguments are named and should be passed using # this name. # This is a non-standard exension to the SOAP protocol, # but is supported by Apache AXIS. # It is enabled by default. To disable, set # Config.specialArgs to False. if Config.specialArgs: ordered_args = {} named_args = {} for (k,v) in kw.items(): if k[0]=="v": try: i = int(k[1:]) ordered_args[i] = v except ValueError: named_args[str(k)] = v else: named_args[str(k)] = v # We have to decide namespace precedence # I'm happy with the following scenario # if r._ns is specified use it, if not check for # a path, if it's specified convert it and use it as the # namespace. If both are specified, use r._ns. ns = r._ns if len(self.path) > 1 and not ns: ns = self.path.replace("/", ":") if ns[0] == ":": ns = ns[1:] # authorization method a = None keylist = ordered_args.keys() keylist.sort() # create list in proper order w/o names tmp = map( lambda x: ordered_args[x], keylist) ordered_args = tmp #print '<-> Argument Matching Yielded:' #print '<-> Ordered Arguments:' + str(ordered_args) #print '<-> Named Arguments :' + str(named_args) resp = "" # For fault messages if ns: nsmethod = "%s:%s" % (ns, method) else: nsmethod = method try: # First look for registered functions if self.server.funcmap.has_key(ns) and \ self.server.funcmap[ns].has_key(method): f = self.server.funcmap[ns][method] # look for the authorization method if self.server.config.authMethod != None: authmethod = self.server.config.authMethod if self.server.funcmap.has_key(ns) and \ self.server.funcmap[ns].has_key(authmethod): a = self.server.funcmap[ns][authmethod] else: # Now look at registered objects # Check for nested attributes. This works even if # there are none, because the split will return # [method] f = self.server.objmap[ns] # Look for the authorization method if self.server.config.authMethod != None: authmethod = self.server.config.authMethod if hasattr(f, authmethod): a = getattr(f, authmethod) # then continue looking for the method l = method.split(".") for i in l: f = getattr(f, i) except: info = sys.exc_info() try: resp = buildSOAP(faultType("%s:Client" % NS.ENV_T, "Method Not Found", "%s : %s %s %s" % (nsmethod, info[0], info[1], info[2])), encoding = self.server.encoding, config = self.server.config) finally: del info status = 500 else: try: if header: x = HeaderHandler(header, attrs) fr = 1 # call context book keeping # We're stuffing the method into the soapaction if there # isn't one, someday, we'll set that on the client # and it won't be necessary here # for now we're doing both if "SOAPAction".lower() not in self.headers.keys() or \ self.headers["SOAPAction"] == "\"\"": self.headers["SOAPAction"] = method thread_id = thread.get_ident() _contexts[thread_id] = SOAPContext(header, body, attrs, data, self.connection, self.headers, self.headers["SOAPAction"]) # Do an authorization check if a != None: if not apply(a, (), {"_SOAPContext" : _contexts[thread_id] }): raise faultType("%s:Server" % NS.ENV_T, "Authorization failed.", "%s" % nsmethod) # If it's wrapped, some special action may be needed if isinstance(f, MethodSig): c = None if f.context: # retrieve context object c = _contexts[thread_id] if Config.specialArgs: if c: named_args["_SOAPContext"] = c fr = apply(f, ordered_args, named_args) elif f.keywords: # This is lame, but have to de-unicode # keywords strkw = {} for (k, v) in kw.items(): strkw[str(k)] = v if c: strkw["_SOAPContext"] = c fr = apply(f, (), strkw) elif c: fr = apply(f, args, {'_SOAPContext':c}) else: fr = apply(f, args, {}) else: if Config.specialArgs: fr = apply(f, ordered_args, named_args) else: fr = apply(f, args, {}) if type(fr) == type(self) and \ isinstance(fr, voidType): resp = buildSOAP(kw = {'%sResponse' % method: fr}, encoding = self.server.encoding, config = self.server.config) else: resp = buildSOAP(kw = {'%sResponse' % method: {'Result': fr}}, encoding = self.server.encoding, config = self.server.config) # Clean up _contexts if _contexts.has_key(thread_id): del _contexts[thread_id] except Exception, e: import traceback info = sys.exc_info() try: if self.server.config.dumpFaultInfo: s = 'Method %s exception' % nsmethod debugHeader(s) traceback.print_exception(info[0], info[1], info[2]) debugFooter(s) if isinstance(e, faultType): f = e else: f = faultType("%s:Server" % NS.ENV_T, "Method Failed", "%s" % nsmethod) if self.server.config.returnFaultInfo: f._setDetail("".join(traceback.format_exception( info[0], info[1], info[2]))) elif not hasattr(f, 'detail'): f._setDetail("%s %s" % (info[0], info[1])) finally: del info resp = buildSOAP(f, encoding = self.server.encoding, config = self.server.config) status = 500 else: status = 200
def do_POST(self): global _contexts status = 500 try: if self.server.config.dumpHeadersIn: s = 'Incoming HTTP headers' debugHeader(s) print self.raw_requestline.strip() print "\n".join(map(lambda x: x.strip(), self.headers.headers)) debugFooter(s) data = self.rfile.read(int(self.headers["Content-length"])) if self.server.config.dumpSOAPIn: s = 'Incoming SOAP' debugHeader(s) print data, if data[-1] != '\n': print debugFooter(s) (r, header, body, attrs) = \ parseSOAPRPC(data, header = 1, body = 1, attrs = 1) method = r._name args = r._aslist() kw = r._asdict() if Config.simplify_objects: args = simplify(args) kw = simplify(kw) # Handle mixed named and unnamed arguments by assuming # that all arguments with names of the form "v[0-9]+" # are unnamed and should be passed in numeric order, # other arguments are named and should be passed using # this name. # This is a non-standard exension to the SOAP protocol, # but is supported by Apache AXIS. # It is enabled by default. To disable, set # Config.specialArgs to False. ordered_args = {} named_args = {} if Config.specialArgs: for (k, v) in kw.items(): if k[0] == "v": try: i = int(k[1:]) ordered_args[i] = v except ValueError: named_args[str(k)] = v else: named_args[str(k)] = v # We have to decide namespace precedence # I'm happy with the following scenario # if r._ns is specified use it, if not check for # a path, if it's specified convert it and use it as the # namespace. If both are specified, use r._ns. ns = r._ns if len(self.path) > 1 and not ns: ns = self.path.replace("/", ":") if ns[0] == ":": ns = ns[1:] # authorization method a = None keylist = ordered_args.keys() keylist.sort() # create list in proper order w/o names tmp = map(lambda x: ordered_args[x], keylist) ordered_args = tmp #print '<-> Argument Matching Yielded:' #print '<-> Ordered Arguments:' + str(ordered_args) #print '<-> Named Arguments :' + str(named_args) resp = "" # For fault messages if ns: nsmethod = "%s:%s" % (ns, method) else: nsmethod = method try: # First look for registered functions if self.server.funcmap.has_key(ns) and \ self.server.funcmap[ns].has_key(method): f = self.server.funcmap[ns][method] # look for the authorization method if self.server.config.authMethod != None: authmethod = self.server.config.authMethod if self.server.funcmap.has_key(ns) and \ self.server.funcmap[ns].has_key(authmethod): a = self.server.funcmap[ns][authmethod] else: # Now look at registered objects # Check for nested attributes. This works even if # there are none, because the split will return # [method] f = self.server.objmap[ns] # Look for the authorization method if self.server.config.authMethod != None: authmethod = self.server.config.authMethod if hasattr(f, authmethod): a = getattr(f, authmethod) # then continue looking for the method l = method.split(".") for i in l: f = getattr(f, i) except: info = sys.exc_info() try: resp = buildSOAP(faultType( "%s:Client" % NS.ENV_T, "Method Not Found", "%s : %s %s %s" % (nsmethod, info[0], info[1], info[2])), encoding=self.server.encoding, config=self.server.config) finally: del info status = 500 else: try: if header: x = HeaderHandler(header, attrs) fr = 1 # call context book keeping # We're stuffing the method into the soapaction if there # isn't one, someday, we'll set that on the client # and it won't be necessary here # for now we're doing both if "SOAPAction".lower() not in self.headers.keys() or \ self.headers["SOAPAction"] == "\"\"": self.headers["SOAPAction"] = method thread_id = thread.get_ident() _contexts[thread_id] = SOAPContext( header, body, attrs, data, self.connection, self.headers, self.headers["SOAPAction"]) # Do an authorization check if a != None: if not apply(a, (), {"_SOAPContext": _contexts[thread_id]}): raise faultType("%s:Server" % NS.ENV_T, "Authorization failed.", "%s" % nsmethod) # If it's wrapped, some special action may be needed if isinstance(f, MethodSig): c = None if f.context: # retrieve context object c = _contexts[thread_id] if Config.specialArgs: if c: named_args["_SOAPContext"] = c fr = apply(f, ordered_args, named_args) elif f.keywords: # This is lame, but have to de-unicode # keywords strkw = {} for (k, v) in kw.items(): strkw[str(k)] = v if c: strkw["_SOAPContext"] = c fr = apply(f, (), strkw) elif c: fr = apply(f, args, {'_SOAPContext': c}) else: fr = apply(f, args, {}) else: if Config.specialArgs: fr = apply(f, ordered_args, named_args) else: fr = apply(f, args, {}) if type(fr) == type(self) and \ isinstance(fr, voidType): resp = buildSOAP(kw={'%sResponse' % method: fr}, encoding=self.server.encoding, config=self.server.config) else: resp = buildSOAP( kw={'%sResponse' % method: { 'Result': fr }}, encoding=self.server.encoding, config=self.server.config) # Clean up _contexts if _contexts.has_key(thread_id): del _contexts[thread_id] except Exception, e: import traceback info = sys.exc_info() try: if self.server.config.dumpFaultInfo: s = 'Method %s exception' % nsmethod debugHeader(s) traceback.print_exception(info[0], info[1], info[2]) debugFooter(s) if isinstance(e, faultType): f = e else: f = faultType("%s:Server" % NS.ENV_T, "Method Failed", "%s" % nsmethod) if self.server.config.returnFaultInfo: f._setDetail("".join( traceback.format_exception( info[0], info[1], info[2]))) elif not hasattr(f, 'detail'): f._setDetail("%s %s" % (info[0], info[1])) finally: del info resp = buildSOAP(f, encoding=self.server.encoding, config=self.server.config) status = 500 else: status = 200
def do_POST(self): status = 500 try: if self.server.config.dumpHeadersIn: s = 'Incoming HTTP headers' debugHeader(s) print self.raw_requestline.strip() print "\n".join(map (lambda x: x.strip(), self.headers.headers)) debugFooter(s) data = self.rfile.read(int(self.headers["content-length"])) # data = data.encode('ascii','replace') if self.server.config.dumpSOAPIn: s = 'Incoming SOAP' debugHeader(s) print data, if data[-1] != '\n': print debugFooter(s) (r, header, body, attrs) = \ parseSOAPRPC(data, header = 1, body = 1, attrs = 1) method = r._name args = r._aslist kw = r._asdict # Handle mixed named and unnamed arguments by assuming # that all arguments with names of the form "_[0-9]+" # are unnamed and should be passed in numeric order, # other arguments are named and should be passed using # this name. This is a custom exension to the SOAP # protocol, and is thus disabled by default. To # enable, set Config.specialArgs to a true value. if Config.specialArgs: ordered_args = {} named_args = {} for (k,v) in kw.items(): m = re.match("_([0-9]+)", k) if m is None: named_args[str(k)] = v else: ordered_args[int(m.group(1))] = v keylist = ordered_args.keys() keylist.sort() tmp = map( lambda x: ordered_args[x], keylist) ordered_args = tmp #print '<-> Argument Matching Yielded:' #print '<-> Ordered Arguments:' + str(ordered_args) #print '<-> Named Arguments :' + str(named_args) ns = r._ns resp = "" # For fault messages if ns: nsmethod = "%s:%s" % (ns, method) else: nsmethod = method try: # First look for registered functions if self.server.funcmap.has_key(ns) and \ self.server.funcmap[ns].has_key(method): f = self.server.funcmap[ns][method] else: # Now look at registered objects # Check for nested attributes. This works even if # there are none, because the split will return # [method] f = self.server.objmap[ns] l = method.split(".") for i in l: f = getattr(f, i) except: resp = buildSOAP(faultType("%s:Client" % NS.ENV_T, "No method %s found" % nsmethod, "%s %s" % tuple(sys.exc_info()[0:2])), encoding = self.server.encoding, config = self.server.config) status = 500 else: try: if header: x = HeaderHandler(header, attrs) # If it's wrapped, some special action may be needed if isinstance(f, MethodSig): c = None if f.context: # Build context object c = SOAPContext(header, body, attrs, data, self.connection, self.headers, self.headers["soapaction"]) if Config.specialArgs: if c: named_args["_SOAPContext"] = c fr = apply(f, ordered_args, named_args) elif f.keywords: # This is lame, but have to de-unicode # keywords strkw = {} for (k, v) in kw.items(): strkw[str(k)] = v if c: strkw["_SOAPContext"] = c fr = apply(f, (), strkw) elif c: fr = apply(f, args, {'_SOAPContext':c}) else: fr = apply(f, args, {}) else: if Config.specialArgs: fr = apply(f, ordered_args, named_args) else: fr = apply(f, args, {}) if type(fr) == type(self) and \ isinstance(fr, voidType): resp = buildSOAP(kw = {'%sResponse' % method: fr}, encoding = self.server.encoding, config = self.server.config) else: resp = buildSOAP(kw = {'%sResponse' % method: {'Result': fr}}, encoding = self.server.encoding, config = self.server.config) except Exception, e: import traceback info = sys.exc_info() if self.server.config.dumpFaultInfo: s = 'Method %s exception' % nsmethod debugHeader(s) traceback.print_exception(info[0], info[1], info[2]) debugFooter(s) if isinstance(e, faultType): f = e else: f = faultType("%s:Server" % NS.ENV_T, "Method %s failed." % nsmethod) if self.server.config.returnFaultInfo: f._setDetail("".join(traceback.format_exception( info[0], info[1], info[2]))) elif not hasattr(f, 'detail'): f._setDetail("%s %s" % (info[0], info[1])) resp = buildSOAP(f, encoding = self.server.encoding, config = self.server.config) status = 500 else: status = 200
def endElementNS(self, name, qname): # Workaround two sax bugs if name[0] is None and name[1][0] == ' ': ns, name = None, name[1][1:] else: ns, name = tuple(name) name = fromXMLname(name) # convert to SOAP 1.2 XML name encoding if self._next == "E": raise Error("didn't get SOAP-ENV:Envelope") if self._next in ("HorB", "B"): raise Error("didn't get SOAP-ENV:Body") cur = self.popFrame() attrs = cur.attrs idval = None if (None, 'id') in attrs: idval = attrs[(None, 'id')] if idval in self._ids: raise Error("duplicate id `%s'" % idval) del attrs[(None, 'id')] root = 1 if len(self._stack) == 3: if (NS.ENC, 'root') in attrs: root = int(attrs[(NS.ENC, 'root')]) # Do some preliminary checks. First, if root="0" is present, # the element must have an id. Next, if root="n" is present, # n something other than 0 or 1, raise an exception. if root == 0: if idval is None: raise Error("non-root element must have an id") elif root != 1: raise Error("SOAP-ENC:root must be `0' or `1'") del attrs[(NS.ENC, 'root')] while 1: href = attrs.get((None, 'href')) if href: if href[0] != '#': raise Error("Non-local hrefs are not yet suppported.") if self._data is not None and \ string.join(self._data, "").strip() != '': raise Error("hrefs can't have data") href = href[1:] if href in self._ids: data = self._ids[href] else: data = RefHolder(name, self._stack[-1]) if href in self._refs: self._refs[href].append(data) else: self._refs[href] = [data] del attrs[(None, 'href')] break kind = None if attrs: for i in NS.XSI_L: if (i, 'type') in attrs: kind = attrs[(i, 'type')] del attrs[(i, 'type')] if kind is not None: i = kind.find(':') if i >= 0: try: kind = (self._prem[kind[:i]], kind[i + 1:]) except Exception: kind = (None, kind) else: # XXX What to do here? (None, kind) is just # going to fail in convertType print "Kind with # no NS:", kind kind = (None, kind) null = 0 if attrs: for i in (NS.XSI, NS.XSI2): if (i, 'null') in attrs: null = attrs[(i, 'null')] del attrs[(i, 'null')] if (NS.XSI3, 'nil') in attrs: null = attrs[(NS.XSI3, 'nil')] del attrs[(NS.XSI3, 'nil')] # Check for nil # check for nil='true' if type(null) in (StringType, UnicodeType): if null.lower() == 'true': null = 1 # check for nil=1, but watch out for string values try: null = int(null) except ValueError, e: if not e[0].startswith("invalid literal for int()"): raise e null = 0 if null: if len(cur) \ or (self._data is not None and string.join(self._data, "").strip() != ''): raise Error("nils can't have data") data = None break if len(self._stack) == 2: if (ns, name) == (NS.ENV, "Header"): self.header = data = headerType(attrs=attrs) self._next = "B" break elif (ns, name) == (NS.ENV, "Body"): self.body = data = bodyType(attrs=attrs) self._next = "" break elif len(self._stack) == 3 and self._next is None: if (ns, name) == (NS.ENV, "Fault"): data = faultType() self._next = None # allow followons break # print "\n" # print "data=", self._data # print "kind=", kind # print "cur.kind=", cur.kind # print "cur.rules=", cur.rules # print "\n" if cur.rules is not None: rule = cur.rules if type(rule) in (StringType, UnicodeType): rule = (None, rule) # none flags special handling elif type(rule) == ListType: rule = tuple(rule) # print "kind=",kind # print "rule=",rule # XXX What if rule != kind? if callable(rule): data = rule(string.join(self._data, "")) elif type(rule) == DictType: data = structType(name=(ns, name), attrs=attrs) elif rule[1][:9] == 'arrayType': data = self.convertType(cur.contents, rule, attrs) else: data = self.convertType(string.join(self._data, ""), rule, attrs) break # print "No rules, using kind or cur.kind..." if (kind is None and cur.kind is not None) or \ (kind == (NS.ENC, 'Array')): kind = cur.kind if kind is None: kind = 'ur-type[%d]' % len(cur) else: kind = kind[1] if len(cur.namecounts) == 1: elemsname = cur.names[0] else: elemsname = None data = self.startArray((ns, name), kind, attrs, elemsname) break if len(self._stack) == 3 and kind is None and \ len(cur) == 0 and \ (self._data is None or string.join(self._data, "").strip() == ''): data = structType(name=(ns, name), attrs=attrs) break if len(cur) == 0 and ns != NS.URN: # Nothing's been added to the current frame so it must be a # simple type. # print "cur:", cur # print "ns:", ns # print "attrs:", attrs # print "kind:", kind if kind is None: # If the current item's container is an array, it will # have a kind. If so, get the bit before the first [, # which is the type of the array, therefore the type of # the current item. kind = self._stack[-1].kind if kind is not None: i = kind[1].find('[') if i >= 0: kind = (kind[0], kind[1][:i]) elif ns is not None: kind = (ns, name) if kind is not None: try: data = self.convertType(string.join(self._data, ""), kind, attrs) except UnknownTypeError: data = None else: data = None if data is None: if self._data is None: data = '' else: data = string.join(self._data, "") if len(attrs) == 0: try: data = str(data) except Exception: pass break data = structType(name=(ns, name), attrs=attrs) break
def startElementNS(self, name, qname, attrs): def toStr(name): prefix = name[0] tag = name[1] if prefix in self._prem_r: tag = self._prem_r[name[0]] + ':' + name[1] elif prefix: tag = prefix + ":" + tag return tag # Workaround two sax bugs if name[0] is None and name[1][0] == ' ': name = (None, name[1][1:]) else: name = tuple(name) # First some checking of the layout of the message if self._next == "E": if name[1] != 'Envelope': raise Error("expected `SOAP-ENV:Envelope', " "got `%s'" % toStr(name)) if name[0] != NS.ENV: raise faultType( "%s:VersionMismatch" % NS.ENV_T, "Don't understand version `%s' Envelope" % name[0]) else: self._next = "HorB" elif self._next == "HorB": if name[0] == NS.ENV and name[1] in ("Header", "Body"): self._next = None else: raise Error("expected `SOAP-ENV:Header' or `SOAP-ENV:Body', " "got `%s'" % toStr(name)) elif self._next == "B": if name == (NS.ENV, "Body"): self._next = None else: raise Error("expected `SOAP-ENV:Body', " "got `%s'" % toStr(name)) elif self._next == "": raise Error("expected nothing, " "got `%s'" % toStr(name)) if len(self._stack) == 2: rules = self._rules else: try: rules = self._stack[-1].rules[name[1]] except Exception: rules = None if type(rules) not in (NoneType, DictType): kind = rules else: kind = attrs.get((NS.ENC, 'arrayType')) if kind is not None: del attrs._attrs[(NS.ENC, 'arrayType')] i = kind.find(':') if i >= 0: try: kind = (self._prem[kind[:i]], kind[i + 1:]) except Exception: kind = None else: kind = None self.pushFrame(self.Frame(name[1], kind, attrs._attrs, rules)) self._data = [] # Start accumulating