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