source: TI12-security/trunk/python/ndg.security.test/ndg/security/test/Echo/urllib2Client.py @ 1542

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.test/ndg/security/test/Echo/urllib2Client.py@3105
Revision 1542, 7.4 KB checked in by pjkersha, 13 years ago (diff)

Added http proxy handling for ZSI - see Tests/Echo?/urllib2Client.py

Line 
1import urlparse, types
2from ZSI.TCcompound import ComplexType, Struct
3from ZSI import client
4import ZSI
5
6from ZSI import _copyright, _seqtypes, ParsedSoap, SoapWriter, TC, ZSI_SCHEMA_URI,\
7    EvaluateException, FaultFromFaultMessage, _child_elements, _attrs,\
8    _get_idstr, FaultException, WSActionException
9from ZSI.auth import AUTH
10from ZSI.TC import AnyElement, AnyType, String, TypeCode, _get_global_element_declaration,\
11    _get_type_definition
12import base64, httplib, Cookie, time
13from ZSI.address import Address
14
15import urllib, urllib2
16
17
18class URLlib2Binding(client.Binding):
19    def Send(self, url, opname, obj, nsdict={}, soapaction=None, wsaction=None, 
20             endPointReference=None, **kw):
21        '''Send a message.  If url is None, use the value from the
22        constructor (else error). obj is the object (data) to send.
23        Data may be described with a requesttypecode keyword, or a
24        requestclass keyword; default is the class's typecode (if
25        there is one), else Any.
26
27        Optional WS-Address Keywords
28            wsaction -- WS-Address Action, goes in SOAP Header.
29            endPointReference --  set by calling party, must be an
30                EndPointReference type instance.
31
32        '''
33        url = url or self.url
34        # Get the TC for the obj.
35        if kw.has_key('requesttypecode'):
36            tc = kw['requesttypecode']
37        elif kw.has_key('requestclass'):
38            tc = kw['requestclass'].typecode
39        elif type(obj) == types.InstanceType:
40            tc = getattr(obj.__class__, 'typecode')
41            if tc is None: tc = TC.Any(opname, aslist=1)
42        else:
43            tc = TC.Any(opname, aslist=1)
44
45        endPointReference = endPointReference or self.endPointReference
46
47        # Serialize the object.
48        d = {}
49
50        d.update(self.nsdict)
51        d.update(nsdict)
52
53        useWSAddress = self.wsAddressURI is not None
54        sw = SoapWriter(nsdict=d, header=True, outputclass=self.writerclass, 
55                 encodingStyle=kw.get('encodingStyle'),)
56        if kw.has_key('_args'):
57            sw.serialize(kw['_args'], tc)
58        else:
59            sw.serialize(obj, tc)
60
61        # Determine the SOAP auth element.  SOAP:Header element
62        if self.auth_style & AUTH.zsibasic:
63            sw.serialize_header(_AuthHeader(self.auth_user, self.auth_pass),
64                _AuthHeader.typecode)
65
66        # Serialize WS-Address
67        if useWSAddress is True:
68            if self.soapaction and wsaction.strip('\'"') != self.soapaction:
69                raise WSActionException, 'soapAction(%s) and WS-Action(%s) must match'\
70                    %(self.soapaction,wsaction)
71            self.address = Address(url, self.wsAddressURI)
72            self.address.setRequest(endPointReference, wsaction)
73            self.address.serialize(sw)
74
75        # WS-Security Signature Handler
76        if self.sig_handler is not None:
77            self.sig_handler.sign(sw)
78        soapdata = str(sw)
79
80        scheme,netloc,path,nil,nil,nil = urlparse.urlparse(url)
81
82        # self.transport httplib.HTTPConnection derived class set-up removed
83        # from HERE - this now handled by urllib2.urlopen()
84        self.SendSOAPData(soapdata, url, soapaction, **kw)
85
86    def SendSOAPData(self, soapdata, url, soapaction, headers={}, **kw):
87        # Tracing?
88        if self.trace:
89            print >>self.trace, "_" * 33, time.ctime(time.time()), "REQUEST:"
90            print >>self.trace, soapdata
91       
92        # Create a request   
93        req = urllib2.Request(url, data=soapdata)
94
95        req.add_header("Content-length", "%d" % len(soapdata))
96        req.add_header("Content-type", 'text/xml; charset=utf-8')
97       
98        # TODO: equivalent method for cookies using urllib2
99        #self.__addcookies()
100
101        for header,value in headers.items():
102            req.add_header(header, value)
103
104        SOAPActionValue = '"%s"' % (soapaction or self.soapaction)
105        req.add_header("SOAPAction", SOAPActionValue)
106       
107        # client.Binding has Authentication handler set-up code here -
108        # urllib2.HTTPBasicAuthHandler can do this instead?
109
110        for header,value in self.user_headers:
111            req.add_header(header, value)
112       
113        # Check for custom urllib2 handler class
114        if 'urlHandler' in kw:
115            if not isinstance(kw['urlHandler'], urllib2.BaseHandler):
116                raise TypeError, \
117            "URL Handler class %s must be derived from urllib2.BaseHandler" %\
118                                    kw['urlHandler']
119           
120            # Make an opener and make it the default so that urllib2.urlopen
121            # will use it
122            urlOpener = urllib2.build_opener(kw['urlHandler'])
123            urllib2.install_opener(urlOpener)
124           
125        # Send request [and receive response all in one (!) - implications
126        # for client.Binding architecture + functionality??]
127        self.response = urllib2.urlopen(req)
128         
129        # Clear prior receive state.
130        self.data, self.ps = None, None
131       
132       
133    def ReceiveRaw(self, **kw):
134        '''Read a server reply, unconverted to any format and return it.
135        '''
136        if self.data: return self.data
137        trace = self.trace
138       
139        if hasattr(self, 'response') and self.response is not None:
140            self.reply_code, self.reply_msg, self.reply_headers, self.data = \
141                self.response.code, self.response.msg, self.response.headers,\
142                self.response.read()
143           
144            # Reset response for next call
145            self.response = None
146            if trace:
147                print >>trace, "_" * 33, time.ctime(time.time()), "RESPONSE:"
148                for i in (self.reply_code, self.reply_msg,):
149                    print >>trace, str(i)
150                print >>trace, "-------"
151                print >>trace, str(self.reply_headers)
152                print >>trace, self.data
153
154            return self.data
155       
156        # else Send didn't use SendSOAPData...
157        while 1:
158            response = self.h.getresponse()
159            self.reply_code, self.reply_msg, self.reply_headers, self.data = \
160                response.status, response.reason, response.msg, response.read()
161            if trace:
162                print >>trace, "_" * 33, time.ctime(time.time()), "RESPONSE:"
163                for i in (self.reply_code, self.reply_msg,):
164                    print >>trace, str(i)
165                print >>trace, "-------"
166                print >>trace, str(self.reply_headers)
167                print >>trace, self.data
168            saved = None
169            for d in response.msg.getallmatchingheaders('set-cookie'):
170                if d[0] in [ ' ', '\t' ]:
171                    saved += d.strip()
172                else:
173                    if saved: self.cookies.load(saved)
174                    saved = d.strip()
175            if saved: self.cookies.load(saved)
176            if response.status == 401:
177                if not callable(self.http_callbacks.get(response.status,None)):
178                    raise RuntimeError, 'HTTP Digest Authorization Failed'
179                self.http_callbacks[response.status](response)
180                continue
181            if response.status != 100: break
182
183            # The httplib doesn't understand the HTTP continuation header.
184            # Horrible internals hack to patch things up.
185            self.h._HTTPConnection__state = httplib._CS_REQ_SENT
186            self.h._HTTPConnection__response = None
187        return self.data
Note: See TracBrowser for help on using the repository browser.