This file is indexed.

/usr/share/pyshared/soaplib/soap.py is in python-soaplib 0.8.1-2build1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
from soaplib.xml import create_xml_element, create_xml_subelement
from soaplib.xml import NamespaceLookup, ElementTree
from soaplib.serializers.primitive import Fault
from soaplib.serializers.binary import Attachment

try:
    #python 2.5
    from email.mime.multipart import MIMEMultipart
    from email.mime.application import MIMEApplication
    from email.encoders import encode_7or8bit
except:
    #python 2.4
    from email.MIMENonMultipart import MIMENonMultipart
    from email.MIMEMultipart import MIMEMultipart
    from email.Encoders import encode_7or8bit

from email import message_from_string


from base64 import b64encode
from StringIO import StringIO

class Message(object):
    def __init__(self,name,params,ns=None,typ=None):
        self.name = name
        self.params = params
        if typ == None:
            typ = name
        self.typ = typ
        self.ns = ns
        
    def to_xml(self,*data):
        if len(self.params):
            if len(data) != len(self.params):
                raise Exception("Parameter number mismatch expected [%s] got [%s]"%(len(self.params),len(data)))
  
        nsmap = NamespaceLookup(self.ns)
        element = create_xml_element(self.name, nsmap, self.ns)

        for i in range(0,len(self.params)):
            name, serializer = self.params[i]
            d = data[i]
            e = serializer.to_xml(d, name, nsmap)
            if type(e) in (list,tuple):
                elist = e
                for e in elist:
                    element.append(e)
            elif e == None:
                pass
            else:
                element.append(e)    
      
        ElementTree.cleanup_namespaces(element)    
        return element
        
    def from_xml(self,element):
        results = []        
        try:
            children = element.getchildren()
        except:
            return []
        
        def findall(name):
            # inner method for finding child node
            nodes = []
            for c in children:
                if c.tag.split('}')[-1] == name:
                    nodes.append(c)
            return nodes
                
        for name, serializer in self.params:
            childnodes = findall(name)
            if len(childnodes) == 0:
                results.append(None)
            else:
                results.append(serializer.from_xml(*childnodes))
        return results
        
    def add_to_schema(self,schemaDict, nsmap):
        complexType = create_xml_element(nsmap.get('xs') + 'complexType', nsmap)
        complexType.set('name',self.typ)
        
        sequence = create_xml_subelement(complexType, nsmap.get('xs') + 'sequence')
        if self.params:
            for name,serializer in self.params:
                e = create_xml_subelement(sequence, nsmap.get('xs') + 'element')
                e.set('name',name)
                e.set('type',
                    "%s:%s" % (serializer.get_namespace_id(), serializer.get_datatype()))
                
        element = create_xml_element(nsmap.get('xs') + 'element', nsmap)
        element.set('name',self.typ)
        element.set('type','%s:%s' % ('tns',self.typ))
        
        schemaDict[self.typ] = complexType
        schemaDict[self.typ+'Element'] = element
        
class MethodDescriptor:
    '''
    This class represents the method signature of a soap method, and is returned
    by the soapdocument, or soapmethod decorators.  
    '''

    def __init__(self, name, soapAction, inMessage, outMessage, doc, isCallback=False, isAsync=False, mtom=False):
        self.inMessage = inMessage
        self.outMessage = outMessage
        self.soapAction = soapAction
        self.name = name
        self.isCallback = isCallback
        self.isAsync = isAsync
        self.doc = doc
        self.mtom = mtom

def from_soap(xml_string):
    '''
    Parses the xml string into the header and payload
    '''
    root, xmlids = ElementTree.XMLID(xml_string)    
    if xmlids:
        resolve_hrefs(root,xmlids)
    body = None
    header = None

    # find the body and header elements
    for e in root.getchildren():
        name = e.tag.split('}')[-1].lower()
        if name == 'body':
            body = e
        elif name == 'header':
            header = e
    payload = None
    if len(body.getchildren()):
        payload = body.getchildren()[0]

    return payload, header

def resolve_hrefs(element,xmlids):
    for e in element:
        if e.get('id'): 
            continue # don't need to resolve this element    
        elif e.get('href'):
            resolved_element = xmlids[e.get('href').replace('#','')]
            if resolved_element is None: continue
            resolve_hrefs(resolved_element,xmlids)

            [e.set(k,v) for k,v in resolved_element.items()]              # copies the attributes
            [e.append(child) for child in resolved_element.getchildren()] # copies the children

        else:
            resolve_hrefs(e,xmlids)
    return element


