00001
00002
00003
00004
00005
00006 import time, urlparse, socket
00007 from ZSI import _seqtypes, EvaluateException, WSActionException
00008 from TC import AnyElement, AnyType, TypeCode
00009 from schema import GED, GTD, _has_type_definition
00010 from ZSI.TCcompound import ComplexType
00011 from ZSI.wstools.Namespaces import WSA_LIST
00012
00013
00014 class Address(object):
00015 '''WS-Address
00016
00017 Implemented is dependent on the default "wsdl2py" convention of generating aname,
00018 so the attributes representing element declaration names should be prefixed with
00019 an underscore.
00020 '''
00021 def __init__(self, addressTo=None, wsAddressURI=None, action=None):
00022 self.wsAddressURI = wsAddressURI
00023 self.anonymousURI = None
00024 self._addressTo = addressTo
00025 self._messageID = None
00026 self._action = action
00027 self._endPointReference = None
00028 self._replyTo = None
00029 self._relatesTo = None
00030 self.setUp()
00031
00032 def setUp(self):
00033 '''Look for WS-Address
00034 '''
00035 toplist = filter(lambda wsa: wsa.ADDRESS==self.wsAddressURI, WSA_LIST)
00036 epr = 'EndpointReferenceType'
00037 for WSA in toplist+WSA_LIST:
00038 if (self.wsAddressURI is not None and self.wsAddressURI != WSA.ADDRESS) or \
00039 _has_type_definition(WSA.ADDRESS, epr) is True:
00040 break
00041 else:
00042 raise EvaluateException,\
00043 'enabling wsAddressing requires the inclusion of that namespace'
00044
00045 self.wsAddressURI = WSA.ADDRESS
00046 self.anonymousURI = WSA.ANONYMOUS
00047 self._replyTo = WSA.ANONYMOUS
00048
00049 def _checkAction(self, action, value):
00050 '''WS-Address Action
00051 action -- Action value expecting.
00052 value -- Action value server returned.
00053 '''
00054 if action is None:
00055 raise WSActionException, 'Response missing WSAddress Action'
00056 if not value:
00057 raise WSActionException, 'missing WSAddress Action, expecting %s' %action
00058 if value != action:
00059 raise WSActionException, 'wrong WSAddress Action(%s), expecting %s'%(value,action)
00060
00061 def _checkFrom(self, pyobj):
00062 '''WS-Address From,
00063 XXX currently not checking the hostname, not forwarding messages.
00064 pyobj -- From server returned.
00065 '''
00066 if pyobj is None: return
00067 value = pyobj._Address
00068 if value != self._addressTo:
00069 scheme,netloc,path,query,fragment = urlparse.urlsplit(value)
00070 hostport = netloc.split(':')
00071 schemeF,netlocF,pathF,queryF,fragmentF = urlparse.urlsplit(self._addressTo)
00072 if scheme==schemeF and path==pathF and query==queryF and fragment==fragmentF:
00073 netloc = netloc.split(':') + ['80']
00074 netlocF = netlocF.split(':') + ['80']
00075 if netloc[1]==netlocF[1] and (socket.gethostbyname(netlocF[0]) in
00076 ('127.0.0.1', socket.gethostbyname(netloc[0]))):
00077 return
00078
00079 raise WSActionException, 'wrong WS-Address From(%s), expecting %s'%(value,self._addressTo)
00080
00081 def _checkRelatesTo(self, value):
00082 '''WS-Address From
00083 value -- From server returned.
00084 '''
00085 if value != self._messageID:
00086 raise WSActionException, 'wrong WS-Address RelatesTo(%s), expecting %s'%(value,self._messageID)
00087
00088 def _checkReplyTo(self, value):
00089 '''WS-Address From
00090 value -- From server returned in wsa:To
00091 '''
00092 if value != self._replyTo:
00093 raise WSActionException, 'wrong WS-Address ReplyTo(%s), expecting %s'%(value,self._replyTo)
00094
00095 def setAction(self, action):
00096 self._action = action
00097
00098 def getAction(self):
00099 return self._action
00100
00101 def getRelatesTo(self):
00102 return self._relatesTo
00103
00104 def getMessageID(self):
00105 return self._messageID
00106
00107 def _getWSAddressTypeCodes(self, **kw):
00108 '''kw -- namespaceURI keys with sequence of element names.
00109 '''
00110 typecodes = []
00111 try:
00112 for nsuri,elements in kw.items():
00113 for el in elements:
00114 typecode = GED(nsuri, el)
00115 if typecode is None:
00116 raise WSActionException, 'Missing namespace, import "%s"' %nsuri
00117
00118 typecodes.append(typecode)
00119 else:
00120 pass
00121 except EvaluateException, ex:
00122 raise EvaluateException, \
00123 'To use ws-addressing register typecodes for namespace(%s)' %self.wsAddressURI
00124 return typecodes
00125
00126 def checkResponse(self, ps, action):
00127 '''
00128 ps -- ParsedSoap
00129 action -- ws-action for response
00130 '''
00131 namespaceURI = self.wsAddressURI
00132 d = {namespaceURI:("MessageID","Action","To","From","RelatesTo")}
00133 typecodes = self._getWSAddressTypeCodes(**d)
00134 pyobjs = ps.ParseHeaderElements(typecodes)
00135
00136 got_action = pyobjs.get((namespaceURI,"Action"))
00137 self._checkAction(action, got_action)
00138
00139 From = pyobjs.get((namespaceURI,"From"))
00140 self._checkFrom(From)
00141
00142 RelatesTo = pyobjs.get((namespaceURI,"RelatesTo"))
00143 self._checkRelatesTo(RelatesTo)
00144
00145 To = pyobjs.get((namespaceURI,"To"))
00146 if To: self._checkReplyTo(To)
00147
00148 def setRequest(self, endPointReference, action):
00149 '''Call For Request
00150 '''
00151 self._action = action
00152 self.header_pyobjs = None
00153 pyobjs = []
00154 namespaceURI = self.wsAddressURI
00155 addressTo = self._addressTo
00156 messageID = self._messageID = "uuid:%s" %time.time()
00157
00158
00159
00160 typecode = GED(namespaceURI, "MessageID")
00161 pyobjs.append(typecode.pyclass(messageID))
00162
00163
00164 typecode = GED(namespaceURI, "Action")
00165 pyobjs.append(typecode.pyclass(action))
00166
00167
00168 typecode = GED(namespaceURI, "To")
00169 pyobjs.append(typecode.pyclass(addressTo))
00170
00171
00172 typecode = GED(namespaceURI, "From")
00173 mihFrom = typecode.pyclass()
00174 mihFrom._Address = self.anonymousURI
00175 pyobjs.append(mihFrom)
00176
00177 if endPointReference:
00178 if hasattr(endPointReference, 'typecode') is False:
00179 raise EvaluateException, 'endPointReference must have a typecode attribute'
00180
00181 if isinstance(endPointReference.typecode, \
00182 GTD(namespaceURI ,'EndpointReferenceType')) is False:
00183 raise EvaluateException, 'endPointReference must be of type %s' \
00184 %GTD(namespaceURI ,'EndpointReferenceType')
00185
00186 ReferenceProperties = getattr(endPointReference, '_ReferenceProperties', None)
00187 if ReferenceProperties is not None:
00188 for v in getattr(ReferenceProperties, '_any', ()):
00189 if not hasattr(v,'typecode'):
00190 raise EvaluateException, '<any> element, instance missing typecode attribute'
00191
00192 pyobjs.append(v)
00193
00194 self.header_pyobjs = tuple(pyobjs)
00195
00196 def setResponseFromWSAddress(self, address, localURL):
00197 '''Server-side has to set these fields in response.
00198 address -- Address instance, representing a WS-Address
00199 '''
00200 self.From = localURL
00201 self.header_pyobjs = None
00202 pyobjs = []
00203 namespaceURI = self.wsAddressURI
00204
00205 for nsuri,name,value in (\
00206 (namespaceURI, "Action", self._action),
00207 (namespaceURI, "MessageID","uuid:%s" %time.time()),
00208 (namespaceURI, "RelatesTo", address.getMessageID()),
00209 (namespaceURI, "To", self.anonymousURI),):
00210
00211 typecode = GED(nsuri, name)
00212 pyobjs.append(typecode.pyclass(value))
00213
00214 typecode = GED(nsuri, "From")
00215 pyobj = typecode.pyclass()
00216 pyobj._Address = self.From
00217 pyobjs.append(pyobj)
00218 self.header_pyobjs = tuple(pyobjs)
00219
00220
00221 def serialize(self, sw, **kw):
00222 '''
00223 sw -- SoapWriter instance, add WS-Address header.
00224 '''
00225 for pyobj in self.header_pyobjs:
00226 if hasattr(pyobj, 'typecode') is False:
00227 raise RuntimeError, 'all header pyobjs must have a typecode attribute'
00228
00229 sw.serialize_header(pyobj, **kw)
00230
00231
00232 def parse(self, ps, **kw):
00233 '''
00234 ps -- ParsedSoap instance
00235 '''
00236 namespaceURI = self.wsAddressURI
00237 elements = ("MessageID","Action","To","From","RelatesTo")
00238 d = {namespaceURI:elements}
00239 typecodes = self._getWSAddressTypeCodes(**d)
00240 pyobjs = ps.ParseHeaderElements(typecodes)
00241 self._messageID = pyobjs[(namespaceURI,elements[0])]
00242 self._action = pyobjs[(namespaceURI,elements[1])]
00243 self._addressTo = pyobjs[(namespaceURI,elements[2])]
00244 self._from = pyobjs[(namespaceURI,elements[3])]
00245 self._relatesTo = pyobjs[(namespaceURI,elements[4])]
00246
00247
00248
00249 if __name__ == '__main__': print _copyright