2to3 -f except
[sfa.git] / sfa / client / sfaserverproxy.py
1 # XMLRPC-specific code for SFA Client
2
3 # starting with 2.7.9 we need to turn off server verification
4 import ssl
5 try:    turn_off_server_verify = { 'context' : ssl._create_unverified_context() } 
6 except: turn_off_server_verify = {}
7
8 import xmlrpclib
9 from httplib import HTTPS, HTTPSConnection
10
11 try:
12     from sfa.util.sfalogging import logger
13 except:
14     import logging
15     logger = logging.getLogger('sfaserverproxy')
16
17 ##
18 # ServerException, ExceptionUnmarshaller
19 #
20 # Used to convert server exception strings back to an exception.
21 #    from usenet, Raghuram Devarakonda
22
23 class ServerException(Exception):
24     pass
25
26 class ExceptionUnmarshaller(xmlrpclib.Unmarshaller):
27     def close(self):
28         try:
29             return xmlrpclib.Unmarshaller.close(self)
30         except xmlrpclib.Fault as e:
31             raise ServerException(e.faultString)
32
33 ##
34 # XMLRPCTransport
35 #
36 # A transport for XMLRPC that works on top of HTTPS
37
38 # targetting only python-2.7 we can get rid of some older code
39
40 class XMLRPCTransport(xmlrpclib.Transport):
41     
42     def __init__(self, key_file = None, cert_file = None, timeout = None):
43         xmlrpclib.Transport.__init__(self)
44         self.timeout=timeout
45         self.key_file = key_file
46         self.cert_file = cert_file
47         
48     def make_connection(self, host):
49         # create a HTTPS connection object from a host descriptor
50         # host may be a string, or a (host, x509-dict) tuple
51         host, extra_headers, x509 = self.get_host_info(host)
52         conn = HTTPSConnection(host, None, key_file = self.key_file,
53                                cert_file = self.cert_file,
54                                **turn_off_server_verify)
55
56         # Some logic to deal with timeouts. It appears that some (or all) versions
57         # of python don't set the timeout after the socket is created. We'll do it
58         # ourselves by forcing the connection to connect, finding the socket, and
59         # calling settimeout() on it. (tested with python 2.6)
60         if self.timeout:
61             if hasattr(conn, 'set_timeout'):
62                 conn.set_timeout(self.timeout)
63
64             if hasattr(conn, "_conn"):
65                 # HTTPS is a wrapper around HTTPSConnection
66                 real_conn = conn._conn
67             else:
68                 real_conn = conn
69             conn.connect()
70             if hasattr(real_conn, "sock") and hasattr(real_conn.sock, "settimeout"):
71                 real_conn.sock.settimeout(float(self.timeout))
72
73         return conn
74
75     def getparser(self):
76         unmarshaller = ExceptionUnmarshaller()
77         parser = xmlrpclib.ExpatParser(unmarshaller)
78         return parser, unmarshaller
79
80 class XMLRPCServerProxy(xmlrpclib.ServerProxy):
81     def __init__(self, url, transport, allow_none=True, verbose=False):
82         # remember url for GetVersion
83         # xxx not sure this is still needed as SfaServerProxy has this too
84         self.url=url
85         xmlrpclib.ServerProxy.__init__(self, url, transport, allow_none=allow_none,
86                                        verbose=verbose,
87                                        **turn_off_server_verify)
88
89     def __getattr__(self, attr):
90         logger.debug ("xml-rpc %s method:%s" % (self.url, attr))
91         return xmlrpclib.ServerProxy.__getattr__(self, attr)
92
93 ########## the object on which we can send methods that get sent over xmlrpc
94 class SfaServerProxy:
95
96     def __init__ (self, url, keyfile, certfile, verbose=False, timeout=None):
97         self.url = url
98         self.keyfile = keyfile
99         self.certfile = certfile
100         self.verbose = verbose
101         self.timeout = timeout
102         # an instance of xmlrpclib.ServerProxy
103         transport = XMLRPCTransport(keyfile, certfile, timeout)
104         self.serverproxy = XMLRPCServerProxy(url, transport, allow_none=True, verbose=verbose)
105
106     # this is python magic to return the code to run when 
107     # SfaServerProxy receives a method call
108     # so essentially we send the same method with identical arguments
109     # to the server_proxy object
110     def __getattr__(self, name):
111         def func(*args, **kwds):
112             return getattr(self.serverproxy, name)(*args, **kwds)
113         return func
114