def make_soap_envelope(message, tns='', header_elements=None):
    '''
    This method takes the results from a soap method call, and wraps them
    in the appropriate soap envelope with any specified headers

    @param the message of the soap envelope, either an element or list of elements
    @param any header elements to be included in the soap response
    @returns the envelope element
    '''
    nsmap = NamespaceLookup(tns)
    
    envelope = create_xml_element(nsmap.get('SOAP-ENV') + 'Envelope', nsmap, tns)

    if header_elements:
        headerElement = create_xml_subelement(envelope, nsmap.get('SOAP-ENV') + 'Header')
        
        for h in header_elements:
            headerElement.append(h)
   
    body = create_xml_subelement(envelope, nsmap.get('SOAP-ENV') + 'Body')

    if type(message) == list:
        for m in message:
            body.append(m)
    elif message != None:
        body.append(message)

    return envelope

def join_attachment(id, envelope, payload, prefix=True):
    '''
    Helper function for swa_to_soap.
    
    Places the data from an attachment back into a SOAP message, replacing
    its xop:Include element or href.
    
    @param  id          content-id or content-location of attachment
    @param  prefix      Set this to true if id is content-id or false if 
                        it is content-location.  It prefixes a "cid:" to
                        the href value.
    @param  envelope    soap envelope string to be operated on
    @param  payload     attachment data
    @return             tuple of length 2 with the new message and the
                        number of replacements made
    '''
    
    # grab the XML element of the message in the SOAP body
    soapmsg = StringIO(envelope)
    soaptree = ElementTree.parse(soapmsg)
    soapns = soaptree.getroot().tag.split('}')[0].strip('{')
    soapbody = soaptree.getroot().find("{%s}Body" % soapns)
    message = None
    for child in list(soapbody):
        if child.tag != "%sFault" % (soapns,):
            message = child
            break
    
    numreplaces = 0
    idprefix = ''
    if prefix == True: idprefix = "cid:"
    id = "%s%s" % (idprefix, id, )
    
    # Make replacement.
    for param in message:
        # Look for Include subelement.
        for sub in param:
            if sub.tag.split('}')[-1] == 'Include' and \
               sub.attrib.get('href') == id:
                param.remove(sub)
                param.text = payload
                numreplaces += 1
        if numreplaces < 1 and param.attrib.get('href') == id:
            del(param.attrib['href'])
            param.text = payload
            numreplaces += 1
            
    soapmsg.close()
    soapmsg = StringIO()
    soaptree.write(soapmsg)
    joinedmsg = soapmsg.getvalue()
    soapmsg.close()
    
    return (joinedmsg, numreplaces)

def collapse_swa(content_type, envelope):
    '''
    Translates an SwA multipart/related message into an application/soap+xml message.
    
    References:
    SwA     http://www.w3.org/TR/SOAP-attachments
    XOP     http://www.w3.org/TR/xop10/
    MTOM    http://www.w3.org/TR/soap12-mtom/
            http://www.w3.org/Submission/soap11mtom10/
            
    @param  content_type value of the Content-Type header field
    @param  envelope     body of the HTTP message, a soap envelope
    @return              appication/soap+xml version of the given HTTP body
    '''
    # convert multipart messages back to pure SOAP
    mime_type = content_type.lower().split(';')
    if 'multipart/related' not in mime_type:
        return envelope
        
    # parse the body into an email.Message object
    msgString = "MIME-Version: 1.0\r\n" \
                "Content-Type: %s\r\n" % (
                content_type, )             
    msgString += "\r\n" + envelope                
    msg = message_from_string(msgString) # our message
    
    soapmsg = None
    root = msg.get_param('start')
    
    # walk through sections, reconstructing pure SOAP
    for part in msg.walk():
        # skip the multipart container section
        if part.get_content_maintype() == 'multipart':
            continue
        
        # detect main soap section
        if (part.get('Content-ID') and part.get('Content-ID') == root) or \
           (root == None and part == msg.get_payload()[0]):
            soapmsg = part.get_payload()
            continue
           
        # binary packages
        cte = part.get("Content-Transfer-Encoding")
        payload = None
        if cte != 'base64':
            payload = b64encode(part.get_payload())
        else:
            payload = part.get_payload()
        cid = part.get("Content-ID").strip("<>")
        cloc = part.get("Content-Location")
        numreplaces = None
        
        # Check for Content-ID and make replacement
        if cid:
            soapmsg, numreplaces = join_attachment(cid, soapmsg, payload)
            
        # Check for Content-Location and make replacement
        if cloc and not cid and not numreplaces:
            soapmsg, numreplaces = join_attachment(cloc,soapmsg,payload,False)
                
    return soapmsg

