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