renamed files used at runtime (see post-install script in specfile)
[nodemanager.git] / curlwrapper.py
index 81c9c14..da5810c 100644 (file)
@@ -1,39 +1,64 @@
-# $Id$
-# $URL$
-
-from subprocess import PIPE, Popen
-from select import select
-# raise xmplrpclib.ProtocolError
-import xmlrpclib
-import signal
 import os
+import xmlrpclib
+import urllib
+import pycurl
+from cStringIO import StringIO
+
 import logger
 
-class Sopen(Popen):
-    def kill(self, signal = signal.SIGTERM):
-        os.kill(self.pid, signal)
+# a pycurl-based replacement for the previous version that relied on forking curl
 
 def retrieve(url, cacert=None, postdata=None, timeout=90):
-#    options = ('/usr/bin/curl', '--fail', '--silent')
-    options = ('/usr/bin/curl', '--fail', )
-    if cacert: options += ('--cacert', cacert)
-    if postdata: options += ('--data', '@-')
+    curl= pycurl.Curl()
+    curl.setopt(pycurl.URL,url)
+
+    # reproduce --fail from the previous version
+    curl.setopt(pycurl.FAILONERROR,1)
+    # don't want curl sending any signals
+    curl.setopt(pycurl.NOSIGNAL, 1)
+
+    # do not follow location when attempting to download a file
+    # curl.setopt(pycurl.FOLLOWLOCATION, 0)
+
+    # store result on the fly 
+    buffer=StringIO()
+    curl.setopt(pycurl.WRITEFUNCTION,buffer.write)
+           
+    # set timeout
     if timeout: 
-        options += ('--max-time', str(timeout))
-        options += ('--connect-timeout', str(timeout))
-    p = Sopen(options + (url,), stdin=PIPE, stdout=PIPE, stderr=PIPE, close_fds=True)
-    if postdata: p.stdin.write(postdata)
-    p.stdin.close()
-    sout, sin, serr = select([p.stdout,p.stderr],[],[], timeout)
-    if len(sout) == 0 and len(sin) == 0 and len(serr) == 0: 
-        logger.verbose("curlwrapper: timed out after %s" % timeout)
-        p.kill(signal.SIGKILL) 
-    data = p.stdout.read()
-    err = p.stderr.read()
-    rc = p.wait()
-    if rc != 0: 
-        # when this triggers, the error sometimes doesn't get printed
-        logger.log ("curlwrapper: retrieve, got stderr <%s>"%err)
-        raise xmlrpclib.ProtocolError(url, rc, err, postdata)
-    else: 
-        return data
+        curl.setopt(pycurl.CONNECTTIMEOUT, timeout)
+        curl.setopt(pycurl.TIMEOUT, timeout)
+
+    # set cacert
+    if cacert: 
+        curl.setopt(pycurl.CAINFO, cacert)
+        curl.setopt(pycurl.SSL_VERIFYPEER, 2)
+    else:
+        curl.setopt(pycurl.SSL_VERIFYPEER, 0)
+
+    # set postdata
+    if postdata:
+        if isinstance(postdata,dict):
+            postfields = urllib.urlencode(postdata)
+        else:
+           postfields=postdata
+        curl.setopt(pycurl.POSTFIELDS, postfields)
+
+    # go
+    try:
+        curl.perform()
+
+        errcode = curl.getinfo(pycurl.HTTP_CODE)
+        curl.close()
+
+        # check the code, return 1 if successfull
+       if errcode == 60:
+           raise xmlrpclib.ProtocolError (url,errcode, "SSL certificate validation failed", postdata)
+        elif errcode != 200:
+            raise xmlrpclib.ProtocolError (url,errcode, "http error %d"%errcode, postdata)
+
+    except pycurl.error, err:
+        errno, errstr = err
+        raise xmlrpclib.ProtocolError(url, errno, "curl error %d: '%s'\n" %(errno,errstr),postdata )
+
+    return buffer.getvalue()