Fix version output when missing.
[plcapi.git] / PLC / PyCurl.py
1 #
2 # Replacement for xmlrpclib.SafeTransport, which does not validate
3 # SSL certificates. Requires PyCurl.
4 #
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2006 The Trustees of Princeton University
7 #
8 # $Id$
9 # $URL$
10 #
11
12 import os
13 import xmlrpclib
14 import pycurl
15 from tempfile import NamedTemporaryFile
16
17 class PyCurlTransport(xmlrpclib.Transport):
18     def __init__(self, uri, cert = None, timeout = 300):
19         if hasattr(xmlrpclib.Transport,'__init__'):
20             xmlrpclib.Transport.__init__(self)
21         self.curl = pycurl.Curl()
22
23         # Suppress signals
24         self.curl.setopt(pycurl.NOSIGNAL, 1)
25
26         # Follow redirections
27         self.curl.setopt(pycurl.FOLLOWLOCATION, 1)
28
29         # Set URL
30         self.url = uri
31         self.curl.setopt(pycurl.URL, str(uri))
32
33         # Set certificate path
34         if cert is not None:
35             if os.path.exists(cert):
36                 cert_path = str(cert)
37             else:
38                 # Keep a reference so that it does not get deleted
39                 self.cert = NamedTemporaryFile(prefix = "cert")
40                 self.cert.write(cert)
41                 self.cert.flush()
42                 cert_path = self.cert.name
43             self.curl.setopt(pycurl.CAINFO, cert_path)
44             self.curl.setopt(pycurl.SSL_VERIFYPEER, 2)
45
46         # Set connection timeout
47         if timeout:
48             self.curl.setopt(pycurl.CONNECTTIMEOUT, timeout)
49             self.curl.setopt(pycurl.TIMEOUT, timeout)
50
51         # Set request callback
52         self.body = ""
53         def body(buf):
54             self.body += buf
55         self.curl.setopt(pycurl.WRITEFUNCTION, body)
56
57     def request(self, host, handler, request_body, verbose = 1):
58         # Set verbosity
59         self.curl.setopt(pycurl.VERBOSE, verbose)
60
61         # Post request
62         self.curl.setopt(pycurl.POST, 1)
63         self.curl.setopt(pycurl.POSTFIELDS, request_body)
64
65         try:
66             self.curl.perform()
67             errcode = self.curl.getinfo(pycurl.HTTP_CODE)
68             response = self.body
69             self.body = ""
70             errmsg="<no known errmsg>"
71         except pycurl.error, err:
72             (errcode, errmsg) = err
73
74         if errcode == 60:
75             raise Exception, "PyCurl: SSL certificate validation failed"
76         elif errcode != 200:
77             raise Exception, "PyCurl: HTTP error %d -- %r" % (errcode,errmsg)
78
79         # Parse response
80         p, u = self.getparser()
81         p.feed(response)
82         p.close()
83
84         return u.close()