def apply_mtom(headers, envelope, params, paramvals):
    '''
    Apply MTOM to a SOAP envelope, separating attachments into a
    MIME multipart message.
    
    References:
    XOP     http://www.w3.org/TR/xop10/
    MTOM    http://www.w3.org/TR/soap12-mtom/
            http://www.w3.org/Submission/soap11mtom10/
    
    @param headers   Headers dictionary of the SOAP message that would 
                     originally be sent.
    @param envelope  SOAP envelope string that would have originally been sent.
    @param params    params attribute from the Message object used for the SOAP
    @param paramvals values of the params, passed to Message.to_xml
    @return          tuple of length 2 with dictionary of headers and 
                     string of body that can be sent with HTTPConnection
    '''
    
    # grab the XML element of the message in the SOAP body
    soapmsg = StringIO(envelope)
    soaptree = ElementTree.parse(soapmsg)
    soapns = soaptree.getroot().tag.split('}')[0].strip('{')
    soapbody = soaptree.getroot().find("{%s}Body" % soapns)
    message = None
    for child in list(soapbody):
        if child.tag != "%sFault" % (soapns,):
            message = child
            break
    
    # Get additional parameters from original Content-Type
    ctarray = []
    for n, v in headers.items():
        if n.lower() == 'content-type':
            ctarray = v.split(';')
            break
    roottype = ctarray[0].strip()
    rootparams = {}
    for ctparam in ctarray[1:]:
        n, v = ctparam.strip().split('=')
        rootparams[n] = v.strip("\"'")
    
    # Set up initial MIME parts
    mtompkg = MIMEMultipart('related',boundary='?//<><>soaplib_MIME_boundary<>')
    rootpkg = None
    try:
        rootpkg = MIMEApplication(envelope,'xop+xml', encode_7or8bit)
    except NameError:
        rootpkg = MIMENonMultipart("application", "xop+xml")
        rootpkg.set_payload(envelope)
        encode_7or8bit(rootpkg)
    
    # Set up multipart headers.
    del(mtompkg['mime-version'])
    mtompkg.set_param('start-info',roottype)
    mtompkg.set_param('start','<soaplibEnvelope>')
    if headers.has_key('SOAPAction'):
        mtompkg.add_header('SOAPAction', headers.get('SOAPAction'))
    
    # Set up root SOAP part headers
    del(rootpkg['mime-version'])
    rootpkg.add_header('Content-ID','<soaplibEnvelope>')
    for n, v in rootparams.items():
        rootpkg.set_param(n,v)
    rootpkg.set_param('type',roottype)
    
    mtompkg.attach(rootpkg)
    
    # Extract attachments from SOAP envelope.
    for i in range(len(params)):
        name, typ = params[i]
        if typ == Attachment:
            id = "soaplibAttachment_%s" % (len(mtompkg.get_payload()),)
            param = message[i]
            param.text = ""
            incl = create_xml_subelement(
                       param, 
                       "{http://www.w3.org/2004/08/xop/include}Include"
                   )
            incl.attrib["href"] = "cid:%s" % id
            if paramvals[i].fileName and not paramvals[i].data:
                paramvals[i].load_from_file()
            data = paramvals[i].data
            attachment = None
            try:
                attachment = MIMEApplication(data, _encoder=encode_7or8bit)
            except NameError:
                attachment = MIMENonMultipart("application", "octet-stream")
                attachment.set_payload(data)
                encode_7or8bit(attachment)
            del(attachment['mime-version'])
            attachment.add_header('Content-ID','<%s>'%(id,))
            mtompkg.attach(attachment)
    
    # Update SOAP envelope.
    soapmsg.close()
    soapmsg = StringIO()
    soaptree.write(soapmsg)
    rootpkg.set_payload(soapmsg.getvalue())
    soapmsg.close()
    
    # extract body string from MIMEMultipart message
    bound = '--%s' % (mtompkg.get_boundary(),)
    marray = mtompkg.as_string().split(bound)
    mtombody = bound
    mtombody += bound.join(marray[1:])
    
    # set Content-Length
    mtompkg.add_header("Content-Length", str(len(mtombody)))
    
    # extract dictionary of headers from MIMEMultipart message
    mtomheaders = {}
    for name, value in mtompkg.items():
        mtomheaders[name] = value
    
    if len(mtompkg.get_payload()) <= 1:
        return (headers, envelope)
    
    return (mtomheaders, mtombody)

def make_soap_fault(faultString, faultCode = 'Server', detail = None, 
    header_elements = None):
    '''
    This method populates a soap fault message with the provided 
    fault string and details.  
    @param faultString the short description of the error
    @param detail the details of the exception, such as a stack trace
    @param faultCode defaults to 'Server', but can be overridden
    @param header_elements A list of XML elements to add to the fault header.
    @returns the element corresponding to the fault message
    '''
    
    nsmap = NamespaceLookup()
    envelope = create_xml_element(nsmap.get('SOAP-ENV') + 'Envelope', nsmap)
    
    if header_elements:
        header = create_xml_subelement(
            envelope, nsmap.get('SOAP-ENV') + 'Header')
        for element in header_elements:
            header.append(element)
    
    body = create_xml_subelement(envelope, nsmap.get('SOAP-ENV') + 'Body')

    f = Fault(faultCode,faultString,detail)
    body.append(Fault.to_xml(f, nsmap.get('SOAP-ENV') + "Fault", nsmap))

    return envelope