debian-koji/koji/compatrequests.py
2016-11-22 16:41:31 -05:00

142 lines
4.5 KiB
Python

"""
koji.compatrequests
~~~~~~~~~~~~~~~~~~~
This module contains a *very limited* partial implemention of the requests
module that is based on the older codepaths in koji. It only provides
the bits that koji needs.
"""
import httplib
import urlparse
import urllib
import sys
import ssl.SSLCommon
try:
from ssl import ssl as pyssl
except ImportError: # pragma: no cover
pass
class Session(object):
def __init__(self):
self.connection = None
def post(self, url, data=None, headers=None, stream=None, verify=None,
cert=None, timeout=None):
uri = urlparse.urlsplit(url)
if uri[3]:
handler = "%s?%s" % (uri[2], uri[3])
else:
handler = uri[2]
cnx = self.get_connection(uri, cert, verify, timeout)
#cnx.set_debuglevel(1)
cnx.putrequest('POST', handler)
if headers:
for k in headers:
cnx.putheader(k, headers[k])
cnx.endheaders()
if data is not None:
cnx.send(data)
response = cnx.getresponse()
return Response(self, response)
def get_connection(self, uri, cert, verify, timeout):
scheme = uri[0]
host, port = urllib.splitport(uri[1])
key = (scheme, host, cert, verify, timeout)
#if self.connection and self.opts.get('keepalive'):
if self.connection: # XXX honor keepalive
if key == self.connection[0]:
cnx = self.connection[1]
if getattr(cnx, 'sock', None):
return cnx
# Otherwise we make a new one
default_port = 80
certs = {}
if isinstance(verify, basestring):
certs['peer_ca_cert'] = verify
if cert:
certs['key_and_cert'] = cert
ctx = ssl.SSLCommon.CreateSSLContext(certs)
cnxOpts = {'ssl_context' : ctx}
cnxClass = ssl.SSLCommon.PlgHTTPSConnection
default_port = 443
elif scheme == 'https':
cnxOpts = {}
if verify:
if sys.version_info[:3] >= (2, 7, 9):
try:
proto = pyssl.PROTOCOL_TLS
except AttributeError:
proto = pyssl.PROTOCOL_SSLv23
ctx = pyssl.SSLContext(proto)
ctx.load_verify_locations(cafile=verify)
ctx.verify_mode = pyssl.CERT_REQUIRED
cnxOpts['context'] = ctx
else:
cnxOpts['cert_file'] = verify
elif verify is None:
# not specified, leave as default
pass
elif sys.version_info[:3] >= (2, 7, 9):
# no verify
ctx = pyssl._create_unverified_context()
cnxOpts['context'] = ctx
cnxClass = httplib.HTTPSConnection
default_port = 443
elif scheme == 'http':
cnxOpts = {}
cnxClass = httplib.HTTPConnection
else:
raise IOError, "unsupported protocol: %s" % scheme
timeout_compat = False
if timeout:
if sys.version_info[:3] < (2, 6, 0) and 'ssl_context' not in cnxOpts:
timeout_compat = True
else:
cnxOpts['timeout'] = timeout
# no need to close connection
port = (port and int(port) or default_port)
cnx = cnxClass(host, port, **cnxOpts)
self.connection = (key, cnx)
if timeout_compat:
# in python < 2.6 httplib does not support the timeout option
# but socket supports it since 2.3
cnx.connect()
cnx.sock.settimeout(timeout)
return cnx
def close(self):
if self.connection:
self.connection[1].close()
self.connection = None
class Response(object):
def __init__(self, session, response):
self.session = session
self.response = response
def iter_content(self, blocksize=8192):
# should we check this in Session.post()?
# should we even check this here?
if self.response.status != 200:
if (self.response.getheader("content-length", 0)):
self.response.read()
# XXX wrong exception
raise Exception("Server status: %s" % self.response.status)
while True:
chunk = self.response.read(blocksize)
if not chunk:
break
yield chunk
def close(self):
self.response.close()