~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/web/soap.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2004-06-21 22:01:11 UTC
  • mto: (2.2.3 sid)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20040621220111-vkf909euqnyrp3nr
Tags: upstream-1.3.0
ImportĀ upstreamĀ versionĀ 1.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- test-case-name: twisted.test.test_soap -*-
 
2
# Twisted, the Framework of Your Internet
 
3
# Copyright (C) 2001 Matthew W. Lefkowitz
 
4
 
5
# This library is free software; you can redistribute it and/or
 
6
# modify it under the terms of version 2.1 of the GNU Lesser General Public
 
7
# License as published by the Free Software Foundation.
 
8
 
9
# This library is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
12
# Lesser General Public License for more details.
 
13
 
14
# You should have received a copy of the GNU Lesser General Public
 
15
# License along with this library; if not, write to the Free Software
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
"""SOAP support for twisted.web.
 
19
 
 
20
Requires SOAPpy 0.10.1 or later.
 
21
 
 
22
API Stability: unstable
 
23
 
 
24
Maintainer: U{Itamar Shtull-Trauring<mailto:twisted@itamarst.org}
 
25
 
 
26
Future plans:
 
27
SOAPContext support of some kind.
 
28
Pluggable method lookup policies.
 
29
"""
 
30
 
 
31
# SOAPpy
 
32
import SOAPpy
 
33
 
 
34
# twisted imports
 
35
from twisted.web import server, resource, client
 
36
from twisted.internet import defer
 
37
from twisted.python import log, failure
 
38
 
 
39
 
 
40
class SOAPPublisher(resource.Resource):
 
41
    """Publish SOAP methods.
 
42
 
 
43
    By default, publish methods beginning with 'soap_'. If the method
 
44
    has an attribute 'useKeywords', it well get the arguments passed
 
45
    as keyword args.
 
46
    """
 
47
 
 
48
    isLeaf = 1
 
49
    
 
50
    # override to change the encoding used for responses
 
51
    encoding = "UTF-8"
 
52
 
 
53
    def lookupFunction(self, functionName):
 
54
        """Lookup published SOAP function.
 
55
 
 
56
        Override in subclasses. Default behaviour - publish methods
 
57
        starting with soap_, if they have true attribute useKeywords
 
58
        they are expected to accept keywords.
 
59
        
 
60
        @return: tuple (callable, useKeywords), or (None, None) if not found.
 
61
        """
 
62
        function = getattr(self, "soap_%s" % functionName, None)
 
63
        if function:
 
64
            return function, getattr(function, "useKeywords", False)
 
65
        else:
 
66
            return None
 
67
    
 
68
    def render(self, request):
 
69
        """Handle a SOAP command."""
 
70
        data = request.content.read()
 
71
 
 
72
        p, header, body, attrs = SOAPpy.parseSOAPRPC(data, 1, 1, 1)
 
73
 
 
74
        methodName, args, kwargs, ns = p._name, p._aslist, p._asdict, p._ns
 
75
 
 
76
        # deal with changes in SOAPpy 0.11
 
77
        if callable(args):
 
78
            args = args()
 
79
        if callable(kwargs):
 
80
            kwargs = kwargs()
 
81
 
 
82
        function, useKeywords = self.lookupFunction(methodName)
 
83
        
 
84
        if not function:
 
85
            self._methodNotFound(request, methodName)
 
86
            return server.NOT_DONE_YET
 
87
        else:
 
88
            if hasattr(function, "useKeywords"):
 
89
                keywords = {}
 
90
                for k, v in kwargs.items():
 
91
                    keywords[str(k)] = v
 
92
                d = defer.maybeDeferred(function, **keywords)
 
93
            else:
 
94
                d = defer.maybeDeferred(function, *args)
 
95
 
 
96
        d.addCallback(self._gotResult, request, methodName)
 
97
        d.addErrback(self._gotError, request, methodName)
 
98
        return server.NOT_DONE_YET
 
99
 
 
100
    def _methodNotFound(self, request, methodName):
 
101
        response = SOAPpy.buildSOAP(SOAPpy.faultType("%s:Client" % SOAPpy.NS.ENV_T,
 
102
                                                 "Method %s not found" % methodName),
 
103
                                  encoding=self.encoding)
 
104
        self._sendResponse(request, response, status=500)
 
105
    
 
106
    def _gotResult(self, result, request, methodName):
 
107
        if not isinstance(result, SOAPpy.voidType):
 
108
            result = {"Result": result}
 
109
        response = SOAPpy.buildSOAP(kw={'%sResponse' % methodName: result},
 
110
                                  encoding=self.encoding)
 
111
        self._sendResponse(request, response)
 
112
 
 
113
    def _gotError(self, failure, request, methodName):
 
114
        e = failure.value
 
115
        if isinstance(e, SOAPpy.faultType):
 
116
            fault = e
 
117
        else:
 
118
            fault = SOAPpy.faultType("%s:Server" % SOAPpy.NS.ENV_T, "Method %s failed." % methodName)
 
119
        response = SOAPpy.buildSOAP(fault, encoding=self.encoding)
 
120
        self._sendResponse(request, response, status=500)
 
121
 
 
122
    def _sendResponse(self, request, response, status=200):
 
123
        request.setResponseCode(status)
 
124
 
 
125
        if self.encoding is not None:
 
126
            mimeType = 'text/xml; charset="%s"' % self.encoding
 
127
        else:
 
128
            mimeType = "text/xml"
 
129
        request.setHeader("Content-type", mimeType)
 
130
        request.setHeader("Content-length", str(len(response)))
 
131
        request.write(response)
 
132
        request.finish()
 
133
 
 
134
 
 
135
class Proxy:
 
136
    """A Proxy for making remote SOAP calls.
 
137
 
 
138
    Pass the URL of the remote SOAP server to the constructor.
 
139
 
 
140
    Use proxy.callRemote('foobar', 1, 2) to call remote method
 
141
    'foobar' with args 1 and 2, proxy.callRemote('foobar', x=1)
 
142
    will call foobar with named argument 'x'.
 
143
    """
 
144
 
 
145
    # at some point this should have encoding etc. kwargs
 
146
    def __init__(self, url, namespace=None, header=None):
 
147
        self.url = url
 
148
        self.namespace = namespace
 
149
        self.header = header
 
150
 
 
151
    def _cbGotResult(self, result):
 
152
        return SOAPpy.parseSOAPRPC(result).Result
 
153
        
 
154
    def callRemote(self, method, *args, **kwargs):
 
155
        payload = SOAPpy.buildSOAP(args=args, kw=kwargs, method=method,
 
156
                                   header=self.header, namespace=self.namespace)
 
157
        return client.getPage(self.url, postdata=payload, method="POST",
 
158
                              headers={'content-type': 'text/xml'}
 
159
                              ).addCallback(self._cbGotResult)