mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
Add a local implementation of httplib.SSLFile and httplib.FakeSocket
Python 2.6 changed its internal implementation which makes it difficult to override in a way that is backwards compatible. 508953
This commit is contained in:
179
ipapython/ipasslfile.py
Normal file
179
ipapython/ipasslfile.py
Normal file
@@ -0,0 +1,179 @@
|
||||
# This is a forward backport of the Python2.5 uuid module. It isn't available
|
||||
# in Python 2.6
|
||||
|
||||
# The next several classes are used to define FakeSocket, a socket-like
|
||||
# interface to an SSL connection.
|
||||
|
||||
# The primary complexity comes from faking a makefile() method. The
|
||||
# standard socket makefile() implementation calls dup() on the socket
|
||||
# file descriptor. As a consequence, clients can call close() on the
|
||||
# parent socket and its makefile children in any order. The underlying
|
||||
# socket isn't closed until they are all closed.
|
||||
|
||||
# The implementation uses reference counting to keep the socket open
|
||||
# until the last client calls close(). SharedSocket keeps track of
|
||||
# the reference counting and SharedSocketClient provides an constructor
|
||||
# and close() method that call incref() and decref() correctly.
|
||||
|
||||
class SharedSocket:
|
||||
def __init__(self, sock):
|
||||
self.sock = sock
|
||||
self._refcnt = 0
|
||||
|
||||
def incref(self):
|
||||
self._refcnt += 1
|
||||
|
||||
def decref(self):
|
||||
self._refcnt -= 1
|
||||
assert self._refcnt >= 0
|
||||
if self._refcnt == 0:
|
||||
self.sock.close()
|
||||
|
||||
def __del__(self):
|
||||
self.sock.close()
|
||||
|
||||
class SharedSocketClient:
|
||||
|
||||
def __init__(self, shared):
|
||||
self._closed = 0
|
||||
self._shared = shared
|
||||
self._shared.incref()
|
||||
self._sock = shared.sock
|
||||
|
||||
def close(self):
|
||||
if not self._closed:
|
||||
self._shared.decref()
|
||||
self._closed = 1
|
||||
self._shared = None
|
||||
|
||||
class SSLFile(SharedSocketClient):
|
||||
"""File-like object wrapping an SSL socket."""
|
||||
|
||||
BUFSIZE = 8192
|
||||
|
||||
def __init__(self, sock, ssl, bufsize=None):
|
||||
SharedSocketClient.__init__(self, sock)
|
||||
self._ssl = ssl
|
||||
self._buf = ''
|
||||
self._bufsize = bufsize or self.__class__.BUFSIZE
|
||||
|
||||
def _read(self):
|
||||
buf = ''
|
||||
# put in a loop so that we retry on transient errors
|
||||
while True:
|
||||
try:
|
||||
buf = self._ssl.read(self._bufsize)
|
||||
except socket.sslerror, err:
|
||||
if (err[0] == socket.SSL_ERROR_WANT_READ
|
||||
or err[0] == socket.SSL_ERROR_WANT_WRITE):
|
||||
continue
|
||||
if (err[0] == socket.SSL_ERROR_ZERO_RETURN
|
||||
or err[0] == socket.SSL_ERROR_EOF):
|
||||
break
|
||||
raise
|
||||
except socket.error, err:
|
||||
if err[0] == errno.EINTR:
|
||||
continue
|
||||
if err[0] == errno.EBADF:
|
||||
# XXX socket was closed?
|
||||
break
|
||||
raise
|
||||
else:
|
||||
break
|
||||
return buf
|
||||
|
||||
def read(self, size=None):
|
||||
L = [self._buf]
|
||||
avail = len(self._buf)
|
||||
while size is None or avail < size:
|
||||
s = self._read()
|
||||
if s == '':
|
||||
break
|
||||
L.append(s)
|
||||
avail += len(s)
|
||||
all = "".join(L)
|
||||
if size is None:
|
||||
self._buf = ''
|
||||
return all
|
||||
else:
|
||||
self._buf = all[size:]
|
||||
return all[:size]
|
||||
|
||||
def readline(self):
|
||||
L = [self._buf]
|
||||
self._buf = ''
|
||||
while 1:
|
||||
i = L[-1].find("\n")
|
||||
if i >= 0:
|
||||
break
|
||||
s = self._read()
|
||||
if s == '':
|
||||
break
|
||||
L.append(s)
|
||||
if i == -1:
|
||||
# loop exited because there is no more data
|
||||
return "".join(L)
|
||||
else:
|
||||
all = "".join(L)
|
||||
# XXX could do enough bookkeeping not to do a 2nd search
|
||||
i = all.find("\n") + 1
|
||||
line = all[:i]
|
||||
self._buf = all[i:]
|
||||
return line
|
||||
|
||||
def readlines(self, sizehint=0):
|
||||
total = 0
|
||||
list = []
|
||||
while True:
|
||||
line = self.readline()
|
||||
if not line:
|
||||
break
|
||||
list.append(line)
|
||||
total += len(line)
|
||||
if sizehint and total >= sizehint:
|
||||
break
|
||||
return list
|
||||
|
||||
def fileno(self):
|
||||
return self._sock.fileno()
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
line = self.readline()
|
||||
if not line:
|
||||
raise StopIteration
|
||||
return line
|
||||
|
||||
class FakeSocket(SharedSocketClient):
|
||||
|
||||
class _closedsocket:
|
||||
def __getattr__(self, name):
|
||||
raise error(9, 'Bad file descriptor')
|
||||
|
||||
def __init__(self, sock, ssl):
|
||||
sock = SharedSocket(sock)
|
||||
SharedSocketClient.__init__(self, sock)
|
||||
self._ssl = ssl
|
||||
|
||||
def close(self):
|
||||
SharedSocketClient.close(self)
|
||||
self._sock = self.__class__._closedsocket()
|
||||
|
||||
def makefile(self, mode, bufsize=None):
|
||||
if mode != 'r' and mode != 'rb':
|
||||
raise UnimplementedFileMode()
|
||||
return SSLFile(self._shared, self._ssl, bufsize)
|
||||
|
||||
def send(self, stuff, flags = 0):
|
||||
return self._ssl.write(stuff)
|
||||
|
||||
sendall = send
|
||||
|
||||
def recv(self, len = 1024, flags = 0):
|
||||
return self._ssl.read(len)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return getattr(self._sock, attr)
|
||||
|
||||
@@ -27,6 +27,13 @@ import nss.io as io
|
||||
import nss.nss as nss
|
||||
import nss.ssl as ssl
|
||||
|
||||
try:
|
||||
from httplib import SSLFile
|
||||
from httplib import FakeSocket
|
||||
except ImportError:
|
||||
from ipapython.ipasslfile import SSLFile
|
||||
from ipapython.ipasslfile import FakeSocket
|
||||
|
||||
def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):
|
||||
cert = None
|
||||
if chosen_nickname:
|
||||
@@ -49,7 +56,7 @@ def client_auth_data_callback(ca_names, chosen_nickname, password, certdb):
|
||||
return False
|
||||
return False
|
||||
|
||||
class SSLFile(httplib.SSLFile):
|
||||
class SSLFile(SSLFile):
|
||||
"""
|
||||
Override the _read method so we can use the NSS recv method.
|
||||
"""
|
||||
@@ -64,7 +71,7 @@ class SSLFile(httplib.SSLFile):
|
||||
break
|
||||
return buf
|
||||
|
||||
class NSSFakeSocket(httplib.FakeSocket):
|
||||
class NSSFakeSocket(FakeSocket):
|
||||
def makefile(self, mode, bufsize=None):
|
||||
if mode != 'r' and mode != 'rb':
|
||||
raise httplib.UnimplementedFileMode()
|
||||
|
||||
Reference in New Issue
Block a user