Skip to content

Commit

Permalink
Merge pull request #563 from sinhote/close-curl-properly
Browse files Browse the repository at this point in the history
Fix #562 : Properly close the cURL and StringIO objects
  • Loading branch information
Alfro authored Jan 17, 2018
2 parents 60146c3 + c938fc8 commit ea61a3d
Showing 1 changed file with 66 additions and 43 deletions.
109 changes: 66 additions & 43 deletions galicaster/opencast/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,59 +102,82 @@ def __init__(self, server, user, password, hostname='galicaster', address=None,
def __call(self, method, endpoint, path_params={}, query_params={}, postfield={}, urlencode=True, server=None, timeout=True, headers={}):

theServer = server or self.server
c = pycurl.Curl()
b = StringIO()

url = list(urlparse.urlparse(theServer, 'http'))
url[2] = urlparse.urljoin(url[2], endpoint.format(**path_params))
url[4] = urllib.urlencode(query_params)
c.setopt(pycurl.URL, urlparse.urlunparse(url))

c.setopt(pycurl.FOLLOWLOCATION, False)
c.setopt(pycurl.CONNECTTIMEOUT, self.connect_timeout)
if timeout:
c.setopt(pycurl.TIMEOUT, self.timeout)
c.setopt(pycurl.NOSIGNAL, 1)
c.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_DIGEST)
c.setopt(pycurl.USERPWD, self.user + ':' + self.password)
sendheaders = ['X-Requested-Auth: Digest', 'X-Opencast-Matterhorn-Authorization: true']
if headers:
for h, v in headers.iteritems():
sendheaders.append('{}: {}'.format(h, v))
# implies we might be interested in passing the response headers
c.setopt(pycurl.HEADERFUNCTION, self.scanforetag)
c.setopt(pycurl.HTTPHEADER, sendheaders)
c.setopt(pycurl.USERAGENT, 'Galicaster' + version)
c.setopt(pycurl.SSL_VERIFYPEER, False) # equivalent to curl's --insecure

if (method == 'POST'):
if urlencode:
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.POSTFIELDS, urllib.urlencode(postfield))
else:
c.setopt(pycurl.HTTPPOST, postfield)
c.setopt(pycurl.WRITEFUNCTION, b.write)

#c.setopt(pycurl.VERBOSE, True) ##TO DEBUG
c = b = None
try:
c = pycurl.Curl()

c.setopt(pycurl.URL, urlparse.urlunparse(url))

c.setopt(pycurl.FOLLOWLOCATION, False)
c.setopt(pycurl.CONNECTTIMEOUT, self.connect_timeout)
if timeout:
c.setopt(pycurl.TIMEOUT, self.timeout)
c.setopt(pycurl.NOSIGNAL, 1)
c.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_DIGEST)
c.setopt(pycurl.USERPWD, self.user + ':' + self.password)
sendheaders = ['X-Requested-Auth: Digest', 'X-Opencast-Matterhorn-Authorization: true']
if headers:
for h, v in headers.iteritems():
sendheaders.append('{}: {}'.format(h, v))
# implies we might be interested in passing the response headers
c.setopt(pycurl.HEADERFUNCTION, self.scanforetag)
c.setopt(pycurl.HTTPHEADER, sendheaders)
c.setopt(pycurl.USERAGENT, 'Galicaster' + version)
c.setopt(pycurl.SSL_VERIFYPEER, False) # equivalent to curl's --insecure

if (method == 'POST'):
if urlencode:
c.setopt(pycurl.POST, 1)
c.setopt(pycurl.POSTFIELDS, urllib.urlencode(postfield))
else:
c.setopt(pycurl.HTTPPOST, postfield)

b = StringIO()
c.setopt(pycurl.WRITEFUNCTION, b.write)

#c.setopt(pycurl.VERBOSE, True) ##TO DEBUG
c.perform()

status_code = c.getinfo(pycurl.HTTP_CODE)
self.response['Status-Code'] = status_code
self.response['Content-Type'] = c.getinfo(pycurl.CONTENT_TYPE)

if status_code != 200 and status_code != 302 and status_code != 304:
if (status_code > 200) and (status_code < 300):
self.logger and self.logger.warning("Opencast client ({}) sent a response with status code {}".format(urlparse.urlunparse(url), status_code))
else:
title = self.find_between(b.getvalue(), "<title>", "</title>")
self.logger and self.logger.error('call error in %s, status code {%r}: %s',
urlparse.urlunparse(url), status_code, title)
raise IOError, 'Error in Opencast client'

return b.getvalue()
except IOError:
# Do not wrap the IOError. We raise it ourselves
raise
except Exception as exc:
raise RuntimeError, exc
finally:
if c is not None:
try:
c.close()
except Exception as e:
# We did our best!
self.logger and self.logger.warning("Could not close cURL object properly: {}", e)
pass
if b is not None:
try:
b.close()
except Exception as e:
# We did our best!
self.logger and self.logger.warning("Could not close StringIO object properly: {}", e)
pass

status_code = c.getinfo(pycurl.HTTP_CODE)
self.response['Status-Code'] = status_code
self.response['Content-Type'] = c.getinfo(pycurl.CONTENT_TYPE)
c.close()
if status_code != 200 and status_code != 302 and status_code != 304:
if (status_code > 200) and (status_code < 300):
self.logger and self.logger.warning("Opencast client ({}) sent a response with status code {}".format(urlparse.urlunparse(url), status_code))
else:
title = self.find_between(b.getvalue(), "<title>", "</title>")
self.logger and self.logger.error('call error in %s, status code {%r}: %s',
urlparse.urlunparse(url), status_code, title)
raise IOError, 'Error in Opencast client'

return b.getvalue()

def scanforetag(self, buffer):
if buffer.startswith('ETag:'):
Expand Down

0 comments on commit ea61a3d

Please sign in to comment.